Imported Upstream version 2.2.0
[deb_libcec.git] / src / LibCecTray / controller / applications / WindowsAPI.cs
CommitLineData
cbbe90dd
JB
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
33using System;
34using System.Runtime.InteropServices;
35using System.Diagnostics;
36using System.Reflection;
37using LibCECTray.Properties;
38
39namespace LibCECTray.controller.applications
40{
41 /// <summary>
42 /// Windows API methods and types
43 /// </summary>
44 internal class WindowsAPI
45 {
46 #region Types
47 public enum VirtualKeyCode : ushort
48 {
49 VK_LBUTTON = 0x01,
50 VK_RBUTTON = 0x02,
51 VK_CANCEL = 0x03,
52 VK_MBUTTON = 0x04,
53 VK_XBUTTON1 = 0x05,
54 VK_XBUTTON2 = 0x06,
55 VK_BACK = 0x08,
56 VK_TAB = 0x09,
57 VK_CLEAR = 0x0C,
58 VK_RETURN = 0x0D,
59 VK_SHIFT = 0x10,
60 VK_CONTROL = 0x11,
61 VK_MENU = 0x12,
62 VK_PAUSE = 0x13,
63 VK_CAPITAL = 0x14,
64 VK_KANA = 0x15,
65 VK_HANGEUL = 0x15,
66 VK_HANGUL = 0x15,
67 VK_JUNJA = 0x17,
68 VK_FINAL = 0x18,
69 VK_HANJA = 0x19,
70 VK_KANJI = 0x19,
71 VK_ESCAPE = 0x1B,
72 VK_CONVERT = 0x1C,
73 VK_NONCONVERT = 0x1D,
74 VK_ACCEPT = 0x1E,
75 VK_MODECHANGE = 0x1F,
76 VK_SPACE = 0x20,
77 VK_PRIOR = 0x21,
78 VK_NEXT = 0x22,
79 VK_END = 0x23,
80 VK_HOME = 0x24,
81 VK_LEFT = 0x25,
82 VK_UP = 0x26,
83 VK_RIGHT = 0x27,
84 VK_DOWN = 0x28,
85 VK_SELECT = 0x29,
86 VK_PRINT = 0x2A,
87 VK_EXECUTE = 0x2B,
88 VK_SNAPSHOT = 0x2C,
89 VK_INSERT = 0x2D,
90 VK_DELETE = 0x2E,
91 VK_HELP = 0x2F,
92 VK_0 = 0x30,
93 VK_1 = 0x31,
94 VK_2 = 0x32,
95 VK_3 = 0x33,
96 VK_4 = 0x34,
97 VK_5 = 0x35,
98 VK_6 = 0x36,
99 VK_7 = 0x37,
100 VK_8 = 0x38,
101 VK_9 = 0x39,
102 VK_B = 0x42,
103 VK_C = 0x43,
104 VK_D = 0x44,
105 VK_E = 0x45,
106 VK_F = 0x46,
107 VK_G = 0x47,
108 VK_H = 0x48,
109 VK_I = 0x49,
110 VK_J = 0x4A,
111 VK_K = 0x4B,
112 VK_L = 0x4C,
113 VK_M = 0x4D,
114 VK_N = 0x4E,
115 VK_O = 0x4F,
116 VK_P = 0x50,
117 VK_Q = 0x51,
118 VK_R = 0x52,
119 VK_S = 0x53,
120 VK_T = 0x54,
121 VK_U = 0x55,
122 VK_V = 0x56,
123 VK_W = 0x57,
124 VK_X = 0x58,
125 VK_Y = 0x59,
126 VK_Z = 0x5A,
127 VK_LWIN = 0x5B,
128 VK_RWIN = 0x5C,
129 VK_APPS = 0x5D,
130 VK_SLEEP = 0x5F,
131 VK_NUMPAD0 = 0x60,
132 VK_NUMPAD1 = 0x61,
133 VK_NUMPAD2 = 0x62,
134 VK_NUMPAD3 = 0x63,
135 VK_NUMPAD4 = 0x64,
136 VK_NUMPAD5 = 0x65,
137 VK_NUMPAD6 = 0x66,
138 VK_NUMPAD7 = 0x67,
139 VK_NUMPAD8 = 0x68,
140 VK_NUMPAD9 = 0x69,
141 VK_MULTIPLY = 0x6A,
142 VK_ADD = 0x6B,
143 VK_SEPARATOR = 0x6C,
144 VK_SUBTRACT = 0x6D,
145 VK_DECIMAL = 0x6E,
146 VK_DIVIDE = 0x6F,
147 VK_F1 = 0x70,
148 VK_F2 = 0x71,
149 VK_F3 = 0x72,
150 VK_F4 = 0x73,
151 VK_F5 = 0x74,
152 VK_F6 = 0x75,
153 VK_F7 = 0x76,
154 VK_F8 = 0x77,
155 VK_F9 = 0x78,
156 VK_F10 = 0x79,
157 VK_F11 = 0x7A,
158 VK_F12 = 0x7B,
159 VK_F13 = 0x7C,
160 VK_F14 = 0x7D,
161 VK_F15 = 0x7E,
162 VK_F16 = 0x7F,
163 VK_F17 = 0x80,
164 VK_F18 = 0x81,
165 VK_F19 = 0x82,
166 VK_F20 = 0x83,
167 VK_F21 = 0x84,
168 VK_F22 = 0x85,
169 VK_F23 = 0x86,
170 VK_F24 = 0x87,
171 VK_NUMLOCK = 0x90,
172 VK_SCROLL = 0x91,
173 VK_LSHIFT = 0xA0,
174 VK_RSHIFT = 0xA1,
175 VK_LCONTROL = 0xA2,
176 VK_RCONTROL = 0xA3,
177 VK_LMENU = 0xA4,
178 VK_RMENU = 0xA5,
179 VK_BROWSER_BACK = 0xA6,
180 VK_BROWSER_FORWARD = 0xA7,
181 VK_BROWSER_REFRESH = 0xA8,
182 VK_BROWSER_STOP = 0xA9,
183 VK_BROWSER_SEARCH = 0xAA,
184 VK_BROWSER_FAVORITES = 0xAB,
185 VK_BROWSER_HOME = 0xAC,
186 VK_VOLUME_MUTE = 0xAD,
187 VK_VOLUME_DOWN = 0xAE,
188 VK_VOLUME_UP = 0xAF,
189 VK_MEDIA_NEXT_TRACK = 0xB0,
190 VK_MEDIA_PREV_TRACK = 0xB1,
191 VK_MEDIA_STOP = 0xB2,
192 VK_MEDIA_PLAY_PAUSE = 0xB3,
193 VK_LAUNCH_MAIL = 0xB4,
194 VK_LAUNCH_MEDIA_SELECT = 0xB5,
195 VK_LAUNCH_APP1 = 0xB6,
196 VK_LAUNCH_APP2 = 0xB7,
197 VK_OEM_1 = 0xBA,
198 VK_OEM_PLUS = 0xBB,
199 VK_OEM_COMMA = 0xBC,
200 VK_OEM_MINUS = 0xBD,
201 VK_OEM_PERIOD = 0xBE,
202 VK_OEM_2 = 0xBF,
203 VK_OEM_3 = 0xC0,
204 VK_OEM_4 = 0xDB,
205 VK_OEM_5 = 0xDC,
206 VK_OEM_6 = 0xDD,
207 VK_OEM_7 = 0xDE,
208 VK_OEM_8 = 0xDF,
209 VK_OEM_102 = 0xE2,
210 VK_PROCESSKEY = 0xE5,
211 VK_PACKET = 0xE7,
212 VK_ATTN = 0xF6,
213 VK_CRSEL = 0xF7,
214 VK_EXSEL = 0xF8,
215 VK_EREOF = 0xF9,
216 VK_PLAY = 0xFA,
217 VK_ZOOM = 0xFB,
218 VK_NONAME = 0xFC,
219 VK_PA1 = 0xFD,
220 VK_OEM_CLEAR = 0xFE,
221 }
222
223 public static string GetVirtualKeyName(VirtualKeyCode key)
224 {
225 var keyName = Enum.GetName(typeof(VirtualKeyCode), key).ToUpper();
226 var friendlyName = Resources.ResourceManager.GetString(keyName, Resources.Culture);
227 return friendlyName ?? keyName.ToLower().Substring(3).Replace('_', ' ');
228 }
229
230 public enum InputType : uint
231 {
232 Mouse = 0,
233 Keyboard = 1,
234 Hardware = 2
235 }
236
237 public enum KeyEvent : uint
238 {
239 ExtendedKey = 0x0001,
240 KeyUp = 0x0002,
241 Unicode = 0x0003,
242 ScanCode = 0x0008
243 }
244
245 public enum XButton : uint
246 {
247 One = 0x0001,
248 Two = 0x0002
249 }
250
251 public enum MouseEvent : uint
252 {
253 Move = 0x0001,
254 LeftDown = 0x0002,
255 LeftUp = 0x0004,
256 RightDown = 0x0008,
257 RightUp = 0x0010,
258 MiddleDown = 0x0020,
259 Middleup = 0x0040,
260 XDown = 0x0080,
261 XUp = 0x0100,
262 Wheel = 0x0800,
263 VirtualDesk = 0x4000,
264 Absolute = 0x8000
265 }
266
267 public enum ShowType
268 {
269 ShowNormal = 1
270 }
271
272 #pragma warning disable 649
273 public struct MouseInput
274 {
275 public Int32 X;
276 public Int32 Y;
277 public UInt32 MouseData;
278 public UInt32 Flags;
279 public UInt32 Time;
280 public IntPtr ExtraInfo;
281 }
282 public struct KeyboardInput
283 {
284 public UInt16 KeyCode;
285 public UInt16 Scan;
286 public UInt32 Flags;
287 public UInt32 Time;
288 public IntPtr ExtraInfo;
289 }
290 public struct HardwareInput
291 {
292 public UInt32 Msg;
293 public UInt16 ParamL;
294 public UInt16 ParamH;
295 }
296
297 [StructLayout(LayoutKind.Explicit)]
298 public struct CombinedInput
299 {
300 [FieldOffset(0)]
301 public MouseInput Mouse;
302 [FieldOffset(0)]
303 public KeyboardInput Keyboard;
304 [FieldOffset(0)]
305 public HardwareInput Hardware;
306 }
307
308 public struct Input
309 {
310 public InputType Type;
311 public CombinedInput Data;
312 }
313 #pragma warning restore 649
314 #endregion
315
316 #region DllImports
317 [DllImport("kernel32.dll")]
318 public static extern uint GetCurrentThreadId();
319
320 [DllImport("kernel32.dll", SetLastError = true)]
321 public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer,
322 int dwSize, out int lpNumberOfBytesRead);
323
324 [DllImport("user32.dll")]
325 public static extern IntPtr GetForegroundWindow();
326
327 [DllImport("user32.dll", SetLastError = true)]
328 public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
329
330 [DllImport("user32.dll")]
331 public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
332
333 [DllImport("user32.dll", SetLastError = true)]
334 public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
335 string lpszWindow);
336
337 [DllImport("user32.Dll", EntryPoint = "PostMessageA")]
338 public static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
339
340 [DllImport("user32.dll")]
341 public static extern byte VkKeyScan(char ch);
342
343 [DllImport("user32.dll")]
344 public static extern uint MapVirtualKey(uint uCode, uint uMapType);
345
346 [DllImport("user32.dll")]
347 public static extern IntPtr SetFocus(IntPtr hWnd);
348
349 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
350 [return: MarshalAs(UnmanagedType.Bool)]
351 public static extern bool SetForegroundWindow(IntPtr hWnd);
352
353 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
354 [return: MarshalAs(UnmanagedType.Bool)]
355 public static extern bool AllowSetForegroundWindow(int dwProcessId);
356
357 [DllImport("user32.dll")]
358 public static extern uint SendInput(uint numberOfInputs,
359 [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] Input[] input, int structSize);
360
361 [DllImport("user32.dll")]
362 public static extern IntPtr GetMessageExtraInfo();
363
364 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
365 public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
366
367 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
368 public static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
369
370 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
371 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
372 #endregion
373
374 /// <summary>
375 /// Forces a window to the foreground
376 /// </summary>
377 /// <param name="windowHandle">Window that becomes the foreground window</param>
378 /// <returns>True when succeeded, false otherwise</returns>
379 public static bool ForceForeground(IntPtr windowHandle)
380 {
381 // get current foreground
382 var currentForeground = GetForegroundWindow();
383
384 // window already foreground window
385 if (currentForeground == windowHandle)
386 return true;
387
388 // get thread id
389 uint temp;
390 var windowThreadId = GetWindowThreadProcessId(windowHandle, out temp);
391
392 // attach thread input
393 if (currentForeground != IntPtr.Zero && !AttachThreadInput(GetCurrentThreadId(), windowThreadId, true))
394 return false;
395
396 // switch foreground
397 SetForegroundWindow(windowHandle);
398 while (GetForegroundWindow() != windowHandle){}
399
400 // (re)attach input
401 if (currentForeground != IntPtr.Zero)
402 AttachThreadInput(GetCurrentThreadId(), windowThreadId, false);
403
404 return (GetForegroundWindow() == windowHandle);
405 }
406
407 /// <summary>
408 /// Makes an application the foreground window and send input to it
409 /// </summary>
410 /// <param name="windowHandle">The window to send the input to</param>
411 /// <param name="numberOfInputs">Number of inputs in the input parameter</param>
412 /// <param name="input">The input to send</param>
413 /// <param name="structSize">The size of an input struct</param>
414 /// <returns>True when sent false otherwise</returns>
415 public static bool SendInputTo(IntPtr windowHandle, uint numberOfInputs, Input[] input, int structSize)
416 {
417 return ShowWindowAsync(windowHandle, (int)ShowType.ShowNormal) &&
418 ForceForeground(windowHandle) &&
419 SendInput(numberOfInputs, input, structSize) == 0;
420 }
421
422 /// <summary>
423 /// Find a window handle given it's name
424 /// </summary>
425 /// <param name="name">The name of the window</param>
426 /// <returns>The requested handle, or IntPtr.Zero when not found</returns>
427 public static IntPtr FindWindow(string name)
428 {
429 foreach (var proc in Process.GetProcesses())
430 {
431 if (proc.MainWindowTitle == name)
432 return proc.MainWindowHandle;
433 }
434
435 return IntPtr.Zero;
436 }
437
438 /// <summary>
439 /// Check whether there's another instance of this program running, and return the process when found
440 /// </summary>
441 /// <returns>The running process, or null when not found</returns>
442 public static Process RunningInstance()
443 {
444 var current = Process.GetCurrentProcess();
445 foreach (var process in Process.GetProcessesByName(current.ProcessName))
446 {
447 if (process.Id != current.Id && Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
448 return process;
449 }
450
451 return null;
452 }
453 }
454}