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 "windowing/WinEvents.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 LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
398 ZeroMemory(&newEvent, sizeof(newEvent));
399 static HDEVNOTIFY hDeviceNotify;
401 if (uMsg == WM_CREATE)
404 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
406 g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
408 shcne.fRecursive = TRUE;
409 long fEvents = SHCNE_DRIVEADD | SHCNE_DRIVEREMOVED | SHCNE_MEDIAREMOVED | SHCNE_MEDIAINSERTED;
410 SHChangeNotifyRegister(hWnd, SHCNRF_ShellLevel | SHCNRF_NewDelivery, fEvents, WM_MEDIA_CHANGE, 1, &shcne);
411 RegisterDeviceInterfaceToHwnd(USB_HID_GUID, hWnd, &hDeviceNotify);
415 if (uMsg == WM_DESTROY)
418 m_pEventFunc = (PHANDLE_EVENT_FUNC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
420 return DefWindowProc(hWnd, uMsg, wParam, lParam);
422 if(g_uQueryCancelAutoPlay != 0 && uMsg == g_uQueryCancelAutoPlay)
431 UnregisterDeviceNotification(hDeviceNotify);
432 newEvent.type = XBMC_QUIT;
433 m_pEventFunc(newEvent);
437 bool active = g_application.GetRenderGUI();
438 g_application.SetRenderGUI(wParam != 0);
439 if (g_application.GetRenderGUI() != active)
440 g_Windowing.NotifyAppActiveChange(g_application.GetRenderGUI());
441 CLog::Log(LOGDEBUG, __FUNCTION__"Window is %s", g_application.GetRenderGUI() ? "shown" : "hidden");
446 if( WA_INACTIVE != wParam )
447 g_Joystick.Reinitialize();
449 bool active = g_application.GetRenderGUI();
452 g_application.SetRenderGUI(false);
456 WINDOWPLACEMENT lpwndpl;
457 lpwndpl.length = sizeof(lpwndpl);
458 if (LOWORD(wParam) != WA_INACTIVE)
460 if (GetWindowPlacement(hWnd, &lpwndpl))
461 g_application.SetRenderGUI(lpwndpl.showCmd != SW_HIDE);
465 g_application.SetRenderGUI(g_Windowing.WindowedMode());
468 if (g_application.GetRenderGUI() != active)
469 g_Windowing.NotifyAppActiveChange(g_application.GetRenderGUI());
470 CLog::Log(LOGDEBUG, __FUNCTION__"Window is %s", g_application.GetRenderGUI() ? "active" : "inactive");
475 g_application.m_AppFocused = uMsg == WM_SETFOCUS;
476 g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
477 if (uMsg == WM_KILLFOCUS)
480 if (CWIN32Util::GetFocussedProcess(procfile))
481 CLog::Log(LOGDEBUG, __FUNCTION__": Focus switched to process %s", procfile.c_str());
484 /* needs to be reviewed after frodo. we reset the system idle timer
485 and the display timer directly now (see m_screenSaverTimer).
487 switch( wParam&0xFFF0 )
489 case SC_MONITORPOWER:
490 if (g_application.IsPlaying() || g_application.IsPaused())
492 else if(CSettings::Get().GetInt("powermanagement.displaysoff") == 0)
502 case VK_F4: //alt-f4, default event quit.
503 return(DefWindowProc(hWnd, uMsg, wParam, lParam));
504 case VK_RETURN: //alt-return
505 if ((lParam & REPEATED_KEYMASK) == 0)
506 g_graphicsContext.ToggleFullScreenRoot();
509 //deliberate fallthrough
515 if ( lParam & EXTENDED_KEYMASK )
516 wParam = VK_RCONTROL;
518 wParam = VK_LCONTROL;
521 /* EXTENDED trick doesn't work here */
522 if (GetKeyState(VK_LSHIFT) & 0x8000)
524 else if (GetKeyState(VK_RSHIFT) & 0x8000)
528 if ( lParam & EXTENDED_KEYMASK )
535 TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
537 newEvent.type = XBMC_KEYDOWN;
538 newEvent.key.keysym = keysym;
539 m_pEventFunc(newEvent);
549 if ( lParam&EXTENDED_KEYMASK )
550 wParam = VK_RCONTROL;
552 wParam = VK_LCONTROL;
556 uint32_t scanCodeL = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
557 uint32_t scanCodeR = MapVirtualKey(VK_RSHIFT, MAPVK_VK_TO_VSC);
558 uint32_t keyCode = (uint32_t)((lParam & 0xFF0000) >> 16);
559 if (keyCode == scanCodeL)
561 else if (keyCode == scanCodeR)
566 if ( lParam&EXTENDED_KEYMASK )
573 TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
575 if (wParam == VK_SNAPSHOT)
576 newEvent.type = XBMC_KEYDOWN;
578 newEvent.type = XBMC_KEYUP;
579 newEvent.key.keysym = keysym;
580 m_pEventFunc(newEvent);
583 case WM_APPCOMMAND: // MULTIMEDIA keys are mapped to APPCOMMANDS
585 CLog::Log(LOGDEBUG, "WinEventsWin32.cpp: APPCOMMAND %d", GET_APPCOMMAND_LPARAM(lParam));
586 newEvent.appcommand.type = XBMC_APPCOMMAND;
587 newEvent.appcommand.action = GET_APPCOMMAND_LPARAM(lParam);
588 if (m_pEventFunc(newEvent))
591 return DefWindowProc(hWnd, uMsg, wParam, lParam);
593 case WM_GESTURENOTIFY:
595 OnGestureNotify(hWnd, lParam);
596 return DefWindowProc(hWnd, WM_GESTURENOTIFY, wParam, lParam);
600 OnGesture(hWnd, lParam);
604 if (wParam == VK_RETURN) //stop system beep on alt-return
608 if (HTCLIENT != LOWORD(lParam))
609 g_Windowing.ShowOSMouse(true);
612 newEvent.type = XBMC_MOUSEMOTION;
613 newEvent.motion.x = GET_X_LPARAM(lParam);
614 newEvent.motion.y = GET_Y_LPARAM(lParam);
615 newEvent.motion.state = 0;
616 m_pEventFunc(newEvent);
621 newEvent.type = XBMC_MOUSEBUTTONDOWN;
622 newEvent.button.state = XBMC_PRESSED;
623 newEvent.button.x = GET_X_LPARAM(lParam);
624 newEvent.button.y = GET_Y_LPARAM(lParam);
625 newEvent.button.button = 0;
626 if (uMsg == WM_LBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_LEFT;
627 else if (uMsg == WM_MBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_MIDDLE;
628 else if (uMsg == WM_RBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_RIGHT;
629 m_pEventFunc(newEvent);
634 newEvent.type = XBMC_MOUSEBUTTONUP;
635 newEvent.button.state = XBMC_RELEASED;
636 newEvent.button.x = GET_X_LPARAM(lParam);
637 newEvent.button.y = GET_Y_LPARAM(lParam);
638 newEvent.button.button = 0;
639 if (uMsg == WM_LBUTTONUP) newEvent.button.button = XBMC_BUTTON_LEFT;
640 else if (uMsg == WM_MBUTTONUP) newEvent.button.button = XBMC_BUTTON_MIDDLE;
641 else if (uMsg == WM_RBUTTONUP) newEvent.button.button = XBMC_BUTTON_RIGHT;
642 m_pEventFunc(newEvent);
646 // SDL, which our events system is based off, sends a MOUSEBUTTONDOWN message
647 // followed by a MOUSEBUTTONUP message. As this is a momentary event, we just
648 // react on the MOUSEBUTTONUP message, resetting the state after processing.
649 newEvent.type = XBMC_MOUSEBUTTONDOWN;
650 newEvent.button.state = XBMC_PRESSED;
651 // the coordinates in WM_MOUSEWHEEL are screen, not client coordinates
653 point.x = GET_X_LPARAM(lParam);
654 point.y = GET_Y_LPARAM(lParam);
655 WindowFromScreenCoords(hWnd, &point);
656 newEvent.button.x = (uint16_t)point.x;
657 newEvent.button.y = (uint16_t)point.y;
658 newEvent.button.button = GET_Y_LPARAM(wParam) > 0 ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN;
659 m_pEventFunc(newEvent);
660 newEvent.type = XBMC_MOUSEBUTTONUP;
661 newEvent.button.state = XBMC_RELEASED;
662 m_pEventFunc(newEvent);
666 newEvent.type = XBMC_VIDEORESIZE;
667 newEvent.resize.w = GET_X_LPARAM(lParam);
668 newEvent.resize.h = GET_Y_LPARAM(lParam);
670 CLog::Log(LOGDEBUG, __FUNCTION__": window resize event");
672 if (!g_Windowing.IsAlteringWindow() && newEvent.resize.w > 0 && newEvent.resize.h > 0)
673 m_pEventFunc(newEvent);
677 newEvent.type = XBMC_VIDEOMOVE;
678 newEvent.move.x = GET_X_LPARAM(lParam);
679 newEvent.move.y = GET_Y_LPARAM(lParam);
681 CLog::Log(LOGDEBUG, __FUNCTION__": window move event");
683 if (!g_Windowing.IsAlteringWindow())
684 m_pEventFunc(newEvent);
687 case WM_MEDIA_CHANGE:
689 // This event detects media changes of usb, sd card and optical media.
690 // It only works if the explorer.exe process is started. Because this
691 // isn't the case for all setups we use WM_DEVICECHANGE for usb and
692 // optical media because this event is also triggered without the
693 // explorer process. Since WM_DEVICECHANGE doesn't detect sd card changes
694 // we still use this event only for sd.
696 PIDLIST_ABSOLUTE *ppidl;
697 HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
701 char drivePath[MAX_PATH+1];
702 if (!SHGetPathFromIDList(ppidl[0], drivePath))
708 case SHCNE_MEDIAINSERTED:
709 if (GetDriveType(drivePath) != DRIVE_CDROM)
711 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", drivePath);
712 CWin32StorageProvider::SetEvent();
716 case SHCNE_DRIVEREMOVED:
717 case SHCNE_MEDIAREMOVED:
718 if (GetDriveType(drivePath) != DRIVE_CDROM)
720 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", drivePath);
721 CWin32StorageProvider::SetEvent();
725 SHChangeNotification_Unlock(hLock);
729 case WM_POWERBROADCAST:
730 if (wParam==PBT_APMSUSPEND)
732 CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMSUSPEND event was sent");
733 CWin32PowerSyscall::SetOnSuspend();
735 else if(wParam==PBT_APMRESUMEAUTOMATIC)
737 CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMRESUMEAUTOMATIC event was sent");
738 CWin32PowerSyscall::SetOnResume();
741 case WM_DEVICECHANGE:
745 case DBT_DEVNODES_CHANGED:
746 g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
748 case DBT_DEVICEARRIVAL:
749 case DBT_DEVICEREMOVECOMPLETE:
750 if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
752 g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
753 g_Joystick.Reinitialize();
755 // check if an usb or optical media was inserted or removed
756 if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_VOLUME)
758 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)((_DEV_BROADCAST_HEADER*) lParam);
760 if (lpdbv -> dbcv_flags & DBTF_MEDIA)
763 strdrive.Format("%c:\\", CWIN32Util::FirstDriveFromMask(lpdbv ->dbcv_unitmask));
764 if(wParam == DBT_DEVICEARRIVAL)
766 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", strdrive.c_str());
767 CJobManager::GetInstance().AddJob(new CDetectDisc(strdrive, true), NULL);
771 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", strdrive.c_str());
773 share.strPath = strdrive;
774 share.strName = share.strPath;
775 g_mediaManager.RemoveAutoSource(share);
779 CWin32StorageProvider::SetEvent();
785 //some other app has painted over our window, mark everything as dirty
786 g_windowManager.MarkDirty();
789 CZeroconf::GetInstance()->ProcessResults();
791 case BONJOUR_BROWSER_EVENT:
792 CZeroconfBrowser::GetInstance()->ProcessResults();
795 return(DefWindowProc(hWnd, uMsg, wParam, lParam));
798 void CWinEventsWin32::RegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND hWnd, HDEVNOTIFY *hDeviceNotify)
800 DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
802 ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) );
803 NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
804 NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
805 NotificationFilter.dbcc_classguid = InterfaceClassGuid;
807 *hDeviceNotify = RegisterDeviceNotification(
808 hWnd, // events recipient
809 &NotificationFilter, // type of device
810 DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
814 void CWinEventsWin32::WindowFromScreenCoords(HWND hWnd, POINT *point)
818 GetClientRect(hWnd, &clientRect);
820 windowPos.x = clientRect.left;
821 windowPos.y = clientRect.top;
822 ClientToScreen(hWnd, &windowPos);
823 point->x -= windowPos.x;
824 point->y -= windowPos.y;
827 void CWinEventsWin32::OnGestureNotify(HWND hWnd, LPARAM lParam)
829 // convert to window coordinates
830 PGESTURENOTIFYSTRUCT gn = (PGESTURENOTIFYSTRUCT)(lParam);
831 POINT point = { gn->ptsLocation.x, gn->ptsLocation.y };
832 WindowFromScreenCoords(hWnd, &point);
834 // by default we only want twofingertap and pressandtap gestures
835 // the other gestures are enabled best on supported gestures
836 GESTURECONFIG gc[] = {{ GID_ZOOM, 0, GC_ZOOM},
837 { GID_ROTATE, 0, GC_ROTATE},
838 { GID_PAN, 0, GC_PAN},
839 { GID_TWOFINGERTAP, GC_TWOFINGERTAP, GC_TWOFINGERTAP },
840 { GID_PRESSANDTAP, GC_PRESSANDTAP, GC_PRESSANDTAP }};
842 // send a message to see if a control wants any
844 if ((gestures = CGenericTouchActionHandler::Get().QuerySupportedGestures((float)point.x, (float)point.y)) != EVENT_RESULT_UNHANDLED)
846 if (gestures & EVENT_RESULT_ZOOM)
847 gc[0].dwWant |= GC_ZOOM;
848 if (gestures & EVENT_RESULT_ROTATE)
849 gc[1].dwWant |= GC_ROTATE;
850 if (gestures & EVENT_RESULT_PAN_VERTICAL)
851 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_GUTTER | GC_PAN_WITH_INERTIA;
852 if (gestures & EVENT_RESULT_PAN_VERTICAL_WITHOUT_INERTIA)
853 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
854 if (gestures & EVENT_RESULT_PAN_HORIZONTAL)
855 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_GUTTER | GC_PAN_WITH_INERTIA;
856 if (gestures & EVENT_RESULT_PAN_HORIZONTAL_WITHOUT_INERTIA)
857 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
858 if (gestures & EVENT_RESULT_SWIPE)
860 gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_GUTTER;
862 // create a new touch swipe detector
863 m_touchSwipeDetector = new CGenericTouchSwipeDetector(&CGenericTouchActionHandler::Get(), 160.0f);
866 gc[0].dwBlock = gc[0].dwWant ^ 0x01;
867 gc[1].dwBlock = gc[1].dwWant ^ 0x01;
868 gc[2].dwBlock = gc[2].dwWant ^ 0x1F;
870 if (g_Windowing.PtrSetGestureConfig)
871 g_Windowing.PtrSetGestureConfig(hWnd, 0, 5, gc, sizeof(GESTURECONFIG));
874 void CWinEventsWin32::OnGesture(HWND hWnd, LPARAM lParam)
876 if (!g_Windowing.PtrGetGestureInfo)
879 GESTUREINFO gi = {0};
880 gi.cbSize = sizeof(gi);
881 g_Windowing.PtrGetGestureInfo((HGESTUREINFO)lParam, &gi);
883 // convert to window coordinates
884 POINT point = { gi.ptsLocation.x, gi.ptsLocation.y };
885 WindowFromScreenCoords(hWnd, &point);
887 if (gi.dwID == GID_BEGIN)
888 m_touchPointer.reset();
890 // if there's a "current" touch from a previous event, copy it to "last"
891 if (m_touchPointer.current.valid())
892 m_touchPointer.last = m_touchPointer.current;
894 // set the "current" touch
895 m_touchPointer.current.x = (float)point.x;
896 m_touchPointer.current.y = (float)point.y;
897 m_touchPointer.current.time = time(NULL);
903 // set the "down" touch
904 m_touchPointer.down = m_touchPointer.current;
905 m_originalZoomDistance = 0;
907 CGenericTouchActionHandler::Get().OnTouchGestureStart((float)point.x, (float)point.y);
912 CGenericTouchActionHandler::Get().OnTouchGestureEnd((float)point.x, (float)point.y, 0.0f, 0.0f, 0.0f, 0.0f);
917 if (!m_touchPointer.moving)
918 m_touchPointer.moving = true;
920 // calculate the velocity of the pan gesture
921 float velocityX, velocityY;
922 m_touchPointer.velocity(velocityX, velocityY);
924 CGenericTouchActionHandler::Get().OnTouchGesturePan(m_touchPointer.current.x, m_touchPointer.current.y,
925 m_touchPointer.current.x - m_touchPointer.last.x, m_touchPointer.current.y - m_touchPointer.last.y,
926 velocityX, velocityY);
928 if (m_touchSwipeDetector != NULL)
930 if (gi.dwFlags & GF_BEGIN)
932 m_touchPointer.down = m_touchPointer.current;
933 m_touchSwipeDetector->OnTouchDown(0, m_touchPointer);
935 else if (gi.dwFlags & GF_END)
937 m_touchSwipeDetector->OnTouchUp(0, m_touchPointer);
939 delete m_touchSwipeDetector;
940 m_touchSwipeDetector = NULL;
943 m_touchSwipeDetector->OnTouchMove(0, m_touchPointer);
950 if (gi.dwFlags == GF_BEGIN)
953 CGenericTouchActionHandler::Get().OnRotate((float)point.x, (float)point.y,
954 -(float)ROTATE_ANGLE_DEGREE(gi.ullArguments));
960 if (gi.dwFlags == GF_BEGIN)
962 m_originalZoomDistance = (int)LODWORD(gi.ullArguments);
966 // avoid division by 0
967 if (m_originalZoomDistance == 0)
970 CGenericTouchActionHandler::Get().OnZoomPinch((float)point.x, (float)point.y,
971 (float)LODWORD(gi.ullArguments) / (float)m_originalZoomDistance);
975 case GID_TWOFINGERTAP:
976 CGenericTouchActionHandler::Get().OnTap((float)point.x, (float)point.y, 2);
979 case GID_PRESSANDTAP:
981 // You have encountered an unknown gesture
984 if(g_Windowing.PtrCloseGestureInfoHandle)
985 g_Windowing.PtrCloseGestureInfoHandle((HGESTUREINFO)lParam);