2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #ifndef _USE_MATH_DEFINES
22 #define _USE_MATH_DEFINES
26 #include "utils/log.h"
28 #include "WinEventsWin32.h"
29 #include "WIN32Util.h"
30 #include "storage/windows/Win32StorageProvider.h"
31 #include "Application.h"
32 #include "input/XBMC_vkeys.h"
33 #include "input/MouseStat.h"
34 #include "input/touch/generic/GenericTouchActionHandler.h"
35 #include "input/touch/generic/GenericTouchSwipeDetector.h"
36 #include "input/windows/WINJoystick.h"
37 #include "storage/MediaManager.h"
38 #include "windowing/WindowingFactory.h"
40 #include "guilib/LocalizeStrings.h"
41 #include "input/KeyboardStat.h"
42 #include "guilib/GUIWindowManager.h"
43 #include "guilib/GUIControl.h" // for EVENT_RESULT
44 #include "powermanagement/windows/Win32PowerSyscall.h"
46 #include "settings/AdvancedSettings.h"
47 #include "settings/Settings.h"
48 #include "peripherals/Peripherals.h"
49 #include "utils/JobManager.h"
50 #include "network/Zeroconf.h"
51 #include "network/ZeroconfBrowser.h"
52 #include "GUIUserMessages.h"
53 #include "utils/CharsetConverter.h"
57 using namespace PERIPHERALS;
62 #define LODWORD(longval) ((DWORD)((DWORDLONG)(longval)))
65 #define ROTATE_ANGLE_DEGREE(arg) GID_ROTATE_ANGLE_FROM_ARGUMENT(LODWORD(arg)) * 180 / M_PI
67 #define XBMC_arraysize(array) (sizeof(array)/sizeof(array[0]))
69 /* Masks for processing the windows KEYDOWN and KEYUP messages */
70 #define REPEATED_KEYMASK (1<<30)
71 #define EXTENDED_KEYMASK (1<<24)
72 #define EXTKEYPAD(keypad) ((scancode & 0x100)?(mvke):(keypad))
74 static XBMCKey VK_keymap[XBMCK_LAST];
76 static GUID USB_HID_GUID = { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
78 uint32_t g_uQueryCancelAutoPlay = 0;
80 int XBMC_TranslateUNICODE = 1;
82 PHANDLE_EVENT_FUNC CWinEventsWin32::m_pEventFunc = NULL;
83 int CWinEventsWin32::m_originalZoomDistance = 0;
84 Pointer CWinEventsWin32::m_touchPointer;
85 CGenericTouchSwipeDetector* CWinEventsWin32::m_touchSwipeDetector = NULL;
87 // register to receive SD card events (insert/remove)
88 // seen at http://www.codeproject.com/Messages/2897423/Re-No-message-triggered-on-SD-card-insertion-remov.aspx
89 #define WM_MEDIA_CHANGE (WM_USER + 666)
90 SHChangeNotifyEntry shcne;
92 void DIB_InitOSKeymap()
94 char current_layout[KL_NAMELENGTH];
96 GetKeyboardLayoutName(current_layout);
98 LoadKeyboardLayout(current_layout, KLF_ACTIVATE);
100 /* Map the VK keysyms */
101 for (int i = 0; i < XBMC_arraysize(VK_keymap); ++i)
102 VK_keymap[i] = XBMCK_UNKNOWN;
104 VK_keymap[VK_BACK] = XBMCK_BACKSPACE;
105 VK_keymap[VK_TAB] = XBMCK_TAB;
106 VK_keymap[VK_CLEAR] = XBMCK_CLEAR;
107 VK_keymap[VK_RETURN] = XBMCK_RETURN;
108 VK_keymap[VK_PAUSE] = XBMCK_PAUSE;
109 VK_keymap[VK_ESCAPE] = XBMCK_ESCAPE;
110 VK_keymap[VK_SPACE] = XBMCK_SPACE;
111 VK_keymap[VK_APOSTROPHE] = XBMCK_QUOTE;
112 VK_keymap[VK_COMMA] = XBMCK_COMMA;
113 VK_keymap[VK_MINUS] = XBMCK_MINUS;
114 VK_keymap[VK_PERIOD] = XBMCK_PERIOD;
115 VK_keymap[VK_SLASH] = XBMCK_SLASH;
116 VK_keymap[VK_0] = XBMCK_0;
117 VK_keymap[VK_1] = XBMCK_1;
118 VK_keymap[VK_2] = XBMCK_2;
119 VK_keymap[VK_3] = XBMCK_3;
120 VK_keymap[VK_4] = XBMCK_4;
121 VK_keymap[VK_5] = XBMCK_5;
122 VK_keymap[VK_6] = XBMCK_6;
123 VK_keymap[VK_7] = XBMCK_7;
124 VK_keymap[VK_8] = XBMCK_8;
125 VK_keymap[VK_9] = XBMCK_9;
126 VK_keymap[VK_SEMICOLON] = XBMCK_SEMICOLON;
127 VK_keymap[VK_EQUALS] = XBMCK_EQUALS;
128 VK_keymap[VK_LBRACKET] = XBMCK_LEFTBRACKET;
129 VK_keymap[VK_BACKSLASH] = XBMCK_BACKSLASH;
130 VK_keymap[VK_OEM_102] = XBMCK_BACKSLASH;
131 VK_keymap[VK_RBRACKET] = XBMCK_RIGHTBRACKET;
132 VK_keymap[VK_GRAVE] = XBMCK_BACKQUOTE;
133 VK_keymap[VK_BACKTICK] = XBMCK_BACKQUOTE;
134 VK_keymap[VK_A] = XBMCK_a;
135 VK_keymap[VK_B] = XBMCK_b;
136 VK_keymap[VK_C] = XBMCK_c;
137 VK_keymap[VK_D] = XBMCK_d;
138 VK_keymap[VK_E] = XBMCK_e;
139 VK_keymap[VK_F] = XBMCK_f;
140 VK_keymap[VK_G] = XBMCK_g;
141 VK_keymap[VK_H] = XBMCK_h;
142 VK_keymap[VK_I] = XBMCK_i;
143 VK_keymap[VK_J] = XBMCK_j;
144 VK_keymap[VK_K] = XBMCK_k;
145 VK_keymap[VK_L] = XBMCK_l;
146 VK_keymap[VK_M] = XBMCK_m;
147 VK_keymap[VK_N] = XBMCK_n;
148 VK_keymap[VK_O] = XBMCK_o;
149 VK_keymap[VK_P] = XBMCK_p;
150 VK_keymap[VK_Q] = XBMCK_q;
151 VK_keymap[VK_R] = XBMCK_r;
152 VK_keymap[VK_S] = XBMCK_s;
153 VK_keymap[VK_T] = XBMCK_t;
154 VK_keymap[VK_U] = XBMCK_u;
155 VK_keymap[VK_V] = XBMCK_v;
156 VK_keymap[VK_W] = XBMCK_w;
157 VK_keymap[VK_X] = XBMCK_x;
158 VK_keymap[VK_Y] = XBMCK_y;
159 VK_keymap[VK_Z] = XBMCK_z;
160 VK_keymap[VK_DELETE] = XBMCK_DELETE;
162 VK_keymap[VK_NUMPAD0] = XBMCK_KP0;
163 VK_keymap[VK_NUMPAD1] = XBMCK_KP1;
164 VK_keymap[VK_NUMPAD2] = XBMCK_KP2;
165 VK_keymap[VK_NUMPAD3] = XBMCK_KP3;
166 VK_keymap[VK_NUMPAD4] = XBMCK_KP4;
167 VK_keymap[VK_NUMPAD5] = XBMCK_KP5;
168 VK_keymap[VK_NUMPAD6] = XBMCK_KP6;
169 VK_keymap[VK_NUMPAD7] = XBMCK_KP7;
170 VK_keymap[VK_NUMPAD8] = XBMCK_KP8;
171 VK_keymap[VK_NUMPAD9] = XBMCK_KP9;
172 VK_keymap[VK_DECIMAL] = XBMCK_KP_PERIOD;
173 VK_keymap[VK_DIVIDE] = XBMCK_KP_DIVIDE;
174 VK_keymap[VK_MULTIPLY] = XBMCK_KP_MULTIPLY;
175 VK_keymap[VK_SUBTRACT] = XBMCK_KP_MINUS;
176 VK_keymap[VK_ADD] = XBMCK_KP_PLUS;
178 VK_keymap[VK_UP] = XBMCK_UP;
179 VK_keymap[VK_DOWN] = XBMCK_DOWN;
180 VK_keymap[VK_RIGHT] = XBMCK_RIGHT;
181 VK_keymap[VK_LEFT] = XBMCK_LEFT;
182 VK_keymap[VK_INSERT] = XBMCK_INSERT;
183 VK_keymap[VK_HOME] = XBMCK_HOME;
184 VK_keymap[VK_END] = XBMCK_END;
185 VK_keymap[VK_PRIOR] = XBMCK_PAGEUP;
186 VK_keymap[VK_NEXT] = XBMCK_PAGEDOWN;
188 VK_keymap[VK_F1] = XBMCK_F1;
189 VK_keymap[VK_F2] = XBMCK_F2;
190 VK_keymap[VK_F3] = XBMCK_F3;
191 VK_keymap[VK_F4] = XBMCK_F4;
192 VK_keymap[VK_F5] = XBMCK_F5;
193 VK_keymap[VK_F6] = XBMCK_F6;
194 VK_keymap[VK_F7] = XBMCK_F7;
195 VK_keymap[VK_F8] = XBMCK_F8;
196 VK_keymap[VK_F9] = XBMCK_F9;
197 VK_keymap[VK_F10] = XBMCK_F10;
198 VK_keymap[VK_F11] = XBMCK_F11;
199 VK_keymap[VK_F12] = XBMCK_F12;
200 VK_keymap[VK_F13] = XBMCK_F13;
201 VK_keymap[VK_F14] = XBMCK_F14;
202 VK_keymap[VK_F15] = XBMCK_F15;
204 VK_keymap[VK_NUMLOCK] = XBMCK_NUMLOCK;
205 VK_keymap[VK_CAPITAL] = XBMCK_CAPSLOCK;
206 VK_keymap[VK_SCROLL] = XBMCK_SCROLLOCK;
207 VK_keymap[VK_RSHIFT] = XBMCK_RSHIFT;
208 VK_keymap[VK_LSHIFT] = XBMCK_LSHIFT;
209 VK_keymap[VK_RCONTROL] = XBMCK_RCTRL;
210 VK_keymap[VK_LCONTROL] = XBMCK_LCTRL;
211 VK_keymap[VK_RMENU] = XBMCK_RALT;
212 VK_keymap[VK_LMENU] = XBMCK_LALT;
213 VK_keymap[VK_RWIN] = XBMCK_RSUPER;
214 VK_keymap[VK_LWIN] = XBMCK_LSUPER;
216 VK_keymap[VK_HELP] = XBMCK_HELP;
218 VK_keymap[VK_PRINT] = XBMCK_PRINT;
220 VK_keymap[VK_SNAPSHOT] = XBMCK_PRINT;
221 VK_keymap[VK_CANCEL] = XBMCK_BREAK;
222 VK_keymap[VK_APPS] = XBMCK_MENU;
224 // Only include the multimedia keys if they have been enabled in the
226 if (g_advancedSettings.m_enableMultimediaKeys)
228 VK_keymap[VK_BROWSER_BACK] = XBMCK_BROWSER_BACK;
229 VK_keymap[VK_BROWSER_FORWARD] = XBMCK_BROWSER_FORWARD;
230 VK_keymap[VK_BROWSER_REFRESH] = XBMCK_BROWSER_REFRESH;
231 VK_keymap[VK_BROWSER_STOP] = XBMCK_BROWSER_STOP;
232 VK_keymap[VK_BROWSER_SEARCH] = XBMCK_BROWSER_SEARCH;
233 VK_keymap[VK_BROWSER_FAVORITES] = XBMCK_BROWSER_FAVORITES;
234 VK_keymap[VK_BROWSER_HOME] = XBMCK_BROWSER_HOME;
235 VK_keymap[VK_VOLUME_MUTE] = XBMCK_VOLUME_MUTE;
236 VK_keymap[VK_VOLUME_DOWN] = XBMCK_VOLUME_DOWN;
237 VK_keymap[VK_VOLUME_UP] = XBMCK_VOLUME_UP;
238 VK_keymap[VK_MEDIA_NEXT_TRACK] = XBMCK_MEDIA_NEXT_TRACK;
239 VK_keymap[VK_MEDIA_PREV_TRACK] = XBMCK_MEDIA_PREV_TRACK;
240 VK_keymap[VK_MEDIA_STOP] = XBMCK_MEDIA_STOP;
241 VK_keymap[VK_MEDIA_PLAY_PAUSE] = XBMCK_MEDIA_PLAY_PAUSE;
242 VK_keymap[VK_LAUNCH_MAIL] = XBMCK_LAUNCH_MAIL;
243 VK_keymap[VK_LAUNCH_MEDIA_SELECT] = XBMCK_LAUNCH_MEDIA_SELECT;
244 VK_keymap[VK_LAUNCH_APP1] = XBMCK_LAUNCH_APP1;
245 VK_keymap[VK_LAUNCH_APP2] = XBMCK_LAUNCH_APP2;
249 static int XBMC_MapVirtualKey(int scancode, int vkey)
251 int mvke = MapVirtualKeyEx(scancode & 0xFF, 1, NULL);
254 { /* These are always correct */
262 /* These are already handled */
271 /* Multimedia keys are already handled */
272 case VK_BROWSER_BACK:
273 case VK_BROWSER_FORWARD:
274 case VK_BROWSER_REFRESH:
275 case VK_BROWSER_STOP:
276 case VK_BROWSER_SEARCH:
277 case VK_BROWSER_FAVORITES:
278 case VK_BROWSER_HOME:
282 case VK_MEDIA_NEXT_TRACK:
283 case VK_MEDIA_PREV_TRACK:
285 case VK_MEDIA_PLAY_PAUSE:
287 case VK_LAUNCH_MEDIA_SELECT:
293 { /* Distinguish between keypad and extended keys */
294 case VK_INSERT: return EXTKEYPAD(VK_NUMPAD0);
295 case VK_DELETE: return EXTKEYPAD(VK_DECIMAL);
296 case VK_END: return EXTKEYPAD(VK_NUMPAD1);
297 case VK_DOWN: return EXTKEYPAD(VK_NUMPAD2);
298 case VK_NEXT: return EXTKEYPAD(VK_NUMPAD3);
299 case VK_LEFT: return EXTKEYPAD(VK_NUMPAD4);
300 case VK_CLEAR: return EXTKEYPAD(VK_NUMPAD5);
301 case VK_RIGHT: return EXTKEYPAD(VK_NUMPAD6);
302 case VK_HOME: return EXTKEYPAD(VK_NUMPAD7);
303 case VK_UP: return EXTKEYPAD(VK_NUMPAD8);
304 case VK_PRIOR: return EXTKEYPAD(VK_NUMPAD9);
306 return mvke ? mvke : vkey;
309 static XBMC_keysym *TranslateKey(WPARAM vkey, UINT scancode, XBMC_keysym *keysym, int pressed)
311 uint8_t keystate[256];
313 /* Set the keysym information */
314 keysym->scancode = (unsigned char) scancode;
317 if ((vkey == VK_RETURN) && (scancode & 0x100))
319 /* No VK_ code for the keypad enter key */
320 keysym->sym = XBMCK_KP_ENTER;
324 keysym->sym = VK_keymap[XBMC_MapVirtualKey(scancode, vkey)];
327 // Attempt to convert the keypress to a UNICODE character
328 GetKeyboardState(keystate);
330 if ( pressed && XBMC_TranslateUNICODE )
331 { uint16_t wchars[2];
333 /* Numlock isn't taken into account in ToUnicode,
334 * so we handle it as a special case here */
335 if ((keystate[VK_NUMLOCK] & 1) && vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9)
337 keysym->unicode = vkey - VK_NUMPAD0 + '0';
339 else if (ToUnicode((UINT)vkey, scancode, keystate, (LPWSTR)wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0)
341 keysym->unicode = wchars[0];
345 // Set the modifier bitmap
347 mod = (uint16_t) XBMCKMOD_NONE;
349 // If left control and right alt are down this usually means that
351 if ((keystate[VK_LCONTROL] & 0x80) && (keystate[VK_RMENU] & 0x80))
353 mod |= XBMCKMOD_MODE;
357 if (keystate[VK_LCONTROL] & 0x80) mod |= XBMCKMOD_LCTRL;
358 if (keystate[VK_RMENU] & 0x80) mod |= XBMCKMOD_RALT;
361 // Check the remaining modifiers
362 if (keystate[VK_LSHIFT] & 0x80) mod |= XBMCKMOD_LSHIFT;
363 if (keystate[VK_RSHIFT] & 0x80) mod |= XBMCKMOD_RSHIFT;
364 if (keystate[VK_RCONTROL] & 0x80) mod |= XBMCKMOD_RCTRL;
365 if (keystate[VK_LMENU] & 0x80) mod |= XBMCKMOD_LALT;
366 if (keystate[VK_LWIN] & 0x80) mod |= XBMCKMOD_LSUPER;
367 if (keystate[VK_RWIN] & 0x80) mod |= XBMCKMOD_LSUPER;
368 keysym->mod = (XBMCMod) mod;
370 // Return the updated keysym
374 void CWinEventsWin32::MessagePush(XBMC_Event *newEvent)
376 // m_pEventFunc should be set because MessagePush is only executed by
377 // methods called from WndProc()
378 if (m_pEventFunc == NULL)
381 m_pEventFunc(*newEvent);
384 bool CWinEventsWin32::MessagePump()
387 while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
389 TranslateMessage( &msg );
390 DispatchMessage( &msg );
395 size_t CWinEventsWin32::GetQueueSize()
398 return PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
401 LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
404 ZeroMemory(&newEvent, sizeof(newEvent));
405 static HDEVNOTIFY hDeviceNotify;
407 if (uMsg == WM_CREATE)
410 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
412 g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
414 shcne.fRecursive = TRUE;
415 long fEvents = SHCNE_DRIVEADD | SHCNE_DRIVEREMOVED | SHCNE_MEDIAREMOVED | SHCNE_MEDIAINSERTED;
416 SHChangeNotifyRegister(hWnd, SHCNRF_ShellLevel | SHCNRF_NewDelivery, fEvents, WM_MEDIA_CHANGE, 1, &shcne);
417 RegisterDeviceInterfaceToHwnd(USB_HID_GUID, hWnd, &hDeviceNotify);
421 if (uMsg == WM_DESTROY)
424 m_pEventFunc = (PHANDLE_EVENT_FUNC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
426 return DefWindowProc(hWnd, uMsg, wParam, lParam);
428 if(g_uQueryCancelAutoPlay != 0 && uMsg == g_uQueryCancelAutoPlay)
437 UnregisterDeviceNotification(hDeviceNotify);
438 newEvent.type = XBMC_QUIT;
439 m_pEventFunc(newEvent);
443 bool active = g_application.GetRenderGUI();
444 g_application.SetRenderGUI(wParam != 0);
445 if (g_application.GetRenderGUI() != active)
446 g_Windowing.NotifyAppActiveChange(g_application.GetRenderGUI());
447 CLog::Log(LOGDEBUG, __FUNCTION__"Window is %s", g_application.GetRenderGUI() ? "shown" : "hidden");
452 if( WA_INACTIVE != wParam )
453 g_Joystick.Reinitialize();
455 bool active = g_application.GetRenderGUI();
458 g_application.SetRenderGUI(false);
462 WINDOWPLACEMENT lpwndpl;
463 lpwndpl.length = sizeof(lpwndpl);
464 if (LOWORD(wParam) != WA_INACTIVE)
466 if (GetWindowPlacement(hWnd, &lpwndpl))
467 g_application.SetRenderGUI(lpwndpl.showCmd != SW_HIDE);
471 g_application.SetRenderGUI(g_Windowing.WindowedMode());
474 if (g_application.GetRenderGUI() != active)
475 g_Windowing.NotifyAppActiveChange(g_application.GetRenderGUI());
476 CLog::Log(LOGDEBUG, __FUNCTION__"Window is %s", g_application.GetRenderGUI() ? "active" : "inactive");
481 g_application.m_AppFocused = uMsg == WM_SETFOCUS;
482 g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
483 if (uMsg == WM_KILLFOCUS)
486 if (CWIN32Util::GetFocussedProcess(procfile))
487 CLog::Log(LOGDEBUG, __FUNCTION__": Focus switched to process %s", procfile.c_str());
490 /* needs to be reviewed after frodo. we reset the system idle timer
491 and the display timer directly now (see m_screenSaverTimer).
493 switch( wParam&0xFFF0 )
495 case SC_MONITORPOWER:
496 if (g_application.m_pPlayer->IsPlaying() || g_application.m_pPlayer->IsPausedPlayback())
498 else if(CSettings::Get().GetInt("powermanagement.displaysoff") == 0)
508 case VK_F4: //alt-f4, default event quit.
509 return(DefWindowProc(hWnd, uMsg, wParam, lParam));
510 case VK_RETURN: //alt-return
511 if ((lParam & REPEATED_KEYMASK) == 0)
512 g_graphicsContext.ToggleFullScreenRoot();
515 //deliberate fallthrough
521 if ( lParam & EXTENDED_KEYMASK )
522 wParam = VK_RCONTROL;
524 wParam = VK_LCONTROL;
527 /* EXTENDED trick doesn't work here */
528 if (GetKeyState(VK_LSHIFT) & 0x8000)
530 else if (GetKeyState(VK_RSHIFT) & 0x8000)
534 if ( lParam & EXTENDED_KEYMASK )
541 TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
543 newEvent.type = XBMC_KEYDOWN;
544 newEvent.key.keysym = keysym;
545 m_pEventFunc(newEvent);
555 if ( lParam&EXTENDED_KEYMASK )
556 wParam = VK_RCONTROL;
558 wParam = VK_LCONTROL;
562 uint32_t scanCodeL = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
563 uint32_t scanCodeR = MapVirtualKey(VK_RSHIFT, MAPVK_VK_TO_VSC);
564 uint32_t keyCode = (uint32_t)((lParam & 0xFF0000) >> 16);
565 if (keyCode == scanCodeL)
567 else if (keyCode == scanCodeR)
572 if ( lParam&EXTENDED_KEYMASK )
579 TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
581 if (wParam == VK_SNAPSHOT)
582 newEvent.type = XBMC_KEYDOWN;
584 newEvent.type = XBMC_KEYUP;
585 newEvent.key.keysym = keysym;
586 m_pEventFunc(newEvent);
589 case WM_APPCOMMAND: // MULTIMEDIA keys are mapped to APPCOMMANDS
591 CLog::Log(LOGDEBUG, "WinEventsWin32.cpp: APPCOMMAND %d", GET_APPCOMMAND_LPARAM(lParam));
592 newEvent.appcommand.type = XBMC_APPCOMMAND;
593 newEvent.appcommand.action = GET_APPCOMMAND_LPARAM(lParam);
594 if (m_pEventFunc(newEvent))
597 return DefWindowProc(hWnd, uMsg, wParam, lParam);
599 case WM_GESTURENOTIFY:
601 OnGestureNotify(hWnd, lParam);
602 return DefWindowProc(hWnd, WM_GESTURENOTIFY, wParam, lParam);
606 OnGesture(hWnd, lParam);
610 if (wParam == VK_RETURN) //stop system beep on alt-return
614 if (HTCLIENT != LOWORD(lParam))
615 g_Windowing.ShowOSMouse(true);
618 newEvent.type = XBMC_MOUSEMOTION;
619 newEvent.motion.x = GET_X_LPARAM(lParam);
620 newEvent.motion.y = GET_Y_LPARAM(lParam);
621 newEvent.motion.state = 0;
622 m_pEventFunc(newEvent);
627 newEvent.type = XBMC_MOUSEBUTTONDOWN;
628 newEvent.button.state = XBMC_PRESSED;
629 newEvent.button.x = GET_X_LPARAM(lParam);
630 newEvent.button.y = GET_Y_LPARAM(lParam);
631 newEvent.button.button = 0;
632 if (uMsg == WM_LBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_LEFT;
633 else if (uMsg == WM_MBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_MIDDLE;
634 else if (uMsg == WM_RBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_RIGHT;
635 m_pEventFunc(newEvent);
640 newEvent.type = XBMC_MOUSEBUTTONUP;
641 newEvent.button.state = XBMC_RELEASED;
642 newEvent.button.x = GET_X_LPARAM(lParam);
643 newEvent.button.y = GET_Y_LPARAM(lParam);
644 newEvent.button.button = 0;
645 if (uMsg == WM_LBUTTONUP) newEvent.button.button = XBMC_BUTTON_LEFT;
646 else if (uMsg == WM_MBUTTONUP) newEvent.button.button = XBMC_BUTTON_MIDDLE;
647 else if (uMsg == WM_RBUTTONUP) newEvent.button.button = XBMC_BUTTON_RIGHT;
648 m_pEventFunc(newEvent);
652 // SDL, which our events system is based off, sends a MOUSEBUTTONDOWN message
653 // followed by a MOUSEBUTTONUP message. As this is a momentary event, we just
654 // react on the MOUSEBUTTONUP message, resetting the state after processing.
655 newEvent.type = XBMC_MOUSEBUTTONDOWN;
656 newEvent.button.state = XBMC_PRESSED;
657 // the coordinates in WM_MOUSEWHEEL are screen, not client coordinates
659 point.x = GET_X_LPARAM(lParam);
660 point.y = GET_Y_LPARAM(lParam);
661 WindowFromScreenCoords(hWnd, &point);
662 newEvent.button.x = (uint16_t)point.x;
663 newEvent.button.y = (uint16_t)point.y;
664 newEvent.button.button = GET_Y_LPARAM(wParam) > 0 ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN;
665 m_pEventFunc(newEvent);
666 newEvent.type = XBMC_MOUSEBUTTONUP;
667 newEvent.button.state = XBMC_RELEASED;
668 m_pEventFunc(newEvent);
672 newEvent.type = XBMC_VIDEORESIZE;
673 newEvent.resize.w = GET_X_LPARAM(lParam);
674 newEvent.resize.h = GET_Y_LPARAM(lParam);
676 CLog::Log(LOGDEBUG, __FUNCTION__": window resize event");
678 if (!g_Windowing.IsAlteringWindow() && newEvent.resize.w > 0 && newEvent.resize.h > 0)
679 m_pEventFunc(newEvent);
683 newEvent.type = XBMC_VIDEOMOVE;
684 newEvent.move.x = GET_X_LPARAM(lParam);
685 newEvent.move.y = GET_Y_LPARAM(lParam);
687 CLog::Log(LOGDEBUG, __FUNCTION__": window move event");
689 if (!g_Windowing.IsAlteringWindow())
690 m_pEventFunc(newEvent);
693 case WM_MEDIA_CHANGE:
695 // This event detects media changes of usb, sd card and optical media.
696 // It only works if the explorer.exe process is started. Because this
697 // isn't the case for all setups we use WM_DEVICECHANGE for usb and
698 // optical media because this event is also triggered without the
699 // explorer process. Since WM_DEVICECHANGE doesn't detect sd card changes
700 // we still use this event only for sd.
702 PIDLIST_ABSOLUTE *ppidl;
703 HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
707 char drivePath[MAX_PATH+1];
708 if (!SHGetPathFromIDList(ppidl[0], drivePath))
714 case SHCNE_MEDIAINSERTED:
715 if (GetDriveType(drivePath) != DRIVE_CDROM)
717 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", drivePath);
718 CWin32StorageProvider::SetEvent();
722 case SHCNE_DRIVEREMOVED:
723 case SHCNE_MEDIAREMOVED:
724 if (GetDriveType(drivePath) != DRIVE_CDROM)
726 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", drivePath);
727 CWin32StorageProvider::SetEvent();
731 SHChangeNotification_Unlock(hLock);
735 case WM_POWERBROADCAST:
736 if (wParam==PBT_APMSUSPEND)
738 CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMSUSPEND event was sent");
739 CWin32PowerSyscall::SetOnSuspend();
741 else if(wParam==PBT_APMRESUMEAUTOMATIC)
743 CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMRESUMEAUTOMATIC event was sent");
744 CWin32PowerSyscall::SetOnResume();
747 case WM_DEVICECHANGE:
751 case DBT_DEVNODES_CHANGED:
752 g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
754 case DBT_DEVICEARRIVAL:
755 case DBT_DEVICEREMOVECOMPLETE:
756 if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
758 g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
759 g_Joystick.Reinitialize();
761 // check if an usb or optical media was inserted or removed
762 if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_VOLUME)
764 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)((_DEV_BROADCAST_HEADER*) lParam);
766 if (lpdbv -> dbcv_flags & DBTF_MEDIA)
769 strdrive.Format("%c:\\", CWIN32Util::FirstDriveFromMask(lpdbv ->dbcv_unitmask));
770 if(wParam == DBT_DEVICEARRIVAL)
772 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", strdrive.c_str());
773 CJobManager::GetInstance().AddJob(new CDetectDisc(strdrive, true), NULL);
777 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", strdrive.c_str());
779 share.strPath = strdrive;
780 share.strName = share.strPath;
781 g_mediaManager.RemoveAutoSource(share);
785 CWin32StorageProvider::SetEvent();
791 //some other app has painted over our window, mark everything as dirty
792 g_windowManager.MarkDirty();
795 CZeroconf::GetInstance()->ProcessResults();
797 case BONJOUR_BROWSER_EVENT:
798 CZeroconfBrowser::GetInstance()->ProcessResults();
801 return(DefWindowProc(hWnd, uMsg, wParam, lParam));
804 void CWinEventsWin32::RegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND hWnd, HDEVNOTIFY *hDeviceNotify)
806 DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
808 ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
809 NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
810 NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
811 NotificationFilter.dbcc_classguid = InterfaceClassGuid;
813 *hDeviceNotify = RegisterDeviceNotification(
814 hWnd, // events recipient
815 &NotificationFilter, // type of device
816 DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
820 void CWinEventsWin32::WindowFromScreenCoords(HWND hWnd, POINT *point)
824 GetClientRect(hWnd, &clientRect);
826 windowPos.x = clientRect.left;
827 windowPos.y = clientRect.top;
828 ClientToScreen(hWnd, &windowPos);
829 point->x -= windowPos.x;
830 point->y -= windowPos.y;
833 void CWinEventsWin32::OnGestureNotify(HWND hWnd, LPARAM lParam)
835 // convert to window coordinates
836 PGESTURENOTIFYSTRUCT gn = (PGESTURENOTIFYSTRUCT)(lParam);
837 POINT point = { gn->ptsLocation.x, gn->ptsLocation.y };
838 WindowFromScreenCoords(hWnd, &point);
840 // by default we only want twofingertap and pressandtap gestures
841 // the other gestures are enabled best on supported gestures
842 GESTURECONFIG gc[] = {{ GID_ZOOM, 0, GC_ZOOM},
843 { GID_ROTATE, 0, GC_ROTATE},
844 { GID_PAN, 0, GC_PAN},
845 { GID_TWOFINGERTAP, GC_TWOFINGERTAP, GC_TWOFINGERTAP },
846 { GID_PRESSANDTAP, GC_PRESSANDTAP, GC_PRESSANDTAP }};
848 // send a message to see if a control wants any
850 if ((gestures = CGenericTouchActionHandler::Get().QuerySupportedGestures((float)point.x, (float)point.y)) != EVENT_RESULT_UNHANDLED)
852 if (gestures & EVENT_RESULT_ZOOM)
853 gc[0].dwWant |= GC_ZOOM;
854 if (gestures & EVENT_RESULT_ROTATE)
855 gc[1].dwWant |= GC_ROTATE;
856 if (gestures & EVENT_RESULT_PAN_VERTICAL)
857 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_GUTTER | GC_PAN_WITH_INERTIA;
858 if (gestures & EVENT_RESULT_PAN_VERTICAL_WITHOUT_INERTIA)
859 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
860 if (gestures & EVENT_RESULT_PAN_HORIZONTAL)
861 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_GUTTER | GC_PAN_WITH_INERTIA;
862 if (gestures & EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA)
863 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
864 if (gestures & EVENT_RESULT_SWIPE)
866 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_GUTTER;
868 // create a new touch swipe detector
869 m_touchSwipeDetector = new CGenericTouchSwipeDetector(&CGenericTouchActionHandler::Get(), 160.0f);
872 gc[0].dwBlock = gc[0].dwWant ^ 0x01;
873 gc[1].dwBlock = gc[1].dwWant ^ 0x01;
874 gc[2].dwBlock = gc[2].dwWant ^ 0x1F;
876 if (g_Windowing.PtrSetGestureConfig)
877 g_Windowing.PtrSetGestureConfig(hWnd, 0, 5, gc, sizeof(GESTURECONFIG));
880 void CWinEventsWin32::OnGesture(HWND hWnd, LPARAM lParam)
882 if (!g_Windowing.PtrGetGestureInfo)
885 GESTUREINFO gi = {0};
886 gi.cbSize = sizeof(gi);
887 g_Windowing.PtrGetGestureInfo((HGESTUREINFO)lParam, &gi);
889 // convert to window coordinates
890 POINT point = { gi.ptsLocation.x, gi.ptsLocation.y };
891 WindowFromScreenCoords(hWnd, &point);
893 if (gi.dwID == GID_BEGIN)
894 m_touchPointer.reset();
896 // if there's a "current" touch from a previous event, copy it to "last"
897 if (m_touchPointer.current.valid())
898 m_touchPointer.last = m_touchPointer.current;
900 // set the "current" touch
901 m_touchPointer.current.x = (float)point.x;
902 m_touchPointer.current.y = (float)point.y;
903 m_touchPointer.current.time = time(NULL);
909 // set the "down" touch
910 m_touchPointer.down = m_touchPointer.current;
911 m_originalZoomDistance = 0;
913 CGenericTouchActionHandler::Get().OnTouchGestureStart((float)point.x, (float)point.y);
918 CGenericTouchActionHandler::Get().OnTouchGestureEnd((float)point.x, (float)point.y, 0.0f, 0.0f, 0.0f, 0.0f);
923 if (!m_touchPointer.moving)
924 m_touchPointer.moving = true;
926 // calculate the velocity of the pan gesture
927 float velocityX, velocityY;
928 m_touchPointer.velocity(velocityX, velocityY);
930 CGenericTouchActionHandler::Get().OnTouchGesturePan(m_touchPointer.current.x, m_touchPointer.current.y,
931 m_touchPointer.current.x - m_touchPointer.last.x, m_touchPointer.current.y - m_touchPointer.last.y,
932 velocityX, velocityY);
934 if (m_touchSwipeDetector != NULL)
936 if (gi.dwFlags & GF_BEGIN)
938 m_touchPointer.down = m_touchPointer.current;
939 m_touchSwipeDetector->OnTouchDown(0, m_touchPointer);
941 else if (gi.dwFlags & GF_END)
943 m_touchSwipeDetector->OnTouchUp(0, m_touchPointer);
945 delete m_touchSwipeDetector;
946 m_touchSwipeDetector = NULL;
949 m_touchSwipeDetector->OnTouchMove(0, m_touchPointer);
956 if (gi.dwFlags == GF_BEGIN)
959 CGenericTouchActionHandler::Get().OnRotate((float)point.x, (float)point.y,
960 -(float)ROTATE_ANGLE_DEGREE(gi.ullArguments));
966 if (gi.dwFlags == GF_BEGIN)
968 m_originalZoomDistance = (int)LODWORD(gi.ullArguments);
972 // avoid division by 0
973 if (m_originalZoomDistance == 0)
976 CGenericTouchActionHandler::Get().OnZoomPinch((float)point.x, (float)point.y,
977 (float)LODWORD(gi.ullArguments) / (float)m_originalZoomDistance);
981 case GID_TWOFINGERTAP:
982 CGenericTouchActionHandler::Get().OnTap((float)point.x, (float)point.y, 2);
985 case GID_PRESSANDTAP:
987 // You have encountered an unknown gesture
990 if(g_Windowing.PtrCloseGestureInfoHandle)
991 g_Windowing.PtrCloseGestureInfoHandle((HGESTUREINFO)lParam);