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