src/video/windows/SDL_windowsevents.c
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Mon, 25 Feb 2013 16:52:51 -0800
changeset 6925 59fedfb8faaf
parent 6922 91d157d9f283
child 6929 7fa90e780e2d
permissions -rw-r--r--
sdl2
- more scancode goodness, removing now dead wparam translation code
- add scancode for SDL_SCANCODE_NONUSBACKSLASH
- don't translate sdl key values for numeric and grave key

CR: SamL
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_WINDOWS
    24 
    25 #include "SDL_windowsvideo.h"
    26 #include "SDL_windowsshape.h"
    27 #include "SDL_syswm.h"
    28 #include "SDL_vkeys.h"
    29 #include "../../events/SDL_events_c.h"
    30 #include "../../events/SDL_touch_c.h"
    31 
    32 /* Dropfile support */
    33 #include <shellapi.h>
    34 
    35 
    36 
    37 
    38 /*#define WMMSG_DEBUG*/
    39 #ifdef WMMSG_DEBUG
    40 #include <stdio.h>	
    41 #include "wmmsg.h"
    42 #endif
    43 
    44 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    45 #define REPEATED_KEYMASK    (1<<30)
    46 #define EXTENDED_KEYMASK    (1<<24)
    47 
    48 #define VK_ENTER    10          /* Keypad Enter ... no VKEY defined? */
    49 
    50 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
    51 #ifndef WM_XBUTTONDOWN
    52 #define WM_XBUTTONDOWN 0x020B
    53 #endif
    54 #ifndef WM_XBUTTONUP
    55 #define WM_XBUTTONUP 0x020C
    56 #endif
    57 #ifndef GET_XBUTTON_WPARAM
    58 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
    59 #endif
    60 #ifndef WM_INPUT
    61 #define WM_INPUT 0x00ff
    62 #endif
    63 #ifndef WM_TOUCH
    64 #define WM_TOUCH 0x0240
    65 #endif
    66 
    67 
    68 static SDL_Scancode 
    69 WindowsScanCodeToSDLScanCode( int lParam, int wParam, const SDL_Scancode *key_map )
    70 {
    71 	SDL_Scancode code;
    72 	char bIsExtended;
    73 	int nScanCode = ( lParam >> 16 ) & 0xFF;
    74 
    75 	if ( nScanCode == 0 )
    76 	{
    77 		switch( wParam )
    78 		{
    79 		case VK_CLEAR: return SDL_SCANCODE_CLEAR;
    80 		case VK_MODECHANGE: return SDL_SCANCODE_MODE;
    81 		case VK_SELECT: return SDL_SCANCODE_SELECT;
    82 		case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
    83 		case VK_HELP: return SDL_SCANCODE_HELP;
    84 
    85 		case VK_F13: return SDL_SCANCODE_F13;
    86 		case VK_F14: return SDL_SCANCODE_F14;
    87 		case VK_F15: return SDL_SCANCODE_F15;
    88 		case VK_F16: return SDL_SCANCODE_F16;
    89 		case VK_F17: return SDL_SCANCODE_F17;
    90 		case VK_F18: return SDL_SCANCODE_F18;
    91 		case VK_F19: return SDL_SCANCODE_F19;
    92 		case VK_F20: return SDL_SCANCODE_F20;
    93 		case VK_F21: return SDL_SCANCODE_F21;
    94 		case VK_F22: return SDL_SCANCODE_F22;
    95 		case VK_F23: return SDL_SCANCODE_F23;
    96 		case VK_F24: return SDL_SCANCODE_F24;
    97 
    98 		case VK_OEM_NEC_EQUAL: return SDL_SCANCODE_KP_EQUALS;
    99 		case VK_BROWSER_BACK: return SDL_SCANCODE_AC_BACK;
   100 		case VK_BROWSER_FORWARD: return SDL_SCANCODE_AC_FORWARD;
   101 		case VK_BROWSER_REFRESH: return SDL_SCANCODE_AC_REFRESH;
   102 		case VK_BROWSER_STOP: return SDL_SCANCODE_AC_STOP;
   103 		case VK_BROWSER_SEARCH: return SDL_SCANCODE_AC_SEARCH;
   104 		case VK_BROWSER_FAVORITES: return SDL_SCANCODE_AC_BOOKMARKS;
   105 		case VK_BROWSER_HOME: return SDL_SCANCODE_AC_HOME;
   106 		case VK_VOLUME_MUTE: return SDL_SCANCODE_AUDIOMUTE;
   107 		case VK_VOLUME_DOWN: return SDL_SCANCODE_VOLUMEDOWN;
   108 		case VK_VOLUME_UP: return SDL_SCANCODE_VOLUMEUP;
   109 	
   110 		case VK_MEDIA_NEXT_TRACK: return SDL_SCANCODE_AUDIONEXT;
   111 		case VK_MEDIA_PREV_TRACK: return SDL_SCANCODE_AUDIOPREV;
   112 		case VK_MEDIA_STOP: return SDL_SCANCODE_AUDIOSTOP;
   113 		case VK_MEDIA_PLAY_PAUSE: return SDL_SCANCODE_AUDIOPLAY;
   114 		case VK_LAUNCH_MAIL: return SDL_SCANCODE_MAIL;
   115 		case VK_LAUNCH_MEDIA_SELECT: return SDL_SCANCODE_MEDIASELECT;
   116 		
   117 		case VK_OEM_102: return SDL_SCANCODE_NONUSBACKSLASH;
   118 
   119 		case VK_ATTN: return SDL_SCANCODE_SYSREQ;
   120 		case VK_CRSEL: return SDL_SCANCODE_CRSEL;
   121 		case VK_EXSEL: return SDL_SCANCODE_EXSEL;
   122 		case VK_OEM_CLEAR: return SDL_SCANCODE_CLEAR;
   123 
   124 		case VK_LAUNCH_APP1: return SDL_SCANCODE_APP1;
   125 		case VK_LAUNCH_APP2: return SDL_SCANCODE_APP2;
   126 
   127 		default: return SDL_SCANCODE_UNKNOWN;
   128 		}
   129 	}
   130 
   131 	if ( nScanCode > 127 )
   132 		return SDL_SCANCODE_UNKNOWN;
   133 
   134 	code = key_map[nScanCode];
   135 
   136 	bIsExtended = ( lParam & ( 1 << 24 ) ) != 0;
   137 	if ( !bIsExtended )
   138 	{
   139 		switch ( code )
   140 		{
   141 		case SDL_SCANCODE_HOME:
   142 			return SDL_SCANCODE_KP_7;
   143 		case SDL_SCANCODE_UP:
   144 			return SDL_SCANCODE_KP_8;
   145 		case SDL_SCANCODE_PAGEUP:
   146 			return SDL_SCANCODE_KP_9;
   147 		case SDL_SCANCODE_LEFT:
   148 			return SDL_SCANCODE_KP_4;
   149 		case SDL_SCANCODE_RIGHT:
   150 			return SDL_SCANCODE_KP_6;
   151 		case SDL_SCANCODE_END:
   152 			return SDL_SCANCODE_KP_1;
   153 		case SDL_SCANCODE_DOWN:
   154 			return SDL_SCANCODE_KP_2;
   155 		case SDL_SCANCODE_PAGEDOWN:
   156 			return SDL_SCANCODE_KP_3;
   157 		case SDL_SCANCODE_INSERT:
   158 			return SDL_SCANCODE_KP_0;
   159 		case SDL_SCANCODE_DELETE:
   160 			return SDL_SCANCODE_KP_DECIMAL;
   161 		case SDL_SCANCODE_PRINTSCREEN:
   162 			return SDL_SCANCODE_KP_MULTIPLY;
   163 		default:
   164 			break;
   165 		}
   166 	}
   167 	else
   168 	{
   169 		switch ( code )
   170 		{
   171 		case SDL_SCANCODE_RETURN:
   172 			return SDL_SCANCODE_KP_ENTER;
   173 		case SDL_SCANCODE_LALT:
   174 			return SDL_SCANCODE_RALT;
   175 		case SDL_SCANCODE_LCTRL:
   176 			return SDL_SCANCODE_RCTRL;
   177 		case SDL_SCANCODE_SLASH:
   178 			return SDL_SCANCODE_KP_DIVIDE;
   179 		case SDL_SCANCODE_CAPSLOCK:
   180 			return SDL_SCANCODE_KP_PLUS;
   181 		}
   182 	}
   183 
   184 	return code;
   185 }
   186 
   187 
   188 LRESULT CALLBACK
   189 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   190 {
   191     SDL_WindowData *data;
   192     LRESULT returnCode = -1;
   193 
   194     /* Send a SDL_SYSWMEVENT if the application wants them */
   195     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   196         SDL_SysWMmsg wmmsg;
   197 
   198         SDL_VERSION(&wmmsg.version);
   199         wmmsg.subsystem = SDL_SYSWM_WINDOWS;
   200         wmmsg.msg.win.hwnd = hwnd;
   201         wmmsg.msg.win.msg = msg;
   202         wmmsg.msg.win.wParam = wParam;
   203         wmmsg.msg.win.lParam = lParam;
   204         SDL_SendSysWMEvent(&wmmsg);
   205     }
   206 
   207     /* Get the window data for the window */
   208     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   209     if (!data) {
   210         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   211     }
   212 
   213 #ifdef WMMSG_DEBUG
   214     {		
   215         FILE *log = fopen("wmmsg.txt", "a");		
   216         fprintf(log, "Received windows message: %p ", hwnd);
   217         if (msg > MAX_WMMSG) {
   218             fprintf(log, "%d", msg);
   219         } else {
   220             fprintf(log, "%s", wmtab[msg]);
   221         }
   222         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   223         fclose(log);
   224     }
   225 #endif
   226 
   227     if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
   228         return 0;
   229 
   230     switch (msg) {
   231 
   232     case WM_SHOWWINDOW:
   233         {
   234             if (wParam) {
   235                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   236             } else {
   237                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   238             }
   239         }
   240         break;
   241 
   242     case WM_ACTIVATE:
   243         {
   244             BOOL minimized;
   245 
   246             minimized = HIWORD(wParam);
   247             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   248                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   249                 SDL_SendWindowEvent(data->window,
   250                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   251                 if (IsZoomed(hwnd)) {
   252                     SDL_SendWindowEvent(data->window,
   253                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   254                 }
   255                 if (SDL_GetKeyboardFocus() != data->window) {
   256                     SDL_SetKeyboardFocus(data->window);
   257                 }
   258 
   259 				if(SDL_GetMouse()->relative_mode) {
   260 					LONG cx, cy;
   261 					RECT rect;
   262 					GetWindowRect(hwnd, &rect);
   263 
   264 					cx = (rect.left + rect.right) / 2;
   265 					cy = (rect.top + rect.bottom) / 2;
   266 
   267 					/* Make an absurdly small clip rect */
   268 					rect.left = cx-1;
   269 					rect.right = cx+1;
   270 					rect.top = cy-1;
   271 					rect.bottom = cy+1;
   272 
   273 					ClipCursor(&rect);
   274 				}
   275 
   276                 /*
   277                  * FIXME: Update keyboard state
   278                  */
   279                 WIN_CheckClipboardUpdate(data->videodata);
   280             } else {
   281                 if (SDL_GetKeyboardFocus() == data->window) {
   282                     SDL_SetKeyboardFocus(NULL);
   283                 }
   284                 if (minimized) {
   285                     SDL_SendWindowEvent(data->window,
   286                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   287                 }
   288             }
   289         }
   290         returnCode = 0;
   291         break;
   292 
   293 	case WM_MOUSEMOVE:
   294 		if(SDL_GetMouse()->relative_mode)
   295 			break;
   296         SDL_SendMouseMotion(data->window, 0, LOWORD(lParam), HIWORD(lParam));
   297         break;
   298 
   299 	case WM_INPUT:
   300 	{
   301 		HRAWINPUT hRawInput = (HRAWINPUT)lParam;
   302 		RAWINPUT inp;
   303 		UINT size = sizeof(inp);
   304 
   305 		if(!SDL_GetMouse()->relative_mode)
   306 			break;
   307 
   308 		GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
   309 
   310 		/* Mouse data */
   311 		if(inp.header.dwType == RIM_TYPEMOUSE)
   312 		{
   313 			RAWMOUSE* mouse = &inp.data.mouse;
   314 
   315 			if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE)
   316 			{
   317 				SDL_SendMouseMotion(data->window, 1, (int)mouse->lLastX, (int)mouse->lLastY);
   318 			}
   319 			else
   320 			{
   321 				// synthesize relative moves from the abs position
   322 				static SDL_Point initialMousePoint;
   323 				if ( initialMousePoint.x == 0 && initialMousePoint.y == 0 )
   324 				{
   325 					initialMousePoint.x = mouse->lLastX;
   326 					initialMousePoint.y = mouse->lLastY;
   327 				}
   328 
   329 				SDL_SendMouseMotion(data->window, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) );
   330 
   331 				initialMousePoint.x = mouse->lLastX;
   332 				initialMousePoint.y = mouse->lLastY;
   333 			}
   334 		}
   335 		break;
   336 	}
   337 
   338     case WM_LBUTTONDOWN:
   339         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_LEFT);
   340         break;
   341 
   342     case WM_LBUTTONUP:
   343         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_LEFT);
   344         break;
   345 
   346     case WM_RBUTTONDOWN:
   347         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_RIGHT);
   348         break;
   349 
   350     case WM_RBUTTONUP:
   351         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_RIGHT);
   352         break;
   353 
   354     case WM_MBUTTONDOWN:
   355         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_MIDDLE);
   356         break;
   357 
   358     case WM_MBUTTONUP:
   359         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_MIDDLE);
   360         break;
   361 
   362     case WM_XBUTTONDOWN:
   363         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(wParam) - 1);
   364         returnCode = TRUE;
   365         break;
   366 
   367     case WM_XBUTTONUP:
   368         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(wParam) - 1);
   369         returnCode = TRUE;
   370         break;
   371 
   372     case WM_MOUSEWHEEL:
   373         {
   374             // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
   375             short motion = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
   376 
   377             SDL_SendMouseWheel(data->window, 0, motion);
   378             break;
   379         }
   380 
   381 #ifdef WM_MOUSELEAVE
   382     /* FIXME: Do we need the SDL 1.2 hack to generate WM_MOUSELEAVE now? */
   383     case WM_MOUSELEAVE:
   384         if (SDL_GetMouseFocus() == data->window) {
   385             SDL_SetMouseFocus(NULL);
   386         }
   387         returnCode = 0;
   388         break;
   389 #endif /* WM_MOUSELEAVE */
   390 
   391     case WM_SYSKEYDOWN:
   392     case WM_KEYDOWN:
   393         {
   394 			SDL_Scancode code =  WindowsScanCodeToSDLScanCode( lParam, wParam, data->videodata->key_layout );
   395 			if ( code != SDL_SCANCODE_UNKNOWN ) {
   396                 SDL_SendKeyboardKey(SDL_PRESSED, code );
   397             }
   398         }
   399         returnCode = 0;
   400         break;
   401 
   402     case WM_SYSKEYUP:
   403     case WM_KEYUP:
   404         {
   405 			SDL_Scancode code =  WindowsScanCodeToSDLScanCode( lParam, wParam, data->videodata->key_layout );
   406 			if ( code != SDL_SCANCODE_UNKNOWN ) {
   407 				if (wParam == VK_SNAPSHOT
   408 				    && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   409 				    SDL_RELEASED) {
   410 				    SDL_SendKeyboardKey(SDL_PRESSED,
   411 				                         code);
   412 				}
   413                 SDL_SendKeyboardKey(SDL_RELEASED, code );
   414             }
   415         }
   416         returnCode = 0;
   417         break;
   418 
   419     case WM_CHAR:
   420         {
   421             char text[4];
   422 
   423             /* Convert to UTF-8 and send it on... */
   424             if (wParam <= 0x7F) {
   425                 text[0] = (char) wParam;
   426                 text[1] = '\0';
   427             } else if (wParam <= 0x7FF) {
   428                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   429                 text[1] = 0x80 | (char) (wParam & 0x3F);
   430                 text[2] = '\0';
   431             } else {
   432                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   433                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   434                 text[2] = 0x80 | (char) (wParam & 0x3F);
   435                 text[3] = '\0';
   436             }
   437             SDL_SendKeyboardText(text);
   438         }
   439         returnCode = 0;
   440         break;
   441 
   442 #ifdef WM_INPUTLANGCHANGE
   443     case WM_INPUTLANGCHANGE:
   444         {
   445             WIN_UpdateKeymap();
   446         }
   447         returnCode = 1;
   448         break;
   449 #endif /* WM_INPUTLANGCHANGE */
   450 
   451 #ifdef WM_GETMINMAXINFO
   452     case WM_GETMINMAXINFO:
   453         {
   454             MINMAXINFO *info;
   455             RECT size;
   456             int x, y;
   457             int w, h;
   458             int min_w, min_h;
   459             int max_w, max_h;
   460             int style;
   461             BOOL menu;
   462 			BOOL constrain_max_size;
   463 
   464             /* If we allow resizing, let the resize happen naturally */
   465             if (SDL_IsShapedWindow(data->window))
   466                 Win32_ResizeWindowShape(data->window);
   467 
   468             /* Get the current position of our window */
   469             GetWindowRect(hwnd, &size);
   470             x = size.left;
   471             y = size.top;
   472 
   473             /* Calculate current size of our window */
   474             SDL_GetWindowSize(data->window, &w, &h);
   475             SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
   476             SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
   477 
   478             /* Store in min_w and min_h difference between current size and minimal 
   479                size so we don't need to call AdjustWindowRectEx twice */
   480             min_w -= w;
   481             min_h -= h;
   482             if (max_w && max_h) {
   483                 max_w -= w;
   484                 max_h -= h;
   485                 constrain_max_size = TRUE;
   486             } else {
   487                 constrain_max_size = FALSE;
   488             }
   489 
   490             size.top = 0;
   491             size.left = 0;
   492             size.bottom = h;
   493             size.right = w;
   494 
   495             style = GetWindowLong(hwnd, GWL_STYLE);
   496             /* DJM - according to the docs for GetMenu(), the
   497                return value is undefined if hwnd is a child window.
   498                Aparently it's too difficult for MS to check
   499                inside their function, so I have to do it here.
   500              */
   501             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   502             AdjustWindowRectEx(&size, style, menu, 0);
   503             w = size.right - size.left;
   504             h = size.bottom - size.top;
   505 
   506             /* Fix our size to the current size */
   507             info = (MINMAXINFO *) lParam;
   508             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   509                 info->ptMinTrackSize.x = w + min_w;
   510                 info->ptMinTrackSize.y = h + min_h;
   511                 if (constrain_max_size) {
   512                     info->ptMaxTrackSize.x = w + max_w;
   513                     info->ptMaxTrackSize.y = h + max_h;
   514                 }
   515             } else {
   516                 info->ptMaxSize.x = w;
   517                 info->ptMaxSize.y = h;
   518                 info->ptMaxPosition.x = x;
   519                 info->ptMaxPosition.y = y;
   520                 info->ptMinTrackSize.x = w;
   521                 info->ptMinTrackSize.y = h;
   522                 info->ptMaxTrackSize.x = w;
   523                 info->ptMaxTrackSize.y = h;
   524             }
   525         }
   526         returnCode = 0;
   527         break;
   528 #endif /* WM_GETMINMAXINFO */
   529 
   530     case WM_WINDOWPOSCHANGED:
   531         {
   532             RECT rect;
   533             int x, y;
   534             int w, h;
   535             Uint32 window_flags;
   536 
   537             if (!GetClientRect(hwnd, &rect) ||
   538                 (rect.right == rect.left && rect.bottom == rect.top)) {
   539                 break;
   540             }
   541             ClientToScreen(hwnd, (LPPOINT) & rect);
   542             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   543 
   544             window_flags = SDL_GetWindowFlags(data->window);
   545             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   546                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   547                 ClipCursor(&rect);
   548             }
   549 
   550             x = rect.left;
   551             y = rect.top;
   552             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   553 
   554             w = rect.right - rect.left;
   555             h = rect.bottom - rect.top;
   556             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   557                                 h);
   558         }
   559         break;
   560 
   561     case WM_SETCURSOR:
   562         {
   563             Uint16 hittest;
   564 
   565             hittest = LOWORD(lParam);
   566             if (hittest == HTCLIENT) {
   567                 SetCursor(SDL_cursor);
   568                 returnCode = TRUE;
   569             }
   570         }
   571         break;
   572 
   573         /* We were occluded, refresh our display */
   574     case WM_PAINT:
   575         {
   576             RECT rect;
   577             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   578                 ValidateRect(hwnd, &rect);
   579                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   580                                     0, 0);
   581             }
   582         }
   583         returnCode = 0;
   584         break;
   585 
   586         /* We'll do our own drawing, prevent flicker */
   587     case WM_ERASEBKGND:
   588         {
   589         }
   590         return (1);
   591 
   592 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   593     case WM_SYSCOMMAND:
   594         {
   595             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   596             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   597                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   598                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   599                     return (0);
   600                 }
   601             }
   602         }
   603         break;
   604 #endif /* System has screensaver support */
   605 
   606     case WM_CLOSE:
   607         {
   608             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   609         }
   610         returnCode = 0;
   611         break;
   612 
   613 	case WM_TOUCH:
   614 		{
   615 			UINT i, num_inputs = LOWORD(wParam);
   616 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   617 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   618 				RECT rect;
   619 				float x, y;
   620 
   621 				if (!GetClientRect(hwnd, &rect) ||
   622 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   623 					break;
   624 				}
   625 				ClientToScreen(hwnd, (LPPOINT) & rect);
   626 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   627 				rect.top *= 100;
   628 				rect.left *= 100;
   629 				rect.bottom *= 100;
   630 				rect.right *= 100;
   631 
   632 				for (i = 0; i < num_inputs; ++i) {
   633 					PTOUCHINPUT input = &inputs[i];
   634 
   635 					const SDL_TouchID touchId = (SDL_TouchID)
   636 												((size_t)input->hSource);
   637 					if (!SDL_GetTouch(touchId)) {
   638 						SDL_Touch touch;
   639 
   640 						touch.id = touchId;
   641 						touch.x_min = 0;
   642 						touch.x_max = 1;
   643 						touch.native_xres = touch.x_max - touch.x_min;
   644 						touch.y_min = 0;
   645 						touch.y_max = 1;
   646 						touch.native_yres = touch.y_max - touch.y_min;
   647 						touch.pressure_min = 0;
   648 						touch.pressure_max = 1;
   649 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   650 
   651 						if (SDL_AddTouch(&touch, "") < 0) {
   652 							continue;
   653 						}
   654 					}
   655 
   656 					// Get the normalized coordinates for the window
   657 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   658 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   659 
   660 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   661 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   662 					}
   663 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   664 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   665 					}
   666 					if (input->dwFlags & TOUCHEVENTF_UP) {
   667 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   668 					}
   669 				}
   670 			}
   671 			SDL_stack_free(inputs);
   672 
   673 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   674 			return 0;
   675 		}
   676 		break;
   677 
   678     case WM_DROPFILES:
   679         {
   680             UINT i;
   681             HDROP drop = (HDROP) wParam;
   682             UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
   683             for (i = 0; i < count; ++i) {
   684                 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
   685                 LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
   686                 if (buffer) {
   687                     if (DragQueryFile(drop, i, buffer, size)) {
   688                         char *file = WIN_StringToUTF8(buffer);
   689                         SDL_SendDropFile(file);
   690                         SDL_free(file);
   691                     }
   692                     SDL_stack_free(buffer);
   693                 }
   694             }
   695             DragFinish(drop);
   696             return 0;
   697         }
   698         break;
   699     }
   700 
   701     /* If there's a window proc, assume it's going to handle messages */
   702     if (data->wndproc) {
   703         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   704     } else if (returnCode >= 0) {
   705         return returnCode;
   706     } else {
   707         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   708     }
   709 }
   710 
   711 void
   712 WIN_PumpEvents(_THIS)
   713 {
   714     MSG msg;
   715     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   716         TranslateMessage(&msg);
   717         DispatchMessage(&msg);
   718     }
   719 }
   720 
   721 static int app_registered = 0;
   722 LPTSTR SDL_Appname = NULL;
   723 Uint32 SDL_Appstyle = 0;
   724 HINSTANCE SDL_Instance = NULL;
   725 
   726 /* Register the class for this application */
   727 int
   728 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   729 {
   730     WNDCLASS class;
   731 
   732     /* Only do this once... */
   733     if (app_registered) {
   734         ++app_registered;
   735         return (0);
   736     }
   737     if (!name && !SDL_Appname) {
   738         name = "SDL_app";
   739 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   740         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   741 #endif
   742         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   743     }
   744 
   745     if (name) {
   746         SDL_Appname = WIN_UTF8ToString(name);
   747         SDL_Appstyle = style;
   748         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   749     }
   750 
   751     /* Register the application class */
   752     class.hCursor = NULL;
   753     class.hIcon =
   754         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   755                   LR_DEFAULTCOLOR);
   756     class.lpszMenuName = NULL;
   757     class.lpszClassName = SDL_Appname;
   758     class.hbrBackground = NULL;
   759     class.hInstance = SDL_Instance;
   760     class.style = SDL_Appstyle;
   761     class.lpfnWndProc = WIN_WindowProc;
   762     class.cbWndExtra = 0;
   763     class.cbClsExtra = 0;
   764     if (!RegisterClass(&class)) {
   765         SDL_SetError("Couldn't register application class");
   766         return (-1);
   767     }
   768 
   769     app_registered = 1;
   770     return (0);
   771 }
   772 
   773 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   774 void
   775 SDL_UnregisterApp()
   776 {
   777     WNDCLASS class;
   778 
   779     /* SDL_RegisterApp might not have been called before */
   780     if (!app_registered) {
   781         return;
   782     }
   783     --app_registered;
   784     if (app_registered == 0) {
   785         /* Check for any registered window classes. */
   786         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   787             UnregisterClass(SDL_Appname, SDL_Instance);
   788         }
   789         SDL_free(SDL_Appname);
   790         SDL_Appname = NULL;
   791     }
   792 }
   793 
   794 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   795 
   796 /* vi: set ts=4 sw=4 expandtab: */