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