src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Feb 2013 11:39:43 -0800
changeset 6945 d97f9251ac3a
parent 6944 e8effbc1a10e
child 6947 18ccf3e4921d
permissions -rw-r--r--
sdl - check for both the up and down flags being set in the raw input calls. Also use WM_ACTIVE to resync mouse buttons on activate
     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 void 
   191 WIN_CheckWParamMouseButton( SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button )
   192 {
   193 	if ( bwParamMousePressed && !bSDLMousePressed )
   194 	{
   195 		SDL_SendMouseButton(data->window, SDL_PRESSED, button);
   196 	}
   197 	else if ( !bwParamMousePressed && bSDLMousePressed )
   198 	{
   199 		SDL_SendMouseButton(data->window, SDL_RELEASED, button);
   200 	}
   201 }
   202 
   203 /*
   204 * Some windows systems fail to send a WM_LBUTTONDOWN sometimes, but each mouse move contains the current button state also
   205 *  so this funciton reconciles our view of the world with the current buttons reported by windows
   206 */
   207 void 
   208 WIN_CheckWParamMouseButtons( WPARAM wParam, SDL_WindowData *data )
   209 {
   210 	if ( wParam != data->mouse_button_flags )
   211 	{
   212 		Uint32 mouseFlags = SDL_GetMouseState( NULL, NULL );
   213 		WIN_CheckWParamMouseButton(  (wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT );
   214 		WIN_CheckWParamMouseButton(  (wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE );
   215 		WIN_CheckWParamMouseButton(  (wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT );
   216 		WIN_CheckWParamMouseButton(  (wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1 );
   217 		WIN_CheckWParamMouseButton(  (wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2 );
   218 		data->mouse_button_flags = wParam;
   219 	}
   220 }
   221 
   222 
   223 void 
   224 WIN_CheckRawMouseButtons( ULONG rawButtons, SDL_WindowData *data )
   225 {
   226 	if ( rawButtons != data->mouse_button_flags )
   227 	{
   228 		Uint32 mouseFlags = SDL_GetMouseState( NULL, NULL );
   229 		if ( (rawButtons & RI_MOUSE_BUTTON_1_DOWN) )
   230 			WIN_CheckWParamMouseButton(  (rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT );
   231 		if ( (rawButtons & RI_MOUSE_BUTTON_1_UP) )
   232 			WIN_CheckWParamMouseButton(  !(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT );
   233 		if ( (rawButtons & RI_MOUSE_BUTTON_2_DOWN) )
   234 			WIN_CheckWParamMouseButton(  (rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT );
   235 		if ( (rawButtons & RI_MOUSE_BUTTON_2_UP) )
   236 			WIN_CheckWParamMouseButton(  !(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT );
   237 		if ( (rawButtons & RI_MOUSE_BUTTON_3_DOWN) )
   238 			WIN_CheckWParamMouseButton(  (rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE );
   239 		if ( (rawButtons & RI_MOUSE_BUTTON_3_UP) )
   240 			WIN_CheckWParamMouseButton(  !(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE );
   241 		if ( (rawButtons & RI_MOUSE_BUTTON_4_DOWN) )
   242 			WIN_CheckWParamMouseButton(  (rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1 );
   243 		if ( (rawButtons & RI_MOUSE_BUTTON_4_UP) )
   244 			WIN_CheckWParamMouseButton(  !(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1 );
   245 		if ( (rawButtons & RI_MOUSE_BUTTON_5_DOWN) )
   246 			WIN_CheckWParamMouseButton(  (rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2 );
   247 		if ( (rawButtons & RI_MOUSE_BUTTON_5_UP) )
   248 			WIN_CheckWParamMouseButton(  !(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2 );
   249 		data->mouse_button_flags = rawButtons;
   250 	}
   251 }
   252 
   253 LRESULT CALLBACK
   254 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   255 {
   256     SDL_WindowData *data;
   257     LRESULT returnCode = -1;
   258 
   259     /* Send a SDL_SYSWMEVENT if the application wants them */
   260     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   261         SDL_SysWMmsg wmmsg;
   262 
   263         SDL_VERSION(&wmmsg.version);
   264         wmmsg.subsystem = SDL_SYSWM_WINDOWS;
   265         wmmsg.msg.win.hwnd = hwnd;
   266         wmmsg.msg.win.msg = msg;
   267         wmmsg.msg.win.wParam = wParam;
   268         wmmsg.msg.win.lParam = lParam;
   269         SDL_SendSysWMEvent(&wmmsg);
   270     }
   271 
   272     /* Get the window data for the window */
   273     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   274     if (!data) {
   275         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   276     }
   277 
   278 #ifdef WMMSG_DEBUG
   279     {		
   280         FILE *log = fopen("wmmsg.txt", "a");		
   281         fprintf(log, "Received windows message: %p ", hwnd);
   282         if (msg > MAX_WMMSG) {
   283             fprintf(log, "%d", msg);
   284         } else {
   285             fprintf(log, "%s", wmtab[msg]);
   286         }
   287         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   288         fclose(log);
   289     }
   290 #endif
   291 
   292     if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
   293         return 0;
   294 
   295     switch (msg) {
   296 
   297     case WM_SHOWWINDOW:
   298         {
   299             if (wParam) {
   300                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   301             } else {
   302                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   303             }
   304         }
   305         break;
   306 
   307     case WM_ACTIVATE:
   308         {
   309             BOOL minimized;
   310 
   311             minimized = HIWORD(wParam);
   312             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   313 				Uint32 mouseFlags;
   314 				SHORT keyState;
   315 
   316                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   317                 SDL_SendWindowEvent(data->window,
   318                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   319                 if (IsZoomed(hwnd)) {
   320                     SDL_SendWindowEvent(data->window,
   321                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   322                 }
   323                 if (SDL_GetKeyboardFocus() != data->window) {
   324                     SDL_SetKeyboardFocus(data->window);
   325                 }
   326 				/* mouse buttons may have changed state here, we need
   327 				to resync them, but we will get a WM_MOUSEMOVE right away which will fix 
   328 				things up if in non raw mode also
   329 				*/
   330 				mouseFlags = SDL_GetMouseState( NULL, NULL );
   331 
   332 				keyState = GetAsyncKeyState( VK_LBUTTON );
   333 				WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT );
   334 				keyState = GetAsyncKeyState( VK_RBUTTON );
   335 				WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT );
   336 				keyState = GetAsyncKeyState( VK_MBUTTON );
   337 				WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE );
   338 				keyState = GetAsyncKeyState( VK_XBUTTON1 );
   339 				WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1 );
   340 				keyState = GetAsyncKeyState( VK_XBUTTON2 );
   341 				WIN_CheckWParamMouseButton( ( keyState & 0x8000 ), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2 );
   342 				data->mouse_button_flags = 0;
   343 
   344 				if(SDL_GetMouse()->relative_mode) {
   345 					LONG cx, cy;
   346 					RECT rect;
   347 					GetWindowRect(hwnd, &rect);
   348 
   349 					cx = (rect.left + rect.right) / 2;
   350 					cy = (rect.top + rect.bottom) / 2;
   351 
   352 					/* Make an absurdly small clip rect */
   353 					rect.left = cx-1;
   354 					rect.right = cx+1;
   355 					rect.top = cy-1;
   356 					rect.bottom = cy+1;
   357 
   358 					ClipCursor(&rect);
   359 				}
   360 
   361                 /*
   362                  * FIXME: Update keyboard state
   363                  */
   364                 WIN_CheckClipboardUpdate(data->videodata);
   365             } else {
   366                 if (SDL_GetKeyboardFocus() == data->window) {
   367                     SDL_SetKeyboardFocus(NULL);
   368                 }
   369                 if (minimized) {
   370                     SDL_SendWindowEvent(data->window,
   371                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   372                 }
   373             }
   374         }
   375         returnCode = 0;
   376         break;
   377 
   378 	case WM_MOUSEMOVE:
   379 		if( !SDL_GetMouse()->relative_mode )
   380 	        SDL_SendMouseMotion(data->window, 0, LOWORD(lParam), HIWORD(lParam));
   381 		/* don't break here, fall through to check the wParam like the button presses */
   382 	case WM_LBUTTONUP:
   383 	case WM_RBUTTONUP:
   384 	case WM_MBUTTONUP:
   385 	case WM_XBUTTONUP:
   386 	case WM_LBUTTONDOWN:
   387 	case WM_RBUTTONDOWN:
   388 	case WM_MBUTTONDOWN:
   389 	case WM_XBUTTONDOWN:
   390 		if( !SDL_GetMouse()->relative_mode )
   391 			WIN_CheckWParamMouseButtons( wParam, data );
   392 		break;
   393 
   394 	case WM_INPUT:
   395 	{
   396 		HRAWINPUT hRawInput = (HRAWINPUT)lParam;
   397 		RAWINPUT inp;
   398 		UINT size = sizeof(inp);
   399 
   400 		if(!SDL_GetMouse()->relative_mode)
   401 			break;
   402 
   403 		GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
   404 
   405 		/* Mouse data */
   406 		if(inp.header.dwType == RIM_TYPEMOUSE)
   407 		{
   408 			RAWMOUSE* mouse = &inp.data.mouse;
   409 
   410 			if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE)
   411 			{
   412 				SDL_SendMouseMotion(data->window, 1, (int)mouse->lLastX, (int)mouse->lLastY);
   413 			}
   414 			else
   415 			{
   416 				// synthesize relative moves from the abs position
   417 				static SDL_Point initialMousePoint;
   418 				if ( initialMousePoint.x == 0 && initialMousePoint.y == 0 )
   419 				{
   420 					initialMousePoint.x = mouse->lLastX;
   421 					initialMousePoint.y = mouse->lLastY;
   422 				}
   423 
   424 				SDL_SendMouseMotion(data->window, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) );
   425 
   426 				initialMousePoint.x = mouse->lLastX;
   427 				initialMousePoint.y = mouse->lLastY;
   428 			}
   429 			WIN_CheckRawMouseButtons( mouse->usButtonFlags, data ); 
   430 		}
   431 		break;
   432 	}
   433 
   434     case WM_MOUSEWHEEL:
   435         {
   436             // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
   437             short motion = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
   438 
   439             SDL_SendMouseWheel(data->window, 0, motion);
   440             break;
   441         }
   442 
   443 #ifdef WM_MOUSELEAVE
   444     /* FIXME: Do we need the SDL 1.2 hack to generate WM_MOUSELEAVE now? */
   445     case WM_MOUSELEAVE:
   446         if (SDL_GetMouseFocus() == data->window) {
   447             SDL_SetMouseFocus(NULL);
   448         }
   449         returnCode = 0;
   450         break;
   451 #endif /* WM_MOUSELEAVE */
   452 
   453     case WM_SYSKEYDOWN:
   454     case WM_KEYDOWN:
   455         {
   456 			SDL_Scancode code =  WindowsScanCodeToSDLScanCode( lParam, wParam, data->videodata->key_layout );
   457 			if ( code != SDL_SCANCODE_UNKNOWN ) {
   458                 SDL_SendKeyboardKey(SDL_PRESSED, code );
   459             }
   460         }
   461         returnCode = 0;
   462         break;
   463 
   464     case WM_SYSKEYUP:
   465     case WM_KEYUP:
   466         {
   467 			SDL_Scancode code =  WindowsScanCodeToSDLScanCode( lParam, wParam, data->videodata->key_layout );
   468 			if ( code != SDL_SCANCODE_UNKNOWN ) {
   469 				if (wParam == VK_SNAPSHOT
   470 				    && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   471 				    SDL_RELEASED) {
   472 				    SDL_SendKeyboardKey(SDL_PRESSED,
   473 				                         code);
   474 				}
   475                 SDL_SendKeyboardKey(SDL_RELEASED, code );
   476             }
   477         }
   478         returnCode = 0;
   479         break;
   480 
   481     case WM_CHAR:
   482         {
   483             char text[4];
   484 
   485             /* Convert to UTF-8 and send it on... */
   486             if (wParam <= 0x7F) {
   487                 text[0] = (char) wParam;
   488                 text[1] = '\0';
   489             } else if (wParam <= 0x7FF) {
   490                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   491                 text[1] = 0x80 | (char) (wParam & 0x3F);
   492                 text[2] = '\0';
   493             } else {
   494                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   495                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   496                 text[2] = 0x80 | (char) (wParam & 0x3F);
   497                 text[3] = '\0';
   498             }
   499             SDL_SendKeyboardText(text);
   500         }
   501         returnCode = 0;
   502         break;
   503 
   504 #ifdef WM_INPUTLANGCHANGE
   505     case WM_INPUTLANGCHANGE:
   506         {
   507             WIN_UpdateKeymap();
   508         }
   509         returnCode = 1;
   510         break;
   511 #endif /* WM_INPUTLANGCHANGE */
   512 
   513 #ifdef WM_GETMINMAXINFO
   514     case WM_GETMINMAXINFO:
   515         {
   516             MINMAXINFO *info;
   517             RECT size;
   518             int x, y;
   519             int w, h;
   520             int min_w, min_h;
   521             int max_w, max_h;
   522             int style;
   523             BOOL menu;
   524 			BOOL constrain_max_size;
   525 
   526             /* If we allow resizing, let the resize happen naturally */
   527             if (SDL_IsShapedWindow(data->window))
   528                 Win32_ResizeWindowShape(data->window);
   529 
   530             /* Get the current position of our window */
   531             GetWindowRect(hwnd, &size);
   532             x = size.left;
   533             y = size.top;
   534 
   535             /* Calculate current size of our window */
   536             SDL_GetWindowSize(data->window, &w, &h);
   537             SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
   538             SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
   539 
   540             /* Store in min_w and min_h difference between current size and minimal 
   541                size so we don't need to call AdjustWindowRectEx twice */
   542             min_w -= w;
   543             min_h -= h;
   544             if (max_w && max_h) {
   545                 max_w -= w;
   546                 max_h -= h;
   547                 constrain_max_size = TRUE;
   548             } else {
   549                 constrain_max_size = FALSE;
   550             }
   551 
   552             size.top = 0;
   553             size.left = 0;
   554             size.bottom = h;
   555             size.right = w;
   556 
   557             style = GetWindowLong(hwnd, GWL_STYLE);
   558             /* DJM - according to the docs for GetMenu(), the
   559                return value is undefined if hwnd is a child window.
   560                Aparently it's too difficult for MS to check
   561                inside their function, so I have to do it here.
   562              */
   563             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   564             AdjustWindowRectEx(&size, style, menu, 0);
   565             w = size.right - size.left;
   566             h = size.bottom - size.top;
   567 
   568             /* Fix our size to the current size */
   569             info = (MINMAXINFO *) lParam;
   570             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   571                 info->ptMinTrackSize.x = w + min_w;
   572                 info->ptMinTrackSize.y = h + min_h;
   573                 if (constrain_max_size) {
   574                     info->ptMaxTrackSize.x = w + max_w;
   575                     info->ptMaxTrackSize.y = h + max_h;
   576                 }
   577             } else {
   578                 info->ptMaxSize.x = w;
   579                 info->ptMaxSize.y = h;
   580                 info->ptMaxPosition.x = x;
   581                 info->ptMaxPosition.y = y;
   582                 info->ptMinTrackSize.x = w;
   583                 info->ptMinTrackSize.y = h;
   584                 info->ptMaxTrackSize.x = w;
   585                 info->ptMaxTrackSize.y = h;
   586             }
   587         }
   588         returnCode = 0;
   589         break;
   590 #endif /* WM_GETMINMAXINFO */
   591 
   592     case WM_WINDOWPOSCHANGED:
   593         {
   594             RECT rect;
   595             int x, y;
   596             int w, h;
   597             Uint32 window_flags;
   598 
   599             if (!GetClientRect(hwnd, &rect) ||
   600                 (rect.right == rect.left && rect.bottom == rect.top)) {
   601                 break;
   602             }
   603             ClientToScreen(hwnd, (LPPOINT) & rect);
   604             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   605 
   606             window_flags = SDL_GetWindowFlags(data->window);
   607             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   608                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   609                 ClipCursor(&rect);
   610             }
   611 
   612             x = rect.left;
   613             y = rect.top;
   614             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   615 
   616             w = rect.right - rect.left;
   617             h = rect.bottom - rect.top;
   618             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   619                                 h);
   620         }
   621         break;
   622 
   623     case WM_SETCURSOR:
   624         {
   625             Uint16 hittest;
   626 
   627             hittest = LOWORD(lParam);
   628             if (hittest == HTCLIENT) {
   629                 SetCursor(SDL_cursor);
   630                 returnCode = TRUE;
   631             }
   632         }
   633         break;
   634 
   635         /* We were occluded, refresh our display */
   636     case WM_PAINT:
   637         {
   638             RECT rect;
   639             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   640                 ValidateRect(hwnd, &rect);
   641                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   642                                     0, 0);
   643             }
   644         }
   645         returnCode = 0;
   646         break;
   647 
   648         /* We'll do our own drawing, prevent flicker */
   649     case WM_ERASEBKGND:
   650         {
   651         }
   652         return (1);
   653 
   654 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   655     case WM_SYSCOMMAND:
   656         {
   657             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   658             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   659                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   660                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   661                     return (0);
   662                 }
   663             }
   664         }
   665         break;
   666 #endif /* System has screensaver support */
   667 
   668     case WM_CLOSE:
   669         {
   670             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   671         }
   672         returnCode = 0;
   673         break;
   674 
   675 	case WM_TOUCH:
   676 		{
   677 			UINT i, num_inputs = LOWORD(wParam);
   678 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   679 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   680 				RECT rect;
   681 				float x, y;
   682 
   683 				if (!GetClientRect(hwnd, &rect) ||
   684 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   685 					break;
   686 				}
   687 				ClientToScreen(hwnd, (LPPOINT) & rect);
   688 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   689 				rect.top *= 100;
   690 				rect.left *= 100;
   691 				rect.bottom *= 100;
   692 				rect.right *= 100;
   693 
   694 				for (i = 0; i < num_inputs; ++i) {
   695 					PTOUCHINPUT input = &inputs[i];
   696 
   697 					const SDL_TouchID touchId = (SDL_TouchID)
   698 												((size_t)input->hSource);
   699 					if (!SDL_GetTouch(touchId)) {
   700 						SDL_Touch touch;
   701 
   702 						touch.id = touchId;
   703 						touch.x_min = 0;
   704 						touch.x_max = 1;
   705 						touch.native_xres = touch.x_max - touch.x_min;
   706 						touch.y_min = 0;
   707 						touch.y_max = 1;
   708 						touch.native_yres = touch.y_max - touch.y_min;
   709 						touch.pressure_min = 0;
   710 						touch.pressure_max = 1;
   711 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   712 
   713 						if (SDL_AddTouch(&touch, "") < 0) {
   714 							continue;
   715 						}
   716 					}
   717 
   718 					// Get the normalized coordinates for the window
   719 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   720 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   721 
   722 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   723 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   724 					}
   725 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   726 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   727 					}
   728 					if (input->dwFlags & TOUCHEVENTF_UP) {
   729 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   730 					}
   731 				}
   732 			}
   733 			SDL_stack_free(inputs);
   734 
   735 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   736 			return 0;
   737 		}
   738 		break;
   739 
   740     case WM_DROPFILES:
   741         {
   742             UINT i;
   743             HDROP drop = (HDROP) wParam;
   744             UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
   745             for (i = 0; i < count; ++i) {
   746                 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
   747                 LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
   748                 if (buffer) {
   749                     if (DragQueryFile(drop, i, buffer, size)) {
   750                         char *file = WIN_StringToUTF8(buffer);
   751                         SDL_SendDropFile(file);
   752                         SDL_free(file);
   753                     }
   754                     SDL_stack_free(buffer);
   755                 }
   756             }
   757             DragFinish(drop);
   758             return 0;
   759         }
   760         break;
   761     }
   762 
   763     /* If there's a window proc, assume it's going to handle messages */
   764     if (data->wndproc) {
   765         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   766     } else if (returnCode >= 0) {
   767         return returnCode;
   768     } else {
   769         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   770     }
   771 }
   772 
   773 void
   774 WIN_PumpEvents(_THIS)
   775 {
   776     MSG msg;
   777     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   778         TranslateMessage(&msg);
   779         DispatchMessage(&msg);
   780     }
   781 }
   782 
   783 static int app_registered = 0;
   784 LPTSTR SDL_Appname = NULL;
   785 Uint32 SDL_Appstyle = 0;
   786 HINSTANCE SDL_Instance = NULL;
   787 
   788 /* Register the class for this application */
   789 int
   790 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   791 {
   792     WNDCLASS class;
   793 
   794     /* Only do this once... */
   795     if (app_registered) {
   796         ++app_registered;
   797         return (0);
   798     }
   799     if (!name && !SDL_Appname) {
   800         name = "SDL_app";
   801 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   802         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   803 #endif
   804         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   805     }
   806 
   807     if (name) {
   808         SDL_Appname = WIN_UTF8ToString(name);
   809         SDL_Appstyle = style;
   810         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   811     }
   812 
   813     /* Register the application class */
   814     class.hCursor = NULL;
   815     class.hIcon =
   816         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   817                   LR_DEFAULTCOLOR);
   818     class.lpszMenuName = NULL;
   819     class.lpszClassName = SDL_Appname;
   820     class.hbrBackground = NULL;
   821     class.hInstance = SDL_Instance;
   822     class.style = SDL_Appstyle;
   823     class.lpfnWndProc = WIN_WindowProc;
   824     class.cbWndExtra = 0;
   825     class.cbClsExtra = 0;
   826     if (!RegisterClass(&class)) {
   827         SDL_SetError("Couldn't register application class");
   828         return (-1);
   829     }
   830 
   831     app_registered = 1;
   832     return (0);
   833 }
   834 
   835 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   836 void
   837 SDL_UnregisterApp()
   838 {
   839     WNDCLASS class;
   840 
   841     /* SDL_RegisterApp might not have been called before */
   842     if (!app_registered) {
   843         return;
   844     }
   845     --app_registered;
   846     if (app_registered == 0) {
   847         /* Check for any registered window classes. */
   848         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   849             UnregisterClass(SDL_Appname, SDL_Instance);
   850         }
   851         SDL_free(SDL_Appname);
   852         SDL_Appname = NULL;
   853     }
   854 }
   855 
   856 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   857 
   858 /* vi: set ts=4 sw=4 expandtab: */