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