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