src/video/win32/SDL_win32events.c
author Eli Gottlieb <eligottlieb@gmail.com>
Fri, 09 Jul 2010 20:24:44 -0400
changeset 4788 0bfda420c936
parent 4429 faa9fc8e7f67
child 4815 93402b9dd20c
permissions -rw-r--r--
Put in a couple of fixes that I realized hadn't gotten done when I wrote out the SCRUM stuff in TODO. Added SCRUM listings in TODO.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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 
    23 #if (_WIN32_WINNT < 0x0501)
    24 #undef _WIN32_WINNT
    25 #define _WIN32_WINNT 0x0501
    26 #endif
    27 
    28 #include "SDL_config.h"
    29 
    30 #include "SDL_win32video.h"
    31 #include "SDL_syswm.h"
    32 #include "SDL_vkeys.h"
    33 #include "../../events/SDL_events_c.h"
    34 
    35 /*#define WMMSG_DEBUG*/
    36 #ifdef WMMSG_DEBUG
    37 #include <stdio.h>
    38 #include "wmmsg.h"
    39 #endif
    40 
    41 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    42 #define REPEATED_KEYMASK    (1<<30)
    43 #define EXTENDED_KEYMASK    (1<<24)
    44 
    45 #define VK_ENTER    10          /* Keypad Enter ... no VKEY defined? */
    46 
    47 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
    48 #ifndef WM_XBUTTONDOWN
    49 #define WM_XBUTTONDOWN 0x020B
    50 #endif
    51 #ifndef WM_XBUTTONUP
    52 #define WM_XBUTTONUP 0x020C
    53 #endif
    54 #ifndef GET_XBUTTON_WPARAM
    55 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
    56 #endif
    57 #ifndef WM_INPUT
    58 #define WM_INPUT 0x00ff
    59 #endif
    60 
    61 extern HCTX *g_hCtx;
    62 extern HANDLE *mice;
    63 extern int total_mice;
    64 extern int tablet;
    65 int pressure = 0;               /* the pressure reported by the tablet */
    66 
    67 static WPARAM
    68 RemapVKEY(WPARAM wParam, LPARAM lParam)
    69 {
    70     int i;
    71     BYTE scancode = (BYTE) ((lParam >> 16) & 0xFF);
    72 
    73     /* Windows remaps alphabetic keys based on current layout.
    74        We try to provide USB scancodes, so undo this mapping.
    75      */
    76     if (wParam >= 'A' && wParam <= 'Z') {
    77         if (scancode != alpha_scancodes[wParam - 'A']) {
    78             for (i = 0; i < SDL_arraysize(alpha_scancodes); ++i) {
    79                 if (scancode == alpha_scancodes[i]) {
    80                     wParam = 'A' + i;
    81                     break;
    82                 }
    83             }
    84         }
    85     }
    86 
    87     /* Keypad keys are a little trickier, we always scan for them.
    88        Keypad arrow keys have the same scancode as normal arrow keys,
    89        except they don't have the extended bit (0x1000000) set.
    90      */
    91     if (!(lParam & 0x1000000)) {
    92         for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) {
    93             if (scancode == keypad_scancodes[i]) {
    94                 wParam = VK_NUMPAD0 + i;
    95                 break;
    96             }
    97         }
    98     }
    99 
   100     return wParam;
   101 }
   102 
   103 LRESULT CALLBACK
   104 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   105 {
   106     SDL_WindowData *data;
   107     RAWINPUT *raw;
   108     PACKET packet;
   109     LRESULT returnCode = -1;
   110 
   111     /* Send a SDL_SYSWMEVENT if the application wants them */
   112     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   113         SDL_SysWMmsg wmmsg;
   114 
   115         SDL_VERSION(&wmmsg.version);
   116         wmmsg.hwnd = hwnd;
   117         wmmsg.msg = msg;
   118         wmmsg.wParam = wParam;
   119         wmmsg.lParam = lParam;
   120         SDL_SendSysWMEvent(&wmmsg);
   121     }
   122 
   123     /* Get the window data for the window */
   124     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   125     if (!data) {
   126         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   127     }
   128 #ifdef WMMSG_DEBUG
   129     {
   130         FILE *log = fopen("wmmsg.txt", "a");
   131         fprintf(log, "Received windows message: %p ", hwnd);
   132         if (msg > MAX_WMMSG) {
   133             fprintf(log, "%d", msg);
   134         } else {
   135             fprintf(log, "%s", wmtab[msg]);
   136         }
   137         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   138         fclose(log);
   139     }
   140 
   141 #endif
   142 
   143     switch (msg) {
   144 
   145     case WT_PACKET:
   146         {
   147             /* if we receive such data we need to update the pressure */
   148             SDL_VideoData *videodata = data->videodata;
   149             if (videodata->wintabDLL
   150                 && videodata->WTPacket((HCTX) lParam, (UINT) wParam, &packet)) {
   151                 SDL_ChangeEnd(tablet, (int) packet.pkCursor);
   152                 pressure = (int) packet.pkNormalPressure;
   153             }
   154         }
   155         break;
   156 
   157     case WT_PROXIMITY:
   158         {
   159             /* checking where the proximity message showed up */
   160             int h_context = LOWORD(lParam);
   161             POINT point;
   162             GetCursorPos(&point);
   163             ScreenToClient(hwnd, &point);
   164 
   165             /* are we in proximity or out of proximity */
   166             if (h_context == 0) {
   167                 SDL_SendProximity(tablet, point.x, point.y, SDL_PROXIMITYOUT);
   168             } else {
   169                 SDL_SendProximity(tablet, point.x, point.y, SDL_PROXIMITYIN);
   170             }
   171         }
   172         break;
   173 
   174     case WM_SHOWWINDOW:
   175         {
   176             if (wParam) {
   177                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   178             } else {
   179                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   180             }
   181         }
   182         break;
   183 
   184     case WM_ACTIVATE:
   185         {
   186             int index;
   187             SDL_Keyboard *keyboard;
   188             BOOL minimized;
   189 
   190             minimized = HIWORD(wParam);
   191             index = data->videodata->keyboard;
   192             keyboard = SDL_GetKeyboard(index);
   193             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   194                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   195                 SDL_SendWindowEvent(data->window,
   196                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   197 #ifndef _WIN32_WCE              /* WinCE misses IsZoomed() */
   198                 if (IsZoomed(hwnd)) {
   199                     SDL_SendWindowEvent(data->window,
   200                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   201                 }
   202 #endif
   203                 if (keyboard && keyboard->focus != data->window) {
   204                     SDL_SetKeyboardFocus(index, data->window);
   205                 }
   206                 /* FIXME: Update keyboard state */
   207             } else {
   208                 if (keyboard && keyboard->focus == data->window) {
   209                     SDL_SetKeyboardFocus(index, 0);
   210                 }
   211                 if (minimized) {
   212                     SDL_SendWindowEvent(data->window,
   213                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   214                 }
   215             }
   216         }
   217         returnCode = 0;
   218         break;
   219 
   220 /* WinCE has no RawInput, so we use the classic mouse events.
   221    In classic Win32 this is done by WM_INPUT
   222  */
   223 #ifdef _WIN32_WCE
   224     case WM_MOUSEMOVE:
   225         SDL_SendMouseMotion(0, 0, LOWORD(lParam), HIWORD(lParam), 0);
   226         break;
   227 
   228     case WM_LBUTTONDOWN:
   229         SDL_SendMouseMotion(0, 0, LOWORD(lParam), HIWORD(lParam), 0);
   230         SDL_SendMouseButton(0, SDL_PRESSED, SDL_BUTTON_LEFT);
   231         break;
   232 
   233     case WM_LBUTTONUP:
   234         SDL_SendMouseMotion(0, 0, LOWORD(lParam), HIWORD(lParam), 0);
   235         SDL_SendMouseButton(0, SDL_RELEASED, SDL_BUTTON_LEFT);
   236         break;
   237 #else /* _WIN32_WCE */
   238 
   239     case WM_INPUT:             /* mouse events */
   240         {
   241             LPBYTE lpb;
   242             const RAWINPUTHEADER *header;
   243             int index = -1;
   244             int i;
   245             int size = 0;
   246             const RAWMOUSE *raw_mouse = NULL;
   247             POINT point;
   248             USHORT flags;
   249             int w, h;
   250 
   251             /* we're collecting raw data to be able to identify the mouse (if there are several) */
   252             GetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &size,
   253                             sizeof(RAWINPUTHEADER));
   254             lpb = SDL_stack_alloc(BYTE, size);
   255             GetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &size,
   256                             sizeof(RAWINPUTHEADER));
   257             raw = (RAWINPUT *) lpb;
   258             header = &raw->header;
   259             flags = raw->data.mouse.usButtonFlags;
   260 
   261             /* we're checking which mouse generated the event */
   262             for (i = 0; i < total_mice; ++i) {
   263                 if (mice[i] == header->hDevice) {
   264                     index = i;
   265                     break;
   266                 }
   267             }
   268             if (index < 0) {
   269                 /* New mouse?  Should we dynamically update mouse list? */
   270                 returnCode = 0;
   271                 break;
   272             }
   273 
   274             GetCursorPos(&point);
   275             ScreenToClient(hwnd, &point);
   276 
   277             SDL_GetWindowSize(data->window, &w, &h);
   278             if (point.x >= 0 && point.y >= 0 && point.x < w && point.y < h) {
   279                 SDL_SetMouseFocus(index, data->window);
   280             } else {
   281                 SDL_SetMouseFocus(index, 0);
   282                 /* FIXME: Should we be doing anything else here? */
   283                 break;
   284             }
   285 
   286             /* if the message was sent by a tablet we have to send also pressure */
   287             if (index == tablet) {
   288                 SDL_SendMouseMotion(index, 0, point.x, point.y, pressure);
   289             } else {
   290                 SDL_SendMouseMotion(index, 0, point.x, point.y, 0);
   291             }
   292             /* we're sending mouse buttons messages to check up if sth changed */
   293             if (flags & RI_MOUSE_LEFT_BUTTON_DOWN) {
   294                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_LEFT);
   295             } else if (flags & RI_MOUSE_LEFT_BUTTON_UP) {
   296                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_LEFT);
   297             }
   298             if (flags & RI_MOUSE_MIDDLE_BUTTON_DOWN) {
   299                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_MIDDLE);
   300             } else if (flags & RI_MOUSE_MIDDLE_BUTTON_UP) {
   301                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_MIDDLE);
   302             }
   303             if (flags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
   304                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_RIGHT);
   305             } else if (flags & RI_MOUSE_RIGHT_BUTTON_UP) {
   306                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_RIGHT);
   307             }
   308             if (flags & RI_MOUSE_BUTTON_4_DOWN) {
   309                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_X1);
   310             } else if (flags & RI_MOUSE_BUTTON_4_UP) {
   311                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_X1);
   312             }
   313             if (flags & RI_MOUSE_BUTTON_5_DOWN) {
   314                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_X2);
   315             } else if (flags & RI_MOUSE_BUTTON_5_UP) {
   316                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_X2);
   317             }
   318             if (flags & RI_MOUSE_WHEEL) {
   319                 SDL_SendMouseWheel(index, 0,
   320                                    (short) raw->data.mouse.usButtonData);
   321             }
   322             SDL_stack_free(lpb);
   323         }
   324         returnCode = 0;
   325         break;
   326 #endif /* _WIN32_WCE */
   327 
   328     case WM_MOUSELEAVE:
   329         {
   330             int i;
   331 
   332             for (i = 0; i < SDL_GetNumMice(); ++i) {
   333                 SDL_Mouse *mouse = SDL_GetMouse(i);
   334 
   335                 if (mouse->focus == data->window) {
   336                     SDL_SetMouseFocus(i, 0);
   337                 }
   338             }
   339         }
   340         returnCode = 0;
   341         break;
   342 
   343     case WM_SYSKEYDOWN:
   344     case WM_KEYDOWN:
   345         {
   346             int index;
   347 
   348             /* Ignore repeated keys */
   349             if (lParam & REPEATED_KEYMASK) {
   350                 returnCode = 0;
   351                 break;
   352             }
   353 
   354             index = data->videodata->keyboard;
   355             wParam = RemapVKEY(wParam, lParam);
   356             switch (wParam) {
   357             case VK_CONTROL:
   358                 if (lParam & EXTENDED_KEYMASK)
   359                     wParam = VK_RCONTROL;
   360                 else
   361                     wParam = VK_LCONTROL;
   362                 break;
   363             case VK_SHIFT:
   364                 /* EXTENDED trick doesn't work here */
   365                 {
   366                     Uint8 *state = SDL_GetKeyboardState(NULL);
   367                     if (state[SDL_SCANCODE_LSHIFT] == SDL_RELEASED
   368                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   369                         wParam = VK_LSHIFT;
   370                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_RELEASED
   371                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   372                         wParam = VK_RSHIFT;
   373                     } else {
   374                         /* Probably a key repeat */
   375                         wParam = 256;
   376                     }
   377                 }
   378                 break;
   379             case VK_MENU:
   380                 if (lParam & EXTENDED_KEYMASK)
   381                     wParam = VK_RMENU;
   382                 else
   383                     wParam = VK_LMENU;
   384                 break;
   385             case VK_RETURN:
   386                 if (lParam & EXTENDED_KEYMASK)
   387                     wParam = VK_ENTER;
   388                 break;
   389             }
   390             if (wParam < 256) {
   391                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   392                                     data->videodata->key_layout[wParam]);
   393             }
   394         }
   395         returnCode = 0;
   396         break;
   397 
   398     case WM_SYSKEYUP:
   399     case WM_KEYUP:
   400         {
   401             int index;
   402 
   403             index = data->videodata->keyboard;
   404             wParam = RemapVKEY(wParam, lParam);
   405             switch (wParam) {
   406             case VK_CONTROL:
   407                 if (lParam & EXTENDED_KEYMASK)
   408                     wParam = VK_RCONTROL;
   409                 else
   410                     wParam = VK_LCONTROL;
   411                 break;
   412             case VK_SHIFT:
   413                 /* EXTENDED trick doesn't work here */
   414                 {
   415                     Uint8 *state = SDL_GetKeyboardState(NULL);
   416                     if (state[SDL_SCANCODE_LSHIFT] == SDL_PRESSED
   417                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   418                         wParam = VK_LSHIFT;
   419                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_PRESSED
   420                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   421                         wParam = VK_RSHIFT;
   422                     } else {
   423                         /* Probably a key repeat */
   424                         wParam = 256;
   425                     }
   426                 }
   427                 break;
   428             case VK_MENU:
   429                 if (lParam & EXTENDED_KEYMASK)
   430                     wParam = VK_RMENU;
   431                 else
   432                     wParam = VK_LMENU;
   433                 break;
   434             case VK_RETURN:
   435                 if (lParam & EXTENDED_KEYMASK)
   436                     wParam = VK_ENTER;
   437                 break;
   438             }
   439 
   440             /* Windows only reports keyup for print screen */
   441             if (wParam == VK_SNAPSHOT
   442                 && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   443                 SDL_RELEASED) {
   444                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   445                                     data->videodata->key_layout[wParam]);
   446             }
   447             if (wParam < 256) {
   448                 SDL_SendKeyboardKey(index, SDL_RELEASED,
   449                                     data->videodata->key_layout[wParam]);
   450             }
   451         }
   452         returnCode = 0;
   453         break;
   454 
   455     case WM_CHAR:
   456         {
   457             char text[4];
   458 
   459             /* Convert to UTF-8 and send it on... */
   460             if (wParam <= 0x7F) {
   461                 text[0] = (char) wParam;
   462                 text[1] = '\0';
   463             } else if (wParam <= 0x7FF) {
   464                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   465                 text[1] = 0x80 | (char) (wParam & 0x3F);
   466                 text[2] = '\0';
   467             } else {
   468                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   469                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   470                 text[2] = 0x80 | (char) (wParam & 0x3F);
   471                 text[3] = '\0';
   472             }
   473             SDL_SendKeyboardText(data->videodata->keyboard, text);
   474         }
   475         returnCode = 0;
   476         break;
   477 
   478     case WM_INPUTLANGCHANGE:
   479         {
   480             WIN_UpdateKeymap(data->videodata->keyboard);
   481         }
   482         returnCode = 1;
   483         break;
   484 
   485     case WM_GETMINMAXINFO:
   486         {
   487             MINMAXINFO *info;
   488             RECT size;
   489             int x, y;
   490             int w, h;
   491             int style;
   492             BOOL menu;
   493 
   494             /* If we allow resizing, let the resize happen naturally */
   495             if(SDL_IsShapedWindow(data->window))
   496                 SDL_ResizeWindowShape(data->window);
   497             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   498                 returnCode = 0;
   499                 break;
   500             }
   501 
   502             /* Get the current position of our window */
   503             GetWindowRect(hwnd, &size);
   504             x = size.left;
   505             y = size.top;
   506 
   507             /* Calculate current size of our window */
   508             SDL_GetWindowSize(data->window, &w, &h);
   509             size.top = 0;
   510             size.left = 0;
   511             size.bottom = h;
   512             size.right = w;
   513 
   514 
   515             style = GetWindowLong(hwnd, GWL_STYLE);
   516 #ifdef _WIN32_WCE
   517             menu = FALSE;
   518 #else
   519             /* DJM - according to the docs for GetMenu(), the
   520                return value is undefined if hwnd is a child window.
   521                Aparently it's too difficult for MS to check
   522                inside their function, so I have to do it here.
   523              */
   524             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   525 #endif
   526             AdjustWindowRectEx(&size, style, menu, 0);
   527             w = size.right - size.left;
   528             h = size.bottom - size.top;
   529 
   530             /* Fix our size to the current size */
   531             info = (MINMAXINFO *) lParam;
   532             info->ptMaxSize.x = w;
   533             info->ptMaxSize.y = h;
   534             info->ptMaxPosition.x = x;
   535             info->ptMaxPosition.y = y;
   536             info->ptMinTrackSize.x = w;
   537             info->ptMinTrackSize.y = h;
   538             info->ptMaxTrackSize.x = w;
   539             info->ptMaxTrackSize.y = h;
   540         }
   541         returnCode = 0;
   542         break;
   543 
   544     case WM_WINDOWPOSCHANGED:
   545         {
   546             RECT rect;
   547             int x, y;
   548             int w, h;
   549             Uint32 window_flags;
   550 
   551             if (!GetClientRect(hwnd, &rect) ||
   552                 (rect.right == rect.left && rect.bottom == rect.top)) {
   553                 break;
   554             }
   555             ClientToScreen(hwnd, (LPPOINT) & rect);
   556             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   557 
   558             window_flags = SDL_GetWindowFlags(data->window);
   559             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   560                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   561                 ClipCursor(&rect);
   562             }
   563 
   564             x = rect.left;
   565             y = rect.top;
   566             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   567 
   568             w = rect.right - rect.left;
   569             h = rect.bottom - rect.top;
   570             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   571                                 h);
   572         }
   573         break;
   574 
   575     case WM_SETCURSOR:
   576         {
   577             Uint16 hittest;
   578 
   579             hittest = LOWORD(lParam);
   580             if (hittest == HTCLIENT) {
   581                 /* FIXME: Implement the cursor API */
   582                 static HCURSOR cursor;
   583                 if (!cursor) {
   584                     cursor = LoadCursor(NULL, IDC_ARROW);
   585                 }
   586                 SetCursor(cursor);
   587                 returnCode = TRUE;
   588             }
   589         }
   590         break;
   591 
   592         /* We are about to get palette focus! */
   593     case WM_QUERYNEWPALETTE:
   594         {
   595             /*
   596                 WIN_RealizePalette(current_video);
   597                 returnCode = TRUE;
   598              */
   599         }
   600         break;
   601 
   602         /* Another application changed the palette */
   603     case WM_PALETTECHANGED:
   604         {
   605             /*
   606                WIN_PaletteChanged(current_video, (HWND) wParam);
   607              */
   608         }
   609         break;
   610 
   611         /* We were occluded, refresh our display */
   612     case WM_PAINT:
   613         {
   614             RECT rect;
   615             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   616                 ValidateRect(hwnd, &rect);
   617                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   618                                     0, 0);
   619             }
   620         }
   621         returnCode = 0;
   622         break;
   623 
   624         /* We'll do our own drawing, prevent flicker */
   625     case WM_ERASEBKGND:
   626         {
   627         }
   628         return (1);
   629 
   630     case WM_SYSCOMMAND:
   631         {
   632             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   633             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   634                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   635                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   636                     return (0);
   637                 }
   638             }
   639         }
   640         break;
   641 
   642     case WM_CLOSE:
   643         {
   644             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   645         }
   646         returnCode = 0;
   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         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   689         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   690     }
   691 
   692     if (name) {
   693         SDL_Appname = WIN_UTF8ToString(name);
   694         SDL_Appstyle = style;
   695         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   696     }
   697 
   698     /* Register the application class */
   699     class.hCursor = NULL;
   700     class.hIcon =
   701         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   702                   LR_DEFAULTCOLOR);
   703     class.lpszMenuName = NULL;
   704     class.lpszClassName = SDL_Appname;
   705     class.hbrBackground = NULL;
   706     class.hInstance = SDL_Instance;
   707     class.style = SDL_Appstyle;
   708     class.lpfnWndProc = DefWindowProc;
   709     class.cbWndExtra = 0;
   710     class.cbClsExtra = 0;
   711     if (!RegisterClass(&class)) {
   712         SDL_SetError("Couldn't register application class");
   713         return (-1);
   714     }
   715 
   716     app_registered = 1;
   717     return (0);
   718 }
   719 
   720 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   721 void
   722 SDL_UnregisterApp()
   723 {
   724     WNDCLASS class;
   725 
   726     /* SDL_RegisterApp might not have been called before */
   727     if (!app_registered) {
   728         return;
   729     }
   730     --app_registered;
   731     if (app_registered == 0) {
   732         /* Check for any registered window classes. */
   733         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   734             UnregisterClass(SDL_Appname, SDL_Instance);
   735         }
   736         SDL_free(SDL_Appname);
   737         SDL_Appname = NULL;
   738     }
   739 }
   740 
   741 /* Sets an error message based on GetLastError() */
   742 void
   743 WIN_SetError(const char *prefix)
   744 {
   745     TCHAR buffer[1024];
   746     char *message;
   747     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
   748                   buffer, SDL_arraysize(buffer), NULL);
   749     message = WIN_StringToUTF8(buffer);
   750     SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message);
   751     SDL_free(message);
   752 }
   753 
   754 /* vi: set ts=4 sw=4 expandtab: */