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