Commit | Line | Data |
---|---|---|
f017f3c4 LOK |
1 | /* |
2 | * This file is part of the libCEC(R) library. | |
3 | * | |
16f47961 | 4 | * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved. |
f017f3c4 LOK |
5 | * libCEC(R) is an original work, containing original code. |
6 | * | |
7 | * libCEC(R) is a trademark of Pulse-Eight Limited. | |
8 | * | |
9 | * This program is dual-licensed; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
22 | * | |
23 | * | |
24 | * Alternatively, you can license this library under a commercial license, | |
25 | * please contact Pulse-Eight Licensing for more information. | |
26 | * | |
27 | * For more information contact: | |
28 | * Pulse-Eight Licensing <license@pulse-eight.com> | |
29 | * http://www.pulse-eight.com/ | |
30 | * http://www.pulse-eight.net/ | |
31 | */ | |
32 | ||
33 | using System; | |
34 | using System.Globalization; | |
35 | using System.IO; | |
36 | using System.Text; | |
37 | using System.Windows.Forms; | |
38 | using System.Xml; | |
39 | using CecSharp; | |
40 | using LibCECTray.Properties; | |
41 | using LibCECTray.settings; | |
42 | ||
43 | namespace LibCECTray.controller.applications.@internal | |
44 | { | |
45 | internal class XBMCController : ApplicationController | |
46 | { | |
97401db1 LOK |
47 | public XBMCController(CECController controller) : |
48 | base(controller, | |
f017f3c4 LOK |
49 | Resources.application_xbmc, |
50 | "XBMC", | |
51 | "XBMC.exe", | |
52 | Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\XBMC") | |
53 | { | |
54 | IsInternal = true; | |
55 | AutoStartApplication.Value = false; | |
56 | ControlApplication.Value = false; | |
57 | ||
58 | LoadXMLConfiguration(); | |
f4729954 LOK |
59 | |
60 | ApplicationRunningChanged += RunningChanged; | |
61 | } | |
62 | ||
63 | static void RunningChanged(bool running) | |
64 | { | |
65 | if (running) | |
66 | { | |
67 | // XBMC is running, close the application, or we'll block communication | |
68 | Application.Exit(); | |
69 | } | |
f017f3c4 LOK |
70 | } |
71 | ||
72 | public override ApplicationAction DefaultValue(CecKeypress key) | |
73 | { | |
74 | return null; | |
75 | } | |
76 | ||
77 | public override ControllerTabPage UiControl | |
78 | { | |
79 | get { return UIControlInternal ?? (UIControlInternal = new XBMCControllerUI(this)); } | |
80 | } | |
81 | ||
82 | public bool LoadXMLConfiguration() | |
49689754 | 83 | { |
5156a42c LOK |
84 | var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data"; |
85 | return LoadXMLConfiguration(xbmcDir + string.Format(@"\usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId)) || | |
86 | LoadXMLConfiguration(xbmcDir + @"\usb_2548_1001.xml") || | |
87 | LoadXMLConfiguration(xbmcDir + @"\usb_2548_1002.xml"); | |
88 | } | |
8768aeca | 89 | |
5156a42c LOK |
90 | public bool LoadXMLConfiguration(string filename) |
91 | { | |
92 | bool gotConfig = false; | |
93 | if (File.Exists(filename)) | |
f017f3c4 | 94 | { |
5156a42c | 95 | XmlTextReader reader = new XmlTextReader(filename); |
0184b751 | 96 | while (true) |
f017f3c4 | 97 | { |
0184b751 LOK |
98 | try |
99 | { | |
100 | if (!reader.Read()) | |
101 | break; | |
102 | } catch (XmlException) {} | |
f017f3c4 LOK |
103 | gotConfig = true; |
104 | switch (reader.NodeType) | |
105 | { | |
106 | case XmlNodeType.Element: | |
107 | if (reader.Name.ToLower() == "setting") | |
108 | { | |
109 | string name = string.Empty; | |
110 | string value = string.Empty; | |
111 | ||
112 | while (reader.MoveToNextAttribute()) | |
113 | { | |
114 | if (reader.Name.ToLower().Equals("id")) | |
115 | name = reader.Value.ToLower(); | |
116 | if (reader.Name.ToLower().Equals("value")) | |
117 | value = reader.Value; | |
118 | } | |
119 | ||
120 | switch (name) | |
121 | { | |
122 | case "cec_hdmi_port": | |
123 | { | |
124 | byte iPort; | |
125 | if (byte.TryParse(value, out iPort)) | |
126 | Settings.HDMIPort.Value = iPort; | |
127 | } | |
128 | break; | |
129 | case "connected_device": | |
130 | { | |
1b09c8f6 LOK |
131 | int iDevice; |
132 | if (int.TryParse(value, out iDevice)) | |
133 | Settings.ConnectedDevice.Value = iDevice == 36038 ? CecLogicalAddress.AudioSystem : CecLogicalAddress.Tv; | |
f017f3c4 LOK |
134 | } |
135 | break; | |
136 | case "cec_power_on_startup": | |
137 | if (value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes")) | |
138 | { | |
139 | Settings.ActivateSource.Value = true; | |
140 | Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv); | |
141 | } | |
142 | break; | |
143 | case "cec_power_off_shutdown": | |
144 | if (value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes")) | |
145 | Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Broadcast); | |
146 | break; | |
147 | case "cec_standby_screensaver": | |
148 | StandbyScreensaver.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"); | |
149 | break; | |
150 | case "standby_pc_on_tv_standby": | |
151 | PowerOffOnStandby.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"); | |
152 | break; | |
153 | case "use_tv_menu_language": | |
154 | UseTVLanguage.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"); | |
155 | break; | |
156 | // 1.5.0+ settings | |
157 | case "physical_address": | |
158 | { | |
159 | ushort physicalAddress; | |
160 | if (ushort.TryParse(value, NumberStyles.AllowHexSpecifier, null, out physicalAddress)) | |
161 | Settings.PhysicalAddress.Value = physicalAddress; | |
162 | } | |
163 | break; | |
164 | case "device_type": | |
165 | { | |
166 | ushort iType; | |
167 | if (ushort.TryParse(value, out iType)) | |
168 | Settings.DeviceType.Value = (CecDeviceType)iType; | |
169 | } | |
170 | break; | |
171 | case "tv_vendor": | |
172 | { | |
173 | UInt64 iVendor; | |
174 | if (UInt64.TryParse(value, out iVendor)) | |
175 | Settings.TVVendor.Value = (CecVendorId)iVendor; | |
176 | } | |
177 | break; | |
1b09c8f6 LOK |
178 | case "wake_device": |
179 | { | |
180 | int iWakeDevices; | |
181 | if (int.TryParse(value, out iWakeDevices)) | |
182 | { | |
183 | Settings.WakeDevices.Value.Clear(); | |
184 | switch (iWakeDevices) | |
185 | { | |
186 | case 36037: | |
187 | Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv); | |
188 | break; | |
189 | case 36038: | |
190 | Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem); | |
191 | break; | |
192 | case 36039: | |
193 | Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv); | |
194 | Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem); | |
195 | break; | |
196 | } | |
197 | } | |
198 | } | |
199 | break; | |
200 | case "wake_devices_advanced": | |
f017f3c4 LOK |
201 | { |
202 | Settings.WakeDevices.Value.Clear(); | |
203 | string[] split = value.Split(new[] { ' ' }); | |
204 | foreach (string dev in split) | |
205 | { | |
206 | byte iLogicalAddress; | |
207 | if (byte.TryParse(dev, out iLogicalAddress)) | |
208 | Settings.WakeDevices.Value.Set((CecLogicalAddress)iLogicalAddress); | |
209 | } | |
210 | } | |
211 | break; | |
212 | case "standby_devices": | |
1b09c8f6 LOK |
213 | { |
214 | int iStandbyDevices; | |
215 | if (int.TryParse(value, out iStandbyDevices)) | |
216 | { | |
217 | Settings.PowerOffDevices.Value.Clear(); | |
218 | switch (iStandbyDevices) | |
219 | { | |
220 | case 36037: | |
221 | Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv); | |
222 | break; | |
223 | case 36038: | |
224 | Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem); | |
225 | break; | |
226 | case 36039: | |
227 | Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv); | |
228 | Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem); | |
229 | break; | |
230 | } | |
231 | } | |
232 | } | |
233 | break; | |
234 | case "standby_devices_advanced": | |
f017f3c4 LOK |
235 | { |
236 | Settings.PowerOffDevices.Value.Clear(); | |
237 | string[] split = value.Split(new[] { ' ' }); | |
238 | foreach (string dev in split) | |
239 | { | |
240 | byte iLogicalAddress; | |
241 | if (byte.TryParse(dev, out iLogicalAddress)) | |
242 | Settings.PowerOffDevices.Value.Set((CecLogicalAddress)iLogicalAddress); | |
243 | } | |
244 | } | |
245 | break; | |
246 | case "enabled": | |
247 | break; | |
248 | case "port": | |
249 | //TODO | |
250 | break; | |
251 | // 1.5.1 settings | |
252 | case "send_inactive_source": | |
253 | SendInactiveSource.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"); | |
254 | break; | |
1b09c8f6 LOK |
255 | // 1.9.0+ settings |
256 | case "pause_playback_on_deactivate": | |
257 | PausePlaybackOnDeactivate.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"); | |
258 | break; | |
f017f3c4 LOK |
259 | } |
260 | } | |
261 | break; | |
262 | } | |
263 | } | |
264 | } | |
265 | return gotConfig; | |
266 | } | |
267 | ||
1b09c8f6 LOK |
268 | static bool HasAdvancedDeviceIdSet(CecLogicalAddresses addresses) |
269 | { | |
270 | foreach (var val in addresses.Addresses) | |
271 | if (val != CecLogicalAddress.Tv && val != CecLogicalAddress.AudioSystem) | |
272 | return true; | |
273 | return false; | |
274 | } | |
275 | ||
f017f3c4 LOK |
276 | public void SaveXMLConfiguration() |
277 | { | |
278 | Settings.Persist(); | |
279 | ||
5156a42c LOK |
280 | var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data"; |
281 | if (!Directory.Exists(xbmcDir)) | |
282 | Directory.CreateDirectory(xbmcDir); | |
283 | ||
284 | if (!Directory.Exists(xbmcDir)) | |
285 | { | |
286 | // couldn't create directory | |
287 | MessageBox.Show(string.Format(Resources.could_not_create_directory, xbmcDir), Resources.error, | |
288 | MessageBoxButtons.OK, MessageBoxIcon.Error); | |
289 | return; | |
290 | } | |
f017f3c4 LOK |
291 | |
292 | SaveFileDialog dialog = new SaveFileDialog | |
5156a42c | 293 | { |
f017f3c4 | 294 | Title = Resources.store_settings_where, |
5156a42c LOK |
295 | InitialDirectory = xbmcDir, |
296 | FileName = string.Format("usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId), | |
f017f3c4 LOK |
297 | Filter = Resources.xml_file_filter, |
298 | FilterIndex = 1 | |
299 | }; | |
300 | if (dialog.ShowDialog() != DialogResult.OK) return; | |
301 | ||
302 | FileStream fs = null; | |
303 | string error = string.Empty; | |
304 | try | |
305 | { | |
306 | fs = (FileStream)dialog.OpenFile(); | |
307 | } | |
308 | catch (Exception ex) | |
309 | { | |
310 | error = ex.Message; | |
311 | } | |
312 | if (fs == null) | |
313 | { | |
314 | MessageBox.Show(string.Format(Resources.cannot_open_file, dialog.FileName) + (error.Length > 0 ? ": " + error : string.Empty), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error); | |
315 | } | |
316 | else | |
317 | { | |
318 | StreamWriter writer = new StreamWriter(fs); | |
319 | StringBuilder output = new StringBuilder(); | |
320 | output.AppendLine("<settings>"); | |
321 | output.AppendLine("<setting id=\"cec_hdmi_port\" value=\"" + Settings.HDMIPort.Value + "\" />"); | |
1b09c8f6 | 322 | output.AppendLine("<setting id=\"connected_device\" value=\"" + (Settings.ConnectedDevice.Value == CecLogicalAddress.AudioSystem ? 36038 : 36037) + "\" />"); |
f017f3c4 LOK |
323 | output.AppendLine("<setting id=\"cec_power_on_startup\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />"); |
324 | output.AppendLine("<setting id=\"cec_power_off_shutdown\" value=\"" + (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Broadcast) ? 1 : 0) + "\" />"); | |
325 | output.AppendLine("<setting id=\"cec_standby_screensaver\" value=\"" + (StandbyScreensaver.Value ? 1 : 0) + "\" />"); | |
326 | output.AppendLine("<setting id=\"standby_pc_on_tv_standby\" value=\"" + (PowerOffOnStandby.Value ? 1 : 0) + "\" />"); | |
327 | output.AppendLine("<setting id=\"use_tv_menu_language\" value=\"" + (UseTVLanguage.Value ? 1 : 0) + "\" />"); | |
328 | output.AppendLine("<setting id=\"enabled\" value=\"1\" />"); | |
329 | output.AppendLine("<setting id=\"port\" value=\"\" />"); | |
330 | ||
331 | // only supported by 1.5.0+ clients | |
332 | output.AppendLine("<!-- the following lines are only supported by v1.5.0+ clients -->"); | |
333 | output.AppendLine("<setting id=\"activate_source\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />"); | |
334 | output.AppendLine("<setting id=\"physical_address\" value=\"" + string.Format("{0,4:X}", Settings.OverridePhysicalAddress.Value ? Settings.PhysicalAddress.Value : 0).Trim() + "\" />"); | |
335 | output.AppendLine("<setting id=\"device_type\" value=\"" + (int)Settings.DeviceType.Value + "\" />"); | |
336 | output.AppendLine("<setting id=\"tv_vendor\" value=\"" + string.Format("{0,6:X}", Settings.OverrideTVVendor.Value ? (int)Settings.TVVendor.Value : 0).Trim() + "\" />"); | |
337 | ||
1b09c8f6 LOK |
338 | if (HasAdvancedDeviceIdSet(Settings.WakeDevices.Value)) |
339 | { | |
340 | output.Append("<setting id=\"wake_devices_advanced\" value=\""); | |
341 | StringBuilder strWakeDevices = new StringBuilder(); | |
342 | foreach (CecLogicalAddress addr in Settings.WakeDevices.Value.Addresses) | |
343 | if (addr != CecLogicalAddress.Unknown) | |
344 | strWakeDevices.Append(" " + (int)addr); | |
345 | output.Append(strWakeDevices.ToString().Trim()); | |
346 | output.AppendLine("\" />"); | |
347 | } | |
348 | ||
349 | if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv) && | |
350 | Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem)) | |
351 | output.Append("<setting id=\"wake_devices\" value=\"36039\">"); | |
352 | else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv)) | |
353 | output.Append("<setting id=\"wake_devices\" value=\"36037\">"); | |
354 | else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem)) | |
355 | output.Append("<setting id=\"wake_devices\" value=\"36038\">"); | |
356 | else | |
357 | output.Append("<setting id=\"wake_devices\" value=\"231\">"); | |
358 | ||
359 | if (HasAdvancedDeviceIdSet(Settings.PowerOffDevices.Value)) | |
360 | { | |
361 | output.Append("<setting id=\"standby_devices_advanced\" value=\""); | |
362 | StringBuilder strSleepDevices = new StringBuilder(); | |
363 | foreach (CecLogicalAddress addr in Settings.PowerOffDevices.Value.Addresses) | |
364 | if (addr != CecLogicalAddress.Unknown) | |
365 | strSleepDevices.Append(" " + (int) addr); | |
366 | output.Append(strSleepDevices.ToString().Trim()); | |
367 | output.AppendLine("\" />"); | |
368 | } | |
f017f3c4 | 369 | |
1b09c8f6 LOK |
370 | if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv) && |
371 | Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem)) | |
372 | output.Append("<setting id=\"standby_devices\" value=\"36039\">"); | |
373 | else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv)) | |
374 | output.Append("<setting id=\"standby_devices\" value=\"36037\">"); | |
375 | else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem)) | |
376 | output.Append("<setting id=\"standby_devices\" value=\"36038\">"); | |
377 | else | |
378 | output.Append("<setting id=\"standby_devices\" value=\"231\">"); | |
f017f3c4 LOK |
379 | |
380 | // only supported by 1.5.1+ clients | |
381 | output.AppendLine("<!-- the following lines are only supported by v1.5.1+ clients -->"); | |
9c72728b | 382 | output.AppendLine("<setting id=\"send_inactive_source\" value=\"" + (SendInactiveSource.Value ? 1 : 0) + "\" />"); |
f017f3c4 | 383 | |
1b09c8f6 LOK |
384 | // only supported by 1.9.0+ clients |
385 | output.AppendLine("<setting id=\"pause_playback_on_deactivate\" value=\"" + (PausePlaybackOnDeactivate.Value ? 1 : 0) + "\" />"); | |
386 | ||
f017f3c4 LOK |
387 | output.AppendLine("</settings>"); |
388 | writer.Write(output.ToString()); | |
389 | writer.Close(); | |
390 | fs.Close(); | |
391 | fs.Dispose(); | |
392 | MessageBox.Show(Resources.settings_stored, Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information); | |
393 | } | |
394 | } | |
395 | ||
396 | public CECSettingBool UseTVLanguage | |
397 | { | |
398 | get | |
399 | { | |
400 | if (!Settings.ContainsKey(ProcessName + "_use_tv_language")) | |
401 | { | |
402 | CECSettingBool setting = new CECSettingBool(ProcessName + "_use_tv_language", Resources.app_use_tv_language, true, null); | |
403 | Settings.Load(setting); | |
404 | Settings[ProcessName + "_use_tv_language"] = setting; | |
405 | } | |
406 | return Settings[ProcessName + "_use_tv_language"].AsSettingBool; | |
407 | } | |
408 | } | |
409 | ||
410 | public CECSettingBool StandbyScreensaver | |
411 | { | |
412 | get | |
413 | { | |
414 | if (!Settings.ContainsKey(ProcessName + "_standby_screensaver")) | |
415 | { | |
416 | CECSettingBool setting = new CECSettingBool(ProcessName + "_standby_screensaver", Resources.app_standby_screensaver, true, null); | |
417 | Settings.Load(setting); | |
418 | Settings[ProcessName + "_standby_screensaver"] = setting; | |
419 | } | |
420 | return Settings[ProcessName + "_standby_screensaver"].AsSettingBool; | |
421 | } | |
422 | } | |
423 | ||
424 | public CECSettingBool ActivateSource | |
425 | { | |
426 | get | |
427 | { | |
428 | if (!Settings.ContainsKey(ProcessName + "_activate_source")) | |
429 | { | |
430 | CECSettingBool setting = new CECSettingBool(ProcessName + "_activate_source", Resources.global_activate_source, true, null); | |
431 | Settings.Load(setting); | |
432 | Settings[ProcessName + "_activate_source"] = setting; | |
433 | } | |
434 | return Settings[ProcessName + "_activate_source"].AsSettingBool; | |
435 | } | |
436 | } | |
437 | ||
438 | public CECSettingBool PowerOffOnStandby | |
439 | { | |
440 | get | |
441 | { | |
442 | if (!Settings.ContainsKey(ProcessName + "_standby_on_tv_standby")) | |
443 | { | |
444 | CECSettingBool setting = new CECSettingBool(ProcessName + "_standby_on_tv_standby", Resources.app_standby_on_tv_standby, true, null); | |
445 | Settings.Load(setting); | |
446 | Settings[ProcessName + "_standby_on_tv_standby"] = setting; | |
447 | } | |
448 | return Settings[ProcessName + "_standby_on_tv_standby"].AsSettingBool; | |
449 | } | |
450 | } | |
451 | ||
452 | public CECSettingBool SendInactiveSource | |
453 | { | |
454 | get | |
455 | { | |
456 | if (!Settings.ContainsKey(ProcessName + "_send_inactive_source")) | |
457 | { | |
458 | CECSettingBool setting = new CECSettingBool(ProcessName + "_send_inactive_source", Resources.app_send_inactive_source, true, null); | |
459 | Settings.Load(setting); | |
460 | Settings[ProcessName + "_send_inactive_source"] = setting; | |
461 | } | |
462 | return Settings[ProcessName + "_send_inactive_source"].AsSettingBool; | |
463 | } | |
464 | } | |
1b09c8f6 LOK |
465 | |
466 | public CECSettingBool PausePlaybackOnDeactivate | |
467 | { | |
468 | get | |
469 | { | |
470 | if (!Settings.ContainsKey(ProcessName + "_pause_playback_on_deactivate")) | |
471 | { | |
472 | CECSettingBool setting = new CECSettingBool(ProcessName + "_pause_playback_on_deactivate", Resources.app_pause_playback_on_deactivate, true, null); | |
473 | Settings.Load(setting); | |
474 | Settings[ProcessName + "_pause_playback_on_deactivate"] = setting; | |
475 | } | |
476 | return Settings[ProcessName + "_pause_playback_on_deactivate"].AsSettingBool; | |
477 | } | |
478 | } | |
f017f3c4 LOK |
479 | } |
480 | } |