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.Runtime.InteropServices; | |
35 | using System.Diagnostics; | |
36 | using System.Reflection; | |
37 | using LibCECTray.Properties; | |
38 | ||
39 | namespace 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 | } | |
16f47961 | 454 | } |