b4801e2e62a40252f3aef5e7060639e3c6aa81e7
[deb_libcec.git] / src / LibCecTray / controller / applications / internal / XBMCController.cs
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
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 {
47 public XBMCController(CECController controller) :
48 base(controller,
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();
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 }
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()
83 {
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 }
89
90 public bool LoadXMLConfiguration(string filename)
91 {
92 bool gotConfig = false;
93 if (File.Exists(filename))
94 {
95 XmlTextReader reader = new XmlTextReader(filename);
96 while (reader.Read())
97 {
98 gotConfig = true;
99 switch (reader.NodeType)
100 {
101 case XmlNodeType.Element:
102 if (reader.Name.ToLower() == "setting")
103 {
104 string name = string.Empty;
105 string value = string.Empty;
106
107 while (reader.MoveToNextAttribute())
108 {
109 if (reader.Name.ToLower().Equals("id"))
110 name = reader.Value.ToLower();
111 if (reader.Name.ToLower().Equals("value"))
112 value = reader.Value;
113 }
114
115 switch (name)
116 {
117 case "cec_hdmi_port":
118 {
119 byte iPort;
120 if (byte.TryParse(value, out iPort))
121 Settings.HDMIPort.Value = iPort;
122 }
123 break;
124 case "connected_device":
125 {
126 int iDevice;
127 if (int.TryParse(value, out iDevice))
128 Settings.ConnectedDevice.Value = iDevice == 36038 ? CecLogicalAddress.AudioSystem : CecLogicalAddress.Tv;
129 }
130 break;
131 case "cec_power_on_startup":
132 if (value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"))
133 {
134 Settings.ActivateSource.Value = true;
135 Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
136 }
137 break;
138 case "cec_power_off_shutdown":
139 if (value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"))
140 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Broadcast);
141 break;
142 case "cec_standby_screensaver":
143 StandbyScreensaver.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
144 break;
145 case "standby_pc_on_tv_standby":
146 PowerOffOnStandby.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
147 break;
148 case "use_tv_menu_language":
149 UseTVLanguage.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
150 break;
151 // 1.5.0+ settings
152 case "physical_address":
153 {
154 ushort physicalAddress;
155 if (ushort.TryParse(value, NumberStyles.AllowHexSpecifier, null, out physicalAddress))
156 Settings.PhysicalAddress.Value = physicalAddress;
157 }
158 break;
159 case "device_type":
160 {
161 ushort iType;
162 if (ushort.TryParse(value, out iType))
163 Settings.DeviceType.Value = (CecDeviceType)iType;
164 }
165 break;
166 case "tv_vendor":
167 {
168 UInt64 iVendor;
169 if (UInt64.TryParse(value, out iVendor))
170 Settings.TVVendor.Value = (CecVendorId)iVendor;
171 }
172 break;
173 case "wake_device":
174 {
175 int iWakeDevices;
176 if (int.TryParse(value, out iWakeDevices))
177 {
178 Settings.WakeDevices.Value.Clear();
179 switch (iWakeDevices)
180 {
181 case 36037:
182 Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
183 break;
184 case 36038:
185 Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem);
186 break;
187 case 36039:
188 Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
189 Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem);
190 break;
191 }
192 }
193 }
194 break;
195 case "wake_devices_advanced":
196 {
197 Settings.WakeDevices.Value.Clear();
198 string[] split = value.Split(new[] { ' ' });
199 foreach (string dev in split)
200 {
201 byte iLogicalAddress;
202 if (byte.TryParse(dev, out iLogicalAddress))
203 Settings.WakeDevices.Value.Set((CecLogicalAddress)iLogicalAddress);
204 }
205 }
206 break;
207 case "standby_devices":
208 {
209 int iStandbyDevices;
210 if (int.TryParse(value, out iStandbyDevices))
211 {
212 Settings.PowerOffDevices.Value.Clear();
213 switch (iStandbyDevices)
214 {
215 case 36037:
216 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv);
217 break;
218 case 36038:
219 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem);
220 break;
221 case 36039:
222 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv);
223 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem);
224 break;
225 }
226 }
227 }
228 break;
229 case "standby_devices_advanced":
230 {
231 Settings.PowerOffDevices.Value.Clear();
232 string[] split = value.Split(new[] { ' ' });
233 foreach (string dev in split)
234 {
235 byte iLogicalAddress;
236 if (byte.TryParse(dev, out iLogicalAddress))
237 Settings.PowerOffDevices.Value.Set((CecLogicalAddress)iLogicalAddress);
238 }
239 }
240 break;
241 case "enabled":
242 break;
243 case "port":
244 //TODO
245 break;
246 // 1.5.1 settings
247 case "send_inactive_source":
248 SendInactiveSource.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
249 break;
250 // 1.9.0+ settings
251 case "pause_playback_on_deactivate":
252 PausePlaybackOnDeactivate.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
253 break;
254 }
255 }
256 break;
257 }
258 }
259 }
260 return gotConfig;
261 }
262
263 static bool HasAdvancedDeviceIdSet(CecLogicalAddresses addresses)
264 {
265 foreach (var val in addresses.Addresses)
266 if (val != CecLogicalAddress.Tv && val != CecLogicalAddress.AudioSystem)
267 return true;
268 return false;
269 }
270
271 public void SaveXMLConfiguration()
272 {
273 Settings.Persist();
274
275 var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
276 if (!Directory.Exists(xbmcDir))
277 Directory.CreateDirectory(xbmcDir);
278
279 if (!Directory.Exists(xbmcDir))
280 {
281 // couldn't create directory
282 MessageBox.Show(string.Format(Resources.could_not_create_directory, xbmcDir), Resources.error,
283 MessageBoxButtons.OK, MessageBoxIcon.Error);
284 return;
285 }
286
287 SaveFileDialog dialog = new SaveFileDialog
288 {
289 Title = Resources.store_settings_where,
290 InitialDirectory = xbmcDir,
291 FileName = string.Format("usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId),
292 Filter = Resources.xml_file_filter,
293 FilterIndex = 1
294 };
295 if (dialog.ShowDialog() != DialogResult.OK) return;
296
297 FileStream fs = null;
298 string error = string.Empty;
299 try
300 {
301 fs = (FileStream)dialog.OpenFile();
302 }
303 catch (Exception ex)
304 {
305 error = ex.Message;
306 }
307 if (fs == null)
308 {
309 MessageBox.Show(string.Format(Resources.cannot_open_file, dialog.FileName) + (error.Length > 0 ? ": " + error : string.Empty), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
310 }
311 else
312 {
313 StreamWriter writer = new StreamWriter(fs);
314 StringBuilder output = new StringBuilder();
315 output.AppendLine("<settings>");
316 output.AppendLine("<setting id=\"cec_hdmi_port\" value=\"" + Settings.HDMIPort.Value + "\" />");
317 output.AppendLine("<setting id=\"connected_device\" value=\"" + (Settings.ConnectedDevice.Value == CecLogicalAddress.AudioSystem ? 36038 : 36037) + "\" />");
318 output.AppendLine("<setting id=\"cec_power_on_startup\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />");
319 output.AppendLine("<setting id=\"cec_power_off_shutdown\" value=\"" + (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Broadcast) ? 1 : 0) + "\" />");
320 output.AppendLine("<setting id=\"cec_standby_screensaver\" value=\"" + (StandbyScreensaver.Value ? 1 : 0) + "\" />");
321 output.AppendLine("<setting id=\"standby_pc_on_tv_standby\" value=\"" + (PowerOffOnStandby.Value ? 1 : 0) + "\" />");
322 output.AppendLine("<setting id=\"use_tv_menu_language\" value=\"" + (UseTVLanguage.Value ? 1 : 0) + "\" />");
323 output.AppendLine("<setting id=\"enabled\" value=\"1\" />");
324 output.AppendLine("<setting id=\"port\" value=\"\" />");
325
326 // only supported by 1.5.0+ clients
327 output.AppendLine("<!-- the following lines are only supported by v1.5.0+ clients -->");
328 output.AppendLine("<setting id=\"activate_source\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />");
329 output.AppendLine("<setting id=\"physical_address\" value=\"" + string.Format("{0,4:X}", Settings.OverridePhysicalAddress.Value ? Settings.PhysicalAddress.Value : 0).Trim() + "\" />");
330 output.AppendLine("<setting id=\"device_type\" value=\"" + (int)Settings.DeviceType.Value + "\" />");
331 output.AppendLine("<setting id=\"tv_vendor\" value=\"" + string.Format("{0,6:X}", Settings.OverrideTVVendor.Value ? (int)Settings.TVVendor.Value : 0).Trim() + "\" />");
332
333 if (HasAdvancedDeviceIdSet(Settings.WakeDevices.Value))
334 {
335 output.Append("<setting id=\"wake_devices_advanced\" value=\"");
336 StringBuilder strWakeDevices = new StringBuilder();
337 foreach (CecLogicalAddress addr in Settings.WakeDevices.Value.Addresses)
338 if (addr != CecLogicalAddress.Unknown)
339 strWakeDevices.Append(" " + (int)addr);
340 output.Append(strWakeDevices.ToString().Trim());
341 output.AppendLine("\" />");
342 }
343
344 if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv) &&
345 Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
346 output.Append("<setting id=\"wake_devices\" value=\"36039\">");
347 else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv))
348 output.Append("<setting id=\"wake_devices\" value=\"36037\">");
349 else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
350 output.Append("<setting id=\"wake_devices\" value=\"36038\">");
351 else
352 output.Append("<setting id=\"wake_devices\" value=\"231\">");
353
354 if (HasAdvancedDeviceIdSet(Settings.PowerOffDevices.Value))
355 {
356 output.Append("<setting id=\"standby_devices_advanced\" value=\"");
357 StringBuilder strSleepDevices = new StringBuilder();
358 foreach (CecLogicalAddress addr in Settings.PowerOffDevices.Value.Addresses)
359 if (addr != CecLogicalAddress.Unknown)
360 strSleepDevices.Append(" " + (int) addr);
361 output.Append(strSleepDevices.ToString().Trim());
362 output.AppendLine("\" />");
363 }
364
365 if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv) &&
366 Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
367 output.Append("<setting id=\"standby_devices\" value=\"36039\">");
368 else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv))
369 output.Append("<setting id=\"standby_devices\" value=\"36037\">");
370 else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
371 output.Append("<setting id=\"standby_devices\" value=\"36038\">");
372 else
373 output.Append("<setting id=\"standby_devices\" value=\"231\">");
374
375 // only supported by 1.5.1+ clients
376 output.AppendLine("<!-- the following lines are only supported by v1.5.1+ clients -->");
377 output.AppendLine("<setting id=\"send_inactive_source\" value=\"" + (SendInactiveSource.Value ? 1 : 0) + "\" />");
378
379 // only supported by 1.9.0+ clients
380 output.AppendLine("<setting id=\"pause_playback_on_deactivate\" value=\"" + (PausePlaybackOnDeactivate.Value ? 1 : 0) + "\" />");
381
382 output.AppendLine("</settings>");
383 writer.Write(output.ToString());
384 writer.Close();
385 fs.Close();
386 fs.Dispose();
387 MessageBox.Show(Resources.settings_stored, Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
388 }
389 }
390
391 public CECSettingBool UseTVLanguage
392 {
393 get
394 {
395 if (!Settings.ContainsKey(ProcessName + "_use_tv_language"))
396 {
397 CECSettingBool setting = new CECSettingBool(ProcessName + "_use_tv_language", Resources.app_use_tv_language, true, null);
398 Settings.Load(setting);
399 Settings[ProcessName + "_use_tv_language"] = setting;
400 }
401 return Settings[ProcessName + "_use_tv_language"].AsSettingBool;
402 }
403 }
404
405 public CECSettingBool StandbyScreensaver
406 {
407 get
408 {
409 if (!Settings.ContainsKey(ProcessName + "_standby_screensaver"))
410 {
411 CECSettingBool setting = new CECSettingBool(ProcessName + "_standby_screensaver", Resources.app_standby_screensaver, true, null);
412 Settings.Load(setting);
413 Settings[ProcessName + "_standby_screensaver"] = setting;
414 }
415 return Settings[ProcessName + "_standby_screensaver"].AsSettingBool;
416 }
417 }
418
419 public CECSettingBool ActivateSource
420 {
421 get
422 {
423 if (!Settings.ContainsKey(ProcessName + "_activate_source"))
424 {
425 CECSettingBool setting = new CECSettingBool(ProcessName + "_activate_source", Resources.global_activate_source, true, null);
426 Settings.Load(setting);
427 Settings[ProcessName + "_activate_source"] = setting;
428 }
429 return Settings[ProcessName + "_activate_source"].AsSettingBool;
430 }
431 }
432
433 public CECSettingBool PowerOffOnStandby
434 {
435 get
436 {
437 if (!Settings.ContainsKey(ProcessName + "_standby_on_tv_standby"))
438 {
439 CECSettingBool setting = new CECSettingBool(ProcessName + "_standby_on_tv_standby", Resources.app_standby_on_tv_standby, true, null);
440 Settings.Load(setting);
441 Settings[ProcessName + "_standby_on_tv_standby"] = setting;
442 }
443 return Settings[ProcessName + "_standby_on_tv_standby"].AsSettingBool;
444 }
445 }
446
447 public CECSettingBool SendInactiveSource
448 {
449 get
450 {
451 if (!Settings.ContainsKey(ProcessName + "_send_inactive_source"))
452 {
453 CECSettingBool setting = new CECSettingBool(ProcessName + "_send_inactive_source", Resources.app_send_inactive_source, true, null);
454 Settings.Load(setting);
455 Settings[ProcessName + "_send_inactive_source"] = setting;
456 }
457 return Settings[ProcessName + "_send_inactive_source"].AsSettingBool;
458 }
459 }
460
461 public CECSettingBool PausePlaybackOnDeactivate
462 {
463 get
464 {
465 if (!Settings.ContainsKey(ProcessName + "_pause_playback_on_deactivate"))
466 {
467 CECSettingBool setting = new CECSettingBool(ProcessName + "_pause_playback_on_deactivate", Resources.app_pause_playback_on_deactivate, true, null);
468 Settings.Load(setting);
469 Settings[ProcessName + "_pause_playback_on_deactivate"] = setting;
470 }
471 return Settings[ProcessName + "_pause_playback_on_deactivate"].AsSettingBool;
472 }
473 }
474 }
475 }