src/video/win32/SDL_win32events.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 03 Jan 2009 06:12:05 +0000
changeset 2975 317b2f8e5e4f
parent 2974 d2f68ec8c1d0
child 2990 502adab079a4
permissions -rw-r--r--
Fixed bug #663
Fixed mouse wheel direction
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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     for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) {
    89         if (scancode == keypad_scancodes[i]) {
    90             wParam = VK_NUMPAD0 + i;
    91             break;
    92         }
    93     }
    94 
    95     return wParam;
    96 }
    97 
    98 LRESULT CALLBACK
    99 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   100 {
   101     SDL_WindowData *data;
   102     RAWINPUT *raw;
   103     PACKET packet;
   104 
   105     /* Send a SDL_SYSWMEVENT if the application wants them */
   106     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
   107         SDL_SysWMmsg wmmsg;
   108 
   109         SDL_VERSION(&wmmsg.version);
   110         wmmsg.hwnd = hwnd;
   111         wmmsg.msg = msg;
   112         wmmsg.wParam = wParam;
   113         wmmsg.lParam = lParam;
   114         SDL_SendSysWMEvent(&wmmsg);
   115     }
   116 
   117     /* Get the window data for the window */
   118     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   119     if (!data) {
   120         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   121     }
   122 #ifdef WMMSG_DEBUG
   123     {
   124         FILE *log = fopen("wmmsg.txt", "a");
   125         fprintf(log, "Received windows message: %p ", hwnd);
   126         if (msg > MAX_WMMSG) {
   127             fprintf(log, "%d", msg);
   128         } else {
   129             fprintf(log, "%s", wmtab[msg]);
   130         }
   131         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   132         fclose(log);
   133     }
   134 
   135 #endif
   136 
   137     switch (msg) {
   138 
   139     case WT_PACKET:
   140         {
   141             /* if we receive such data we need to update the pressure */
   142             SDL_VideoData *videodata = data->videodata;
   143             if (videodata->wintabDLL
   144                 && videodata->WTPacket((HCTX) lParam, wParam, &packet)) {
   145                 SDL_ChangeEnd(tablet, (int) packet.pkCursor);
   146                 pressure = (int) packet.pkNormalPressure;
   147             }
   148         }
   149         break;
   150 
   151     case WT_PROXIMITY:
   152         {
   153             /* checking where the proximity message showed up */
   154             int h_context = LOWORD(lParam);
   155             POINT point;
   156             GetCursorPos(&point);
   157             ScreenToClient(hwnd, &point);
   158 
   159             /* are we in proximity or out of proximity */
   160             if (h_context == 0) {
   161                 SDL_SendProximity(tablet, point.x, point.y, SDL_PROXIMITYOUT);
   162             } else {
   163                 SDL_SendProximity(tablet, point.x, point.y, SDL_PROXIMITYIN);
   164             }
   165         }
   166         break;
   167 
   168     case WM_SHOWWINDOW:
   169         {
   170             if (wParam) {
   171                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0,
   172                                     0);
   173             } else {
   174                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0,
   175                                     0);
   176             }
   177         }
   178         break;
   179 
   180     case WM_ACTIVATE:
   181         {
   182             int index;
   183             SDL_Keyboard *keyboard;
   184             BOOL minimized;
   185 
   186             minimized = HIWORD(wParam);
   187             index = data->videodata->keyboard;
   188             keyboard = SDL_GetKeyboard(index);
   189             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   190                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN,
   191                                     0, 0);
   192                 SDL_SendWindowEvent(data->windowID,
   193                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   194                 if (IsZoomed(hwnd)) {
   195                     SDL_SendWindowEvent(data->windowID,
   196                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   197                 }
   198                 if (keyboard && keyboard->focus != data->windowID) {
   199                     SDL_SetKeyboardFocus(index, data->windowID);
   200                 }
   201                 /* FIXME: Update keyboard state */
   202             } else {
   203                 if (keyboard && keyboard->focus == data->windowID) {
   204                     SDL_SetKeyboardFocus(index, 0);
   205                 }
   206                 if (minimized) {
   207                     SDL_SendWindowEvent(data->windowID,
   208                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   209                 }
   210             }
   211         }
   212         return (0);
   213 
   214     case WM_INPUT:             /* mouse events */
   215         {
   216             LPBYTE lpb;
   217             const RAWINPUTHEADER *header;
   218             int index;
   219             int i;
   220             int size = 0;
   221             const RAWMOUSE *raw_mouse = NULL;
   222             POINT point;
   223             USHORT flags;
   224             int w, h;
   225 
   226             /* we're collecting data from the mouse */
   227             GetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &size,
   228                             sizeof(RAWINPUTHEADER));
   229             lpb = SDL_stack_alloc(BYTE, size);
   230             GetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &size,
   231                             sizeof(RAWINPUTHEADER));
   232             raw = (RAWINPUT *) lpb;
   233             header = &raw->header;
   234             flags = raw->data.mouse.usButtonFlags;
   235 
   236             /* we're checking which mouse generated the event */
   237             for (i = 0; i < total_mice; ++i) {
   238                 if (mice[i] == header->hDevice) {
   239                     index = i;
   240                     break;
   241                 }
   242             }
   243 /* FIXME: Doesn't this defeat the point of using raw input? */
   244             GetCursorPos(&point);
   245             ScreenToClient(hwnd, &point);
   246 
   247             SDL_GetWindowSize(data->windowID, &w, &h);
   248             if (point.x >= 0 && point.y >= 0 && point.x < w && point.y < h) {
   249                 SDL_SetMouseFocus(index, data->windowID);
   250             } else {
   251                 SDL_SetMouseFocus(index, 0);
   252                 /* FIXME: Should we be doing anything else here? */
   253                 break;
   254             }
   255 
   256             /* if the message was sent by a tablet we have to send also pressure */
   257             if (index == tablet) {
   258                 SDL_SendMouseMotion(index, 0, point.x, point.y, pressure);
   259             } else {
   260                 SDL_SendMouseMotion(index, 0, point.x, point.y, 0);
   261             }
   262             /* we're sending mouse buttons messages to check up if sth changed */
   263             if (flags & RI_MOUSE_LEFT_BUTTON_DOWN) {
   264                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_LEFT);
   265             } else if (flags & RI_MOUSE_LEFT_BUTTON_UP) {
   266                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_LEFT);
   267             }
   268             if (flags & RI_MOUSE_MIDDLE_BUTTON_DOWN) {
   269                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_MIDDLE);
   270             } else if (flags & RI_MOUSE_MIDDLE_BUTTON_UP) {
   271                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_MIDDLE);
   272             }
   273             if (flags & RI_MOUSE_RIGHT_BUTTON_DOWN) {
   274                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_RIGHT);
   275             } else if (flags & RI_MOUSE_RIGHT_BUTTON_UP) {
   276                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_RIGHT);
   277             }
   278             if (flags & RI_MOUSE_BUTTON_4_DOWN) {
   279                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_X1);
   280             } else if (flags & RI_MOUSE_BUTTON_4_UP) {
   281                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_X1);
   282             }
   283             if (flags & RI_MOUSE_BUTTON_5_DOWN) {
   284                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_X2);
   285             } else if (flags & RI_MOUSE_BUTTON_5_UP) {
   286                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_X2);
   287             }
   288             if (flags & RI_MOUSE_WHEEL) {
   289                 SDL_SendMouseWheel(index, 0,
   290                                    (short)raw->data.mouse.usButtonData);
   291             }
   292             SDL_stack_free(lpb);
   293         }
   294         return (0);
   295 
   296     case WM_MOUSELEAVE:
   297         {
   298             int i;
   299 
   300             for (i = 0; i < SDL_GetNumMice(); ++i) {
   301                 SDL_Mouse *mouse = SDL_GetMouse(i);
   302 
   303                 if (mouse->focus == data->windowID) {
   304                     SDL_SetMouseFocus(i, 0);
   305                 }
   306             }
   307         }
   308         return (0);
   309 
   310     case WM_SYSKEYDOWN:
   311     case WM_KEYDOWN:
   312         {
   313             int index;
   314 
   315             /* Ignore repeated keys */
   316             if (lParam & REPEATED_KEYMASK) {
   317                 return (0);
   318             }
   319 
   320             index = data->videodata->keyboard;
   321             wParam = RemapVKEY(wParam, lParam);
   322             switch (wParam) {
   323             case VK_CONTROL:
   324                 if (lParam & EXTENDED_KEYMASK)
   325                     wParam = VK_RCONTROL;
   326                 else
   327                     wParam = VK_LCONTROL;
   328                 break;
   329             case VK_SHIFT:
   330                 /* EXTENDED trick doesn't work here */
   331                 {
   332                     Uint8 *state = SDL_GetKeyboardState(NULL);
   333                     if (state[SDL_SCANCODE_LSHIFT] == SDL_RELEASED
   334                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   335                         wParam = VK_LSHIFT;
   336                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_RELEASED
   337                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   338                         wParam = VK_RSHIFT;
   339                     } else {
   340                         /* Probably a key repeat */
   341                         return (0);
   342                     }
   343                 }
   344                 break;
   345             case VK_MENU:
   346                 if (lParam & EXTENDED_KEYMASK)
   347                     wParam = VK_RMENU;
   348                 else
   349                     wParam = VK_LMENU;
   350                 break;
   351             case VK_RETURN:
   352                 if (lParam & EXTENDED_KEYMASK)
   353                     wParam = VK_ENTER;
   354                 break;
   355             }
   356             if (wParam < 256) {
   357                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   358                                     data->videodata->key_layout[wParam]);
   359             }
   360         }
   361         return (0);
   362 
   363     case WM_SYSKEYUP:
   364     case WM_KEYUP:
   365         {
   366             int index;
   367 
   368             index = data->videodata->keyboard;
   369             wParam = RemapVKEY(wParam, lParam);
   370             switch (wParam) {
   371             case VK_CONTROL:
   372                 if (lParam & EXTENDED_KEYMASK)
   373                     wParam = VK_RCONTROL;
   374                 else
   375                     wParam = VK_LCONTROL;
   376                 break;
   377             case VK_SHIFT:
   378                 /* EXTENDED trick doesn't work here */
   379                 {
   380                     Uint8 *state = SDL_GetKeyboardState(NULL);
   381                     if (state[SDL_SCANCODE_LSHIFT] == SDL_PRESSED
   382                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   383                         wParam = VK_LSHIFT;
   384                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_PRESSED
   385                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   386                         wParam = VK_RSHIFT;
   387                     } else {
   388                         /* Probably a key repeat */
   389                         return (0);
   390                     }
   391                 }
   392                 break;
   393             case VK_MENU:
   394                 if (lParam & EXTENDED_KEYMASK)
   395                     wParam = VK_RMENU;
   396                 else
   397                     wParam = VK_LMENU;
   398                 break;
   399             case VK_RETURN:
   400                 if (lParam & EXTENDED_KEYMASK)
   401                     wParam = VK_ENTER;
   402                 break;
   403             }
   404 
   405             /* Windows only reports keyup for print screen */
   406             if (wParam == VK_SNAPSHOT
   407                 && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   408                 SDL_RELEASED) {
   409                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   410                                     data->videodata->key_layout[wParam]);
   411             }
   412             if (wParam < 256) {
   413                 SDL_SendKeyboardKey(index, SDL_RELEASED,
   414                                     data->videodata->key_layout[wParam]);
   415             }
   416         }
   417         return (0);
   418 
   419     case WM_CHAR:
   420         {
   421             char text[4];
   422 
   423             /* Convert to UTF-8 and send it on... */
   424             if (wParam <= 0x7F) {
   425                 text[0] = (char) wParam;
   426                 text[1] = '\0';
   427             } else if (wParam <= 0x7FF) {
   428                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   429                 text[1] = 0x80 | (char) (wParam & 0x3F);
   430                 text[2] = '\0';
   431             } else {
   432                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   433                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   434                 text[2] = 0x80 | (char) (wParam & 0x3F);
   435                 text[3] = '\0';
   436             }
   437             SDL_SendKeyboardText(data->videodata->keyboard, text);
   438         }
   439         return (0);
   440 
   441     case WM_INPUTLANGCHANGE:
   442         {
   443             WIN_UpdateKeymap(data->videodata->keyboard);
   444         }
   445         return (1);
   446 
   447     case WM_GETMINMAXINFO:
   448         {
   449             MINMAXINFO *info;
   450             RECT size;
   451             int x, y;
   452             int w, h;
   453             int style;
   454 
   455             /* If we allow resizing, let the resize happen naturally */
   456             if (SDL_GetWindowFlags(data->windowID) & SDL_WINDOW_RESIZABLE) {
   457                 return (0);
   458             }
   459 
   460             /* Get the current position of our window */
   461             GetWindowRect(hwnd, &size);
   462             x = size.left;
   463             y = size.top;
   464 
   465             /* Calculate current size of our window */
   466             SDL_GetWindowSize(data->windowID, &w, &h);
   467             size.top = 0;
   468             size.left = 0;
   469             size.bottom = h;
   470             size.right = w;
   471 
   472             /* DJM - according to the docs for GetMenu(), the
   473                return value is undefined if hwnd is a child window.
   474                Aparently it's too difficult for MS to check
   475                inside their function, so I have to do it here.
   476              */
   477             style = GetWindowLong(hwnd, GWL_STYLE);
   478             AdjustWindowRect(&size, style,
   479                              style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd)
   480                              != NULL);
   481             w = size.right - size.left;
   482             h = size.bottom - size.top;
   483 
   484             /* Fix our size to the current size */
   485             info = (MINMAXINFO *) lParam;
   486             info->ptMaxSize.x = w;
   487             info->ptMaxSize.y = h;
   488             info->ptMaxPosition.x = x;
   489             info->ptMaxPosition.y = y;
   490             info->ptMinTrackSize.x = w;
   491             info->ptMinTrackSize.y = h;
   492             info->ptMaxTrackSize.x = w;
   493             info->ptMaxTrackSize.y = h;
   494         }
   495         return (0);
   496 
   497     case WM_WINDOWPOSCHANGED:
   498         {
   499             RECT rect;
   500             int x, y;
   501             int w, h;
   502             Uint32 window_flags;
   503 
   504             GetClientRect(hwnd, &rect);
   505             ClientToScreen(hwnd, (LPPOINT) & rect);
   506             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   507 
   508             window_flags = SDL_GetWindowFlags(data->windowID);
   509             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   510                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   511                 ClipCursor(&rect);
   512             }
   513 
   514             x = rect.left;
   515             y = rect.top;
   516             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED, x, y);
   517 
   518             w = rect.right - rect.left;
   519             h = rect.bottom - rect.top;
   520             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED, w,
   521                                 h);
   522         }
   523         break;
   524 
   525     case WM_SETCURSOR:
   526         {
   527             /*
   528                Uint16 hittest;
   529 
   530                hittest = LOWORD(lParam);
   531                if (hittest == HTCLIENT) {
   532                SetCursor(SDL_hcursor);
   533                return (TRUE);
   534                }
   535              */
   536         }
   537         break;
   538 
   539         /* We are about to get palette focus! */
   540     case WM_QUERYNEWPALETTE:
   541         {
   542             /*
   543                WIN_RealizePalette(current_video);
   544                return (TRUE);
   545              */
   546         }
   547         break;
   548 
   549         /* Another application changed the palette */
   550     case WM_PALETTECHANGED:
   551         {
   552             /*
   553                WIN_PaletteChanged(current_video, (HWND) wParam);
   554              */
   555         }
   556         break;
   557 
   558         /* We were occluded, refresh our display */
   559     case WM_PAINT:
   560         {
   561             RECT rect;
   562             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   563                 ValidateRect(hwnd, &rect);
   564                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED,
   565                                     0, 0);
   566             }
   567         }
   568         return (0);
   569 
   570         /* We'll do our own drawing, prevent flicker */
   571     case WM_ERASEBKGND:
   572         {
   573         }
   574         return (1);
   575 
   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_GetWindowFlags(data->windowID) &
   582                     SDL_WINDOW_FULLSCREEN) {
   583                     return (0);
   584                 }
   585             }
   586         }
   587         break;
   588 
   589     case WM_CLOSE:
   590         {
   591             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0, 0);
   592         }
   593         return (0);
   594     }
   595     return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   596 }
   597 
   598 void
   599 WIN_PumpEvents(_THIS)
   600 {
   601     MSG msg;
   602     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   603         TranslateMessage(&msg);
   604         DispatchMessage(&msg);
   605     }
   606 }
   607 
   608 static int app_registered = 0;
   609 LPTSTR SDL_Appname = NULL;
   610 Uint32 SDL_Appstyle = 0;
   611 HINSTANCE SDL_Instance = NULL;
   612 
   613 /* Register the class for this application */
   614 int
   615 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   616 {
   617     WNDCLASS class;
   618 
   619     /* Only do this once... */
   620     if (app_registered) {
   621         ++app_registered;
   622         return (0);
   623     }
   624     if (!name && !SDL_Appname) {
   625         name = "SDL_app";
   626         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   627         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   628     }
   629 
   630     if (name) {
   631         SDL_Appname = WIN_UTF8ToString(name);
   632         SDL_Appstyle = style;
   633         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   634     }
   635 
   636     /* Register the application class */
   637     class.hCursor = NULL;
   638     class.hIcon =
   639         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   640                   LR_DEFAULTCOLOR);
   641     class.lpszMenuName = NULL;
   642     class.lpszClassName = SDL_Appname;
   643     class.hbrBackground = NULL;
   644     class.hInstance = SDL_Instance;
   645     class.style = SDL_Appstyle;
   646     class.lpfnWndProc = DefWindowProc;
   647     class.cbWndExtra = 0;
   648     class.cbClsExtra = 0;
   649     if (!RegisterClass(&class)) {
   650         SDL_SetError("Couldn't register application class");
   651         return (-1);
   652     }
   653 
   654     app_registered = 1;
   655     return (0);
   656 }
   657 
   658 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   659 void
   660 SDL_UnregisterApp()
   661 {
   662     WNDCLASS class;
   663 
   664     /* SDL_RegisterApp might not have been called before */
   665     if (!app_registered) {
   666         return;
   667     }
   668     --app_registered;
   669     if (app_registered == 0) {
   670         /* Check for any registered window classes. */
   671         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   672             UnregisterClass(SDL_Appname, SDL_Instance);
   673         }
   674         SDL_free(SDL_Appname);
   675         SDL_Appname = NULL;
   676     }
   677 }
   678 
   679 /* Sets an error message based on GetLastError() */
   680 void
   681 WIN_SetError(const char *prefix)
   682 {
   683     TCHAR buffer[1024];
   684     char *message;
   685     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
   686                   buffer, SDL_arraysize(buffer), NULL);
   687     message = WIN_StringToUTF8(buffer);
   688     SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ":" : "", message);
   689     SDL_free(message);
   690 }
   691 
   692 /* vi: set ts=4 sw=4 expandtab: */