src/video/windows/SDL_windowsevents.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 31 Mar 2013 12:48:50 -0400
changeset 7037 3fedf1f25b94
parent 7029 377cc88f3dc8
child 7060 9d96148c2e3e
permissions -rw-r--r--
Make SDL_SetError and friends unconditionally return -1.

This lets us change things like this...

if (Failed) {
SDL_SetError("We failed");
return -1;
}

...into this...

if (Failed) {
return SDL_SetError("We failed");
}


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