src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 08 Feb 2013 01:04:07 -0800
changeset 6837 a69e10925a58
parent 6788 036f53f2f5aa
child 6861 c1c9eab3bd20
permissions -rw-r--r--
Fixed bug 1682 - Resize collapses window instantly to a size of 0 x 124.

Marco Schmidt

After sizing my main window (the only window in my application) through
grabbing the window border with the mouse the window collapses instantly to a
size of 0 x 124. In my application I can not resize the window to a normal size
again.

I tried to reproduce the problem - and here a the minimal steps I found.

I'm running WIN8 x64, VS2012Pro, HG SDL-2.0 tip, WIN32-Build.

Minimal steps to reproduce my problem:

- open solution SDL_VS2012
- make testdraw2 the start project
- pass command line option --resize to the debuggee testdraw2
- starting the application testdraw2
- try to resize the window
- the application window resizes to a minimal size 0 x 124.
- the application crashes to divide by zero .... (this is only the aftermath
but a unhandled error condition)
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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 LRESULT CALLBACK
   109 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   110 {
   111     SDL_WindowData *data;
   112     LRESULT returnCode = -1;
   113 
   114     /* Send a SDL_SYSWMEVENT if the application wants them */
   115     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   116         SDL_SysWMmsg wmmsg;
   117 
   118         SDL_VERSION(&wmmsg.version);
   119         wmmsg.subsystem = SDL_SYSWM_WINDOWS;
   120         wmmsg.msg.win.hwnd = hwnd;
   121         wmmsg.msg.win.msg = msg;
   122         wmmsg.msg.win.wParam = wParam;
   123         wmmsg.msg.win.lParam = lParam;
   124         SDL_SendSysWMEvent(&wmmsg);
   125     }
   126 
   127     /* Get the window data for the window */
   128     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   129     if (!data) {
   130         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   131     }
   132 
   133 #ifdef WMMSG_DEBUG
   134     {		
   135         FILE *log = fopen("wmmsg.txt", "a");		
   136         fprintf(log, "Received windows message: %p ", hwnd);
   137         if (msg > MAX_WMMSG) {
   138             fprintf(log, "%d", msg);
   139         } else {
   140             fprintf(log, "%s", wmtab[msg]);
   141         }
   142         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   143         fclose(log);
   144     }
   145 #endif
   146 
   147     if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
   148         return 0;
   149 
   150     switch (msg) {
   151 
   152     case WM_SHOWWINDOW:
   153         {
   154             if (wParam) {
   155                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   156             } else {
   157                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   158             }
   159         }
   160         break;
   161 
   162     case WM_ACTIVATE:
   163         {
   164             BOOL minimized;
   165 
   166             minimized = HIWORD(wParam);
   167             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   168                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   169                 SDL_SendWindowEvent(data->window,
   170                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   171                 if (IsZoomed(hwnd)) {
   172                     SDL_SendWindowEvent(data->window,
   173                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   174                 }
   175                 if (SDL_GetKeyboardFocus() != data->window) {
   176                     SDL_SetKeyboardFocus(data->window);
   177                 }
   178 
   179 				if(SDL_GetMouse()->relative_mode) {
   180 					LONG cx, cy;
   181 					RECT rect;
   182 					GetWindowRect(hwnd, &rect);
   183 
   184 					cx = (rect.left + rect.right) / 2;
   185 					cy = (rect.top + rect.bottom) / 2;
   186 
   187 					/* Make an absurdly small clip rect */
   188 					rect.left = cx-1;
   189 					rect.right = cx+1;
   190 					rect.top = cy-1;
   191 					rect.bottom = cy+1;
   192 
   193 					ClipCursor(&rect);
   194 				}
   195 
   196                 /*
   197                  * FIXME: Update keyboard state
   198                  */
   199                 WIN_CheckClipboardUpdate(data->videodata);
   200             } else {
   201                 if (SDL_GetKeyboardFocus() == data->window) {
   202                     SDL_SetKeyboardFocus(NULL);
   203                 }
   204                 if (minimized) {
   205                     SDL_SendWindowEvent(data->window,
   206                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   207                 }
   208             }
   209         }
   210         returnCode = 0;
   211         break;
   212 
   213 	case WM_MOUSEMOVE:
   214 		if(SDL_GetMouse()->relative_mode)
   215 			break;
   216         SDL_SendMouseMotion(data->window, 0, LOWORD(lParam), HIWORD(lParam));
   217         break;
   218 
   219 	case WM_INPUT:
   220 	{
   221 		HRAWINPUT hRawInput = (HRAWINPUT)lParam;
   222 		RAWINPUT inp;
   223 		UINT size = sizeof(inp);
   224 
   225 		if(!SDL_GetMouse()->relative_mode)
   226 			break;
   227 
   228 		GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
   229 
   230 		/* Mouse data */
   231 		if(inp.header.dwType == RIM_TYPEMOUSE)
   232 		{
   233 			RAWMOUSE* mouse = &inp.data.mouse;
   234 
   235 			if((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE)
   236 			{
   237 				SDL_SendMouseMotion(data->window, 1, (int)mouse->lLastX, (int)mouse->lLastY);
   238 			}
   239 			else
   240 			{
   241 				// synthesize relative moves from the abs position
   242 				static SDL_Point initialMousePoint;
   243 				if ( initialMousePoint.x == 0 && initialMousePoint.y == 0 )
   244 				{
   245 					initialMousePoint.x = mouse->lLastX;
   246 					initialMousePoint.y = mouse->lLastY;
   247 				}
   248 
   249 				SDL_SendMouseMotion(data->window, 1, (int)(mouse->lLastX-initialMousePoint.x), (int)(mouse->lLastY-initialMousePoint.y) );
   250 
   251 				initialMousePoint.x = mouse->lLastX;
   252 				initialMousePoint.y = mouse->lLastY;
   253 			}
   254 		}
   255 		break;
   256 	}
   257 
   258     case WM_LBUTTONDOWN:
   259         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_LEFT);
   260         break;
   261 
   262     case WM_LBUTTONUP:
   263         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_LEFT);
   264         break;
   265 
   266     case WM_RBUTTONDOWN:
   267         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_RIGHT);
   268         break;
   269 
   270     case WM_RBUTTONUP:
   271         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_RIGHT);
   272         break;
   273 
   274     case WM_MBUTTONDOWN:
   275         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_MIDDLE);
   276         break;
   277 
   278     case WM_MBUTTONUP:
   279         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_MIDDLE);
   280         break;
   281 
   282     case WM_XBUTTONDOWN:
   283         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(wParam) - 1);
   284         returnCode = TRUE;
   285         break;
   286 
   287     case WM_XBUTTONUP:
   288         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(wParam) - 1);
   289         returnCode = TRUE;
   290         break;
   291 
   292     case WM_MOUSEWHEEL:
   293         {
   294             int motion = (short) HIWORD(wParam);
   295 
   296             SDL_SendMouseWheel(data->window, 0, motion);
   297             break;
   298         }
   299 
   300 #ifdef WM_MOUSELEAVE
   301     /* FIXME: Do we need the SDL 1.2 hack to generate WM_MOUSELEAVE now? */
   302     case WM_MOUSELEAVE:
   303         if (SDL_GetMouseFocus() == data->window) {
   304             SDL_SetMouseFocus(NULL);
   305         }
   306         returnCode = 0;
   307         break;
   308 #endif /* WM_MOUSELEAVE */
   309 
   310     case WM_SYSKEYDOWN:
   311     case WM_KEYDOWN:
   312         {
   313             wParam = RemapVKEY(wParam, lParam);
   314             switch (wParam) {
   315             case VK_CONTROL:
   316                 if (lParam & EXTENDED_KEYMASK)
   317                     wParam = VK_RCONTROL;
   318                 else
   319                     wParam = VK_LCONTROL;
   320                 break;
   321             case VK_SHIFT:
   322                 /* EXTENDED trick doesn't work here */
   323                 {
   324                     Uint8 *state = SDL_GetKeyboardState(NULL);
   325                     if (state[SDL_SCANCODE_LSHIFT] == SDL_RELEASED
   326                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   327                         wParam = VK_LSHIFT;
   328                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_RELEASED
   329                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   330                         wParam = VK_RSHIFT;
   331                     } else {
   332                         /* Probably a key repeat */
   333                         wParam = 256;
   334                     }
   335                 }
   336                 break;
   337             case VK_MENU:
   338                 if (lParam & EXTENDED_KEYMASK)
   339                     wParam = VK_RMENU;
   340                 else
   341                     wParam = VK_LMENU;
   342                 break;
   343             case VK_RETURN:
   344                 if (lParam & EXTENDED_KEYMASK)
   345                     wParam = VK_ENTER;
   346                 break;
   347             }
   348             if (wParam < 256) {
   349                 SDL_SendKeyboardKey(SDL_PRESSED,
   350                                     data->videodata->key_layout[wParam]);
   351             }
   352         }
   353         returnCode = 0;
   354         break;
   355 
   356     case WM_SYSKEYUP:
   357     case WM_KEYUP:
   358         {
   359             wParam = RemapVKEY(wParam, lParam);
   360             switch (wParam) {
   361             case VK_CONTROL:
   362                 if (lParam & EXTENDED_KEYMASK)
   363                     wParam = VK_RCONTROL;
   364                 else
   365                     wParam = VK_LCONTROL;
   366                 break;
   367             case VK_SHIFT:
   368                 /* EXTENDED trick doesn't work here */
   369                 {
   370                     Uint8 *state = SDL_GetKeyboardState(NULL);
   371                     if (state[SDL_SCANCODE_LSHIFT] == SDL_PRESSED
   372                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   373                         wParam = VK_LSHIFT;
   374                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_PRESSED
   375                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   376                         wParam = VK_RSHIFT;
   377                     } else {
   378                         /* Probably a key repeat */
   379                         wParam = 256;
   380                     }
   381                 }
   382                 break;
   383             case VK_MENU:
   384                 if (lParam & EXTENDED_KEYMASK)
   385                     wParam = VK_RMENU;
   386                 else
   387                     wParam = VK_LMENU;
   388                 break;
   389             case VK_RETURN:
   390                 if (lParam & EXTENDED_KEYMASK)
   391                     wParam = VK_ENTER;
   392                 break;
   393             }
   394 
   395             /* Windows only reports keyup for print screen */
   396             if (wParam == VK_SNAPSHOT
   397                 && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   398                 SDL_RELEASED) {
   399                 SDL_SendKeyboardKey(SDL_PRESSED,
   400                                     data->videodata->key_layout[wParam]);
   401             }
   402             if (wParam < 256) {
   403                 SDL_SendKeyboardKey(SDL_RELEASED,
   404                                     data->videodata->key_layout[wParam]);
   405             }
   406         }
   407         returnCode = 0;
   408         break;
   409 
   410     case WM_CHAR:
   411         {
   412             char text[4];
   413 
   414             /* Convert to UTF-8 and send it on... */
   415             if (wParam <= 0x7F) {
   416                 text[0] = (char) wParam;
   417                 text[1] = '\0';
   418             } else if (wParam <= 0x7FF) {
   419                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   420                 text[1] = 0x80 | (char) (wParam & 0x3F);
   421                 text[2] = '\0';
   422             } else {
   423                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   424                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   425                 text[2] = 0x80 | (char) (wParam & 0x3F);
   426                 text[3] = '\0';
   427             }
   428             SDL_SendKeyboardText(text);
   429         }
   430         returnCode = 0;
   431         break;
   432 
   433 #ifdef WM_INPUTLANGCHANGE
   434     case WM_INPUTLANGCHANGE:
   435         {
   436             WIN_UpdateKeymap();
   437         }
   438         returnCode = 1;
   439         break;
   440 #endif /* WM_INPUTLANGCHANGE */
   441 
   442 #ifdef WM_GETMINMAXINFO
   443     case WM_GETMINMAXINFO:
   444         {
   445             MINMAXINFO *info;
   446             RECT size;
   447             int x, y;
   448             int w, h;
   449             int min_w, min_h;
   450             int max_w, max_h;
   451             int style;
   452             BOOL menu;
   453 
   454             /* If we allow resizing, let the resize happen naturally */
   455             if (SDL_IsShapedWindow(data->window))
   456                 Win32_ResizeWindowShape(data->window);
   457 
   458             /* Get the current position of our window */
   459             GetWindowRect(hwnd, &size);
   460             x = size.left;
   461             y = size.top;
   462 
   463             /* Calculate current size of our window */
   464             SDL_GetWindowSize(data->window, &w, &h);
   465             SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
   466             SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
   467 
   468             /* Store in min_w and min_h difference between current size and minimal 
   469                size so we don't need to call AdjustWindowRectEx twice */
   470             min_w -= w;
   471             min_h -= h;
   472             if (max_w && max_h) {
   473                 max_w -= w;
   474                 max_h -= h;
   475             }
   476 
   477             size.top = 0;
   478             size.left = 0;
   479             size.bottom = h;
   480             size.right = w;
   481 
   482             style = GetWindowLong(hwnd, GWL_STYLE);
   483             /* DJM - according to the docs for GetMenu(), the
   484                return value is undefined if hwnd is a child window.
   485                Aparently it's too difficult for MS to check
   486                inside their function, so I have to do it here.
   487              */
   488             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   489             AdjustWindowRectEx(&size, style, menu, 0);
   490             w = size.right - size.left;
   491             h = size.bottom - size.top;
   492 
   493             /* Fix our size to the current size */
   494             info = (MINMAXINFO *) lParam;
   495             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   496                 info->ptMinTrackSize.x = w + min_w;
   497                 info->ptMinTrackSize.y = h + min_h;
   498                 info->ptMaxTrackSize.x = w + max_w;
   499                 info->ptMaxTrackSize.y = h + max_h;
   500             } else {
   501                 info->ptMaxSize.x = w;
   502                 info->ptMaxSize.y = h;
   503                 info->ptMaxPosition.x = x;
   504                 info->ptMaxPosition.y = y;
   505                 info->ptMinTrackSize.x = w;
   506                 info->ptMinTrackSize.y = h;
   507                 info->ptMaxTrackSize.x = w;
   508                 info->ptMaxTrackSize.y = h;
   509             }
   510         }
   511         returnCode = 0;
   512         break;
   513 #endif /* WM_GETMINMAXINFO */
   514 
   515     case WM_WINDOWPOSCHANGED:
   516         {
   517             RECT rect;
   518             int x, y;
   519             int w, h;
   520             Uint32 window_flags;
   521 
   522             if (!GetClientRect(hwnd, &rect) ||
   523                 (rect.right == rect.left && rect.bottom == rect.top)) {
   524                 break;
   525             }
   526             ClientToScreen(hwnd, (LPPOINT) & rect);
   527             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   528 
   529             window_flags = SDL_GetWindowFlags(data->window);
   530             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   531                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   532                 ClipCursor(&rect);
   533             }
   534 
   535             x = rect.left;
   536             y = rect.top;
   537             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   538 
   539             w = rect.right - rect.left;
   540             h = rect.bottom - rect.top;
   541             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   542                                 h);
   543         }
   544         break;
   545 
   546     case WM_SETCURSOR:
   547         {
   548             Uint16 hittest;
   549 
   550             hittest = LOWORD(lParam);
   551             if (hittest == HTCLIENT) {
   552                 SetCursor(SDL_cursor);
   553                 returnCode = TRUE;
   554             }
   555         }
   556         break;
   557 
   558         /* We were occluded, refresh our display */
   559     case WM_PAINT:
   560         {
   561             RECT rect;
   562             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   563                 ValidateRect(hwnd, &rect);
   564                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   565                                     0, 0);
   566             }
   567         }
   568         returnCode = 0;
   569         break;
   570 
   571         /* We'll do our own drawing, prevent flicker */
   572     case WM_ERASEBKGND:
   573         {
   574         }
   575         return (1);
   576 
   577 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   578     case WM_SYSCOMMAND:
   579         {
   580             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   581             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   582                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   583                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   584                     return (0);
   585                 }
   586             }
   587         }
   588         break;
   589 #endif /* System has screensaver support */
   590 
   591     case WM_CLOSE:
   592         {
   593             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   594         }
   595         returnCode = 0;
   596         break;
   597 
   598 	case WM_TOUCH:
   599 		{
   600 			UINT i, num_inputs = LOWORD(wParam);
   601 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   602 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   603 				RECT rect;
   604 				float x, y;
   605 
   606 				if (!GetClientRect(hwnd, &rect) ||
   607 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   608 					break;
   609 				}
   610 				ClientToScreen(hwnd, (LPPOINT) & rect);
   611 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   612 				rect.top *= 100;
   613 				rect.left *= 100;
   614 				rect.bottom *= 100;
   615 				rect.right *= 100;
   616 
   617 				for (i = 0; i < num_inputs; ++i) {
   618 					PTOUCHINPUT input = &inputs[i];
   619 
   620 					const SDL_TouchID touchId = (SDL_TouchID)
   621 												((size_t)input->hSource);
   622 					if (!SDL_GetTouch(touchId)) {
   623 						SDL_Touch touch;
   624 
   625 						touch.id = touchId;
   626 						touch.x_min = 0;
   627 						touch.x_max = 1;
   628 						touch.native_xres = touch.x_max - touch.x_min;
   629 						touch.y_min = 0;
   630 						touch.y_max = 1;
   631 						touch.native_yres = touch.y_max - touch.y_min;
   632 						touch.pressure_min = 0;
   633 						touch.pressure_max = 1;
   634 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   635 
   636 						if (SDL_AddTouch(&touch, "") < 0) {
   637 							continue;
   638 						}
   639 					}
   640 
   641 					// Get the normalized coordinates for the window
   642 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   643 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   644 
   645 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   646 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   647 					}
   648 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   649 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   650 					}
   651 					if (input->dwFlags & TOUCHEVENTF_UP) {
   652 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   653 					}
   654 				}
   655 			}
   656 			SDL_stack_free(inputs);
   657 
   658 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   659 			return 0;
   660 		}
   661 		break;
   662 
   663     case WM_DROPFILES:
   664         {
   665             UINT i;
   666             HDROP drop = (HDROP) wParam;
   667             UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
   668             for (i = 0; i < count; ++i) {
   669                 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
   670                 LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
   671                 if (buffer) {
   672                     if (DragQueryFile(drop, i, buffer, size)) {
   673                         char *file = WIN_StringToUTF8(buffer);
   674                         SDL_SendDropFile(file);
   675                         SDL_free(file);
   676                     }
   677                     SDL_stack_free(buffer);
   678                 }
   679             }
   680             DragFinish(drop);
   681             return 0;
   682         }
   683         break;
   684     }
   685 
   686     /* If there's a window proc, assume it's going to handle messages */
   687     if (data->wndproc) {
   688         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   689     } else if (returnCode >= 0) {
   690         return returnCode;
   691     } else {
   692         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   693     }
   694 }
   695 
   696 void
   697 WIN_PumpEvents(_THIS)
   698 {
   699     MSG msg;
   700     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   701         TranslateMessage(&msg);
   702         DispatchMessage(&msg);
   703     }
   704 }
   705 
   706 static int app_registered = 0;
   707 LPTSTR SDL_Appname = NULL;
   708 Uint32 SDL_Appstyle = 0;
   709 HINSTANCE SDL_Instance = NULL;
   710 
   711 /* Register the class for this application */
   712 int
   713 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   714 {
   715     WNDCLASS class;
   716 
   717     /* Only do this once... */
   718     if (app_registered) {
   719         ++app_registered;
   720         return (0);
   721     }
   722     if (!name && !SDL_Appname) {
   723         name = "SDL_app";
   724 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   725         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   726 #endif
   727         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   728     }
   729 
   730     if (name) {
   731         SDL_Appname = WIN_UTF8ToString(name);
   732         SDL_Appstyle = style;
   733         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   734     }
   735 
   736     /* Register the application class */
   737     class.hCursor = NULL;
   738     class.hIcon =
   739         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   740                   LR_DEFAULTCOLOR);
   741     class.lpszMenuName = NULL;
   742     class.lpszClassName = SDL_Appname;
   743     class.hbrBackground = NULL;
   744     class.hInstance = SDL_Instance;
   745     class.style = SDL_Appstyle;
   746     class.lpfnWndProc = WIN_WindowProc;
   747     class.cbWndExtra = 0;
   748     class.cbClsExtra = 0;
   749     if (!RegisterClass(&class)) {
   750         SDL_SetError("Couldn't register application class");
   751         return (-1);
   752     }
   753 
   754     app_registered = 1;
   755     return (0);
   756 }
   757 
   758 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   759 void
   760 SDL_UnregisterApp()
   761 {
   762     WNDCLASS class;
   763 
   764     /* SDL_RegisterApp might not have been called before */
   765     if (!app_registered) {
   766         return;
   767     }
   768     --app_registered;
   769     if (app_registered == 0) {
   770         /* Check for any registered window classes. */
   771         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   772             UnregisterClass(SDL_Appname, SDL_Instance);
   773         }
   774         SDL_free(SDL_Appname);
   775         SDL_Appname = NULL;
   776     }
   777 }
   778 
   779 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   780 
   781 /* vi: set ts=4 sw=4 expandtab: */