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