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