src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 11 Feb 2013 21:29:36 -0800
changeset 6861 c1c9eab3bd20
parent 6837 a69e10925a58
child 6862 d189a1e771fe
permissions -rw-r--r--
Fixed mouse wheel delta on 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 
   455             /* If we allow resizing, let the resize happen naturally */
   456             if (SDL_IsShapedWindow(data->window))
   457                 Win32_ResizeWindowShape(data->window);
   458 
   459             /* Get the current position of our window */
   460             GetWindowRect(hwnd, &size);
   461             x = size.left;
   462             y = size.top;
   463 
   464             /* Calculate current size of our window */
   465             SDL_GetWindowSize(data->window, &w, &h);
   466             SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
   467             SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
   468 
   469             /* Store in min_w and min_h difference between current size and minimal 
   470                size so we don't need to call AdjustWindowRectEx twice */
   471             min_w -= w;
   472             min_h -= h;
   473             if (max_w && max_h) {
   474                 max_w -= w;
   475                 max_h -= h;
   476             }
   477 
   478             size.top = 0;
   479             size.left = 0;
   480             size.bottom = h;
   481             size.right = w;
   482 
   483             style = GetWindowLong(hwnd, GWL_STYLE);
   484             /* DJM - according to the docs for GetMenu(), the
   485                return value is undefined if hwnd is a child window.
   486                Aparently it's too difficult for MS to check
   487                inside their function, so I have to do it here.
   488              */
   489             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   490             AdjustWindowRectEx(&size, style, menu, 0);
   491             w = size.right - size.left;
   492             h = size.bottom - size.top;
   493 
   494             /* Fix our size to the current size */
   495             info = (MINMAXINFO *) lParam;
   496             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   497                 info->ptMinTrackSize.x = w + min_w;
   498                 info->ptMinTrackSize.y = h + min_h;
   499                 info->ptMaxTrackSize.x = w + max_w;
   500                 info->ptMaxTrackSize.y = h + max_h;
   501             } else {
   502                 info->ptMaxSize.x = w;
   503                 info->ptMaxSize.y = h;
   504                 info->ptMaxPosition.x = x;
   505                 info->ptMaxPosition.y = y;
   506                 info->ptMinTrackSize.x = w;
   507                 info->ptMinTrackSize.y = h;
   508                 info->ptMaxTrackSize.x = w;
   509                 info->ptMaxTrackSize.y = h;
   510             }
   511         }
   512         returnCode = 0;
   513         break;
   514 #endif /* WM_GETMINMAXINFO */
   515 
   516     case WM_WINDOWPOSCHANGED:
   517         {
   518             RECT rect;
   519             int x, y;
   520             int w, h;
   521             Uint32 window_flags;
   522 
   523             if (!GetClientRect(hwnd, &rect) ||
   524                 (rect.right == rect.left && rect.bottom == rect.top)) {
   525                 break;
   526             }
   527             ClientToScreen(hwnd, (LPPOINT) & rect);
   528             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   529 
   530             window_flags = SDL_GetWindowFlags(data->window);
   531             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   532                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   533                 ClipCursor(&rect);
   534             }
   535 
   536             x = rect.left;
   537             y = rect.top;
   538             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   539 
   540             w = rect.right - rect.left;
   541             h = rect.bottom - rect.top;
   542             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   543                                 h);
   544         }
   545         break;
   546 
   547     case WM_SETCURSOR:
   548         {
   549             Uint16 hittest;
   550 
   551             hittest = LOWORD(lParam);
   552             if (hittest == HTCLIENT) {
   553                 SetCursor(SDL_cursor);
   554                 returnCode = TRUE;
   555             }
   556         }
   557         break;
   558 
   559         /* We were occluded, refresh our display */
   560     case WM_PAINT:
   561         {
   562             RECT rect;
   563             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   564                 ValidateRect(hwnd, &rect);
   565                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   566                                     0, 0);
   567             }
   568         }
   569         returnCode = 0;
   570         break;
   571 
   572         /* We'll do our own drawing, prevent flicker */
   573     case WM_ERASEBKGND:
   574         {
   575         }
   576         return (1);
   577 
   578 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   579     case WM_SYSCOMMAND:
   580         {
   581             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   582             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   583                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   584                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   585                     return (0);
   586                 }
   587             }
   588         }
   589         break;
   590 #endif /* System has screensaver support */
   591 
   592     case WM_CLOSE:
   593         {
   594             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   595         }
   596         returnCode = 0;
   597         break;
   598 
   599 	case WM_TOUCH:
   600 		{
   601 			UINT i, num_inputs = LOWORD(wParam);
   602 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   603 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   604 				RECT rect;
   605 				float x, y;
   606 
   607 				if (!GetClientRect(hwnd, &rect) ||
   608 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   609 					break;
   610 				}
   611 				ClientToScreen(hwnd, (LPPOINT) & rect);
   612 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   613 				rect.top *= 100;
   614 				rect.left *= 100;
   615 				rect.bottom *= 100;
   616 				rect.right *= 100;
   617 
   618 				for (i = 0; i < num_inputs; ++i) {
   619 					PTOUCHINPUT input = &inputs[i];
   620 
   621 					const SDL_TouchID touchId = (SDL_TouchID)
   622 												((size_t)input->hSource);
   623 					if (!SDL_GetTouch(touchId)) {
   624 						SDL_Touch touch;
   625 
   626 						touch.id = touchId;
   627 						touch.x_min = 0;
   628 						touch.x_max = 1;
   629 						touch.native_xres = touch.x_max - touch.x_min;
   630 						touch.y_min = 0;
   631 						touch.y_max = 1;
   632 						touch.native_yres = touch.y_max - touch.y_min;
   633 						touch.pressure_min = 0;
   634 						touch.pressure_max = 1;
   635 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   636 
   637 						if (SDL_AddTouch(&touch, "") < 0) {
   638 							continue;
   639 						}
   640 					}
   641 
   642 					// Get the normalized coordinates for the window
   643 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   644 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   645 
   646 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   647 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   648 					}
   649 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   650 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   651 					}
   652 					if (input->dwFlags & TOUCHEVENTF_UP) {
   653 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   654 					}
   655 				}
   656 			}
   657 			SDL_stack_free(inputs);
   658 
   659 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   660 			return 0;
   661 		}
   662 		break;
   663 
   664     case WM_DROPFILES:
   665         {
   666             UINT i;
   667             HDROP drop = (HDROP) wParam;
   668             UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
   669             for (i = 0; i < count; ++i) {
   670                 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
   671                 LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
   672                 if (buffer) {
   673                     if (DragQueryFile(drop, i, buffer, size)) {
   674                         char *file = WIN_StringToUTF8(buffer);
   675                         SDL_SendDropFile(file);
   676                         SDL_free(file);
   677                     }
   678                     SDL_stack_free(buffer);
   679                 }
   680             }
   681             DragFinish(drop);
   682             return 0;
   683         }
   684         break;
   685     }
   686 
   687     /* If there's a window proc, assume it's going to handle messages */
   688     if (data->wndproc) {
   689         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   690     } else if (returnCode >= 0) {
   691         return returnCode;
   692     } else {
   693         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   694     }
   695 }
   696 
   697 void
   698 WIN_PumpEvents(_THIS)
   699 {
   700     MSG msg;
   701     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   702         TranslateMessage(&msg);
   703         DispatchMessage(&msg);
   704     }
   705 }
   706 
   707 static int app_registered = 0;
   708 LPTSTR SDL_Appname = NULL;
   709 Uint32 SDL_Appstyle = 0;
   710 HINSTANCE SDL_Instance = NULL;
   711 
   712 /* Register the class for this application */
   713 int
   714 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   715 {
   716     WNDCLASS class;
   717 
   718     /* Only do this once... */
   719     if (app_registered) {
   720         ++app_registered;
   721         return (0);
   722     }
   723     if (!name && !SDL_Appname) {
   724         name = "SDL_app";
   725 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   726         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   727 #endif
   728         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   729     }
   730 
   731     if (name) {
   732         SDL_Appname = WIN_UTF8ToString(name);
   733         SDL_Appstyle = style;
   734         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   735     }
   736 
   737     /* Register the application class */
   738     class.hCursor = NULL;
   739     class.hIcon =
   740         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   741                   LR_DEFAULTCOLOR);
   742     class.lpszMenuName = NULL;
   743     class.lpszClassName = SDL_Appname;
   744     class.hbrBackground = NULL;
   745     class.hInstance = SDL_Instance;
   746     class.style = SDL_Appstyle;
   747     class.lpfnWndProc = WIN_WindowProc;
   748     class.cbWndExtra = 0;
   749     class.cbClsExtra = 0;
   750     if (!RegisterClass(&class)) {
   751         SDL_SetError("Couldn't register application class");
   752         return (-1);
   753     }
   754 
   755     app_registered = 1;
   756     return (0);
   757 }
   758 
   759 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   760 void
   761 SDL_UnregisterApp()
   762 {
   763     WNDCLASS class;
   764 
   765     /* SDL_RegisterApp might not have been called before */
   766     if (!app_registered) {
   767         return;
   768     }
   769     --app_registered;
   770     if (app_registered == 0) {
   771         /* Check for any registered window classes. */
   772         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   773             UnregisterClass(SDL_Appname, SDL_Instance);
   774         }
   775         SDL_free(SDL_Appname);
   776         SDL_Appname = NULL;
   777     }
   778 }
   779 
   780 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   781 
   782 /* vi: set ts=4 sw=4 expandtab: */