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