src/video/win32/SDL_win32events.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 06 Jul 2007 09:22:18 +0000
changeset 2152 003c1b5b07da
parent 2141 e1a70460c354
child 2284 545fbf461c5b
permissions -rw-r--r--
Fixed bug #382

Added horizontal scrolling support
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_win32video.h"
    25 #include "SDL_syswm.h"
    26 #include "SDL_vkeys.h"
    27 #include "../../events/SDL_events_c.h"
    28 
    29 /*#define WMMSG_DEBUG*/
    30 #ifdef WMMSG_DEBUG
    31 #include <stdio.h>
    32 #include "wmmsg.h"
    33 #endif
    34 
    35 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    36 #define REPEATED_KEYMASK	(1<<30)
    37 #define EXTENDED_KEYMASK	(1<<24)
    38 
    39 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
    40 #ifndef WM_XBUTTONDOWN
    41 #define WM_XBUTTONDOWN 0x020B
    42 #endif
    43 #ifndef WM_XBUTTONUP
    44 #define WM_XBUTTONUP 0x020C
    45 #endif
    46 #ifndef GET_XBUTTON_WPARAM
    47 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
    48 #endif
    49 
    50 static SDLKey
    51 TranslateKey(WPARAM vkey)
    52 {
    53     SDLKey key;
    54 
    55     /* FIXME: Assign vkey directly to key if in ASCII range */
    56     switch (vkey) {
    57     case VK_BACK:
    58         key = SDLK_BACKSPACE;
    59         break;
    60     case VK_TAB:
    61         key = SDLK_TAB;
    62         break;
    63     case VK_CLEAR:
    64         key = SDLK_CLEAR;
    65         break;
    66     case VK_RETURN:
    67         key = SDLK_RETURN;
    68         break;
    69     case VK_PAUSE:
    70         key = SDLK_PAUSE;
    71         break;
    72     case VK_ESCAPE:
    73         key = SDLK_ESCAPE;
    74         break;
    75     case VK_SPACE:
    76         key = SDLK_SPACE;
    77         break;
    78     case VK_APOSTROPHE:
    79         key = SDLK_QUOTE;
    80         break;
    81     case VK_COMMA:
    82         key = SDLK_COMMA;
    83         break;
    84     case VK_MINUS:
    85         key = SDLK_MINUS;
    86         break;
    87     case VK_PERIOD:
    88         key = SDLK_PERIOD;
    89         break;
    90     case VK_SLASH:
    91         key = SDLK_SLASH;
    92         break;
    93     case VK_0:
    94         key = SDLK_0;
    95         break;
    96     case VK_1:
    97         key = SDLK_1;
    98         break;
    99     case VK_2:
   100         key = SDLK_2;
   101         break;
   102     case VK_3:
   103         key = SDLK_3;
   104         break;
   105     case VK_4:
   106         key = SDLK_4;
   107         break;
   108     case VK_5:
   109         key = SDLK_5;
   110         break;
   111     case VK_6:
   112         key = SDLK_6;
   113         break;
   114     case VK_7:
   115         key = SDLK_7;
   116         break;
   117     case VK_8:
   118         key = SDLK_8;
   119         break;
   120     case VK_9:
   121         key = SDLK_9;
   122         break;
   123     case VK_SEMICOLON:
   124         key = SDLK_SEMICOLON;
   125         break;
   126     case VK_EQUALS:
   127         key = SDLK_EQUALS;
   128         break;
   129     case VK_LBRACKET:
   130         key = SDLK_LEFTBRACKET;
   131         break;
   132     case VK_BACKSLASH:
   133         key = SDLK_BACKSLASH;
   134         break;
   135     case VK_OEM_102:
   136         key = SDLK_LESS;
   137         break;
   138     case VK_RBRACKET:
   139         key = SDLK_RIGHTBRACKET;
   140         break;
   141     case VK_GRAVE:
   142         key = SDLK_BACKQUOTE;
   143         break;
   144     case VK_BACKTICK:
   145         key = SDLK_BACKQUOTE;
   146         break;
   147     case VK_A:
   148         key = SDLK_a;
   149         break;
   150     case VK_B:
   151         key = SDLK_b;
   152         break;
   153     case VK_C:
   154         key = SDLK_c;
   155         break;
   156     case VK_D:
   157         key = SDLK_d;
   158         break;
   159     case VK_E:
   160         key = SDLK_e;
   161         break;
   162     case VK_F:
   163         key = SDLK_f;
   164         break;
   165     case VK_G:
   166         key = SDLK_g;
   167         break;
   168     case VK_H:
   169         key = SDLK_h;
   170         break;
   171     case VK_I:
   172         key = SDLK_i;
   173         break;
   174     case VK_J:
   175         key = SDLK_j;
   176         break;
   177     case VK_K:
   178         key = SDLK_k;
   179         break;
   180     case VK_L:
   181         key = SDLK_l;
   182         break;
   183     case VK_M:
   184         key = SDLK_m;
   185         break;
   186     case VK_N:
   187         key = SDLK_n;
   188         break;
   189     case VK_O:
   190         key = SDLK_o;
   191         break;
   192     case VK_P:
   193         key = SDLK_p;
   194         break;
   195     case VK_Q:
   196         key = SDLK_q;
   197         break;
   198     case VK_R:
   199         key = SDLK_r;
   200         break;
   201     case VK_S:
   202         key = SDLK_s;
   203         break;
   204     case VK_T:
   205         key = SDLK_t;
   206         break;
   207     case VK_U:
   208         key = SDLK_u;
   209         break;
   210     case VK_V:
   211         key = SDLK_v;
   212         break;
   213     case VK_W:
   214         key = SDLK_w;
   215         break;
   216     case VK_X:
   217         key = SDLK_x;
   218         break;
   219     case VK_Y:
   220         key = SDLK_y;
   221         break;
   222     case VK_Z:
   223         key = SDLK_z;
   224         break;
   225     case VK_DELETE:
   226         key = SDLK_DELETE;
   227         break;
   228     case VK_NUMPAD0:
   229         key = SDLK_KP0;
   230         break;
   231     case VK_NUMPAD1:
   232         key = SDLK_KP1;
   233         break;
   234     case VK_NUMPAD2:
   235         key = SDLK_KP2;
   236         break;
   237     case VK_NUMPAD3:
   238         key = SDLK_KP3;
   239         break;
   240     case VK_NUMPAD4:
   241         key = SDLK_KP4;
   242         break;
   243     case VK_NUMPAD5:
   244         key = SDLK_KP5;
   245         break;
   246     case VK_NUMPAD6:
   247         key = SDLK_KP6;
   248         break;
   249     case VK_NUMPAD7:
   250         key = SDLK_KP7;
   251         break;
   252     case VK_NUMPAD8:
   253         key = SDLK_KP8;
   254         break;
   255     case VK_NUMPAD9:
   256         key = SDLK_KP9;
   257         break;
   258     case VK_DECIMAL:
   259         key = SDLK_KP_PERIOD;
   260         break;
   261     case VK_DIVIDE:
   262         key = SDLK_KP_DIVIDE;
   263         break;
   264     case VK_MULTIPLY:
   265         key = SDLK_KP_MULTIPLY;
   266         break;
   267     case VK_SUBTRACT:
   268         key = SDLK_KP_MINUS;
   269         break;
   270     case VK_ADD:
   271         key = SDLK_KP_PLUS;
   272         break;
   273     case VK_UP:
   274         key = SDLK_UP;
   275         break;
   276     case VK_DOWN:
   277         key = SDLK_DOWN;
   278         break;
   279     case VK_RIGHT:
   280         key = SDLK_RIGHT;
   281         break;
   282     case VK_LEFT:
   283         key = SDLK_LEFT;
   284         break;
   285     case VK_INSERT:
   286         key = SDLK_INSERT;
   287         break;
   288     case VK_HOME:
   289         key = SDLK_HOME;
   290         break;
   291     case VK_END:
   292         key = SDLK_END;
   293         break;
   294     case VK_PRIOR:
   295         key = SDLK_PAGEUP;
   296         break;
   297     case VK_NEXT:
   298         key = SDLK_PAGEDOWN;
   299         break;
   300     case VK_F1:
   301         key = SDLK_F1;
   302         break;
   303     case VK_F2:
   304         key = SDLK_F2;
   305         break;
   306     case VK_F3:
   307         key = SDLK_F3;
   308         break;
   309     case VK_F4:
   310         key = SDLK_F4;
   311         break;
   312     case VK_F5:
   313         key = SDLK_F5;
   314         break;
   315     case VK_F6:
   316         key = SDLK_F6;
   317         break;
   318     case VK_F7:
   319         key = SDLK_F7;
   320         break;
   321     case VK_F8:
   322         key = SDLK_F8;
   323         break;
   324     case VK_F9:
   325         key = SDLK_F9;
   326         break;
   327     case VK_F10:
   328         key = SDLK_F10;
   329         break;
   330     case VK_F11:
   331         key = SDLK_F11;
   332         break;
   333     case VK_F12:
   334         key = SDLK_F12;
   335         break;
   336     case VK_F13:
   337         key = SDLK_F13;
   338         break;
   339     case VK_F14:
   340         key = SDLK_F14;
   341         break;
   342     case VK_F15:
   343         key = SDLK_F15;
   344         break;
   345     case VK_NUMLOCK:
   346         key = SDLK_NUMLOCK;
   347         break;
   348     case VK_CAPITAL:
   349         key = SDLK_CAPSLOCK;
   350         break;
   351     case VK_SCROLL:
   352         key = SDLK_SCROLLOCK;
   353         break;
   354     case VK_RSHIFT:
   355         key = SDLK_RSHIFT;
   356         break;
   357     case VK_LSHIFT:
   358         key = SDLK_LSHIFT;
   359         break;
   360     case VK_RCONTROL:
   361         key = SDLK_RCTRL;
   362         break;
   363     case VK_LCONTROL:
   364         key = SDLK_LCTRL;
   365         break;
   366     case VK_RMENU:
   367         key = SDLK_RALT;
   368         break;
   369     case VK_LMENU:
   370         key = SDLK_LALT;
   371         break;
   372     case VK_RWIN:
   373         key = SDLK_RSUPER;
   374         break;
   375     case VK_LWIN:
   376         key = SDLK_LSUPER;
   377         break;
   378     case VK_HELP:
   379         key = SDLK_HELP;
   380         break;
   381     case VK_PRINT:
   382         key = SDLK_PRINT;
   383         break;
   384     case VK_SNAPSHOT:
   385         key = SDLK_PRINT;
   386         break;
   387     case VK_CANCEL:
   388         key = SDLK_BREAK;
   389         break;
   390     case VK_APPS:
   391         key = SDLK_MENU;
   392         break;
   393     default:
   394         key = SDLK_UNKNOWN;
   395         break;
   396     }
   397     return key;
   398 }
   399 
   400 LRESULT CALLBACK
   401 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   402 {
   403     SDL_WindowData *data;
   404 
   405     /* Send a SDL_SYSWMEVENT if the application wants them */
   406     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
   407         SDL_SysWMmsg wmmsg;
   408 
   409         SDL_VERSION(&wmmsg.version);
   410         wmmsg.hwnd = hwnd;
   411         wmmsg.msg = msg;
   412         wmmsg.wParam = wParam;
   413         wmmsg.lParam = lParam;
   414         SDL_SendSysWMEvent(&wmmsg);
   415     }
   416 
   417     /* Get the window data for the window */
   418     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   419     if (!data) {
   420         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   421     }
   422 #ifdef WMMSG_DEBUG
   423     {
   424         FILE *log = fopen("wmmsg.txt", "a");
   425         fprintf(log, "Received windows message: %p ", hwnd);
   426         if (msg > MAX_WMMSG) {
   427             fprintf(log, "%d", msg);
   428         } else {
   429             fprintf(log, "%s", wmtab[msg]);
   430         }
   431         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   432         fclose(log);
   433     }
   434 #endif
   435 
   436     switch (msg) {
   437 
   438     case WM_SHOWWINDOW:
   439         {
   440             if (wParam) {
   441                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0,
   442                                     0);
   443             } else {
   444                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0,
   445                                     0);
   446             }
   447         }
   448         break;
   449 
   450     case WM_ACTIVATE:
   451         {
   452             int index;
   453             SDL_Keyboard *keyboard;
   454             BOOL minimized;
   455 
   456             minimized = HIWORD(wParam);
   457             index = data->videodata->keyboard;
   458             keyboard = SDL_GetKeyboard(index);
   459             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   460                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN,
   461                                     0, 0);
   462                 SDL_SendWindowEvent(data->windowID,
   463                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   464                 if (IsZoomed(hwnd)) {
   465                     SDL_SendWindowEvent(data->windowID,
   466                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   467                 }
   468                 if (keyboard && keyboard->focus != data->windowID) {
   469                     SDL_SetKeyboardFocus(index, data->windowID);
   470                 }
   471                 /* FIXME: Update keyboard state */
   472             } else {
   473                 if (keyboard && keyboard->focus == data->windowID) {
   474                     SDL_SetKeyboardFocus(index, 0);
   475                 }
   476                 if (minimized) {
   477                     SDL_SendWindowEvent(data->windowID,
   478                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   479                 }
   480             }
   481             return (0);
   482         }
   483         break;
   484 
   485     case WM_MOUSEMOVE:
   486         {
   487             int index;
   488             SDL_Mouse *mouse;
   489             int x, y;
   490 
   491             index = data->videodata->mouse;
   492             mouse = SDL_GetMouse(index);
   493 
   494             if (mouse->focus != data->windowID) {
   495                 TRACKMOUSEEVENT tme;
   496 
   497                 tme.cbSize = sizeof(tme);
   498                 tme.dwFlags = TME_LEAVE;
   499                 tme.hwndTrack = hwnd;
   500                 TrackMouseEvent(&tme);
   501 
   502                 SDL_SetMouseFocus(index, data->windowID);
   503             }
   504 
   505             /* mouse has moved within the window */
   506             x = LOWORD(lParam);
   507             y = HIWORD(lParam);
   508             if (mouse->relative_mode) {
   509                 int w, h;
   510                 POINT center;
   511                 SDL_GetWindowSize(data->windowID, &w, &h);
   512                 center.x = (w / 2);
   513                 center.y = (h / 2);
   514                 x -= center.x;
   515                 y -= center.y;
   516                 if (x || y) {
   517                     ClientToScreen(hwnd, &center);
   518                     SetCursorPos(center.x, center.y);
   519                     SDL_SendMouseMotion(index, 1, x, y);
   520                 }
   521             } else {
   522                 SDL_SendMouseMotion(index, 0, x, y);
   523             }
   524         }
   525         return (0);
   526 
   527     case WM_MOUSELEAVE:
   528         {
   529             int index;
   530             SDL_Mouse *mouse;
   531 
   532             index = data->videodata->mouse;
   533             mouse = SDL_GetMouse(index);
   534 
   535             if (mouse->focus == data->windowID) {
   536                 SDL_SetMouseFocus(index, 0);
   537             }
   538         }
   539         return (0);
   540 
   541     case WM_LBUTTONDOWN:
   542     case WM_LBUTTONUP:
   543     case WM_MBUTTONDOWN:
   544     case WM_MBUTTONUP:
   545     case WM_RBUTTONDOWN:
   546     case WM_RBUTTONUP:
   547     case WM_XBUTTONDOWN:
   548     case WM_XBUTTONUP:
   549         {
   550             int xbuttonval = 0;
   551             int index;
   552             SDL_Mouse *mouse;
   553             Uint8 button, state;
   554 
   555             /* DJM:
   556                We want the SDL window to take focus so that
   557                it acts like a normal windows "component"
   558                (e.g. gains keyboard focus on a mouse click).
   559              */
   560             SetFocus(hwnd);
   561 
   562             index = data->videodata->mouse;
   563             mouse = SDL_GetMouse(index);
   564 
   565             /* Figure out which button to use */
   566             switch (msg) {
   567             case WM_LBUTTONDOWN:
   568                 button = SDL_BUTTON_LEFT;
   569                 state = SDL_PRESSED;
   570                 break;
   571             case WM_LBUTTONUP:
   572                 button = SDL_BUTTON_LEFT;
   573                 state = SDL_RELEASED;
   574                 break;
   575             case WM_MBUTTONDOWN:
   576                 button = SDL_BUTTON_MIDDLE;
   577                 state = SDL_PRESSED;
   578                 break;
   579             case WM_MBUTTONUP:
   580                 button = SDL_BUTTON_MIDDLE;
   581                 state = SDL_RELEASED;
   582                 break;
   583             case WM_RBUTTONDOWN:
   584                 button = SDL_BUTTON_RIGHT;
   585                 state = SDL_PRESSED;
   586                 break;
   587             case WM_RBUTTONUP:
   588                 button = SDL_BUTTON_RIGHT;
   589                 state = SDL_RELEASED;
   590                 break;
   591             case WM_XBUTTONDOWN:
   592                 xbuttonval = GET_XBUTTON_WPARAM(wParam);
   593                 button = SDL_BUTTON_RIGHT + xbuttonval;
   594                 state = SDL_PRESSED;
   595                 break;
   596             case WM_XBUTTONUP:
   597                 xbuttonval = GET_XBUTTON_WPARAM(wParam);
   598                 button = SDL_BUTTON_RIGHT + xbuttonval;
   599                 state = SDL_RELEASED;
   600                 break;
   601             default:
   602                 /* Eh? Unknown button? */
   603                 return (0);
   604             }
   605             if (state == SDL_PRESSED) {
   606                 /* Grab mouse so we get up events */
   607                 if (++data->mouse_pressed > 0) {
   608                     SetCapture(hwnd);
   609                 }
   610             } else {
   611                 /* Release mouse after all up events */
   612                 if (--data->mouse_pressed <= 0) {
   613                     ReleaseCapture();
   614                     data->mouse_pressed = 0;
   615                 }
   616             }
   617 
   618             if (!mouse->relative_mode) {
   619                 int x, y;
   620                 x = LOWORD(lParam);
   621                 y = HIWORD(lParam);
   622                 SDL_SendMouseMotion(index, 0, x, y);
   623             }
   624             SDL_SendMouseButton(index, state, button);
   625 
   626             /*
   627              * MSDN says:
   628              *  "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP
   629              *   messages, an application should return TRUE from [an
   630              *   XBUTTON message] if it processes it. Doing so will allow
   631              *   software that simulates this message on Microsoft Windows
   632              *   systems earlier than Windows 2000 to determine whether
   633              *   the window procedure processed the message or called
   634              *   DefWindowProc to process it.
   635              */
   636             if (xbuttonval > 0) {
   637                 return (TRUE);
   638             }
   639         }
   640         return (0);
   641 
   642     case WM_MOUSEWHEEL:
   643         {
   644             int index;
   645             int motion = (short) HIWORD(wParam);
   646 
   647             index = data->videodata->mouse;
   648             SDL_SendMouseWheel(index, 0, motion);
   649         }
   650         return (0);
   651 
   652     case WM_SYSKEYDOWN:
   653     case WM_KEYDOWN:
   654         {
   655             int index;
   656 
   657             /* Ignore repeated keys */
   658             if (lParam & REPEATED_KEYMASK) {
   659                 return (0);
   660             }
   661 
   662             index = data->videodata->keyboard;
   663             switch (wParam) {
   664             case VK_CONTROL:
   665                 if (lParam & EXTENDED_KEYMASK)
   666                     wParam = VK_RCONTROL;
   667                 else
   668                     wParam = VK_LCONTROL;
   669                 break;
   670             case VK_SHIFT:
   671                 /* EXTENDED trick doesn't work here */
   672                 {
   673                     Uint8 *state = SDL_GetKeyState(NULL);
   674                     if (state[SDLK_LSHIFT] == SDL_RELEASED
   675                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   676                         wParam = VK_LSHIFT;
   677                     } else if (state[SDLK_RSHIFT] == SDL_RELEASED
   678                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   679                         wParam = VK_RSHIFT;
   680                     } else {
   681                         /* Probably a key repeat */
   682                         return (0);
   683                     }
   684                 }
   685                 break;
   686             case VK_MENU:
   687                 if (lParam & EXTENDED_KEYMASK)
   688                     wParam = VK_RMENU;
   689                 else
   690                     wParam = VK_LMENU;
   691                 break;
   692             }
   693             SDL_SendKeyboardKey(index, SDL_PRESSED, (Uint8) HIWORD(lParam),
   694                                 TranslateKey(wParam));
   695         }
   696         return (0);
   697 
   698     case WM_SYSKEYUP:
   699     case WM_KEYUP:
   700         {
   701             int index;
   702 
   703             index = data->videodata->keyboard;
   704             switch (wParam) {
   705             case VK_CONTROL:
   706                 if (lParam & EXTENDED_KEYMASK)
   707                     wParam = VK_RCONTROL;
   708                 else
   709                     wParam = VK_LCONTROL;
   710                 break;
   711             case VK_SHIFT:
   712                 /* EXTENDED trick doesn't work here */
   713                 {
   714                     Uint8 *state = SDL_GetKeyState(NULL);
   715                     if (state[SDLK_LSHIFT] == SDL_PRESSED
   716                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   717                         wParam = VK_LSHIFT;
   718                     } else if (state[SDLK_RSHIFT] == SDL_PRESSED
   719                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   720                         wParam = VK_RSHIFT;
   721                     } else {
   722                         /* Probably a key repeat */
   723                         return (0);
   724                     }
   725                 }
   726                 break;
   727             case VK_MENU:
   728                 if (lParam & EXTENDED_KEYMASK)
   729                     wParam = VK_RMENU;
   730                 else
   731                     wParam = VK_LMENU;
   732                 break;
   733             }
   734             /* Windows only reports keyup for print screen */
   735             if (wParam == VK_SNAPSHOT
   736                 && SDL_GetKeyState(NULL)[SDLK_PRINT] == SDL_RELEASED) {
   737                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   738                                     (Uint8) HIWORD(lParam),
   739                                     TranslateKey(wParam));
   740             }
   741             SDL_SendKeyboardKey(index, SDL_RELEASED, (Uint8) HIWORD(lParam),
   742                                 TranslateKey(wParam));
   743         }
   744         return (0);
   745 
   746     case WM_GETMINMAXINFO:
   747         {
   748             MINMAXINFO *info;
   749             RECT size;
   750             int x, y;
   751             int w, h;
   752             int style;
   753 
   754             /* If we allow resizing, let the resize happen naturally */
   755             if (SDL_GetWindowFlags(data->windowID) & SDL_WINDOW_RESIZABLE) {
   756                 return (0);
   757             }
   758 
   759             /* Get the current position of our window */
   760             GetWindowRect(hwnd, &size);
   761             x = size.left;
   762             y = size.top;
   763 
   764             /* Calculate current size of our window */
   765             SDL_GetWindowSize(data->windowID, &w, &h);
   766             size.top = 0;
   767             size.left = 0;
   768             size.bottom = h;
   769             size.right = w;
   770 
   771             /* DJM - according to the docs for GetMenu(), the
   772                return value is undefined if hwnd is a child window.
   773                Aparently it's too difficult for MS to check
   774                inside their function, so I have to do it here.
   775              */
   776             style = GetWindowLong(hwnd, GWL_STYLE);
   777             AdjustWindowRect(&size,
   778                              style,
   779                              style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd) !=
   780                              NULL);
   781 
   782             w = size.right - size.left;
   783             h = size.bottom - size.top;
   784 
   785             /* Fix our size to the current size */
   786             info = (MINMAXINFO *) lParam;
   787             info->ptMaxSize.x = w;
   788             info->ptMaxSize.y = h;
   789             info->ptMaxPosition.x = x;
   790             info->ptMaxPosition.y = y;
   791             info->ptMinTrackSize.x = w;
   792             info->ptMinTrackSize.y = h;
   793             info->ptMaxTrackSize.x = w;
   794             info->ptMaxTrackSize.y = h;
   795         }
   796         return (0);
   797 
   798     case WM_WINDOWPOSCHANGED:
   799         {
   800             RECT rect;
   801             int x, y;
   802             int w, h;
   803             Uint32 window_flags;
   804 
   805             GetClientRect(hwnd, &rect);
   806             ClientToScreen(hwnd, (LPPOINT) & rect);
   807             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   808 
   809             window_flags = SDL_GetWindowFlags(data->windowID);
   810             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   811                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   812                 ClipCursor(&rect);
   813             }
   814 
   815             x = rect.left;
   816             y = rect.top;
   817             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED, x, y);
   818 
   819             w = rect.right - rect.left;
   820             h = rect.bottom - rect.top;
   821             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED, w,
   822                                 h);
   823         }
   824         break;
   825 
   826     case WM_SETCURSOR:
   827         {
   828             /*
   829                Uint16 hittest;
   830 
   831                hittest = LOWORD(lParam);
   832                if (hittest == HTCLIENT) {
   833                SetCursor(SDL_hcursor);
   834                return (TRUE);
   835                }
   836              */
   837         }
   838         break;
   839 
   840         /* We are about to get palette focus! */
   841     case WM_QUERYNEWPALETTE:
   842         {
   843             /*
   844                WIN_RealizePalette(current_video);
   845                return (TRUE);
   846              */
   847         }
   848         break;
   849 
   850         /* Another application changed the palette */
   851     case WM_PALETTECHANGED:
   852         {
   853             /*
   854                WIN_PaletteChanged(current_video, (HWND) wParam);
   855              */
   856         }
   857         break;
   858 
   859         /* We were occluded, refresh our display */
   860     case WM_PAINT:
   861         {
   862             RECT rect;
   863             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   864                 ValidateRect(hwnd, &rect);
   865                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED,
   866                                     0, 0);
   867             }
   868         }
   869         return (0);
   870 
   871         /* We'll do our own drawing, prevent flicker */
   872     case WM_ERASEBKGND:
   873         {
   874         }
   875         return (1);
   876 
   877     case WM_SYSCOMMAND:
   878         {
   879             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   880             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   881                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   882                 if (SDL_GetWindowFlags(data->windowID) &
   883                     SDL_WINDOW_FULLSCREEN) {
   884                     return (0);
   885                 }
   886             }
   887         }
   888         break;
   889 
   890     case WM_CLOSE:
   891         {
   892             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0, 0);
   893         }
   894         return (0);
   895     }
   896     return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   897 }
   898 
   899 void
   900 WIN_PumpEvents(_THIS)
   901 {
   902     MSG msg;
   903     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   904         TranslateMessage(&msg);
   905         DispatchMessage(&msg);
   906     }
   907 }
   908 
   909 static int app_registered = 0;
   910 LPTSTR SDL_Appname = NULL;
   911 Uint32 SDL_Appstyle = 0;
   912 HINSTANCE SDL_Instance = NULL;
   913 
   914 /* Register the class for this application */
   915 int
   916 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   917 {
   918     WNDCLASS class;
   919 
   920     /* Only do this once... */
   921     if (app_registered) {
   922         ++app_registered;
   923         return (0);
   924     }
   925     if (!name && !SDL_Appname) {
   926         name = "SDL_app";
   927         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   928         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   929     }
   930 
   931     if (name) {
   932         SDL_Appname = WIN_UTF8ToString(name);
   933         SDL_Appstyle = style;
   934         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   935     }
   936 
   937     /* Register the application class */
   938     class.hCursor = NULL;
   939     class.hIcon = LoadImage(SDL_Instance, SDL_Appname,
   940                             IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
   941     class.lpszMenuName = NULL;
   942     class.lpszClassName = SDL_Appname;
   943     class.hbrBackground = NULL;
   944     class.hInstance = SDL_Instance;
   945     class.style = SDL_Appstyle;
   946     class.lpfnWndProc = DefWindowProc;
   947     class.cbWndExtra = 0;
   948     class.cbClsExtra = 0;
   949     if (!RegisterClass(&class)) {
   950         SDL_SetError("Couldn't register application class");
   951         return (-1);
   952     }
   953 
   954     app_registered = 1;
   955     return (0);
   956 }
   957 
   958 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   959 void
   960 SDL_UnregisterApp()
   961 {
   962     WNDCLASS class;
   963 
   964     /* SDL_RegisterApp might not have been called before */
   965     if (!app_registered) {
   966         return;
   967     }
   968     --app_registered;
   969     if (app_registered == 0) {
   970         /* Check for any registered window classes. */
   971         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   972             UnregisterClass(SDL_Appname, SDL_Instance);
   973         }
   974         SDL_free(SDL_Appname);
   975         SDL_Appname = NULL;
   976     }
   977 }
   978 
   979 /* Sets an error message based on GetLastError() */
   980 void
   981 WIN_SetError(const char *prefix)
   982 {
   983     TCHAR buffer[1024];
   984     char *message;
   985 
   986     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
   987                   NULL,
   988                   GetLastError(), 0, buffer, SDL_arraysize(buffer), NULL);
   989 
   990     message = WIN_StringToUTF8(buffer);
   991     SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ":" : "", message);
   992     SDL_free(message);
   993 }
   994 
   995 /* vi: set ts=4 sw=4 expandtab: */