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"
54 #include "utils/StringUtils.h"
58 using namespace PERIPHERALS;
63 #define LODWORD(longval) ((DWORD)((DWORDLONG)(longval)))
66 #define ROTATE_ANGLE_DEGREE(arg) GID_ROTATE_ANGLE_FROM_ARGUMENT(LODWORD(arg)) * 180 / M_PI
68 #define XBMC_arraysize(array) (sizeof(array)/sizeof(array[0]))
70 /* Masks for processing the windows KEYDOWN and KEYUP messages */
71 #define REPEATED_KEYMASK (1<<30)
72 #define EXTENDED_KEYMASK (1<<24)
73 #define EXTKEYPAD(keypad) ((scancode & 0x100)?(mvke):(keypad))
75 static XBMCKey VK_keymap[XBMCK_LAST];
77 static GUID USB_HID_GUID = { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
79 uint32_t g_uQueryCancelAutoPlay = 0;
81 int XBMC_TranslateUNICODE = 1;
83 PHANDLE_EVENT_FUNC CWinEventsWin32::m_pEventFunc = NULL;
84 int CWinEventsWin32::m_originalZoomDistance = 0;
85 Pointer CWinEventsWin32::m_touchPointer;
86 CGenericTouchSwipeDetector* CWinEventsWin32::m_touchSwipeDetector = NULL;
88 // register to receive SD card events (insert/remove)
89 // seen at http://www.codeproject.com/Messages/2897423/Re-No-message-triggered-on-SD-card-insertion-remov.aspx
90 #define WM_MEDIA_CHANGE (WM_USER + 666)
91 SHChangeNotifyEntry shcne;
93 void DIB_InitOSKeymap()
95 char current_layout[KL_NAMELENGTH];
97 GetKeyboardLayoutName(current_layout);
99 LoadKeyboardLayout(current_layout, KLF_ACTIVATE);
101 /* Map the VK keysyms */
102 for (int i = 0; i < XBMC_arraysize(VK_keymap); ++i)
103 VK_keymap[i] = XBMCK_UNKNOWN;
105 VK_keymap[VK_BACK] = XBMCK_BACKSPACE;
106 VK_keymap[VK_TAB] = XBMCK_TAB;
107 VK_keymap[VK_CLEAR] = XBMCK_CLEAR;
108 VK_keymap[VK_RETURN] = XBMCK_RETURN;
109 VK_keymap[VK_PAUSE] = XBMCK_PAUSE;
110 VK_keymap[VK_ESCAPE] = XBMCK_ESCAPE;
111 VK_keymap[VK_SPACE] = XBMCK_SPACE;
112 VK_keymap[VK_APOSTROPHE] = XBMCK_QUOTE;
113 VK_keymap[VK_COMMA] = XBMCK_COMMA;
114 VK_keymap[VK_MINUS] = XBMCK_MINUS;
115 VK_keymap[VK_PERIOD] = XBMCK_PERIOD;
116 VK_keymap[VK_SLASH] = XBMCK_SLASH;
117 VK_keymap[VK_0] = XBMCK_0;
118 VK_keymap[VK_1] = XBMCK_1;
119 VK_keymap[VK_2] = XBMCK_2;
120 VK_keymap[VK_3] = XBMCK_3;
121 VK_keymap[VK_4] = XBMCK_4;
122 VK_keymap[VK_5] = XBMCK_5;
123 VK_keymap[VK_6] = XBMCK_6;
124 VK_keymap[VK_7] = XBMCK_7;
125 VK_keymap[VK_8] = XBMCK_8;
126 VK_keymap[VK_9] = XBMCK_9;
127 VK_keymap[VK_SEMICOLON] = XBMCK_SEMICOLON;
128 VK_keymap[VK_EQUALS] = XBMCK_EQUALS;
129 VK_keymap[VK_LBRACKET] = XBMCK_LEFTBRACKET;
130 VK_keymap[VK_BACKSLASH] = XBMCK_BACKSLASH;
131 VK_keymap[VK_OEM_102] = XBMCK_BACKSLASH;
132 VK_keymap[VK_RBRACKET] = XBMCK_RIGHTBRACKET;
133 VK_keymap[VK_GRAVE] = XBMCK_BACKQUOTE;
134 VK_keymap[VK_BACKTICK] = XBMCK_BACKQUOTE;
135 VK_keymap[VK_A] = XBMCK_a;
136 VK_keymap[VK_B] = XBMCK_b;
137 VK_keymap[VK_C] = XBMCK_c;
138 VK_keymap[VK_D] = XBMCK_d;
139 VK_keymap[VK_E] = XBMCK_e;
140 VK_keymap[VK_F] = XBMCK_f;
141 VK_keymap[VK_G] = XBMCK_g;
142 VK_keymap[VK_H] = XBMCK_h;
143 VK_keymap[VK_I] = XBMCK_i;
144 VK_keymap[VK_J] = XBMCK_j;
145 VK_keymap[VK_K] = XBMCK_k;
146 VK_keymap[VK_L] = XBMCK_l;
147 VK_keymap[VK_M] = XBMCK_m;
148 VK_keymap[VK_N] = XBMCK_n;
149 VK_keymap[VK_O] = XBMCK_o;
150 VK_keymap[VK_P] = XBMCK_p;
151 VK_keymap[VK_Q] = XBMCK_q;
152 VK_keymap[VK_R] = XBMCK_r;
153 VK_keymap[VK_S] = XBMCK_s;
154 VK_keymap[VK_T] = XBMCK_t;
155 VK_keymap[VK_U] = XBMCK_u;
156 VK_keymap[VK_V] = XBMCK_v;
157 VK_keymap[VK_W] = XBMCK_w;
158 VK_keymap[VK_X] = XBMCK_x;
159 VK_keymap[VK_Y] = XBMCK_y;
160 VK_keymap[VK_Z] = XBMCK_z;
161 VK_keymap[VK_DELETE] = XBMCK_DELETE;
163 VK_keymap[VK_NUMPAD0] = XBMCK_KP0;
164 VK_keymap[VK_NUMPAD1] = XBMCK_KP1;
165 VK_keymap[VK_NUMPAD2] = XBMCK_KP2;
166 VK_keymap[VK_NUMPAD3] = XBMCK_KP3;
167 VK_keymap[VK_NUMPAD4] = XBMCK_KP4;
168 VK_keymap[VK_NUMPAD5] = XBMCK_KP5;
169 VK_keymap[VK_NUMPAD6] = XBMCK_KP6;
170 VK_keymap[VK_NUMPAD7] = XBMCK_KP7;
171 VK_keymap[VK_NUMPAD8] = XBMCK_KP8;
172 VK_keymap[VK_NUMPAD9] = XBMCK_KP9;
173 VK_keymap[VK_DECIMAL] = XBMCK_KP_PERIOD;
174 VK_keymap[VK_DIVIDE] = XBMCK_KP_DIVIDE;
175 VK_keymap[VK_MULTIPLY] = XBMCK_KP_MULTIPLY;
176 VK_keymap[VK_SUBTRACT] = XBMCK_KP_MINUS;
177 VK_keymap[VK_ADD] = XBMCK_KP_PLUS;
179 VK_keymap[VK_UP] = XBMCK_UP;
180 VK_keymap[VK_DOWN] = XBMCK_DOWN;
181 VK_keymap[VK_RIGHT] = XBMCK_RIGHT;
182 VK_keymap[VK_LEFT] = XBMCK_LEFT;
183 VK_keymap[VK_INSERT] = XBMCK_INSERT;
184 VK_keymap[VK_HOME] = XBMCK_HOME;
185 VK_keymap[VK_END] = XBMCK_END;
186 VK_keymap[VK_PRIOR] = XBMCK_PAGEUP;
187 VK_keymap[VK_NEXT] = XBMCK_PAGEDOWN;
189 VK_keymap[VK_F1] = XBMCK_F1;
190 VK_keymap[VK_F2] = XBMCK_F2;
191 VK_keymap[VK_F3] = XBMCK_F3;
192 VK_keymap[VK_F4] = XBMCK_F4;
193 VK_keymap[VK_F5] = XBMCK_F5;
194 VK_keymap[VK_F6] = XBMCK_F6;
195 VK_keymap[VK_F7] = XBMCK_F7;
196 VK_keymap[VK_F8] = XBMCK_F8;
197 VK_keymap[VK_F9] = XBMCK_F9;
198 VK_keymap[VK_F10] = XBMCK_F10;
199 VK_keymap[VK_F11] = XBMCK_F11;
200 VK_keymap[VK_F12] = XBMCK_F12;
201 VK_keymap[VK_F13] = XBMCK_F13;
202 VK_keymap[VK_F14] = XBMCK_F14;
203 VK_keymap[VK_F15] = XBMCK_F15;
205 VK_keymap[VK_NUMLOCK] = XBMCK_NUMLOCK;
206 VK_keymap[VK_CAPITAL] = XBMCK_CAPSLOCK;
207 VK_keymap[VK_SCROLL] = XBMCK_SCROLLOCK;
208 VK_keymap[VK_RSHIFT] = XBMCK_RSHIFT;
209 VK_keymap[VK_LSHIFT] = XBMCK_LSHIFT;
210 VK_keymap[VK_RCONTROL] = XBMCK_RCTRL;
211 VK_keymap[VK_LCONTROL] = XBMCK_LCTRL;
212 VK_keymap[VK_RMENU] = XBMCK_RALT;
213 VK_keymap[VK_LMENU] = XBMCK_LALT;
214 VK_keymap[VK_RWIN] = XBMCK_RSUPER;
215 VK_keymap[VK_LWIN] = XBMCK_LSUPER;
217 VK_keymap[VK_HELP] = XBMCK_HELP;
219 VK_keymap[VK_PRINT] = XBMCK_PRINT;
221 VK_keymap[VK_SNAPSHOT] = XBMCK_PRINT;
222 VK_keymap[VK_CANCEL] = XBMCK_BREAK;
223 VK_keymap[VK_APPS] = XBMCK_MENU;
225 // Only include the multimedia keys if they have been enabled in the
227 if (g_advancedSettings.m_enableMultimediaKeys)
229 VK_keymap[VK_BROWSER_BACK] = XBMCK_BROWSER_BACK;
230 VK_keymap[VK_BROWSER_FORWARD] = XBMCK_BROWSER_FORWARD;
231 VK_keymap[VK_BROWSER_REFRESH] = XBMCK_BROWSER_REFRESH;
232 VK_keymap[VK_BROWSER_STOP] = XBMCK_BROWSER_STOP;
233 VK_keymap[VK_BROWSER_SEARCH] = XBMCK_BROWSER_SEARCH;
234 VK_keymap[VK_BROWSER_FAVORITES] = XBMCK_BROWSER_FAVORITES;
235 VK_keymap[VK_BROWSER_HOME] = XBMCK_BROWSER_HOME;
236 VK_keymap[VK_VOLUME_MUTE] = XBMCK_VOLUME_MUTE;
237 VK_keymap[VK_VOLUME_DOWN] = XBMCK_VOLUME_DOWN;
238 VK_keymap[VK_VOLUME_UP] = XBMCK_VOLUME_UP;
239 VK_keymap[VK_MEDIA_NEXT_TRACK] = XBMCK_MEDIA_NEXT_TRACK;
240 VK_keymap[VK_MEDIA_PREV_TRACK] = XBMCK_MEDIA_PREV_TRACK;
241 VK_keymap[VK_MEDIA_STOP] = XBMCK_MEDIA_STOP;
242 VK_keymap[VK_MEDIA_PLAY_PAUSE] = XBMCK_MEDIA_PLAY_PAUSE;
243 VK_keymap[VK_LAUNCH_MAIL] = XBMCK_LAUNCH_MAIL;
244 VK_keymap[VK_LAUNCH_MEDIA_SELECT] = XBMCK_LAUNCH_MEDIA_SELECT;
245 VK_keymap[VK_LAUNCH_APP1] = XBMCK_LAUNCH_APP1;
246 VK_keymap[VK_LAUNCH_APP2] = XBMCK_LAUNCH_APP2;
250 static int XBMC_MapVirtualKey(int scancode, int vkey)
252 int mvke = MapVirtualKeyEx(scancode & 0xFF, 1, NULL);
255 { /* These are always correct */
263 /* These are already handled */
272 /* Multimedia keys are already handled */
273 case VK_BROWSER_BACK:
274 case VK_BROWSER_FORWARD:
275 case VK_BROWSER_REFRESH:
276 case VK_BROWSER_STOP:
277 case VK_BROWSER_SEARCH:
278 case VK_BROWSER_FAVORITES:
279 case VK_BROWSER_HOME:
283 case VK_MEDIA_NEXT_TRACK:
284 case VK_MEDIA_PREV_TRACK:
286 case VK_MEDIA_PLAY_PAUSE:
288 case VK_LAUNCH_MEDIA_SELECT:
294 { /* Distinguish between keypad and extended keys */
295 case VK_INSERT: return EXTKEYPAD(VK_NUMPAD0);
296 case VK_DELETE: return EXTKEYPAD(VK_DECIMAL);
297 case VK_END: return EXTKEYPAD(VK_NUMPAD1);
298 case VK_DOWN: return EXTKEYPAD(VK_NUMPAD2);
299 case VK_NEXT: return EXTKEYPAD(VK_NUMPAD3);
300 case VK_LEFT: return EXTKEYPAD(VK_NUMPAD4);
301 case VK_CLEAR: return EXTKEYPAD(VK_NUMPAD5);
302 case VK_RIGHT: return EXTKEYPAD(VK_NUMPAD6);
303 case VK_HOME: return EXTKEYPAD(VK_NUMPAD7);
304 case VK_UP: return EXTKEYPAD(VK_NUMPAD8);
305 case VK_PRIOR: return EXTKEYPAD(VK_NUMPAD9);
307 return mvke ? mvke : vkey;
310 static XBMC_keysym *TranslateKey(WPARAM vkey, UINT scancode, XBMC_keysym *keysym, int pressed)
312 uint8_t keystate[256];
314 /* Set the keysym information */
315 keysym->scancode = (unsigned char) scancode;
318 if ((vkey == VK_RETURN) && (scancode & 0x100))
320 /* No VK_ code for the keypad enter key */
321 keysym->sym = XBMCK_KP_ENTER;
325 keysym->sym = VK_keymap[XBMC_MapVirtualKey(scancode, vkey)];
328 // Attempt to convert the keypress to a UNICODE character
329 GetKeyboardState(keystate);
331 if ( pressed && XBMC_TranslateUNICODE )
332 { uint16_t wchars[2];
334 /* Numlock isn't taken into account in ToUnicode,
335 * so we handle it as a special case here */
336 if ((keystate[VK_NUMLOCK] & 1) && vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9)
338 keysym->unicode = vkey - VK_NUMPAD0 + '0';
340 else if (ToUnicode((UINT)vkey, scancode, keystate, (LPWSTR)wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0)
342 keysym->unicode = wchars[0];
346 // Set the modifier bitmap
348 mod = (uint16_t) XBMCKMOD_NONE;
350 // If left control and right alt are down this usually means that
352 if ((keystate[VK_LCONTROL] & 0x80) && (keystate[VK_RMENU] & 0x80))
354 mod |= XBMCKMOD_MODE;
358 if (keystate[VK_LCONTROL] & 0x80) mod |= XBMCKMOD_LCTRL;
359 if (keystate[VK_RMENU] & 0x80) mod |= XBMCKMOD_RALT;
362 // Check the remaining modifiers
363 if (keystate[VK_LSHIFT] & 0x80) mod |= XBMCKMOD_LSHIFT;
364 if (keystate[VK_RSHIFT] & 0x80) mod |= XBMCKMOD_RSHIFT;
365 if (keystate[VK_RCONTROL] & 0x80) mod |= XBMCKMOD_RCTRL;
366 if (keystate[VK_LMENU] & 0x80) mod |= XBMCKMOD_LALT;
367 if (keystate[VK_LWIN] & 0x80) mod |= XBMCKMOD_LSUPER;
368 if (keystate[VK_RWIN] & 0x80) mod |= XBMCKMOD_LSUPER;
369 keysym->mod = (XBMCMod) mod;
371 // Return the updated keysym
375 void CWinEventsWin32::MessagePush(XBMC_Event *newEvent)
377 // m_pEventFunc should be set because MessagePush is only executed by
378 // methods called from WndProc()
379 if (m_pEventFunc == NULL)
382 m_pEventFunc(*newEvent);
385 bool CWinEventsWin32::MessagePump()
388 while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
390 TranslateMessage( &msg );
391 DispatchMessage( &msg );
396 size_t CWinEventsWin32::GetQueueSize()
399 return PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
402 LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
405 ZeroMemory(&newEvent, sizeof(newEvent));
406 static HDEVNOTIFY hDeviceNotify;
408 if (uMsg == WM_CREATE)
411 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
413 g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
415 shcne.fRecursive = TRUE;
416 long fEvents = SHCNE_DRIVEADD | SHCNE_DRIVEREMOVED | SHCNE_MEDIAREMOVED | SHCNE_MEDIAINSERTED;
417 SHChangeNotifyRegister(hWnd, SHCNRF_ShellLevel | SHCNRF_NewDelivery, fEvents, WM_MEDIA_CHANGE, 1, &shcne);
418 RegisterDeviceInterfaceToHwnd(USB_HID_GUID, hWnd, &hDeviceNotify);
422 if (uMsg == WM_DESTROY)
425 m_pEventFunc = (PHANDLE_EVENT_FUNC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
427 return DefWindowProc(hWnd, uMsg, wParam, lParam);
429 if(g_uQueryCancelAutoPlay != 0 && uMsg == g_uQueryCancelAutoPlay)
438 UnregisterDeviceNotification(hDeviceNotify);
439 newEvent.type = XBMC_QUIT;
440 m_pEventFunc(newEvent);
444 bool active = g_application.GetRenderGUI();
445 g_application.SetRenderGUI(wParam != 0);
446 if (g_application.GetRenderGUI() != active)
447 g_Windowing.NotifyAppActiveChange(g_application.GetRenderGUI());
448 CLog::Log(LOGDEBUG, __FUNCTION__"Window is %s", g_application.GetRenderGUI() ? "shown" : "hidden");
453 if( WA_INACTIVE != wParam )
454 g_Joystick.Reinitialize();
456 bool active = g_application.GetRenderGUI();
459 g_application.SetRenderGUI(false);
463 WINDOWPLACEMENT lpwndpl;
464 lpwndpl.length = sizeof(lpwndpl);
465 if (LOWORD(wParam) != WA_INACTIVE)
467 if (GetWindowPlacement(hWnd, &lpwndpl))
468 g_application.SetRenderGUI(lpwndpl.showCmd != SW_HIDE);
472 g_application.SetRenderGUI(g_Windowing.WindowedMode());
475 if (g_application.GetRenderGUI() != active)
476 g_Windowing.NotifyAppActiveChange(g_application.GetRenderGUI());
477 CLog::Log(LOGDEBUG, __FUNCTION__"Window is %s", g_application.GetRenderGUI() ? "active" : "inactive");
482 g_application.m_AppFocused = uMsg == WM_SETFOCUS;
483 g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
484 if (uMsg == WM_KILLFOCUS)
487 if (CWIN32Util::GetFocussedProcess(procfile))
488 CLog::Log(LOGDEBUG, __FUNCTION__": Focus switched to process %s", procfile.c_str());
491 /* needs to be reviewed after frodo. we reset the system idle timer
492 and the display timer directly now (see m_screenSaverTimer).
494 switch( wParam&0xFFF0 )
496 case SC_MONITORPOWER:
497 if (g_application.m_pPlayer->IsPlaying() || g_application.m_pPlayer->IsPausedPlayback())
499 else if(CSettings::Get().GetInt("powermanagement.displaysoff") == 0)
509 case VK_F4: //alt-f4, default event quit.
510 return(DefWindowProc(hWnd, uMsg, wParam, lParam));
511 case VK_RETURN: //alt-return
512 if ((lParam & REPEATED_KEYMASK) == 0)
513 g_graphicsContext.ToggleFullScreenRoot();
516 //deliberate fallthrough
522 if ( lParam & EXTENDED_KEYMASK )
523 wParam = VK_RCONTROL;
525 wParam = VK_LCONTROL;
528 /* EXTENDED trick doesn't work here */
529 if (GetKeyState(VK_LSHIFT) & 0x8000)
531 else if (GetKeyState(VK_RSHIFT) & 0x8000)
535 if ( lParam & EXTENDED_KEYMASK )
542 TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
544 newEvent.type = XBMC_KEYDOWN;
545 newEvent.key.keysym = keysym;
546 m_pEventFunc(newEvent);
556 if ( lParam&EXTENDED_KEYMASK )
557 wParam = VK_RCONTROL;
559 wParam = VK_LCONTROL;
563 uint32_t scanCodeL = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
564 uint32_t scanCodeR = MapVirtualKey(VK_RSHIFT, MAPVK_VK_TO_VSC);
565 uint32_t keyCode = (uint32_t)((lParam & 0xFF0000) >> 16);
566 if (keyCode == scanCodeL)
568 else if (keyCode == scanCodeR)
573 if ( lParam&EXTENDED_KEYMASK )
580 TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
582 if (wParam == VK_SNAPSHOT)
583 newEvent.type = XBMC_KEYDOWN;
585 newEvent.type = XBMC_KEYUP;
586 newEvent.key.keysym = keysym;
587 m_pEventFunc(newEvent);
590 case WM_APPCOMMAND: // MULTIMEDIA keys are mapped to APPCOMMANDS
592 CLog::Log(LOGDEBUG, "WinEventsWin32.cpp: APPCOMMAND %d", GET_APPCOMMAND_LPARAM(lParam));
593 newEvent.appcommand.type = XBMC_APPCOMMAND;
594 newEvent.appcommand.action = GET_APPCOMMAND_LPARAM(lParam);
595 if (m_pEventFunc(newEvent))
598 return DefWindowProc(hWnd, uMsg, wParam, lParam);
600 case WM_GESTURENOTIFY:
602 OnGestureNotify(hWnd, lParam);
603 return DefWindowProc(hWnd, WM_GESTURENOTIFY, wParam, lParam);
607 OnGesture(hWnd, lParam);
611 if (wParam == VK_RETURN) //stop system beep on alt-return
615 if (HTCLIENT != LOWORD(lParam))
616 g_Windowing.ShowOSMouse(true);
619 newEvent.type = XBMC_MOUSEMOTION;
620 newEvent.motion.x = GET_X_LPARAM(lParam);
621 newEvent.motion.y = GET_Y_LPARAM(lParam);
622 newEvent.motion.state = 0;
623 m_pEventFunc(newEvent);
628 newEvent.type = XBMC_MOUSEBUTTONDOWN;
629 newEvent.button.state = XBMC_PRESSED;
630 newEvent.button.x = GET_X_LPARAM(lParam);
631 newEvent.button.y = GET_Y_LPARAM(lParam);
632 newEvent.button.button = 0;
633 if (uMsg == WM_LBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_LEFT;
634 else if (uMsg == WM_MBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_MIDDLE;
635 else if (uMsg == WM_RBUTTONDOWN) newEvent.button.button = XBMC_BUTTON_RIGHT;
636 m_pEventFunc(newEvent);
641 newEvent.type = XBMC_MOUSEBUTTONUP;
642 newEvent.button.state = XBMC_RELEASED;
643 newEvent.button.x = GET_X_LPARAM(lParam);
644 newEvent.button.y = GET_Y_LPARAM(lParam);
645 newEvent.button.button = 0;
646 if (uMsg == WM_LBUTTONUP) newEvent.button.button = XBMC_BUTTON_LEFT;
647 else if (uMsg == WM_MBUTTONUP) newEvent.button.button = XBMC_BUTTON_MIDDLE;
648 else if (uMsg == WM_RBUTTONUP) newEvent.button.button = XBMC_BUTTON_RIGHT;
649 m_pEventFunc(newEvent);
653 // SDL, which our events system is based off, sends a MOUSEBUTTONDOWN message
654 // followed by a MOUSEBUTTONUP message. As this is a momentary event, we just
655 // react on the MOUSEBUTTONUP message, resetting the state after processing.
656 newEvent.type = XBMC_MOUSEBUTTONDOWN;
657 newEvent.button.state = XBMC_PRESSED;
658 // the coordinates in WM_MOUSEWHEEL are screen, not client coordinates
660 point.x = GET_X_LPARAM(lParam);
661 point.y = GET_Y_LPARAM(lParam);
662 WindowFromScreenCoords(hWnd, &point);
663 newEvent.button.x = (uint16_t)point.x;
664 newEvent.button.y = (uint16_t)point.y;
665 newEvent.button.button = GET_Y_LPARAM(wParam) > 0 ? XBMC_BUTTON_WHEELUP : XBMC_BUTTON_WHEELDOWN;
666 m_pEventFunc(newEvent);
667 newEvent.type = XBMC_MOUSEBUTTONUP;
668 newEvent.button.state = XBMC_RELEASED;
669 m_pEventFunc(newEvent);
673 newEvent.type = XBMC_VIDEORESIZE;
674 newEvent.resize.w = GET_X_LPARAM(lParam);
675 newEvent.resize.h = GET_Y_LPARAM(lParam);
677 CLog::Log(LOGDEBUG, __FUNCTION__": window resize event");
679 if (!g_Windowing.IsAlteringWindow() && newEvent.resize.w > 0 && newEvent.resize.h > 0)
680 m_pEventFunc(newEvent);
684 newEvent.type = XBMC_VIDEOMOVE;
685 newEvent.move.x = GET_X_LPARAM(lParam);
686 newEvent.move.y = GET_Y_LPARAM(lParam);
688 CLog::Log(LOGDEBUG, __FUNCTION__": window move event");
690 if (!g_Windowing.IsAlteringWindow())
691 m_pEventFunc(newEvent);
694 case WM_MEDIA_CHANGE:
696 // This event detects media changes of usb, sd card and optical media.
697 // It only works if the explorer.exe process is started. Because this
698 // isn't the case for all setups we use WM_DEVICECHANGE for usb and
699 // optical media because this event is also triggered without the
700 // explorer process. Since WM_DEVICECHANGE doesn't detect sd card changes
701 // we still use this event only for sd.
703 PIDLIST_ABSOLUTE *ppidl;
704 HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
708 char drivePath[MAX_PATH+1];
709 if (!SHGetPathFromIDList(ppidl[0], drivePath))
715 case SHCNE_MEDIAINSERTED:
716 if (GetDriveType(drivePath) != DRIVE_CDROM)
718 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", drivePath);
719 CWin32StorageProvider::SetEvent();
723 case SHCNE_DRIVEREMOVED:
724 case SHCNE_MEDIAREMOVED:
725 if (GetDriveType(drivePath) != DRIVE_CDROM)
727 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", drivePath);
728 CWin32StorageProvider::SetEvent();
732 SHChangeNotification_Unlock(hLock);
736 case WM_POWERBROADCAST:
737 if (wParam==PBT_APMSUSPEND)
739 CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMSUSPEND event was sent");
740 CWin32PowerSyscall::SetOnSuspend();
742 else if(wParam==PBT_APMRESUMEAUTOMATIC)
744 CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMRESUMEAUTOMATIC event was sent");
745 CWin32PowerSyscall::SetOnResume();
748 case WM_DEVICECHANGE:
752 case DBT_DEVNODES_CHANGED:
753 g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
755 case DBT_DEVICEARRIVAL:
756 case DBT_DEVICEREMOVECOMPLETE:
757 if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
759 g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
760 g_Joystick.Reinitialize();
762 // check if an usb or optical media was inserted or removed
763 if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_VOLUME)
765 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)((_DEV_BROADCAST_HEADER*) lParam);
767 if (lpdbv -> dbcv_flags & DBTF_MEDIA)
769 CStdString strdrive = StringUtils::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);