src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 11 Feb 2013 21:39:58 -0800
changeset 6862 d189a1e771fe
parent 6861 c1c9eab3bd20
child 6885 700f1b25f77f
permissions -rw-r--r--
Fixed increasing the size of resizable windows
     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             // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
   295             short motion = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
   296 
   297             SDL_SendMouseWheel(data->window, 0, motion);
   298             break;
   299         }
   300 
   301 #ifdef WM_MOUSELEAVE
   302     /* FIXME: Do we need the SDL 1.2 hack to generate WM_MOUSELEAVE now? */
   303     case WM_MOUSELEAVE:
   304         if (SDL_GetMouseFocus() == data->window) {
   305             SDL_SetMouseFocus(NULL);
   306         }
   307         returnCode = 0;
   308         break;
   309 #endif /* WM_MOUSELEAVE */
   310 
   311     case WM_SYSKEYDOWN:
   312     case WM_KEYDOWN:
   313         {
   314             wParam = RemapVKEY(wParam, lParam);
   315             switch (wParam) {
   316             case VK_CONTROL:
   317                 if (lParam & EXTENDED_KEYMASK)
   318                     wParam = VK_RCONTROL;
   319                 else
   320                     wParam = VK_LCONTROL;
   321                 break;
   322             case VK_SHIFT:
   323                 /* EXTENDED trick doesn't work here */
   324                 {
   325                     Uint8 *state = SDL_GetKeyboardState(NULL);
   326                     if (state[SDL_SCANCODE_LSHIFT] == SDL_RELEASED
   327                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   328                         wParam = VK_LSHIFT;
   329                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_RELEASED
   330                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   331                         wParam = VK_RSHIFT;
   332                     } else {
   333                         /* Probably a key repeat */
   334                         wParam = 256;
   335                     }
   336                 }
   337                 break;
   338             case VK_MENU:
   339                 if (lParam & EXTENDED_KEYMASK)
   340                     wParam = VK_RMENU;
   341                 else
   342                     wParam = VK_LMENU;
   343                 break;
   344             case VK_RETURN:
   345                 if (lParam & EXTENDED_KEYMASK)
   346                     wParam = VK_ENTER;
   347                 break;
   348             }
   349             if (wParam < 256) {
   350                 SDL_SendKeyboardKey(SDL_PRESSED,
   351                                     data->videodata->key_layout[wParam]);
   352             }
   353         }
   354         returnCode = 0;
   355         break;
   356 
   357     case WM_SYSKEYUP:
   358     case WM_KEYUP:
   359         {
   360             wParam = RemapVKEY(wParam, lParam);
   361             switch (wParam) {
   362             case VK_CONTROL:
   363                 if (lParam & EXTENDED_KEYMASK)
   364                     wParam = VK_RCONTROL;
   365                 else
   366                     wParam = VK_LCONTROL;
   367                 break;
   368             case VK_SHIFT:
   369                 /* EXTENDED trick doesn't work here */
   370                 {
   371                     Uint8 *state = SDL_GetKeyboardState(NULL);
   372                     if (state[SDL_SCANCODE_LSHIFT] == SDL_PRESSED
   373                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   374                         wParam = VK_LSHIFT;
   375                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_PRESSED
   376                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   377                         wParam = VK_RSHIFT;
   378                     } else {
   379                         /* Probably a key repeat */
   380                         wParam = 256;
   381                     }
   382                 }
   383                 break;
   384             case VK_MENU:
   385                 if (lParam & EXTENDED_KEYMASK)
   386                     wParam = VK_RMENU;
   387                 else
   388                     wParam = VK_LMENU;
   389                 break;
   390             case VK_RETURN:
   391                 if (lParam & EXTENDED_KEYMASK)
   392                     wParam = VK_ENTER;
   393                 break;
   394             }
   395 
   396             /* Windows only reports keyup for print screen */
   397             if (wParam == VK_SNAPSHOT
   398                 && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   399                 SDL_RELEASED) {
   400                 SDL_SendKeyboardKey(SDL_PRESSED,
   401                                     data->videodata->key_layout[wParam]);
   402             }
   403             if (wParam < 256) {
   404                 SDL_SendKeyboardKey(SDL_RELEASED,
   405                                     data->videodata->key_layout[wParam]);
   406             }
   407         }
   408         returnCode = 0;
   409         break;
   410 
   411     case WM_CHAR:
   412         {
   413             char text[4];
   414 
   415             /* Convert to UTF-8 and send it on... */
   416             if (wParam <= 0x7F) {
   417                 text[0] = (char) wParam;
   418                 text[1] = '\0';
   419             } else if (wParam <= 0x7FF) {
   420                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   421                 text[1] = 0x80 | (char) (wParam & 0x3F);
   422                 text[2] = '\0';
   423             } else {
   424                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   425                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   426                 text[2] = 0x80 | (char) (wParam & 0x3F);
   427                 text[3] = '\0';
   428             }
   429             SDL_SendKeyboardText(text);
   430         }
   431         returnCode = 0;
   432         break;
   433 
   434 #ifdef WM_INPUTLANGCHANGE
   435     case WM_INPUTLANGCHANGE:
   436         {
   437             WIN_UpdateKeymap();
   438         }
   439         returnCode = 1;
   440         break;
   441 #endif /* WM_INPUTLANGCHANGE */
   442 
   443 #ifdef WM_GETMINMAXINFO
   444     case WM_GETMINMAXINFO:
   445         {
   446             MINMAXINFO *info;
   447             RECT size;
   448             int x, y;
   449             int w, h;
   450             int min_w, min_h;
   451             int max_w, max_h;
   452             int style;
   453             BOOL menu;
   454 			BOOL constrain_max_size;
   455 
   456             /* If we allow resizing, let the resize happen naturally */
   457             if (SDL_IsShapedWindow(data->window))
   458                 Win32_ResizeWindowShape(data->window);
   459 
   460             /* Get the current position of our window */
   461             GetWindowRect(hwnd, &size);
   462             x = size.left;
   463             y = size.top;
   464 
   465             /* Calculate current size of our window */
   466             SDL_GetWindowSize(data->window, &w, &h);
   467             SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
   468             SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
   469 
   470             /* Store in min_w and min_h difference between current size and minimal 
   471                size so we don't need to call AdjustWindowRectEx twice */
   472             min_w -= w;
   473             min_h -= h;
   474             if (max_w && max_h) {
   475                 max_w -= w;
   476                 max_h -= h;
   477                 constrain_max_size = TRUE;
   478             } else {
   479                 constrain_max_size = FALSE;
   480             }
   481 
   482             size.top = 0;
   483             size.left = 0;
   484             size.bottom = h;
   485             size.right = w;
   486 
   487             style = GetWindowLong(hwnd, GWL_STYLE);
   488             /* DJM - according to the docs for GetMenu(), the
   489                return value is undefined if hwnd is a child window.
   490                Aparently it's too difficult for MS to check
   491                inside their function, so I have to do it here.
   492              */
   493             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   494             AdjustWindowRectEx(&size, style, menu, 0);
   495             w = size.right - size.left;
   496             h = size.bottom - size.top;
   497 
   498             /* Fix our size to the current size */
   499             info = (MINMAXINFO *) lParam;
   500             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   501                 info->ptMinTrackSize.x = w + min_w;
   502                 info->ptMinTrackSize.y = h + min_h;
   503                 if (constrain_max_size) {
   504                     info->ptMaxTrackSize.x = w + max_w;
   505                     info->ptMaxTrackSize.y = h + max_h;
   506                 }
   507             } else {
   508                 info->ptMaxSize.x = w;
   509                 info->ptMaxSize.y = h;
   510                 info->ptMaxPosition.x = x;
   511                 info->ptMaxPosition.y = y;
   512                 info->ptMinTrackSize.x = w;
   513                 info->ptMinTrackSize.y = h;
   514                 info->ptMaxTrackSize.x = w;
   515                 info->ptMaxTrackSize.y = h;
   516             }
   517         }
   518         returnCode = 0;
   519         break;
   520 #endif /* WM_GETMINMAXINFO */
   521 
   522     case WM_WINDOWPOSCHANGED:
   523         {
   524             RECT rect;
   525             int x, y;
   526             int w, h;
   527             Uint32 window_flags;
   528 
   529             if (!GetClientRect(hwnd, &rect) ||
   530                 (rect.right == rect.left && rect.bottom == rect.top)) {
   531                 break;
   532             }
   533             ClientToScreen(hwnd, (LPPOINT) & rect);
   534             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   535 
   536             window_flags = SDL_GetWindowFlags(data->window);
   537             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   538                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   539                 ClipCursor(&rect);
   540             }
   541 
   542             x = rect.left;
   543             y = rect.top;
   544             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   545 
   546             w = rect.right - rect.left;
   547             h = rect.bottom - rect.top;
   548             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   549                                 h);
   550         }
   551         break;
   552 
   553     case WM_SETCURSOR:
   554         {
   555             Uint16 hittest;
   556 
   557             hittest = LOWORD(lParam);
   558             if (hittest == HTCLIENT) {
   559                 SetCursor(SDL_cursor);
   560                 returnCode = TRUE;
   561             }
   562         }
   563         break;
   564 
   565         /* We were occluded, refresh our display */
   566     case WM_PAINT:
   567         {
   568             RECT rect;
   569             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   570                 ValidateRect(hwnd, &rect);
   571                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   572                                     0, 0);
   573             }
   574         }
   575         returnCode = 0;
   576         break;
   577 
   578         /* We'll do our own drawing, prevent flicker */
   579     case WM_ERASEBKGND:
   580         {
   581         }
   582         return (1);
   583 
   584 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   585     case WM_SYSCOMMAND:
   586         {
   587             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   588             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   589                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   590                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   591                     return (0);
   592                 }
   593             }
   594         }
   595         break;
   596 #endif /* System has screensaver support */
   597 
   598     case WM_CLOSE:
   599         {
   600             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   601         }
   602         returnCode = 0;
   603         break;
   604 
   605 	case WM_TOUCH:
   606 		{
   607 			UINT i, num_inputs = LOWORD(wParam);
   608 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   609 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   610 				RECT rect;
   611 				float x, y;
   612 
   613 				if (!GetClientRect(hwnd, &rect) ||
   614 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   615 					break;
   616 				}
   617 				ClientToScreen(hwnd, (LPPOINT) & rect);
   618 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   619 				rect.top *= 100;
   620 				rect.left *= 100;
   621 				rect.bottom *= 100;
   622 				rect.right *= 100;
   623 
   624 				for (i = 0; i < num_inputs; ++i) {
   625 					PTOUCHINPUT input = &inputs[i];
   626 
   627 					const SDL_TouchID touchId = (SDL_TouchID)
   628 												((size_t)input->hSource);
   629 					if (!SDL_GetTouch(touchId)) {
   630 						SDL_Touch touch;
   631 
   632 						touch.id = touchId;
   633 						touch.x_min = 0;
   634 						touch.x_max = 1;
   635 						touch.native_xres = touch.x_max - touch.x_min;
   636 						touch.y_min = 0;
   637 						touch.y_max = 1;
   638 						touch.native_yres = touch.y_max - touch.y_min;
   639 						touch.pressure_min = 0;
   640 						touch.pressure_max = 1;
   641 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   642 
   643 						if (SDL_AddTouch(&touch, "") < 0) {
   644 							continue;
   645 						}
   646 					}
   647 
   648 					// Get the normalized coordinates for the window
   649 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   650 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   651 
   652 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   653 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   654 					}
   655 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   656 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   657 					}
   658 					if (input->dwFlags & TOUCHEVENTF_UP) {
   659 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   660 					}
   661 				}
   662 			}
   663 			SDL_stack_free(inputs);
   664 
   665 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   666 			return 0;
   667 		}
   668 		break;
   669 
   670     case WM_DROPFILES:
   671         {
   672             UINT i;
   673             HDROP drop = (HDROP) wParam;
   674             UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
   675             for (i = 0; i < count; ++i) {
   676                 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
   677                 LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
   678                 if (buffer) {
   679                     if (DragQueryFile(drop, i, buffer, size)) {
   680                         char *file = WIN_StringToUTF8(buffer);
   681                         SDL_SendDropFile(file);
   682                         SDL_free(file);
   683                     }
   684                     SDL_stack_free(buffer);
   685                 }
   686             }
   687             DragFinish(drop);
   688             return 0;
   689         }
   690         break;
   691     }
   692 
   693     /* If there's a window proc, assume it's going to handle messages */
   694     if (data->wndproc) {
   695         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   696     } else if (returnCode >= 0) {
   697         return returnCode;
   698     } else {
   699         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   700     }
   701 }
   702 
   703 void
   704 WIN_PumpEvents(_THIS)
   705 {
   706     MSG msg;
   707     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   708         TranslateMessage(&msg);
   709         DispatchMessage(&msg);
   710     }
   711 }
   712 
   713 static int app_registered = 0;
   714 LPTSTR SDL_Appname = NULL;
   715 Uint32 SDL_Appstyle = 0;
   716 HINSTANCE SDL_Instance = NULL;
   717 
   718 /* Register the class for this application */
   719 int
   720 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   721 {
   722     WNDCLASS class;
   723 
   724     /* Only do this once... */
   725     if (app_registered) {
   726         ++app_registered;
   727         return (0);
   728     }
   729     if (!name && !SDL_Appname) {
   730         name = "SDL_app";
   731 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   732         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   733 #endif
   734         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   735     }
   736 
   737     if (name) {
   738         SDL_Appname = WIN_UTF8ToString(name);
   739         SDL_Appstyle = style;
   740         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   741     }
   742 
   743     /* Register the application class */
   744     class.hCursor = NULL;
   745     class.hIcon =
   746         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   747                   LR_DEFAULTCOLOR);
   748     class.lpszMenuName = NULL;
   749     class.lpszClassName = SDL_Appname;
   750     class.hbrBackground = NULL;
   751     class.hInstance = SDL_Instance;
   752     class.style = SDL_Appstyle;
   753     class.lpfnWndProc = WIN_WindowProc;
   754     class.cbWndExtra = 0;
   755     class.cbClsExtra = 0;
   756     if (!RegisterClass(&class)) {
   757         SDL_SetError("Couldn't register application class");
   758         return (-1);
   759     }
   760 
   761     app_registered = 1;
   762     return (0);
   763 }
   764 
   765 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   766 void
   767 SDL_UnregisterApp()
   768 {
   769     WNDCLASS class;
   770 
   771     /* SDL_RegisterApp might not have been called before */
   772     if (!app_registered) {
   773         return;
   774     }
   775     --app_registered;
   776     if (app_registered == 0) {
   777         /* Check for any registered window classes. */
   778         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   779             UnregisterClass(SDL_Appname, SDL_Instance);
   780         }
   781         SDL_free(SDL_Appname);
   782         SDL_Appname = NULL;
   783     }
   784 }
   785 
   786 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   787 
   788 /* vi: set ts=4 sw=4 expandtab: */