├── App.config
├── README.md
├── Properties
├── Settings.settings
├── Settings.Designer.cs
├── AssemblyInfo.cs
├── Resources.Designer.cs
└── Resources.resx
├── Program.cs
├── Form1.resx
├── GameshowSC2.csproj
├── .gitignore
├── Form1.Designer.cs
└── Form1.cs
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GameShowSC2Switcher
2 | Port of XSplitSC2Switcher to work in the GameShow broadcasting app
3 |
4 | [Download](https://github.com/leigholiver/GameShowSC2Switcher/releases/download/0.1/GameshowSC2.exe)
5 |
--------------------------------------------------------------------------------
/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace GameshowSC2
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// The main entry point for the application.
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | Application.EnableVisualStyles();
18 | Application.SetCompatibleTextRenderingDefault(false);
19 | Application.Run(new Form1());
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace GameshowSC2.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("GameshowSC2")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("GameshowSC2")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("7a3a7cec-6779-4438-bcf1-986f4960b5ae")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace GameshowSC2.Properties
12 | {
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GameshowSC2.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Form1.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/GameshowSC2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7A3A7CEC-6779-4438-BCF1-986F4960B5AE}
8 | WinExe
9 | GameshowSC2
10 | GameshowSC2
11 | v4.5.2
12 | 512
13 | true
14 | false
15 | publish\
16 | true
17 | Disk
18 | false
19 | Foreground
20 | 7
21 | Days
22 | false
23 | false
24 | true
25 | 1
26 | 1.0.0.%2a
27 | false
28 | true
29 | true
30 |
31 |
32 | AnyCPU
33 | true
34 | full
35 | false
36 | bin\Debug\
37 | DEBUG;TRACE
38 | prompt
39 | 4
40 |
41 |
42 | AnyCPU
43 | pdbonly
44 | true
45 | bin\Release\
46 | TRACE
47 | prompt
48 | 4
49 |
50 |
51 | 8B2A99242B33A3DE49D19DD2DBB7694D790B6ACB
52 |
53 |
54 | GameshowSC2_TemporaryKey.pfx
55 |
56 |
57 | true
58 |
59 |
60 | true
61 |
62 |
63 | bin\Release32\
64 | TRACE
65 | true
66 | pdbonly
67 | AnyCPU
68 | prompt
69 | MinimumRecommendedRules.ruleset
70 | true
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | Form
88 |
89 |
90 | Form1.cs
91 |
92 |
93 |
94 |
95 | Form1.cs
96 |
97 |
98 | ResXFileCodeGenerator
99 | Resources.Designer.cs
100 | Designer
101 |
102 |
103 | True
104 | Resources.resx
105 |
106 |
107 |
108 | SettingsSingleFileGenerator
109 | Settings.Designer.cs
110 |
111 |
112 | True
113 | Settings.settings
114 | True
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | False
123 | Microsoft .NET Framework 4.5.2 %28x86 and x64%29
124 | true
125 |
126 |
127 | False
128 | .NET Framework 3.5 SP1
129 | false
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
--------------------------------------------------------------------------------
/Form1.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace GameshowSC2
2 | {
3 | partial class Form1
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.inGameList = new System.Windows.Forms.ComboBox();
32 | this.outGameList = new System.Windows.Forms.ComboBox();
33 | this.ipBox = new System.Windows.Forms.TextBox();
34 | this.layerBox = new System.Windows.Forms.ComboBox();
35 | this.label1 = new System.Windows.Forms.Label();
36 | this.label2 = new System.Windows.Forms.Label();
37 | this.label3 = new System.Windows.Forms.Label();
38 | this.label4 = new System.Windows.Forms.Label();
39 | this.button1 = new System.Windows.Forms.Button();
40 | this.textBox1 = new System.Windows.Forms.TextBox();
41 | this.errorLabel = new System.Windows.Forms.Label();
42 | this.label5 = new System.Windows.Forms.Label();
43 | this.label6 = new System.Windows.Forms.Label();
44 | this.textBox2 = new System.Windows.Forms.TextBox();
45 | this.button2 = new System.Windows.Forms.Button();
46 | this.SuspendLayout();
47 | //
48 | // inGameList
49 | //
50 | this.inGameList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
51 | this.inGameList.FormattingEnabled = true;
52 | this.inGameList.Location = new System.Drawing.Point(119, 87);
53 | this.inGameList.Name = "inGameList";
54 | this.inGameList.Size = new System.Drawing.Size(152, 21);
55 | this.inGameList.TabIndex = 0;
56 | //
57 | // outGameList
58 | //
59 | this.outGameList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
60 | this.outGameList.FormattingEnabled = true;
61 | this.outGameList.Location = new System.Drawing.Point(119, 129);
62 | this.outGameList.Name = "outGameList";
63 | this.outGameList.Size = new System.Drawing.Size(152, 21);
64 | this.outGameList.TabIndex = 1;
65 | //
66 | // ipBox
67 | //
68 | this.ipBox.Location = new System.Drawing.Point(119, 265);
69 | this.ipBox.Name = "ipBox";
70 | this.ipBox.Size = new System.Drawing.Size(152, 20);
71 | this.ipBox.TabIndex = 2;
72 | //
73 | // layerBox
74 | //
75 | this.layerBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
76 | this.layerBox.FormattingEnabled = true;
77 | this.layerBox.Items.AddRange(new object[] {
78 | "Master Layer 1",
79 | "Master Layer 2",
80 | "Master Layer 3",
81 | "Master Layer 4",
82 | "Master Layer 5"});
83 | this.layerBox.Location = new System.Drawing.Point(119, 47);
84 | this.layerBox.Name = "layerBox";
85 | this.layerBox.Size = new System.Drawing.Size(152, 21);
86 | this.layerBox.TabIndex = 3;
87 | this.layerBox.SelectedIndexChanged += new System.EventHandler(this.layerBox_SelectedIndexChanged);
88 | //
89 | // label1
90 | //
91 | this.label1.AutoSize = true;
92 | this.label1.Location = new System.Drawing.Point(80, 50);
93 | this.label1.Name = "label1";
94 | this.label1.Size = new System.Drawing.Size(33, 13);
95 | this.label1.TabIndex = 4;
96 | this.label1.Text = "Layer";
97 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
98 | //
99 | // label2
100 | //
101 | this.label2.AutoSize = true;
102 | this.label2.Location = new System.Drawing.Point(41, 90);
103 | this.label2.Name = "label2";
104 | this.label2.Size = new System.Drawing.Size(72, 13);
105 | this.label2.TabIndex = 5;
106 | this.label2.Text = "In Game Shot";
107 | this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
108 | //
109 | // label3
110 | //
111 | this.label3.AutoSize = true;
112 | this.label3.Location = new System.Drawing.Point(21, 132);
113 | this.label3.Name = "label3";
114 | this.label3.Size = new System.Drawing.Size(92, 13);
115 | this.label3.TabIndex = 6;
116 | this.label3.Text = "Out of Game Shot";
117 | this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
118 | //
119 | // label4
120 | //
121 | this.label4.AutoSize = true;
122 | this.label4.Location = new System.Drawing.Point(15, 268);
123 | this.label4.Name = "label4";
124 | this.label4.Size = new System.Drawing.Size(98, 13);
125 | this.label4.TabIndex = 7;
126 | this.label4.Text = "SC2 PC IP Address";
127 | //
128 | // button1
129 | //
130 | this.button1.Location = new System.Drawing.Point(18, 172);
131 | this.button1.Name = "button1";
132 | this.button1.Size = new System.Drawing.Size(253, 23);
133 | this.button1.TabIndex = 8;
134 | this.button1.Text = "Start";
135 | this.button1.UseVisualStyleBackColor = true;
136 | this.button1.Click += new System.EventHandler(this.button1_Click);
137 | //
138 | // textBox1
139 | //
140 | this.textBox1.ForeColor = System.Drawing.SystemColors.WindowFrame;
141 | this.textBox1.Location = new System.Drawing.Point(382, 12);
142 | this.textBox1.Multiline = true;
143 | this.textBox1.Name = "textBox1";
144 | this.textBox1.Size = new System.Drawing.Size(240, 212);
145 | this.textBox1.TabIndex = 9;
146 | //
147 | // errorLabel
148 | //
149 | this.errorLabel.Location = new System.Drawing.Point(18, 198);
150 | this.errorLabel.Name = "errorLabel";
151 | this.errorLabel.Size = new System.Drawing.Size(253, 22);
152 | this.errorLabel.TabIndex = 10;
153 | this.errorLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
154 | //
155 | // label5
156 | //
157 | this.label5.AutoSize = true;
158 | this.label5.Location = new System.Drawing.Point(41, 297);
159 | this.label5.MaximumSize = new System.Drawing.Size(200, 0);
160 | this.label5.Name = "label5";
161 | this.label5.Size = new System.Drawing.Size(195, 91);
162 | this.label5.TabIndex = 11;
163 | this.label5.Text = "Note: You need to go into the Battle.net launcher, click Options, Game Settings, " +
164 | "check \'Additional command line arguments\' and paste the following into the texbo" +
165 | "x:\r\n \r\n\r\n";
166 | this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
167 | //
168 | // label6
169 | //
170 | this.label6.AutoSize = true;
171 | this.label6.Location = new System.Drawing.Point(41, 240);
172 | this.label6.Name = "label6";
173 | this.label6.Size = new System.Drawing.Size(195, 13);
174 | this.label6.TabIndex = 12;
175 | this.label6.Text = "If you are using a second PC to stream: ";
176 | //
177 | // textBox2
178 | //
179 | this.textBox2.Location = new System.Drawing.Point(92, 368);
180 | this.textBox2.Name = "textBox2";
181 | this.textBox2.Size = new System.Drawing.Size(100, 20);
182 | this.textBox2.TabIndex = 13;
183 | this.textBox2.Text = "-clientapi 6119";
184 | this.textBox2.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
185 | //
186 | // button2
187 | //
188 | this.button2.Location = new System.Drawing.Point(190, 12);
189 | this.button2.Name = "button2";
190 | this.button2.Size = new System.Drawing.Size(81, 23);
191 | this.button2.TabIndex = 14;
192 | this.button2.Text = "Save Settings";
193 | this.button2.UseVisualStyleBackColor = true;
194 | this.button2.Click += new System.EventHandler(this.button2_Click);
195 | //
196 | // Form1
197 | //
198 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
199 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
200 | this.ClientSize = new System.Drawing.Size(285, 396);
201 | this.Controls.Add(this.button2);
202 | this.Controls.Add(this.textBox2);
203 | this.Controls.Add(this.label6);
204 | this.Controls.Add(this.label5);
205 | this.Controls.Add(this.errorLabel);
206 | this.Controls.Add(this.textBox1);
207 | this.Controls.Add(this.button1);
208 | this.Controls.Add(this.label4);
209 | this.Controls.Add(this.label3);
210 | this.Controls.Add(this.label2);
211 | this.Controls.Add(this.label1);
212 | this.Controls.Add(this.layerBox);
213 | this.Controls.Add(this.ipBox);
214 | this.Controls.Add(this.outGameList);
215 | this.Controls.Add(this.inGameList);
216 | this.Name = "Form1";
217 | this.Text = "GameShow SC2 Switcher";
218 | this.Load += new System.EventHandler(this.Form1_Load);
219 | this.ResumeLayout(false);
220 | this.PerformLayout();
221 |
222 | }
223 |
224 | #endregion
225 |
226 | private System.Windows.Forms.ComboBox inGameList;
227 | private System.Windows.Forms.ComboBox outGameList;
228 | private System.Windows.Forms.TextBox ipBox;
229 | private System.Windows.Forms.ComboBox layerBox;
230 | private System.Windows.Forms.Label label1;
231 | private System.Windows.Forms.Label label2;
232 | private System.Windows.Forms.Label label3;
233 | private System.Windows.Forms.Label label4;
234 | private System.Windows.Forms.Button button1;
235 | private System.Windows.Forms.TextBox textBox1;
236 | private System.Windows.Forms.Label errorLabel;
237 | private System.Windows.Forms.Label label5;
238 | private System.Windows.Forms.Label label6;
239 | private System.Windows.Forms.TextBox textBox2;
240 | private System.Windows.Forms.Button button2;
241 | }
242 | }
243 |
244 |
--------------------------------------------------------------------------------
/Form1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Forms;
4 | using System.Runtime.InteropServices;
5 | using System.Reflection;
6 | using System.Timers;
7 | using System.Net;
8 | using System.IO;
9 | using System.Xml;
10 |
11 | namespace GameshowSC2
12 | {
13 | public partial class Form1 : Form
14 | {
15 | private WirecastBinding _Wirecast;
16 | private BindingList inGameShotList;
17 | private BindingList outGameShotList;
18 | private System.Timers.Timer _timer;
19 |
20 | private Boolean isRunning;
21 | private Boolean inGame;
22 |
23 | public Form1()
24 | {
25 | InitializeComponent();
26 | _Wirecast = new WirecastBinding();
27 | _Wirecast.Initialize();
28 |
29 | inGameShotList = new BindingList();
30 | inGameList.DataSource = inGameShotList;
31 | inGameList.DisplayMember = "statusName";
32 |
33 | outGameShotList = new BindingList();
34 | outGameList.DataSource = outGameShotList;
35 | outGameList.DisplayMember = "statusName";
36 |
37 | isRunning = false;
38 | inGame = false;
39 |
40 | _timer = new System.Timers.Timer(1000);
41 | _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
42 | _timer.Start();
43 | checkSC2State();
44 | }
45 |
46 | private void layerBox_SelectedIndexChanged(object sender, EventArgs e)
47 | {
48 | int selIndex = layerBox.SelectedIndex + 1;
49 | _Wirecast.SwitchLayer(selIndex);
50 | LoadLayerShots();
51 | }
52 |
53 | private void LoadLayerShots()
54 | {
55 | inGameShotList.Clear();
56 | outGameShotList.Clear();
57 |
58 | // Populate Listbox with shots
59 | int count = _Wirecast.GetShotCount();
60 | for (int idx = 1; idx <= count; idx++)
61 | {
62 | string name = _Wirecast.GetShotNameWithIndex(idx);
63 | bool isInPreview = _Wirecast.IsShotNameInPreview(name);
64 | bool isLive = _Wirecast.IsShotNameLive(name);
65 | bool isPlaylist = _Wirecast.IsPlaylistByShotName(name);
66 |
67 | ShotItem sItem = new ShotItem();
68 | sItem.name = name;
69 | sItem.id = _Wirecast.GetShotIDByName(name);
70 | sItem.UpdateStatusName(isLive, isInPreview, isPlaylist);
71 | inGameShotList.Add(sItem);
72 | outGameShotList.Add(sItem);
73 | }
74 | }
75 |
76 | private void button1_Click(object sender, EventArgs e)
77 | {
78 | toggleRunning();
79 | }
80 |
81 | private void toggleRunning()
82 | {
83 | if (isRunning)
84 | {
85 | inGameList.Enabled = true;
86 | outGameList.Enabled = true;
87 | ipBox.Enabled = true;
88 | layerBox.Enabled = true;
89 |
90 | isRunning = false;
91 | button1.Text = "Start";
92 | }
93 | else
94 | {
95 | inGameList.Enabled = false;
96 | outGameList.Enabled = false;
97 | ipBox.Enabled = false;
98 | layerBox.Enabled = false;
99 |
100 | isRunning = true;
101 | button1.Text = "Stop";
102 | }
103 | }
104 |
105 | private void _timer_Elapsed(object sender, ElapsedEventArgs e)
106 | {
107 | checkSC2State();
108 | }
109 |
110 | private void checkSC2State() {
111 | String ip = "localhost";
112 | if (ipBox.Text != "")
113 | {
114 | ip = ipBox.Text;
115 | }
116 |
117 | String url = "http://" + ip + ":6119/ui";
118 | WebRequest request = WebRequest.Create(url);
119 | request.Timeout = 1000;
120 |
121 | try
122 | {
123 | WebResponse response = request.GetResponse();
124 | Stream dataStream = response.GetResponseStream();
125 | StreamReader reader = new StreamReader(dataStream);
126 | string responseFromServer = reader.ReadToEnd();
127 | reader.Close();
128 | response.Close();
129 |
130 | // this is disgusting but im just prototyping and i kinda dont really
131 | // need to go through the hassle of working out json parsing libraries
132 | // #SorryNotSorry
133 | Boolean tmpInGame = false;
134 | if (responseFromServer == "{\"activeScreens\":[\"ScreenLoading/ScreenLoading\"]}" || responseFromServer == "{\"activeScreens\":[]}")
135 | {
136 | tmpInGame = true;
137 | }
138 | Invoke(new Action(() =>
139 | {
140 | errorLabel.Text = "";
141 | textBox1.Text = responseFromServer;
142 |
143 | if (inGame && !tmpInGame) // state has changed from in game to out of game
144 | {
145 | inGame = false;
146 | errorLabel.Text = "out of game";
147 | if (isRunning)
148 | {
149 | ShotItem sItem = (ShotItem)outGameList.SelectedItem;
150 | _Wirecast.SetActiveShot(sItem.name);
151 | _Wirecast.Go();
152 | }
153 | }
154 | else if(!inGame && tmpInGame) // state has changed from out of game to in game
155 | {
156 | inGame = true;
157 | errorLabel.Text = "in game";
158 | if (isRunning)
159 | {
160 | ShotItem sItem = (ShotItem)inGameList.SelectedItem;
161 | _Wirecast.SetActiveShot(sItem.name);
162 | _Wirecast.Go();
163 | }
164 | }
165 | }));
166 | }
167 | catch (Exception)
168 | {
169 | try
170 | {
171 | Invoke(new Action(() =>
172 | {
173 | errorLabel.Text = "Could not reach SC2";
174 | }));
175 | }
176 | catch (Exception)
177 | {
178 | // do nothing
179 | }
180 | }
181 | }
182 |
183 | private void Form1_Load(object sender, EventArgs e)
184 | {
185 | try
186 | {
187 | FormSerialisor.Deserialise(this, Application.StartupPath + @"\cfg.xml");
188 | }
189 | catch (Exception)
190 | {
191 | errorLabel.Text = "Error loading configuration";
192 | }
193 | }
194 |
195 | private void button2_Click(object sender, EventArgs e)
196 | {
197 | FormSerialisor.Serialise(this, Application.StartupPath + @"\cfg.xml");
198 | }
199 | }
200 |
201 | public class ShotItem
202 | {
203 | public string name { get; set; }
204 | public int id { get; set; }
205 | public string statusName { get; set; }
206 | public void UpdateStatusName(bool live, bool preview, bool playlist)
207 | {
208 | statusName = name;
209 | }
210 | }
211 |
212 | ///
213 | /// Proxy Object for the Late binding
214 | /// Provide more logical API for bindings
215 | ///
216 | public class WirecastBinding
217 | {
218 | private object _Wirecast;
219 | private object _Document;
220 | private object _SelectedLayer;
221 | private int _SelectedLayerIndex;
222 |
223 | ///
224 | /// Late binding helper class.
225 | /// static bindings to help you get/set via OLE/COM.
226 | ///
227 | class Late
228 | {
229 | public static void Set(object obj, string sProperty, object oValue)
230 | {
231 | object[] oParam = new object[1];
232 | oParam[0] = oValue;
233 | obj.GetType().InvokeMember(sProperty, BindingFlags.SetProperty, null, obj, oParam);
234 | }
235 | public static object Get(object obj, string sProperty, object oValue)
236 | {
237 | object[] oParam = new object[1];
238 | oParam[0] = oValue;
239 | return obj.GetType().InvokeMember(sProperty, BindingFlags.GetProperty, null, obj, oParam);
240 | }
241 | public static object Get(object obj, string sProperty, object[] oValue)
242 | {
243 | return obj.GetType().InvokeMember(sProperty, BindingFlags.GetProperty, null, obj, oValue);
244 | }
245 | public static object Get(object obj, string sProperty)
246 | {
247 | return obj.GetType().InvokeMember(sProperty, BindingFlags.GetProperty, null, obj, null);
248 | }
249 | public static object Invoke(object obj, string sProperty, object[] oParam)
250 | {
251 | return obj.GetType().InvokeMember(sProperty, BindingFlags.InvokeMethod, null, obj, oParam);
252 | }
253 | public static object Invoke(object obj, string sProperty, object oValue)
254 | {
255 | object[] oParam = new object[1];
256 | oParam[0] = oValue;
257 | return obj.GetType().InvokeMember(sProperty, BindingFlags.InvokeMethod, null, obj, oParam);
258 | }
259 | public static object Invoke(object obj, string sProperty, object oValue, object oValue2)
260 | {
261 | object[] oParam = new object[2];
262 | oParam[0] = oValue;
263 | oParam[1] = oValue2;
264 | return obj.GetType().InvokeMember(sProperty, BindingFlags.InvokeMethod, null, obj, oParam);
265 | }
266 | public static object Invoke(object obj, string sProperty)
267 | {
268 | return obj.GetType().InvokeMember(sProperty, BindingFlags.InvokeMethod, null, obj, null);
269 | }
270 | }
271 |
272 | ///
273 | /// Initialize the Binding object with Document Index 1
274 | /// And the Normal Layer (3) Selected
275 | ///
276 | public void Initialize()
277 | {
278 | _Wirecast = null;
279 | _Document = null;
280 | _SelectedLayer = null;
281 | _SelectedLayerIndex = -1;
282 | try
283 | {
284 | _Wirecast = Marshal.GetActiveObject("Wirecast.Application");
285 | }
286 | catch
287 | {
288 | Type objClassType = Type.GetTypeFromProgID("Wirecast.Application");
289 | _Wirecast = Activator.CreateInstance(objClassType);
290 | }
291 |
292 | SwitchDocument(1);
293 | }
294 |
295 | ///
296 | /// Returns a string array of the layer names
297 | ///
298 | public string[] ValidLayerNames()
299 | {
300 | return new string[] { "text", "overlay", "normal", "underlay", "audio" };
301 | }
302 |
303 | ///
304 | /// Converts a given Layer Name to the associated Index value
305 | /// If the name is invalid, returns -1
306 | ///
307 | public int LayerNameToIndex(string layer)
308 | {
309 | string[] layerNames = ValidLayerNames();
310 | for (int i = 0; i < 5; i++)
311 | {
312 | if (layerNames[i] == layer)
313 | {
314 | return i + 1;
315 | }
316 | }
317 |
318 | return -1;
319 | }
320 | ///
321 | /// Get the Name of the layer associated with the index value.
322 | /// If the index is out of bounds, returns an empty string
323 | ///
324 | public string LayerIndexToName(int index)
325 | {
326 | if (index >= 1 && index <= 5)
327 | {
328 | string[] layerNames = ValidLayerNames();
329 | return layerNames[index - 1];
330 | }
331 |
332 | return "";
333 | }
334 |
335 | ///
336 | /// Switches the internal document of the binding object to the new one
337 | /// The seletec layer of the new document will be the same as the previous document
338 | /// So if the selected layer was "text"/1, then that is the selected layer of the new document
339 | /// All future call to the Document and Layer API will apply to the new document
340 | ///
341 | public bool SwitchDocument(int index)
342 | {
343 | bool validDoc = false;
344 | object newDocument = Late.Invoke(_Wirecast, "DocumentByIndex", index);
345 |
346 | if (newDocument != null)
347 | {
348 | _Document = newDocument;
349 | validDoc = true;
350 |
351 | // After Change the Document, we need to update the layer
352 | SwitchLayer(3);
353 | }
354 |
355 | return validDoc;
356 | }
357 |
358 | ///
359 | /// Same as SwitchDocument with an index except indead of a document index, use the document name
360 | ///
361 | public bool SwitchDocument(string docName)
362 | {
363 | bool validDoc = false;
364 | object newDocument = Late.Invoke(_Wirecast, "DocumentByName", docName);
365 |
366 | if (newDocument != null)
367 | {
368 | _Document = newDocument;
369 | validDoc = true;
370 |
371 | // After Change the Document, we need to update the layer
372 | SwitchLayer(_SelectedLayerIndex); // 3 is the "normal" layer
373 | }
374 |
375 | return validDoc;
376 | }
377 |
378 | ///
379 | /// Returns the index of the currently selected layer
380 | ///
381 | public int GetSelectedLayerIndex()
382 | {
383 | return _SelectedLayerIndex;
384 | }
385 |
386 | ///
387 | /// Returns the name of the currently selected layer
388 | ///
389 | public string GetSelectedLayerName()
390 | {
391 | return LayerIndexToName(_SelectedLayerIndex);
392 | }
393 |
394 | ///
395 | /// Returns the number of master layers in the system
396 | ///
397 | public int GetMasterLayerCount()
398 | {
399 | return 5;
400 | }
401 |
402 | ///
403 | /// Change the internal selected layer of the binding object
404 | /// All future calls to layer related APIs will be use this new layer
405 | ///
406 | public bool SwitchLayer(int index)
407 | {
408 | bool hasLayer = false;
409 | string layerName = LayerIndexToName(index);
410 |
411 | if (layerName != "")
412 | {
413 | _SelectedLayer = Late.Invoke(_Document, "LayerByName", layerName);
414 | _SelectedLayerIndex = index;
415 | hasLayer = true;
416 | }
417 |
418 | return hasLayer;
419 | }
420 |
421 | ///
422 | /// Change the internal selected layer of the binding object
423 | /// All future calls to layer related APIs will be use this new layer
424 | ///
425 | public bool SwitchLayer(string name)
426 | {
427 | bool validName = false;
428 | int index = LayerNameToIndex(name.ToLower());
429 |
430 | if (index != -1)
431 | {
432 | SwitchLayer(index);
433 | validName = true;
434 | }
435 |
436 | return validName;
437 | }
438 |
439 | ///
440 | /// Return whether or not the current document is broadcasting a stream
441 | ///
442 | public bool IsBroadcasting()
443 | {
444 | int isBroadcasting = (int)Late.Invoke(_Document, "IsBroadcasting");
445 | return isBroadcasting == 1;
446 | }
447 |
448 | ///
449 | /// Toggles the Broadcast state
450 | /// If it is not broadcasting, start a broadcast
451 | /// If it is, stop it
452 | ///
453 | public void ToggleBroadcast()
454 | {
455 | if (IsBroadcasting())
456 | {
457 | StopBroadcast();
458 | }
459 | else
460 | {
461 | StartBroadcast();
462 | }
463 | }
464 | public void StartBroadcast()
465 | {
466 | Late.Invoke(_Document, "Broadcast", "start");
467 | }
468 | public void StopBroadcast()
469 | {
470 | Late.Invoke(_Document, "Broadcast", "stop");
471 | }
472 |
473 | ///
474 | /// Returns whether or not the current document is recording to disk
475 | ///
476 | public bool IsRecording()
477 | {
478 | int isRecording = (int)Late.Invoke(_Document, "IsArchivingToDisk");
479 | return isRecording == 1;
480 | }
481 |
482 | ///
483 | /// Toggles the Record to Disk state
484 | /// If it is not recording, start the recording
485 | /// If it is, stop it
486 | ///
487 | public void ToggleRecord()
488 | {
489 | if (IsRecording())
490 | {
491 | StopRecording();
492 | }
493 | else
494 | {
495 | StartRecording();
496 | }
497 | }
498 | public void StartRecording()
499 | {
500 | Late.Invoke(_Document, "ArchiveToDisk", "start");
501 | }
502 | public void StopRecording()
503 | {
504 | Late.Invoke(_Document, "ArchiveToDisk", "stop");
505 | }
506 |
507 | ///
508 | /// Returns the total umber of shots in the selected layer
509 | /// To change which layer to count the shots in, use switch layers
510 | /// To get the total number of shots in the document, use GetTotalShotCount
511 | ///
512 | public int GetShotCount()
513 | {
514 | int shotCount = (int)Late.Invoke(_SelectedLayer, "ShotCount");
515 | return shotCount;
516 | }
517 |
518 | ///
519 | /// Returns the total number of shots in the document
520 | ///
521 | public int GetTotalShotCount()
522 | {
523 | int totalLayers = GetMasterLayerCount();
524 | int totalShotCount = 0;
525 | for (int i = 0; i < totalLayers; i++)
526 | {
527 | totalShotCount += (int)Late.Invoke(i, "ShotCount");
528 | }
529 |
530 | return totalShotCount;
531 | }
532 |
533 | ///
534 | /// Returns the ShotID for associated with the Shot name
535 | /// The name is the text under the shot in the Shot bin
536 | ///
537 | public int GetShotIDByName(string name)
538 | {
539 | int shotID = (int)Late.Invoke(_SelectedLayer, "ShotIDByName", name, 2);
540 | return shotID;
541 | }
542 |
543 | ///
544 | /// Returns the ShotID for the index within the selected layer
545 | /// The index is Zero based and from left to right in the layer
546 | ///
547 | public int GetShotIDByIndex(int index)
548 | {
549 | int shotID = (int)Late.Invoke(_SelectedLayer, "ShotIDByIndex", index);
550 | return shotID;
551 | }
552 |
553 | ///
554 | /// Returns the Shot COM object for the index
555 | /// Usually would not need to call this method directly
556 | ///
557 | /// Returns null if there are no shots assoicated witht he index
558 | ///
559 | public object GetShotWithIndex(int index)
560 | {
561 | object shot = null;
562 | int shotID = GetShotIDByIndex(index);
563 |
564 | if (shotID != 0)
565 | {
566 | shot = GetShotWithID(shotID);
567 | }
568 |
569 | return shot;
570 | }
571 |
572 | ///
573 | /// Returns the Shot COM object for the shotID
574 | /// Usually would not need to call this method directly
575 | ///
576 | /// Returns null if there are no shots assoicated witht he shotID
577 | ///
578 | public object GetShotWithID(int shotID)
579 | {
580 | return Late.Invoke(_Document, "ShotByShotID", shotID);
581 | }
582 |
583 | ///
584 | /// Returns the Shot COM object for the name
585 | /// Usually would not need to call this method directly
586 | ///
587 | /// Returns null if there are no shots assoicated witht he name
588 | ///
589 | public object GetShotWithName(string name)
590 | {
591 | int shotID = GetShotIDByName(name);
592 | return GetShotWithID(shotID);
593 | }
594 |
595 | ///
596 | /// Returns the name of the shot associated with the shotID
597 | /// If there are no shots associated with that ID, returns an empty string
598 | ///
599 | public string GetShotNameWithID(int shotID)
600 | {
601 | object shot = GetShotWithID(shotID);
602 | if (shot != null)
603 | {
604 | return (string)Late.Get(shot, "Name");
605 | }
606 | else
607 | {
608 | return "";
609 | }
610 | }
611 |
612 | ///
613 | /// Returns the name of the shot at "index"
614 | /// If there are no shots associated with the index, returns an empty string
615 | ///
616 | public string GetShotNameWithIndex(int index)
617 | {
618 | int shotID = GetShotIDByIndex(index);
619 | return GetShotNameWithID(shotID);
620 | }
621 |
622 | ///
623 | /// Sets the name of the shot associated with the shot ID
624 | /// Returns true if the name was set successfully
625 | /// Returns false if there is no shot associated with the shot ID
626 | ///
627 | public bool SetShotNameWithID(int shotID, string newName)
628 | {
629 | bool isShotValid = false;
630 | object shot = GetShotWithID(shotID);
631 |
632 | if (shot != null)
633 | {
634 | Late.Set(shot, "Name", newName);
635 | isShotValid = true;
636 | }
637 |
638 | return isShotValid;
639 | }
640 |
641 | ///
642 | /// Returns true if the name was set successfully
643 | /// Returns false if there is no shot called "oldName"
644 | ///
645 | public bool SetShotNameWithName(string oldName, string newName)
646 | {
647 | bool isShotValid = false;
648 | object shot = GetShotWithName(oldName);
649 | if (shot != null)
650 | {
651 | Late.Set(shot, "Name", newName);
652 | isShotValid = true;
653 | }
654 | return isShotValid;
655 | }
656 |
657 | ///
658 | /// Returns true if the speed input string is a valid transition speed name
659 | /// Returns false if it is not
660 | ///
661 | private bool isSpeedValid(string speed)
662 | {
663 | bool isValid = (speed == "slowest" || speed == "slow" || speed == "normal" || speed == "faster" || speed == "fastest");
664 | return isValid;
665 | }
666 |
667 | ///
668 | /// Returns a string array of all the valid Transition Speeds
669 | ///
670 | public string[] GetValidTransitionSpeeds()
671 | {
672 | return new string[] { "slowest", "slow", "normal", "faster", "fastest" };
673 | }
674 |
675 | ///
676 | /// Returns the currently select Transition speed name
677 | ///
678 | /// For a list of valid transition speeds, see GetValidTransitionSpeeds()
679 | ///
680 | public string GetTransitionSpeed()
681 | {
682 | string transSpeed = (string)Late.Get(_Document, "TransitionSpeed");
683 | return transSpeed;
684 | }
685 |
686 | ///
687 | /// Sets the Transition speed of the durrent document
688 | /// Returns true if the speed is valie
689 | /// Returns false if the speed is invalid
690 | ///
691 | /// For a list of valid transition speeds, see GetValidTransitionSpeeds()
692 | ///
693 | public bool SetTransitionSpeed(string speed)
694 | {
695 | string lowerSpeed = speed.ToLower();
696 | bool isValidSpeed = isSpeedValid(lowerSpeed);
697 | if (isValidSpeed)
698 | {
699 | Late.Set(_Document, "TransitionSpeed", lowerSpeed);
700 | }
701 |
702 | return isValidSpeed;
703 | }
704 |
705 | ///
706 | /// Returns the current sate of AutoLive in the selected document
707 | ///
708 | public bool IsAutoLiveOn()
709 | {
710 | int autoLiveOn = (int)Late.Get(_Document, "AutoLive");
711 | return autoLiveOn == 1;
712 | }
713 |
714 | ///
715 | /// Toggles the AutoLive state
716 | /// If it is off, turn it on
717 | /// If it is on, turn it off
718 | ///
719 | public void ToggleAutoLive()
720 | {
721 | SetAutoLive(!IsAutoLiveOn());
722 | }
723 | public void SetAutoLive(bool on)
724 | {
725 | Late.Set(_Document, "AutoLive", on);
726 | }
727 |
728 | ///
729 | /// Returns true if the index maps to a Transition popup in Wirecast, false otherwise
730 | ///
731 | public bool isTransitionIndexValid(int index)
732 | {
733 | return (index == 1 || index == 2);
734 | }
735 |
736 | ///
737 | /// Returns the index of the currently active Transition popup
738 | /// A value of 0 represents the left most popup in the Wirecast UI
739 | ///
740 | public int GetActiveTransitionIndex()
741 | {
742 | int activeTransIndex = (int)Late.Get(_Document, "ActiveTransitionIndex");
743 | return activeTransIndex;
744 | }
745 |
746 | ///
747 | /// Set the Active Transition popup in Wirecast
748 | /// A value of 0 represents the left most popup in the Wirecast UI
749 | ///
750 | public bool SetActiveTransitionIndex(int index)
751 | {
752 | bool isIndexValid = isTransitionIndexValid(index);
753 | if (isIndexValid)
754 | {
755 | Late.Set(_Document, "ActiveTransitionIndex", index);
756 | }
757 | return isIndexValid;
758 | }
759 |
760 | ///
761 | /// Returns true if the Audio is muted tot he speakers
762 | ///
763 | public bool IsAudioMutedToSpeakers()
764 | {
765 | int audioMuted = (int)Late.Get(_Document, "AudioMutedToSpeaker");
766 | return audioMuted == 1;
767 | }
768 | public void ToggleAudioMutedToSpeakers()
769 | {
770 | bool audioMuted = IsAudioMutedToSpeakers();
771 | SetAudioMutedToSpeakers(!audioMuted);
772 | }
773 | public void SetAudioMutedToSpeakers(bool muted)
774 | {
775 | Late.Set(_Document, "AudioMutedToSpeaker", muted);
776 | }
777 |
778 | ///
779 | /// Takes a snapshot still image of the current output and saves it as a JPEG to the given path
780 | ///
781 | public void SaveSnapshot(string path)
782 | {
783 | Late.Invoke(_Document, "SaveSnapshot", path);
784 | }
785 |
786 | ///
787 | /// Remove the media asset at the given path from Wirecast
788 | /// The path is not the shot name, but the actual media location on disk
789 | ///
790 | public void RemoveMedia(string path)
791 | {
792 | Late.Invoke(_Document, "RemoveMedia", path);
793 | }
794 |
795 | ///
796 | /// Creates a new shot with the asset located in the given path and adds it to the currently selected layer
797 | ///
798 | public int AddShotWithMedia(string path)
799 | {
800 | int shotID = (int)Late.Invoke(_SelectedLayer, "AddShotWithMedia", path);
801 | return shotID;
802 | }
803 |
804 | ///
805 | /// Removes the shot with the given ID from the currently selected layer
806 | /// Does nothing if the shot ID is invalid or not associated with any shots in the currently selected layer
807 | ///
808 | public void RemoveShotWithID(int shotID)
809 | {
810 | Late.Invoke(_SelectedLayer, "RemoveShotByID", shotID);
811 | }
812 |
813 | ///
814 | /// Removes the shot with the given name from the currently selected layer
815 | /// Does nothing if the name is not associated with any shots in the currently selected layer
816 | ///
817 | public void RemoveShotWithName(string name)
818 | {
819 | int shotID = GetShotIDByName(name);
820 | RemoveShotWithID(shotID);
821 | }
822 |
823 | ///
824 | /// Makes the active shot of the selected layer go live
825 | ///
826 | public void Go()
827 | {
828 | Late.Invoke(_SelectedLayer, "Go");
829 | }
830 |
831 | ///
832 | /// Returns true if the currently selected layer is visible, false otherwise
833 | ///
834 | public bool IsLayerVisible()
835 | {
836 | int visible = (int)Late.Get(_SelectedLayer, "Visible");
837 | return visible == 1;
838 | }
839 |
840 | ///
841 | /// Toggles the selected layer's visibility
842 | ///
843 | public void ToggleLayerVisibility()
844 | {
845 | bool visible = IsLayerVisible();
846 | Late.Set(_SelectedLayer, "Visible", !visible);
847 | }
848 |
849 | ///
850 | /// Returns true if the shot ID is the ID of current active shot of the currently selected layer
851 | /// Returns false if the shot ID is invalid or not in the currently selected layer
852 | ///
853 | public bool IsActiveShot(int shotID)
854 | {
855 | int activeShotID = GetActiveShotID();
856 | return activeShotID == shotID;
857 | }
858 |
859 | ///
860 | /// Returns true if the name is the name of the current active shot of the currently selected layer
861 | /// Returns false if the name is not
862 | ///
863 | public bool IsActiveShot(string name)
864 | {
865 | string activeShotName = GetActiveShotName();
866 | return activeShotName == name;
867 | }
868 |
869 | ///
870 | /// Returns the shot ID of the active shot, of the currently selected layer
871 | /// The Active shot is equivilent to the shot the user has clicked
872 | /// It doesn't mean the shot that is currently live or in preview, though it is possible the active shot is live or in preview
873 | ///
874 | public int GetActiveShotID()
875 | {
876 | int shotID = (int)Late.Get(_SelectedLayer, "ActiveShotID");
877 | return shotID;
878 | }
879 |
880 | ///
881 | /// Sets the active shot of the currently selected layer
882 | /// The Active shot is equivilent to the shot the user has clicked, so this method is the same as when a user clicked the shot
883 | /// It doesn't mean the shot that is currently live or in preview, though it is possible the active shot is live or in preview
884 | ///
885 | public bool SetActiveShot(int shotID)
886 | {
887 | bool isShotValid = false;
888 | object shot = GetShotWithID(shotID);
889 | if (shot != null)
890 | {
891 | Late.Set(_SelectedLayer, "ActiveShotID", shotID);
892 | }
893 | return isShotValid;
894 | }
895 | public bool SetActiveShot(string name)
896 | {
897 | bool isShotValid = false;
898 | object shot = GetShotWithName(name);
899 | if (shot != null)
900 | {
901 | int shotID = GetShotIDByName(name);
902 | Late.Set(_SelectedLayer, "ActiveShotID", shotID);
903 | }
904 | return isShotValid;
905 | }
906 |
907 | ///
908 | /// Returns the shot info of the shot currently in preview, of the currently selected layer
909 | /// The shot in preview is equivilent to the active shot
910 | ///
911 | public int GetPreviewShotID()
912 | {
913 | int shotID = (int)Late.Invoke(_SelectedLayer, "PreviewShotID");
914 | return shotID;
915 | }
916 | public string GetPreviewShotName()
917 | {
918 | int shotID = GetPreviewShotID();
919 | return GetShotNameWithID(shotID);
920 | }
921 | public object GetPreviewShot()
922 | {
923 | int shotID = GetPreviewShotID();
924 | return GetShotWithID(shotID);
925 | }
926 |
927 | ///
928 | /// Returns the shot info of the shot currently live, in the currently selected layer
929 | ///
930 | public int GetLiveShotID()
931 | {
932 | int shotID = (int)Late.Invoke(_SelectedLayer, "LiveShotID");
933 | return shotID;
934 | }
935 | public string GetLiveShotName()
936 | {
937 | int shotID = GetLiveShotID();
938 | return GetShotNameWithID(shotID);
939 | }
940 | public object GetLiveShot()
941 | {
942 | int shotID = GetLiveShotID();
943 | return GetShotWithID(shotID);
944 | }
945 |
946 | ///
947 | /// Returns the name of the active shot in the currently selected layer
948 | ///
949 | public string GetActiveShotName()
950 | {
951 | int shotID = GetActiveShotID();
952 | return GetShotNameWithID(shotID);
953 | }
954 |
955 | ///
956 | /// Returns true if the shot is currently in preview
957 | /// false otherwise
958 | ///
959 | public bool IsShotIDInPreview(int shotID)
960 | {
961 | object shot = GetShotWithID(shotID);
962 | int result = (int)Late.Invoke(shot, "Preview");
963 |
964 | return result == 1;
965 | }
966 | public bool IsShotNameInPreview(string name)
967 | {
968 | object shot = GetShotWithName(name);
969 | int result = (int)Late.Invoke(shot, "Preview");
970 |
971 | return result == 1;
972 | }
973 |
974 | ///
975 | /// Returns true if the shot is currently live
976 | /// false otherwise
977 | ///
978 | public bool IsShotIDLive(int shotID)
979 | {
980 | object shot = GetShotWithID(shotID);
981 | int result = (int)Late.Invoke(shot, "Live");
982 |
983 | return result == 1;
984 | }
985 | public bool IsShotNameLive(string name)
986 | {
987 | object shot = GetShotWithName(name);
988 | int result = (int)Late.Invoke(shot, "Live");
989 |
990 | return result == 1;
991 | }
992 |
993 | ///
994 | /// Returns true if the shot is a Playlist Shot
995 | /// false otherwise
996 | ///
997 | public bool IsPlaylistByShotID(int shotID)
998 | {
999 | object shot = GetShotWithID(shotID);
1000 | int result = (int)Late.Invoke(shot, "Playlist");
1001 |
1002 | return result == 1;
1003 | }
1004 | public bool IsPlaylistByShotName(string name)
1005 | {
1006 | object shot = GetShotWithName(name);
1007 | int result = (int)Late.Invoke(shot, "Playlist");
1008 |
1009 | return result == 1;
1010 | }
1011 |
1012 | ///
1013 | /// Tells the input Playlist Shot to transition to the next shot
1014 | ///
1015 | public void NextShotByShotID(int shotID)
1016 | {
1017 | object shot = GetShotWithID(shotID);
1018 | Late.Invoke(shot, "NextShot");
1019 | }
1020 | public void NextShotByShotName(string name)
1021 | {
1022 | object shot = GetShotWithName(name);
1023 | Late.Invoke(shot, "NextShot");
1024 | }
1025 |
1026 | ///
1027 | /// Tells the input Playlist Shot to transition to the previous shot
1028 | ///
1029 | public void PreviousShotByShotID(int shotID)
1030 | {
1031 | object shot = GetShotWithID(shotID);
1032 | Late.Invoke(shot, "PreviousShot");
1033 | }
1034 | public void PreviousShotByShotName(string name)
1035 | {
1036 | object shot = GetShotWithName(name);
1037 | Late.Invoke(shot, "PreviousShot");
1038 | }
1039 | }
1040 |
1041 | public static class FormSerialisor
1042 | {
1043 | /*
1044 | * Drop this class into your project, and add the following line at the top of any class/form that wishes to use it...
1045 | using FormSerialisation;
1046 | To use the code, simply call FormSerialisor.Serialise(FormOrControlToBeSerialised, FullPathToXMLFile)
1047 | *
1048 | * For more details, see http://www.codeproject.com/KB/dialog/SavingTheStateOfAForm.aspx
1049 | *
1050 | * Last updated 13th June '10 to account for the odd behaviour of the two Panel controls in a SplitContainer (see the article)
1051 | */
1052 | public static void Serialise(Control c, string XmlFileName)
1053 | {
1054 | XmlTextWriter xmlSerialisedForm = new XmlTextWriter(XmlFileName, System.Text.Encoding.Default);
1055 | xmlSerialisedForm.Formatting = Formatting.Indented;
1056 | xmlSerialisedForm.WriteStartDocument();
1057 | xmlSerialisedForm.WriteStartElement("ChildForm");
1058 | // enumerate all controls on the form, and serialise them as appropriate
1059 | AddChildControls(xmlSerialisedForm, c);
1060 | xmlSerialisedForm.WriteEndElement(); // ChildForm
1061 | xmlSerialisedForm.WriteEndDocument();
1062 | xmlSerialisedForm.Flush();
1063 | xmlSerialisedForm.Close();
1064 | }
1065 |
1066 | private static void AddChildControls(XmlTextWriter xmlSerialisedForm, Control c)
1067 | {
1068 | foreach (Control childCtrl in c.Controls)
1069 | {
1070 | if (!(childCtrl is Label))
1071 | {
1072 | // serialise this control
1073 | xmlSerialisedForm.WriteStartElement("Control");
1074 | xmlSerialisedForm.WriteAttributeString("Type", childCtrl.GetType().ToString());
1075 | xmlSerialisedForm.WriteAttributeString("Name", childCtrl.Name);
1076 | if (childCtrl is TextBox)
1077 | {
1078 | xmlSerialisedForm.WriteElementString("Text", ((TextBox)childCtrl).Text);
1079 | }
1080 | else if (childCtrl is ComboBox)
1081 | {
1082 | xmlSerialisedForm.WriteElementString("Text", ((ComboBox)childCtrl).Text);
1083 | xmlSerialisedForm.WriteElementString("SelectedIndex", ((ComboBox)childCtrl).SelectedIndex.ToString());
1084 | }
1085 | else if (childCtrl is ListBox)
1086 | {
1087 | // need to account for multiply selected items
1088 | ListBox lst = (ListBox)childCtrl;
1089 | if (lst.SelectedIndex == -1)
1090 | {
1091 | xmlSerialisedForm.WriteElementString("SelectedIndex", "-1");
1092 | }
1093 | else
1094 | {
1095 | for (int i = 0; i < lst.SelectedIndices.Count; i++)
1096 | {
1097 | xmlSerialisedForm.WriteElementString("SelectedIndex", (lst.SelectedIndices[i].ToString()));
1098 | }
1099 | }
1100 | }
1101 | else if (childCtrl is CheckBox)
1102 | {
1103 | xmlSerialisedForm.WriteElementString("Checked", ((CheckBox)childCtrl).Checked.ToString());
1104 | }
1105 | // this next line was taken from http://stackoverflow.com/questions/391888/how-to-get-the-real-value-of-the-visible-property
1106 | // which dicusses the problem of child controls claiming to have Visible=false even when they haven't, based on the parent
1107 | // having Visible=true
1108 | bool visible = (bool)typeof(Control).GetMethod("GetState", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(childCtrl, new object[] { 2 });
1109 | xmlSerialisedForm.WriteElementString("Visible", visible.ToString());
1110 | // see if this control has any children, and if so, serialise them
1111 | if (childCtrl.HasChildren)
1112 | {
1113 | if (childCtrl is SplitContainer)
1114 | {
1115 | // handle this one as a special case
1116 | AddChildControls(xmlSerialisedForm, ((SplitContainer)childCtrl).Panel1);
1117 | AddChildControls(xmlSerialisedForm, ((SplitContainer)childCtrl).Panel2);
1118 | }
1119 | else
1120 | {
1121 | AddChildControls(xmlSerialisedForm, childCtrl);
1122 | }
1123 | }
1124 | xmlSerialisedForm.WriteEndElement(); // Control
1125 | }
1126 | }
1127 | }
1128 |
1129 | public static void Deserialise(Control c, string XmlFileName)
1130 | {
1131 | if (File.Exists(XmlFileName))
1132 | {
1133 | XmlDocument xmlSerialisedForm = new XmlDocument();
1134 | xmlSerialisedForm.Load(XmlFileName);
1135 | XmlNode topLevel = xmlSerialisedForm.ChildNodes[1];
1136 | foreach (XmlNode n in topLevel.ChildNodes)
1137 | {
1138 | SetControlProperties((Control)c, n);
1139 | }
1140 | }
1141 | }
1142 |
1143 | private static void SetControlProperties(Control currentCtrl, XmlNode n)
1144 | {
1145 | // get the control's name and type
1146 | string controlName = n.Attributes["Name"].Value;
1147 | string controlType = n.Attributes["Type"].Value;
1148 | // find the control
1149 | Control[] ctrl = currentCtrl.Controls.Find(controlName, true);
1150 | if (ctrl.Length == 0)
1151 | {
1152 | // can't find the control
1153 | }
1154 | else
1155 | {
1156 | Control ctrlToSet = GetImmediateChildControl(ctrl, currentCtrl);
1157 | if (ctrlToSet != null)
1158 | {
1159 | if (ctrlToSet.GetType().ToString() == controlType)
1160 | {
1161 | // the right type too ;-)
1162 | switch (controlType)
1163 | {
1164 | case "System.Windows.Forms.TextBox":
1165 | ((System.Windows.Forms.TextBox)ctrlToSet).Text = n["Text"].InnerText;
1166 | break;
1167 | case "System.Windows.Forms.ComboBox":
1168 | ((System.Windows.Forms.ComboBox)ctrlToSet).Text = n["Text"].InnerText;
1169 | ((System.Windows.Forms.ComboBox)ctrlToSet).SelectedIndex = Convert.ToInt32(n["SelectedIndex"].InnerText);
1170 | break;
1171 | case "System.Windows.Forms.ListBox":
1172 | // need to account for multiply selected items
1173 | ListBox lst = (ListBox)ctrlToSet;
1174 | XmlNodeList xnlSelectedIndex = n.SelectNodes("SelectedIndex");
1175 | for (int i = 0; i < xnlSelectedIndex.Count; i++)
1176 | {
1177 | lst.SelectedIndex = Convert.ToInt32(xnlSelectedIndex[i].InnerText);
1178 | }
1179 | break;
1180 | case "System.Windows.Forms.CheckBox":
1181 | ((System.Windows.Forms.CheckBox)ctrlToSet).Checked = Convert.ToBoolean(n["Checked"].InnerText);
1182 | break;
1183 | }
1184 | ctrlToSet.Visible = Convert.ToBoolean(n["Visible"].InnerText);
1185 | // if n has any children that are controls, deserialise them as well
1186 | if (n.HasChildNodes && ctrlToSet.HasChildren)
1187 | {
1188 | XmlNodeList xnlControls = n.SelectNodes("Control");
1189 | foreach (XmlNode n2 in xnlControls)
1190 | {
1191 | SetControlProperties(ctrlToSet, n2);
1192 | }
1193 | }
1194 | }
1195 | else
1196 | {
1197 | // not the right type
1198 | }
1199 | }
1200 | else
1201 | {
1202 | // can't find a control whose parent is the current control
1203 | }
1204 | }
1205 | }
1206 |
1207 | private static Control GetImmediateChildControl(Control[] ctrl, Control currentCtrl)
1208 | {
1209 | Control c = null;
1210 | for (int i = 0; i < ctrl.Length; i++)
1211 | {
1212 | if ((ctrl[i].Parent.Name == currentCtrl.Name) || (currentCtrl is SplitContainer && ctrl[i].Parent.Parent.Name == currentCtrl.Name))
1213 | {
1214 | c = ctrl[i];
1215 | break;
1216 | }
1217 | }
1218 | return c;
1219 | }
1220 |
1221 | }
1222 | }
1223 |
--------------------------------------------------------------------------------