Merge pull request #2703 from ace20022/cores_revised
[vuplus_xbmc] / xbmc / windowing / windows / WinEventsWin32.cpp
1 /*
2 *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #ifndef _USE_MATH_DEFINES
22 #define _USE_MATH_DEFINES
23 #endif
24 #include <math.h>
25
26 #include "utils/log.h"
27 #include "Windowsx.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"
39 #include <dbt.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"
45 #include "Shlobj.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
55 #ifdef TARGET_WINDOWS
56
57 using namespace PERIPHERALS;
58
59 HWND g_hWnd = NULL;
60
61 #ifndef LODWORD
62 #define LODWORD(longval) ((DWORD)((DWORDLONG)(longval)))
63 #endif
64
65 #define ROTATE_ANGLE_DEGREE(arg) GID_ROTATE_ANGLE_FROM_ARGUMENT(LODWORD(arg)) * 180 / M_PI
66
67 #define XBMC_arraysize(array)   (sizeof(array)/sizeof(array[0]))
68
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))
73
74 static XBMCKey VK_keymap[XBMCK_LAST];
75
76 static GUID USB_HID_GUID = { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
77
78 uint32_t g_uQueryCancelAutoPlay = 0;
79
80 int XBMC_TranslateUNICODE = 1;
81
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;
86
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;
91
92 void DIB_InitOSKeymap()
93 {
94   char current_layout[KL_NAMELENGTH];
95
96   GetKeyboardLayoutName(current_layout);
97
98   LoadKeyboardLayout(current_layout, KLF_ACTIVATE);
99
100   /* Map the VK keysyms */
101   for (int i = 0; i < XBMC_arraysize(VK_keymap); ++i)
102     VK_keymap[i] = XBMCK_UNKNOWN;
103
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;
161
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;
177
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;
187
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;
203
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;
215
216   VK_keymap[VK_HELP] = XBMCK_HELP;
217 #ifdef VK_PRINT
218   VK_keymap[VK_PRINT] = XBMCK_PRINT;
219 #endif
220   VK_keymap[VK_SNAPSHOT] = XBMCK_PRINT;
221   VK_keymap[VK_CANCEL] = XBMCK_BREAK;
222   VK_keymap[VK_APPS] = XBMCK_MENU;
223
224   // Only include the multimedia keys if they have been enabled in the
225   // advanced settings
226   if (g_advancedSettings.m_enableMultimediaKeys)
227   {
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;
246   }
247 }
248
249 static int XBMC_MapVirtualKey(int scancode, int vkey)
250 {
251   int mvke = MapVirtualKeyEx(scancode & 0xFF, 1, NULL);
252
253   switch(vkey)
254   { /* These are always correct */
255     case VK_DIVIDE:
256     case VK_MULTIPLY:
257     case VK_SUBTRACT:
258     case VK_ADD:
259     case VK_LWIN:
260     case VK_RWIN:
261     case VK_APPS:
262     /* These are already handled */
263     case VK_LCONTROL:
264     case VK_RCONTROL:
265     case VK_LSHIFT:
266     case VK_RSHIFT:
267     case VK_LMENU:
268     case VK_RMENU:
269     case VK_SNAPSHOT:
270     case VK_PAUSE:
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:
279     case VK_VOLUME_MUTE:
280     case VK_VOLUME_DOWN:
281     case VK_VOLUME_UP:
282     case VK_MEDIA_NEXT_TRACK:
283     case VK_MEDIA_PREV_TRACK:
284     case VK_MEDIA_STOP:
285     case VK_MEDIA_PLAY_PAUSE:
286     case VK_LAUNCH_MAIL:
287     case VK_LAUNCH_MEDIA_SELECT:
288     case VK_LAUNCH_APP1:
289     case VK_LAUNCH_APP2:
290       return vkey;
291   }
292   switch(mvke)
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);
305   }
306   return mvke ? mvke : vkey;
307 }
308
309 static XBMC_keysym *TranslateKey(WPARAM vkey, UINT scancode, XBMC_keysym *keysym, int pressed)
310 { uint16_t mod;
311   uint8_t keystate[256];
312
313   /* Set the keysym information */
314   keysym->scancode = (unsigned char) scancode;
315   keysym->unicode = 0;
316
317   if ((vkey == VK_RETURN) && (scancode & 0x100))
318   {
319     /* No VK_ code for the keypad enter key */
320     keysym->sym = XBMCK_KP_ENTER;
321   }
322   else
323   {
324     keysym->sym = VK_keymap[XBMC_MapVirtualKey(scancode, vkey)];
325   }
326
327   // Attempt to convert the keypress to a UNICODE character
328   GetKeyboardState(keystate);
329
330   if ( pressed && XBMC_TranslateUNICODE )
331   { uint16_t  wchars[2];
332
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)
336     {
337       keysym->unicode = vkey - VK_NUMPAD0 + '0';
338     }
339     else if (ToUnicode((UINT)vkey, scancode, keystate, (LPWSTR)wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0)
340     {
341       keysym->unicode = wchars[0];
342     }
343   }
344
345   // Set the modifier bitmap
346
347   mod = (uint16_t) XBMCKMOD_NONE;
348
349   // If left control and right alt are down this usually means that
350   // AltGr is down
351   if ((keystate[VK_LCONTROL] & 0x80) && (keystate[VK_RMENU] & 0x80))
352   {
353     mod |= XBMCKMOD_MODE;
354   }
355   else
356   {
357     if (keystate[VK_LCONTROL] & 0x80) mod |= XBMCKMOD_LCTRL;
358     if (keystate[VK_RMENU]    & 0x80) mod |= XBMCKMOD_RALT;
359   }
360
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;
369
370   // Return the updated keysym
371   return(keysym);
372 }
373
374 void CWinEventsWin32::MessagePush(XBMC_Event *newEvent)
375 {
376   // m_pEventFunc should be set because MessagePush is only executed by
377   // methods called from WndProc()
378   if (m_pEventFunc == NULL)
379     return;
380
381   m_pEventFunc(*newEvent);
382 }
383
384 bool CWinEventsWin32::MessagePump()
385 {
386   MSG  msg;
387   while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
388   {
389     TranslateMessage( &msg );
390     DispatchMessage( &msg );
391   }
392   return true;
393 }
394
395 LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
396 {
397   XBMC_Event newEvent;
398   ZeroMemory(&newEvent, sizeof(newEvent));
399   static HDEVNOTIFY hDeviceNotify;
400
401   if (uMsg == WM_CREATE)
402   {
403     g_hWnd = hWnd;
404     SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
405     DIB_InitOSKeymap();
406     g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
407     shcne.pidl = NULL;
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);
412     return 0;
413   }
414
415   if (uMsg == WM_DESTROY)
416     g_hWnd = NULL;
417
418   m_pEventFunc = (PHANDLE_EVENT_FUNC)GetWindowLongPtr(hWnd, GWLP_USERDATA);
419   if (!m_pEventFunc)
420     return DefWindowProc(hWnd, uMsg, wParam, lParam);
421
422   if(g_uQueryCancelAutoPlay != 0 && uMsg == g_uQueryCancelAutoPlay)
423     return S_FALSE;
424
425   switch (uMsg)
426   {
427     case WM_CLOSE:
428     case WM_QUIT:
429     case WM_DESTROY:
430       if (hDeviceNotify)
431         UnregisterDeviceNotification(hDeviceNotify);
432       newEvent.type = XBMC_QUIT;
433       m_pEventFunc(newEvent);
434       break;
435     case WM_SHOWWINDOW:
436       {
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");
442       }
443       break;
444     case WM_ACTIVATE:
445       {
446         if( WA_INACTIVE != wParam )
447           g_Joystick.Reinitialize();
448
449         bool active = g_application.GetRenderGUI();
450         if (HIWORD(wParam))
451         {
452           g_application.SetRenderGUI(false);
453         }
454         else
455         {
456           WINDOWPLACEMENT lpwndpl;
457           lpwndpl.length = sizeof(lpwndpl);
458           if (LOWORD(wParam) != WA_INACTIVE)
459           {
460             if (GetWindowPlacement(hWnd, &lpwndpl))
461               g_application.SetRenderGUI(lpwndpl.showCmd != SW_HIDE);
462           }
463           else
464           {
465             g_application.SetRenderGUI(g_Windowing.WindowedMode());
466           }
467         }
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");
471       }
472       break;
473     case WM_SETFOCUS:
474     case WM_KILLFOCUS:
475       g_application.m_AppFocused = uMsg == WM_SETFOCUS;
476       g_Windowing.NotifyAppFocusChange(g_application.m_AppFocused);
477       if (uMsg == WM_KILLFOCUS)
478       {
479         CStdString procfile;
480         if (CWIN32Util::GetFocussedProcess(procfile))
481           CLog::Log(LOGDEBUG, __FUNCTION__": Focus switched to process %s", procfile.c_str());
482       }
483       break;
484     /* needs to be reviewed after frodo. we reset the system idle timer
485        and the display timer directly now (see m_screenSaverTimer).
486     case WM_SYSCOMMAND:
487       switch( wParam&0xFFF0 )
488       {
489         case SC_MONITORPOWER:
490           if (g_application.m_pPlayer->IsPlaying() || g_application.m_pPlayer->IsPausedPlayback())
491             return 0;
492           else if(CSettings::Get().GetInt("powermanagement.displaysoff") == 0)
493             return 0;
494           break;
495         case SC_SCREENSAVE:
496           return 0;
497       }
498       break;*/
499     case WM_SYSKEYDOWN:
500       switch (wParam)
501       {
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();
507           return 0;
508       }
509       //deliberate fallthrough
510     case WM_KEYDOWN:
511     {
512       switch (wParam)
513       {
514         case VK_CONTROL:
515           if ( lParam & EXTENDED_KEYMASK )
516             wParam = VK_RCONTROL;
517           else
518             wParam = VK_LCONTROL;
519           break;
520         case VK_SHIFT:
521           /* EXTENDED trick doesn't work here */
522           if (GetKeyState(VK_LSHIFT) & 0x8000)
523             wParam = VK_LSHIFT;
524           else if (GetKeyState(VK_RSHIFT) & 0x8000)
525             wParam = VK_RSHIFT;
526           break;
527         case VK_MENU:
528           if ( lParam & EXTENDED_KEYMASK )
529             wParam = VK_RMENU;
530           else
531             wParam = VK_LMENU;
532           break;
533       }
534       XBMC_keysym keysym;
535       TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
536
537       newEvent.type = XBMC_KEYDOWN;
538       newEvent.key.keysym = keysym;
539       m_pEventFunc(newEvent);
540     }
541     return(0);
542
543     case WM_SYSKEYUP:
544     case WM_KEYUP:
545       {
546       switch (wParam)
547       {
548         case VK_CONTROL:
549           if ( lParam&EXTENDED_KEYMASK )
550             wParam = VK_RCONTROL;
551           else
552             wParam = VK_LCONTROL;
553           break;
554         case VK_SHIFT:
555           {
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)
560               wParam = VK_LSHIFT;
561             else if (keyCode == scanCodeR)
562               wParam = VK_RSHIFT;
563           }
564           break;
565         case VK_MENU:
566           if ( lParam&EXTENDED_KEYMASK )
567             wParam = VK_RMENU;
568           else
569             wParam = VK_LMENU;
570           break;
571       }
572       XBMC_keysym keysym;
573       TranslateKey(wParam, HIWORD(lParam), &keysym, 1);
574
575       if (wParam == VK_SNAPSHOT)
576         newEvent.type = XBMC_KEYDOWN;
577       else
578         newEvent.type = XBMC_KEYUP;
579       newEvent.key.keysym = keysym;
580       m_pEventFunc(newEvent);
581     }
582     return(0);
583     case WM_APPCOMMAND: // MULTIMEDIA keys are mapped to APPCOMMANDS
584     {
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))
589         return TRUE;
590       else
591         return DefWindowProc(hWnd, uMsg, wParam, lParam);
592     }
593     case WM_GESTURENOTIFY:
594     {
595       OnGestureNotify(hWnd, lParam);
596       return DefWindowProc(hWnd, WM_GESTURENOTIFY, wParam, lParam);
597     }
598     case WM_GESTURE:
599     {
600       OnGesture(hWnd, lParam);
601       return 0;
602     }
603     case WM_SYSCHAR:
604       if (wParam == VK_RETURN) //stop system beep on alt-return
605         return 0;
606       break;
607     case WM_SETCURSOR:
608       if (HTCLIENT != LOWORD(lParam))
609         g_Windowing.ShowOSMouse(true);
610       break;
611     case WM_MOUSEMOVE:
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);
617       return(0);
618     case WM_LBUTTONDOWN:
619     case WM_MBUTTONDOWN:
620     case WM_RBUTTONDOWN:
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);
630       return(0);
631     case WM_LBUTTONUP:
632     case WM_MBUTTONUP:
633     case WM_RBUTTONUP:
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);
643       return(0);
644     case WM_MOUSEWHEEL:
645       {
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
652         POINT point;
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);
663       }
664       return(0);
665     case WM_SIZE:
666       newEvent.type = XBMC_VIDEORESIZE;
667       newEvent.resize.w = GET_X_LPARAM(lParam);
668       newEvent.resize.h = GET_Y_LPARAM(lParam);
669
670       CLog::Log(LOGDEBUG, __FUNCTION__": window resize event");
671
672       if (!g_Windowing.IsAlteringWindow() && newEvent.resize.w > 0 && newEvent.resize.h > 0)
673         m_pEventFunc(newEvent);
674
675       return(0);
676     case WM_MOVE:
677       newEvent.type = XBMC_VIDEOMOVE;
678       newEvent.move.x = GET_X_LPARAM(lParam);
679       newEvent.move.y = GET_Y_LPARAM(lParam);
680
681       CLog::Log(LOGDEBUG, __FUNCTION__": window move event");
682
683       if (!g_Windowing.IsAlteringWindow())
684         m_pEventFunc(newEvent);
685
686       return(0);
687     case WM_MEDIA_CHANGE:
688       {
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.
695         long lEvent;
696         PIDLIST_ABSOLUTE *ppidl;
697         HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
698
699         if (hLock)
700         {
701           char drivePath[MAX_PATH+1];
702           if (!SHGetPathFromIDList(ppidl[0], drivePath))
703             break;
704
705           switch(lEvent)
706           {
707             case SHCNE_DRIVEADD:
708             case SHCNE_MEDIAINSERTED:
709               if (GetDriveType(drivePath) != DRIVE_CDROM)
710               {
711                 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", drivePath);
712                 CWin32StorageProvider::SetEvent();
713               }
714               break;
715
716             case SHCNE_DRIVEREMOVED:
717             case SHCNE_MEDIAREMOVED:
718               if (GetDriveType(drivePath) != DRIVE_CDROM)
719               {
720                 CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", drivePath);
721                 CWin32StorageProvider::SetEvent();
722               }
723               break;
724           }
725           SHChangeNotification_Unlock(hLock);
726         }
727         break;
728       }
729     case WM_POWERBROADCAST:
730       if (wParam==PBT_APMSUSPEND)
731       {
732         CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMSUSPEND event was sent");
733         CWin32PowerSyscall::SetOnSuspend();
734       }
735       else if(wParam==PBT_APMRESUMEAUTOMATIC)
736       {
737         CLog::Log(LOGDEBUG,"WM_POWERBROADCAST: PBT_APMRESUMEAUTOMATIC event was sent");
738         CWin32PowerSyscall::SetOnResume();
739       }
740       break;
741     case WM_DEVICECHANGE:
742       {
743         switch(wParam)
744         {
745           case DBT_DEVNODES_CHANGED:
746             g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
747             break;
748           case DBT_DEVICEARRIVAL:
749           case DBT_DEVICEREMOVECOMPLETE:
750             if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
751             {
752               g_peripherals.TriggerDeviceScan(PERIPHERAL_BUS_USB);
753               g_Joystick.Reinitialize();
754             }
755             // check if an usb or optical media was inserted or removed
756             if (((_DEV_BROADCAST_HEADER*) lParam)->dbcd_devicetype == DBT_DEVTYP_VOLUME)
757             {
758               PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)((_DEV_BROADCAST_HEADER*) lParam);
759               // optical medium
760               if (lpdbv -> dbcv_flags & DBTF_MEDIA)
761               {
762                 CStdString strdrive;
763                 strdrive.Format("%c:\\", CWIN32Util::FirstDriveFromMask(lpdbv ->dbcv_unitmask));
764                 if(wParam == DBT_DEVICEARRIVAL)
765                 {
766                   CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media has arrived.", strdrive.c_str());
767                   CJobManager::GetInstance().AddJob(new CDetectDisc(strdrive, true), NULL);
768                 }
769                 else
770                 {
771                   CLog::Log(LOGDEBUG, __FUNCTION__": Drive %s Media was removed.", strdrive.c_str());
772                   CMediaSource share;
773                   share.strPath = strdrive;
774                   share.strName = share.strPath;
775                   g_mediaManager.RemoveAutoSource(share);
776                 }
777               }
778               else
779                 CWin32StorageProvider::SetEvent();
780             }
781         }
782         break;
783       }
784     case WM_PAINT:
785       //some other app has painted over our window, mark everything as dirty
786       g_windowManager.MarkDirty();
787       break;
788     case BONJOUR_EVENT:
789       CZeroconf::GetInstance()->ProcessResults();
790       break;
791     case BONJOUR_BROWSER_EVENT:
792       CZeroconfBrowser::GetInstance()->ProcessResults();
793       break;
794   }
795   return(DefWindowProc(hWnd, uMsg, wParam, lParam));
796 }
797
798 void CWinEventsWin32::RegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND hWnd, HDEVNOTIFY *hDeviceNotify)
799 {
800   DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
801
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;
806
807   *hDeviceNotify = RegisterDeviceNotification(
808       hWnd,                       // events recipient
809       &NotificationFilter,        // type of device
810       DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle
811       );
812 }
813
814 void CWinEventsWin32::WindowFromScreenCoords(HWND hWnd, POINT *point)
815 {
816   if (!point) return;
817   RECT clientRect;
818   GetClientRect(hWnd, &clientRect);
819   POINT windowPos;
820   windowPos.x = clientRect.left;
821   windowPos.y = clientRect.top;
822   ClientToScreen(hWnd, &windowPos);
823   point->x -= windowPos.x;
824   point->y -= windowPos.y;
825 }
826
827 void CWinEventsWin32::OnGestureNotify(HWND hWnd, LPARAM lParam)
828 {
829   // convert to window coordinates
830   PGESTURENOTIFYSTRUCT gn = (PGESTURENOTIFYSTRUCT)(lParam);
831   POINT point = { gn->ptsLocation.x, gn->ptsLocation.y };
832   WindowFromScreenCoords(hWnd, &point);
833
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 }};
841
842   // send a message to see if a control wants any
843   int gestures = 0;
844   if ((gestures = CGenericTouchActionHandler::Get().QuerySupportedGestures((float)point.x, (float)point.y)) != EVENT_RESULT_UNHANDLED)
845   {
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)
859     {
860       gc[2].dwWant |= GC_PAN | GC_PAN_WITH_SINGLE_FINGER_VERTICALLY | GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY | GC_PAN_WITH_GUTTER;
861
862       // create a new touch swipe detector
863       m_touchSwipeDetector = new CGenericTouchSwipeDetector(&CGenericTouchActionHandler::Get(), 160.0f);
864     }
865
866     gc[0].dwBlock = gc[0].dwWant ^ 0x01;
867     gc[1].dwBlock = gc[1].dwWant ^ 0x01;
868     gc[2].dwBlock = gc[2].dwWant ^ 0x1F;
869   }
870   if (g_Windowing.PtrSetGestureConfig)
871     g_Windowing.PtrSetGestureConfig(hWnd, 0, 5, gc, sizeof(GESTURECONFIG));
872 }
873
874 void CWinEventsWin32::OnGesture(HWND hWnd, LPARAM lParam)
875 {
876   if (!g_Windowing.PtrGetGestureInfo)
877     return;
878
879   GESTUREINFO gi = {0};
880   gi.cbSize = sizeof(gi);
881   g_Windowing.PtrGetGestureInfo((HGESTUREINFO)lParam, &gi);
882
883   // convert to window coordinates
884   POINT point = { gi.ptsLocation.x, gi.ptsLocation.y };
885   WindowFromScreenCoords(hWnd, &point);
886
887   if (gi.dwID == GID_BEGIN)
888     m_touchPointer.reset();
889
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;
893
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);
898
899   switch (gi.dwID)
900   {
901   case GID_BEGIN:
902     {
903       // set the "down" touch
904       m_touchPointer.down = m_touchPointer.current;
905       m_originalZoomDistance = 0;
906
907       CGenericTouchActionHandler::Get().OnTouchGestureStart((float)point.x, (float)point.y);
908     }
909     break;
910
911   case GID_END:
912     CGenericTouchActionHandler::Get().OnTouchGestureEnd((float)point.x, (float)point.y, 0.0f, 0.0f, 0.0f, 0.0f);
913     break;
914
915   case GID_PAN:
916     {
917       if (!m_touchPointer.moving)
918         m_touchPointer.moving = true;
919
920       // calculate the velocity of the pan gesture
921       float velocityX, velocityY;
922       m_touchPointer.velocity(velocityX, velocityY);
923
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);
927
928       if (m_touchSwipeDetector != NULL)
929       {
930         if (gi.dwFlags & GF_BEGIN)
931         {
932           m_touchPointer.down = m_touchPointer.current;
933           m_touchSwipeDetector->OnTouchDown(0, m_touchPointer);
934         }
935         else if (gi.dwFlags & GF_END)
936         {
937           m_touchSwipeDetector->OnTouchUp(0, m_touchPointer);
938
939           delete m_touchSwipeDetector;
940           m_touchSwipeDetector = NULL;
941         }
942         else
943           m_touchSwipeDetector->OnTouchMove(0, m_touchPointer);
944       }
945     }
946     break;
947
948   case GID_ROTATE:
949     {
950       if (gi.dwFlags == GF_BEGIN)
951         break;
952
953       CGenericTouchActionHandler::Get().OnRotate((float)point.x, (float)point.y,
954                                                  -(float)ROTATE_ANGLE_DEGREE(gi.ullArguments));
955     }
956     break;
957
958   case GID_ZOOM:
959     {
960       if (gi.dwFlags == GF_BEGIN)
961       {
962         m_originalZoomDistance = (int)LODWORD(gi.ullArguments);
963         break;
964       }
965
966       // avoid division by 0
967       if (m_originalZoomDistance == 0)
968         break;
969
970       CGenericTouchActionHandler::Get().OnZoomPinch((float)point.x, (float)point.y,
971                                                     (float)LODWORD(gi.ullArguments) / (float)m_originalZoomDistance);
972     }
973     break;
974
975   case GID_TWOFINGERTAP:
976     CGenericTouchActionHandler::Get().OnTap((float)point.x, (float)point.y, 2);
977     break;
978
979   case GID_PRESSANDTAP:
980   default:
981     // You have encountered an unknown gesture
982     break;
983   }
984   if(g_Windowing.PtrCloseGestureInfoHandle)
985     g_Windowing.PtrCloseGestureInfoHandle((HGESTUREINFO)lParam);
986 }
987
988 #endif