src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 14 Aug 2017 21:28:04 -0700
changeset 11300 68a80d7afec3
parent 11261 2d458a198021
child 11528 80328fb347c8
permissions -rw-r--r--
Fixed bug 2293 - Precise scrolling events

Martijn Courteaux

I implemented precise scrolling events. I have been through all the folders in /src/video/[platform] to implement where possible. This works on OS X, but I can't speak for others. Build farm will figure that out, I guess. I think this patch should introduce precise scrolling on OS X, Wayland, Mir, Windows, Android, Nacl, Windows RT.

The way I provide precise scrolling events is by adding two float fields to the SDL_MouseWheelScrollEvent datastructure, called "preciseX" and "preciseY". The old integer fields "x" and "y" are still present. The idea is that every platform specific code normalises the scroll amounts and forwards them to the SDL_SendMouseWheel function. It is this function that will now accumulate these (using a static variable, as I have seen how it was implemented in the Windows specific code) and once we hit a unit size, set the traditional integer "x" and "y" fields.

I believe this is pretty solid way of doing it, although I'm not the expert here.

There is also a fix in the patch for a typo recently introduced, that might need to be taken away by the time anybody merges this in. There is also a file in Nacl which I have stripped a horrible amount of trailing whitespaces. (Leave that part out if you want).
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1895
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1895
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1895
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@2710
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_WINDOWS
slouken@1895
    24
slouken@5062
    25
#include "SDL_windowsvideo.h"
slouken@5062
    26
#include "SDL_windowsshape.h"
slouken@9597
    27
#include "SDL_system.h"
slouken@1895
    28
#include "SDL_syswm.h"
slouken@8218
    29
#include "SDL_timer.h"
slouken@1895
    30
#include "SDL_vkeys.h"
slouken@11261
    31
#include "SDL_hints.h"
slouken@1895
    32
#include "../../events/SDL_events_c.h"
slouken@4919
    33
#include "../../events/SDL_touch_c.h"
slouken@6938
    34
#include "../../events/scancodes_windows.h"
icculus@8942
    35
#include "SDL_assert.h"
andrewb@9829
    36
#include "SDL_hints.h"
slouken@1895
    37
slouken@6523
    38
/* Dropfile support */
slouken@6523
    39
#include <shellapi.h>
slouken@6523
    40
jorgen@7276
    41
/* For GET_X_LPARAM, GET_Y_LPARAM. */
jorgen@7276
    42
#include <windowsx.h>
slouken@6523
    43
gabomdq@7678
    44
/* #define WMMSG_DEBUG */
slouken@1895
    45
#ifdef WMMSG_DEBUG
slouken@7191
    46
#include <stdio.h>
slouken@1895
    47
#include "wmmsg.h"
slouken@1895
    48
#endif
slouken@1895
    49
dludwig@9668
    50
/* For processing mouse WM_*BUTTON* and WM_MOUSEMOVE message-data from GetMessageExtraInfo() */
dludwig@9668
    51
#define MOUSEEVENTF_FROMTOUCH 0xFF515700
dludwig@9668
    52
slouken@1895
    53
/* Masks for processing the windows KEYDOWN and KEYUP messages */
slouken@2317
    54
#define REPEATED_KEYMASK    (1<<30)
slouken@2317
    55
#define EXTENDED_KEYMASK    (1<<24)
slouken@1895
    56
bob@2324
    57
#define VK_ENTER    10          /* Keypad Enter ... no VKEY defined? */
slouken@6931
    58
#ifndef VK_OEM_NEC_EQUAL
slouken@7191
    59
#define VK_OEM_NEC_EQUAL 0x92
slouken@6931
    60
#endif
slouken@2313
    61
icculus@2127
    62
/* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
icculus@2127
    63
#ifndef WM_XBUTTONDOWN
icculus@2127
    64
#define WM_XBUTTONDOWN 0x020B
icculus@2127
    65
#endif
icculus@2127
    66
#ifndef WM_XBUTTONUP
icculus@2127
    67
#define WM_XBUTTONUP 0x020C
icculus@2127
    68
#endif
icculus@2127
    69
#ifndef GET_XBUTTON_WPARAM
icculus@2127
    70
#define GET_XBUTTON_WPARAM(w) (HIWORD(w))
icculus@2127
    71
#endif
bobbens@2733
    72
#ifndef WM_INPUT
bobbens@2733
    73
#define WM_INPUT 0x00ff
bobbens@2733
    74
#endif
slouken@4932
    75
#ifndef WM_TOUCH
slouken@4868
    76
#define WM_TOUCH 0x0240
slouken@4932
    77
#endif
slouken@7911
    78
#ifndef WM_MOUSEHWHEEL
slouken@7911
    79
#define WM_MOUSEHWHEEL 0x020E
slouken@7911
    80
#endif
slouken@8624
    81
#ifndef WM_UNICHAR
slouken@8624
    82
#define WM_UNICHAR 0x0109
slouken@8624
    83
#endif
slouken@4919
    84
slouken@7191
    85
static SDL_Scancode
michael@11241
    86
VKeytoScancode(WPARAM vkey)
michael@11241
    87
{
michael@11241
    88
    switch (vkey) {
michael@11241
    89
    case VK_CLEAR: return SDL_SCANCODE_CLEAR;
michael@11241
    90
    case VK_MODECHANGE: return SDL_SCANCODE_MODE;
michael@11241
    91
    case VK_SELECT: return SDL_SCANCODE_SELECT;
michael@11241
    92
    case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
michael@11241
    93
    case VK_HELP: return SDL_SCANCODE_HELP;
michael@11241
    94
    case VK_PAUSE: return SDL_SCANCODE_PAUSE;
michael@11241
    95
    case VK_NUMLOCK: return SDL_SCANCODE_NUMLOCKCLEAR;
michael@11241
    96
michael@11241
    97
    case VK_F13: return SDL_SCANCODE_F13;
michael@11241
    98
    case VK_F14: return SDL_SCANCODE_F14;
michael@11241
    99
    case VK_F15: return SDL_SCANCODE_F15;
michael@11241
   100
    case VK_F16: return SDL_SCANCODE_F16;
michael@11241
   101
    case VK_F17: return SDL_SCANCODE_F17;
michael@11241
   102
    case VK_F18: return SDL_SCANCODE_F18;
michael@11241
   103
    case VK_F19: return SDL_SCANCODE_F19;
michael@11241
   104
    case VK_F20: return SDL_SCANCODE_F20;
michael@11241
   105
    case VK_F21: return SDL_SCANCODE_F21;
michael@11241
   106
    case VK_F22: return SDL_SCANCODE_F22;
michael@11241
   107
    case VK_F23: return SDL_SCANCODE_F23;
michael@11241
   108
    case VK_F24: return SDL_SCANCODE_F24;
michael@11241
   109
michael@11241
   110
    case VK_OEM_NEC_EQUAL: return SDL_SCANCODE_KP_EQUALS;
michael@11241
   111
    case VK_BROWSER_BACK: return SDL_SCANCODE_AC_BACK;
michael@11241
   112
    case VK_BROWSER_FORWARD: return SDL_SCANCODE_AC_FORWARD;
michael@11241
   113
    case VK_BROWSER_REFRESH: return SDL_SCANCODE_AC_REFRESH;
michael@11241
   114
    case VK_BROWSER_STOP: return SDL_SCANCODE_AC_STOP;
michael@11241
   115
    case VK_BROWSER_SEARCH: return SDL_SCANCODE_AC_SEARCH;
michael@11241
   116
    case VK_BROWSER_FAVORITES: return SDL_SCANCODE_AC_BOOKMARKS;
michael@11241
   117
    case VK_BROWSER_HOME: return SDL_SCANCODE_AC_HOME;
michael@11241
   118
    case VK_VOLUME_MUTE: return SDL_SCANCODE_AUDIOMUTE;
michael@11241
   119
    case VK_VOLUME_DOWN: return SDL_SCANCODE_VOLUMEDOWN;
michael@11241
   120
    case VK_VOLUME_UP: return SDL_SCANCODE_VOLUMEUP;
michael@11241
   121
michael@11241
   122
    case VK_MEDIA_NEXT_TRACK: return SDL_SCANCODE_AUDIONEXT;
michael@11241
   123
    case VK_MEDIA_PREV_TRACK: return SDL_SCANCODE_AUDIOPREV;
michael@11241
   124
    case VK_MEDIA_STOP: return SDL_SCANCODE_AUDIOSTOP;
michael@11241
   125
    case VK_MEDIA_PLAY_PAUSE: return SDL_SCANCODE_AUDIOPLAY;
michael@11241
   126
    case VK_LAUNCH_MAIL: return SDL_SCANCODE_MAIL;
michael@11241
   127
    case VK_LAUNCH_MEDIA_SELECT: return SDL_SCANCODE_MEDIASELECT;
michael@11241
   128
michael@11241
   129
    case VK_OEM_102: return SDL_SCANCODE_NONUSBACKSLASH;
michael@11241
   130
michael@11241
   131
    case VK_ATTN: return SDL_SCANCODE_SYSREQ;
michael@11241
   132
    case VK_CRSEL: return SDL_SCANCODE_CRSEL;
michael@11241
   133
    case VK_EXSEL: return SDL_SCANCODE_EXSEL;
michael@11241
   134
    case VK_OEM_CLEAR: return SDL_SCANCODE_CLEAR;
michael@11241
   135
michael@11241
   136
    case VK_LAUNCH_APP1: return SDL_SCANCODE_APP1;
michael@11241
   137
    case VK_LAUNCH_APP2: return SDL_SCANCODE_APP2;
michael@11241
   138
michael@11241
   139
    default: return SDL_SCANCODE_UNKNOWN;
michael@11241
   140
    }
michael@11241
   141
}
michael@11241
   142
michael@11241
   143
static SDL_Scancode
slouken@8813
   144
WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam)
jorgen@6922
   145
{
slouken@7191
   146
    SDL_Scancode code;
slouken@8813
   147
    int nScanCode = (lParam >> 16) & 0xFF;
slouken@11242
   148
    SDL_bool bIsExtended = (lParam & (1 << 24)) != 0;
jorgen@6922
   149
slouken@11242
   150
    code = VKeytoScancode(wParam);
jorgen@6922
   151
slouken@11242
   152
    if (code == SDL_SCANCODE_UNKNOWN && nScanCode <= 127) {
slouken@11242
   153
        code = windows_scancode_table[nScanCode];
slouken@7191
   154
slouken@11242
   155
        if (bIsExtended) {
slouken@11242
   156
            switch (code) {
slouken@11242
   157
            case SDL_SCANCODE_RETURN:
slouken@11242
   158
                code = SDL_SCANCODE_KP_ENTER;
slouken@11242
   159
                break;
slouken@11242
   160
            case SDL_SCANCODE_LALT:
slouken@11242
   161
                code = SDL_SCANCODE_RALT;
slouken@11242
   162
                break;
slouken@11242
   163
            case SDL_SCANCODE_LCTRL:
slouken@11242
   164
                code = SDL_SCANCODE_RCTRL;
slouken@11242
   165
                break;
slouken@11242
   166
            case SDL_SCANCODE_SLASH:
slouken@11242
   167
                code = SDL_SCANCODE_KP_DIVIDE;
slouken@11242
   168
                break;
slouken@11242
   169
            case SDL_SCANCODE_CAPSLOCK:
slouken@11242
   170
                code = SDL_SCANCODE_KP_PLUS;
slouken@11242
   171
                break;
slouken@11242
   172
            default:
slouken@11242
   173
                break;
slouken@11242
   174
            }
michael@11241
   175
        } else {
michael@11241
   176
            switch (code) {
slouken@11242
   177
            case SDL_SCANCODE_HOME:
slouken@11242
   178
                code = SDL_SCANCODE_KP_7;
slouken@11242
   179
                break;
slouken@11242
   180
            case SDL_SCANCODE_UP:
slouken@11242
   181
                code = SDL_SCANCODE_KP_8;
slouken@11242
   182
                break;
slouken@11242
   183
            case SDL_SCANCODE_PAGEUP:
slouken@11242
   184
                code = SDL_SCANCODE_KP_9;
slouken@11242
   185
                break;
slouken@11242
   186
            case SDL_SCANCODE_LEFT:
slouken@11242
   187
                code = SDL_SCANCODE_KP_4;
slouken@11242
   188
                break;
slouken@11242
   189
            case SDL_SCANCODE_RIGHT:
slouken@11242
   190
                code = SDL_SCANCODE_KP_6;
slouken@11242
   191
                break;
slouken@11242
   192
            case SDL_SCANCODE_END:
slouken@11242
   193
                code = SDL_SCANCODE_KP_1;
slouken@11242
   194
                break;
slouken@11242
   195
            case SDL_SCANCODE_DOWN:
slouken@11242
   196
                code = SDL_SCANCODE_KP_2;
slouken@11242
   197
                break;
slouken@11242
   198
            case SDL_SCANCODE_PAGEDOWN:
slouken@11242
   199
                code = SDL_SCANCODE_KP_3;
slouken@11242
   200
                break;
slouken@11242
   201
            case SDL_SCANCODE_INSERT:
slouken@11242
   202
                code = SDL_SCANCODE_KP_0;
slouken@11242
   203
                break;
slouken@11242
   204
            case SDL_SCANCODE_DELETE:
slouken@11242
   205
                code = SDL_SCANCODE_KP_PERIOD;
slouken@11242
   206
                break;
slouken@11242
   207
            case SDL_SCANCODE_PRINTSCREEN:
slouken@11242
   208
                code = SDL_SCANCODE_KP_MULTIPLY;
slouken@11242
   209
                break;
michael@11241
   210
            default:
michael@11241
   211
                break;
michael@11241
   212
            }
slouken@7191
   213
        }
slouken@7191
   214
    }
slouken@7191
   215
    return code;
jorgen@6922
   216
}
jorgen@6922
   217
slouken@10379
   218
static SDL_bool
slouken@10379
   219
WIN_ShouldIgnoreFocusClick()
slouken@10379
   220
{
slouken@10499
   221
    return !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE);
slouken@10379
   222
}
jorgen@6922
   223
philipp@10982
   224
static void
dludwig@9668
   225
WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID)
slouken@6943
   226
{
slouken@10377
   227
    if (data->focus_click_pending & SDL_BUTTON(button)) {
slouken@10377
   228
        /* Ignore the button click for activation */
slouken@10377
   229
        if (!bwParamMousePressed) {
slouken@10377
   230
            data->focus_click_pending &= ~SDL_BUTTON(button);
slouken@10377
   231
            if (!data->focus_click_pending) {
slouken@10377
   232
                WIN_UpdateClipCursor(data->window);
slouken@10377
   233
            }
slouken@10377
   234
        }
slouken@10379
   235
        if (WIN_ShouldIgnoreFocusClick()) {
slouken@10379
   236
            return;
slouken@10379
   237
        }
slouken@8916
   238
    }
slouken@8916
   239
slouken@8813
   240
    if (bwParamMousePressed && !bSDLMousePressed) {
dludwig@9668
   241
        SDL_SendMouseButton(data->window, mouseID, SDL_PRESSED, button);
slouken@8813
   242
    } else if (!bwParamMousePressed && bSDLMousePressed) {
dludwig@9668
   243
        SDL_SendMouseButton(data->window, mouseID, SDL_RELEASED, button);
slouken@7191
   244
    }
slouken@6943
   245
}
slouken@6943
   246
slouken@6943
   247
/*
slouken@6943
   248
* Some windows systems fail to send a WM_LBUTTONDOWN sometimes, but each mouse move contains the current button state also
slouken@6943
   249
*  so this funciton reconciles our view of the world with the current buttons reported by windows
slouken@6943
   250
*/
philipp@10982
   251
static void
dludwig@9668
   252
WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mouseID)
slouken@6943
   253
{
slouken@8813
   254
    if (wParam != data->mouse_button_flags) {
slouken@8813
   255
        Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
dludwig@9668
   256
        WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, mouseID);
dludwig@9668
   257
        WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, mouseID);
dludwig@9668
   258
        WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, mouseID);
dludwig@9668
   259
        WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, mouseID);
dludwig@9668
   260
        WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, mouseID);
slouken@7191
   261
        data->mouse_button_flags = wParam;
slouken@7191
   262
    }
slouken@6943
   263
}
slouken@6943
   264
slouken@6943
   265
philipp@10982
   266
static void
slouken@8813
   267
WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data)
slouken@6943
   268
{
slouken@8813
   269
    if (rawButtons != data->mouse_button_flags) {
slouken@8813
   270
        Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
slouken@8813
   271
        if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN))
dludwig@9668
   272
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
slouken@8813
   273
        if ((rawButtons & RI_MOUSE_BUTTON_1_UP))
dludwig@9668
   274
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
slouken@8813
   275
        if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN))
dludwig@9668
   276
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
slouken@8813
   277
        if ((rawButtons & RI_MOUSE_BUTTON_2_UP))
dludwig@9668
   278
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
slouken@8813
   279
        if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN))
dludwig@9668
   280
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
slouken@8813
   281
        if ((rawButtons & RI_MOUSE_BUTTON_3_UP))
dludwig@9668
   282
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
slouken@8813
   283
        if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN))
dludwig@9668
   284
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
slouken@8813
   285
        if ((rawButtons & RI_MOUSE_BUTTON_4_UP))
dludwig@9668
   286
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
slouken@8813
   287
        if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN))
dludwig@9668
   288
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
slouken@8813
   289
        if ((rawButtons & RI_MOUSE_BUTTON_5_UP))
dludwig@9668
   290
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
slouken@7191
   291
        data->mouse_button_flags = rawButtons;
slouken@7191
   292
    }
slouken@6943
   293
}
slouken@6943
   294
philipp@10982
   295
static void
slouken@8813
   296
WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
slouken@8212
   297
{
slouken@8212
   298
    Uint32 mouseFlags;
slouken@8212
   299
    SHORT keyState;
slouken@8212
   300
slouken@8212
   301
    /* mouse buttons may have changed state here, we need to resync them,
slouken@8212
   302
       but we will get a WM_MOUSEMOVE right away which will fix things up if in non raw mode also
slouken@8212
   303
    */
slouken@8813
   304
    mouseFlags = SDL_GetMouseState(NULL, NULL);
slouken@8212
   305
slouken@8813
   306
    keyState = GetAsyncKeyState(VK_LBUTTON);
slouken@8796
   307
    if (!(keyState & 0x8000)) {
dludwig@9668
   308
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
slouken@8796
   309
    }
slouken@8796
   310
    keyState = GetAsyncKeyState(VK_RBUTTON);
slouken@8796
   311
    if (!(keyState & 0x8000)) {
dludwig@9668
   312
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
slouken@8796
   313
    }
slouken@8796
   314
    keyState = GetAsyncKeyState(VK_MBUTTON);
slouken@8796
   315
    if (!(keyState & 0x8000)) {
dludwig@9668
   316
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
slouken@8796
   317
    }
slouken@8796
   318
    keyState = GetAsyncKeyState(VK_XBUTTON1);
slouken@8796
   319
    if (!(keyState & 0x8000)) {
dludwig@9668
   320
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
slouken@8796
   321
    }
slouken@8796
   322
    keyState = GetAsyncKeyState(VK_XBUTTON2);
slouken@8796
   323
    if (!(keyState & 0x8000)) {
dludwig@9668
   324
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
slouken@8796
   325
    }
slouken@8212
   326
    data->mouse_button_flags = 0;
slouken@8212
   327
}
slouken@8212
   328
philipp@10982
   329
static BOOL
slouken@7645
   330
WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
slouken@7645
   331
{
slouken@7645
   332
    if (codepoint <= 0x7F) {
slouken@7645
   333
        text[0] = (char) codepoint;
slouken@7645
   334
        text[1] = '\0';
slouken@7645
   335
    } else if (codepoint <= 0x7FF) {
slouken@7645
   336
        text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
slouken@7645
   337
        text[1] = 0x80 | (char) (codepoint & 0x3F);
slouken@7645
   338
        text[2] = '\0';
slouken@7645
   339
    } else if (codepoint <= 0xFFFF) {
slouken@7645
   340
        text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
slouken@7645
   341
        text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
slouken@7645
   342
        text[2] = 0x80 | (char) (codepoint & 0x3F);
slouken@7645
   343
        text[3] = '\0';
slouken@7645
   344
    } else if (codepoint <= 0x10FFFF) {
slouken@7645
   345
        text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
slouken@7645
   346
        text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
slouken@7645
   347
        text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
slouken@7645
   348
        text[3] = 0x80 | (char) (codepoint & 0x3F);
slouken@7645
   349
        text[4] = '\0';
slouken@7645
   350
    } else {
slouken@7645
   351
        return SDL_FALSE;
slouken@7645
   352
    }
slouken@7645
   353
    return SDL_TRUE;
slouken@7645
   354
}
slouken@7645
   355
andrewb@9829
   356
static SDL_bool
andrewb@9829
   357
ShouldGenerateWindowCloseOnAltF4(void)
andrewb@9829
   358
{
slouken@10499
   359
    return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
andrewb@9829
   360
}
andrewb@9829
   361
slouken@1895
   362
LRESULT CALLBACK
slouken@1895
   363
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
slouken@1895
   364
{
slouken@1895
   365
    SDL_WindowData *data;
slouken@3566
   366
    LRESULT returnCode = -1;
slouken@1895
   367
slouken@1951
   368
    /* Send a SDL_SYSWMEVENT if the application wants them */
slouken@4429
   369
    if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
slouken@1951
   370
        SDL_SysWMmsg wmmsg;
slouken@1951
   371
slouken@1951
   372
        SDL_VERSION(&wmmsg.version);
slouken@4900
   373
        wmmsg.subsystem = SDL_SYSWM_WINDOWS;
slouken@5056
   374
        wmmsg.msg.win.hwnd = hwnd;
slouken@5056
   375
        wmmsg.msg.win.msg = msg;
slouken@5056
   376
        wmmsg.msg.win.wParam = wParam;
slouken@5056
   377
        wmmsg.msg.win.lParam = lParam;
slouken@1951
   378
        SDL_SendSysWMEvent(&wmmsg);
slouken@1951
   379
    }
slouken@1951
   380
slouken@1895
   381
    /* Get the window data for the window */
slouken@1895
   382
    data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
slouken@1895
   383
    if (!data) {
slouken@1895
   384
        return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
slouken@1895
   385
    }
jimtla@4650
   386
slouken@1895
   387
#ifdef WMMSG_DEBUG
slouken@7941
   388
    {
slouken@7941
   389
        char message[1024];
slouken@7941
   390
        if (msg > MAX_WMMSG) {
slouken@7941
   391
            SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam);
slouken@7941
   392
        } else {
slouken@7941
   393
            SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam);
slouken@7941
   394
        }
slouken@7941
   395
        OutputDebugStringA(message);
slouken@7941
   396
    }
slouken@7816
   397
#endif /* WMMSG_DEBUG */
slouken@2710
   398
dewyatt@4752
   399
    if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
dewyatt@4752
   400
        return 0;
slouken@1895
   401
slouken@1895
   402
    switch (msg) {
slouken@1895
   403
slouken@1895
   404
    case WM_SHOWWINDOW:
slouken@1895
   405
        {
slouken@1895
   406
            if (wParam) {
slouken@3685
   407
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
slouken@1895
   408
            } else {
slouken@3685
   409
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
slouken@1895
   410
            }
slouken@1895
   411
        }
slouken@1895
   412
        break;
slouken@1895
   413
slouken@1895
   414
    case WM_ACTIVATE:
slouken@1895
   415
        {
slouken@8796
   416
            POINT cursorPos;
slouken@1895
   417
            BOOL minimized;
slouken@1895
   418
slouken@1895
   419
            minimized = HIWORD(wParam);
slouken@1895
   420
            if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
slouken@10539
   421
                if (LOWORD(wParam) == WA_CLICKACTIVE) {
slouken@10539
   422
                    if (GetAsyncKeyState(VK_LBUTTON)) {
slouken@10539
   423
                        data->focus_click_pending |= SDL_BUTTON_LMASK;
slouken@10539
   424
                    }
slouken@10539
   425
                    if (GetAsyncKeyState(VK_RBUTTON)) {
slouken@10539
   426
                        data->focus_click_pending |= SDL_BUTTON_RMASK;
slouken@10539
   427
                    }
slouken@10539
   428
                    if (GetAsyncKeyState(VK_MBUTTON)) {
slouken@10539
   429
                        data->focus_click_pending |= SDL_BUTTON_MMASK;
slouken@10539
   430
                    }
slouken@10539
   431
                    if (GetAsyncKeyState(VK_XBUTTON1)) {
slouken@10539
   432
                        data->focus_click_pending |= SDL_BUTTON_X1MASK;
slouken@10539
   433
                    }
slouken@10539
   434
                    if (GetAsyncKeyState(VK_XBUTTON2)) {
slouken@10539
   435
                        data->focus_click_pending |= SDL_BUTTON_X2MASK;
slouken@10539
   436
                    }
slouken@10377
   437
                }
slouken@10377
   438
                
slouken@3685
   439
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
slouken@4465
   440
                if (SDL_GetKeyboardFocus() != data->window) {
slouken@4465
   441
                    SDL_SetKeyboardFocus(data->window);
slouken@1895
   442
                }
slouken@11300
   443
slouken@8796
   444
                GetCursorPos(&cursorPos);
slouken@8796
   445
                ScreenToClient(hwnd, &cursorPos);
slouken@8796
   446
                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
slouken@11300
   447
slouken@8212
   448
                WIN_CheckAsyncMouseRelease(data);
slouken@6350
   449
slouken@4504
   450
                /*
slouken@4504
   451
                 * FIXME: Update keyboard state
slouken@4504
   452
                 */
slouken@4504
   453
                WIN_CheckClipboardUpdate(data->videodata);
icculus@9974
   454
icculus@9974
   455
                SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
icculus@9974
   456
                SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
slouken@1895
   457
            } else {
dludwig@9990
   458
                data->in_window_deactivation = SDL_TRUE;
dludwig@9990
   459
slouken@4465
   460
                if (SDL_GetKeyboardFocus() == data->window) {
slouken@4465
   461
                    SDL_SetKeyboardFocus(NULL);
slouken@10411
   462
                    WIN_ResetDeadKeys();
slouken@1895
   463
                }
slouken@8050
   464
slouken@8050
   465
                ClipCursor(NULL);
dludwig@9990
   466
dludwig@9990
   467
                data->in_window_deactivation = SDL_FALSE;
slouken@1895
   468
            }
slouken@1895
   469
        }
slouken@3566
   470
        returnCode = 0;
slouken@3566
   471
        break;
slouken@1895
   472
slouken@7191
   473
    case WM_MOUSEMOVE:
slouken@8071
   474
        {
slouken@8071
   475
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   476
            if (!mouse->relative_mode || mouse->relative_mode_warp) {
dludwig@9668
   477
                SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
dludwig@9668
   478
                SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
slouken@8071
   479
            }
slouken@8071
   480
        }
slouken@7191
   481
        /* don't break here, fall through to check the wParam like the button presses */
slouken@7191
   482
    case WM_LBUTTONUP:
slouken@7191
   483
    case WM_RBUTTONUP:
slouken@7191
   484
    case WM_MBUTTONUP:
slouken@7191
   485
    case WM_XBUTTONUP:
slouken@7191
   486
    case WM_LBUTTONDOWN:
slouken@8713
   487
    case WM_LBUTTONDBLCLK:
slouken@7191
   488
    case WM_RBUTTONDOWN:
slouken@8713
   489
    case WM_RBUTTONDBLCLK:
slouken@7191
   490
    case WM_MBUTTONDOWN:
slouken@8713
   491
    case WM_MBUTTONDBLCLK:
slouken@7191
   492
    case WM_XBUTTONDOWN:
slouken@8713
   493
    case WM_XBUTTONDBLCLK:
slouken@8071
   494
        {
slouken@8071
   495
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   496
            if (!mouse->relative_mode || mouse->relative_mode_warp) {
dludwig@9668
   497
                SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
dludwig@9668
   498
                WIN_CheckWParamMouseButtons(wParam, data, mouseID);
slouken@8071
   499
            }
slouken@8071
   500
        }
slouken@7191
   501
        break;
slouken@3139
   502
slouken@7191
   503
    case WM_INPUT:
slouken@8071
   504
        {
slouken@8071
   505
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   506
            HRAWINPUT hRawInput = (HRAWINPUT)lParam;
slouken@8071
   507
            RAWINPUT inp;
slouken@8071
   508
            UINT size = sizeof(inp);
icculus@8942
   509
            const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
icculus@8942
   510
            const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
slouken@6782
   511
icculus@8942
   512
            if (!isRelative || mouse->focus != data->window) {
icculus@8942
   513
                if (!isCapture) {
icculus@8942
   514
                    break;
icculus@8942
   515
                }
slouken@8071
   516
            }
slouken@6782
   517
slouken@8071
   518
            GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
slouken@6350
   519
slouken@8071
   520
            /* Mouse data */
slouken@8071
   521
            if (inp.header.dwType == RIM_TYPEMOUSE) {
icculus@8942
   522
                if (isRelative) {
slouken@8976
   523
                    RAWMOUSE* rawmouse = &inp.data.mouse;
slouken@6350
   524
slouken@8976
   525
                    if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
slouken@8976
   526
                        SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
icculus@8942
   527
                    } else {
icculus@8942
   528
                        /* synthesize relative moves from the abs position */
icculus@8942
   529
                        static SDL_Point initialMousePoint;
icculus@8942
   530
                        if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
slouken@8976
   531
                            initialMousePoint.x = rawmouse->lLastX;
slouken@8976
   532
                            initialMousePoint.y = rawmouse->lLastY;
icculus@8942
   533
                        }
icculus@8942
   534
slouken@10864
   535
                        SDL_SendMouseMotion(data->window, 0, 1, (int)(rawmouse->lLastX-initialMousePoint.x), (int)(rawmouse->lLastY-initialMousePoint.y));
icculus@8942
   536
slouken@8976
   537
                        initialMousePoint.x = rawmouse->lLastX;
slouken@8976
   538
                        initialMousePoint.y = rawmouse->lLastY;
slouken@8071
   539
                    }
slouken@8976
   540
                    WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
icculus@8942
   541
                } else if (isCapture) {
icculus@8942
   542
                    /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
icculus@8942
   543
                    POINT pt;
slouken@10863
   544
                    RECT hwndRect;
slouken@10864
   545
                    HWND currentHnd;
slouken@10864
   546
icculus@8942
   547
                    GetCursorPos(&pt);
slouken@10864
   548
                    currentHnd = WindowFromPoint(pt);
slouken@10864
   549
                    ScreenToClient(hwnd, &pt);
slouken@10864
   550
                    GetClientRect(hwnd, &hwndRect);
slouken@10863
   551
slouken@10863
   552
                    /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
slouken@10864
   553
                    if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
slouken@10864
   554
                        SDL_SendMouseMotion(data->window, 0, 0, (int)pt.x, (int)pt.y);
icculus@8949
   555
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
icculus@8949
   556
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
icculus@8949
   557
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
icculus@8949
   558
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
icculus@8949
   559
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
icculus@8942
   560
                    }
icculus@8942
   561
                } else {
icculus@8942
   562
                    SDL_assert(0 && "Shouldn't happen");
slouken@7191
   563
                }
slouken@7191
   564
            }
slouken@7191
   565
        }
slouken@7191
   566
        break;
slouken@6350
   567
slouken@5049
   568
    case WM_MOUSEWHEEL:
slouken@7911
   569
    case WM_MOUSEHWHEEL:
slouken@7911
   570
        {
slouken@11300
   571
            short amount = GET_WHEEL_DELTA_WPARAM(wParam);
slouken@11300
   572
            float fAmount = (float) amount / WHEEL_DELTA;
slouken@11300
   573
            if (msg == WM_MOUSEWHEEL)
slouken@11300
   574
                SDL_SendMouseWheel(data->window, 0, 0.0f, fAmount, SDL_MOUSEWHEEL_NORMAL);
slouken@11300
   575
            else
slouken@11300
   576
                SDL_SendMouseWheel(data->window, 0, fAmount, 0.0f, SDL_MOUSEWHEEL_NORMAL);
slouken@7911
   577
        }
slouken@8071
   578
        break;
slouken@7911
   579
slouken@5086
   580
#ifdef WM_MOUSELEAVE
slouken@1895
   581
    case WM_MOUSELEAVE:
icculus@8942
   582
        if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
slouken@8035
   583
            if (!IsIconic(hwnd)) {
slouken@8035
   584
                POINT cursorPos;
slouken@8035
   585
                GetCursorPos(&cursorPos);
slouken@8035
   586
                ScreenToClient(hwnd, &cursorPos);
slouken@8035
   587
                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
slouken@8035
   588
            }
slouken@7191
   589
            SDL_SetMouseFocus(NULL);
slouken@1895
   590
        }
slouken@3566
   591
        returnCode = 0;
slouken@3566
   592
        break;
slouken@5086
   593
#endif /* WM_MOUSELEAVE */
slouken@1895
   594
slouken@7645
   595
    case WM_KEYDOWN:
slouken@7646
   596
    case WM_SYSKEYDOWN:
slouken@7645
   597
        {
slouken@8813
   598
            SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
icculus@9641
   599
            const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
icculus@9641
   600
icculus@9641
   601
            /* Detect relevant keyboard shortcuts */
icculus@9641
   602
            if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) {
icculus@9641
   603
                /* ALT+F4: Close window */
andrewb@9829
   604
                if (code == SDL_SCANCODE_F4 && ShouldGenerateWindowCloseOnAltF4()) {
icculus@9641
   605
                    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
icculus@9641
   606
                }
icculus@9641
   607
            }
icculus@9641
   608
slouken@8813
   609
            if (code != SDL_SCANCODE_UNKNOWN) {
slouken@8813
   610
                SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@7646
   611
            }
slouken@7646
   612
        }
slouken@11300
   613
slouken@3566
   614
        returnCode = 0;
slouken@3566
   615
        break;
slouken@1895
   616
slouken@1895
   617
    case WM_SYSKEYUP:
slouken@1895
   618
    case WM_KEYUP:
slouken@1895
   619
        {
slouken@8813
   620
            SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
gabomdq@7975
   621
            const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
gabomdq@7975
   622
slouken@8813
   623
            if (code != SDL_SCANCODE_UNKNOWN) {
slouken@6938
   624
                if (code == SDL_SCANCODE_PRINTSCREEN &&
gabomdq@7975
   625
                    keyboardState[code] == SDL_RELEASED) {
slouken@6938
   626
                    SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@6938
   627
                }
slouken@6938
   628
                SDL_SendKeyboardKey(SDL_RELEASED, code);
slouken@2308
   629
            }
slouken@1895
   630
        }
slouken@3566
   631
        returnCode = 0;
slouken@3566
   632
        break;
slouken@1895
   633
slouken@8143
   634
    case WM_UNICHAR:
slouken@9889
   635
        if ( wParam == UNICODE_NOCHAR ) {
slouken@9889
   636
            returnCode = 1;
slouken@9889
   637
            break;
slouken@9889
   638
        }
slouken@9889
   639
        /* otherwise fall through to below */
slouken@9889
   640
    case WM_CHAR:
slouken@9889
   641
        {
slouken@9889
   642
            char text[5];
slouken@9889
   643
            if ( WIN_ConvertUTF32toUTF8( (UINT32)wParam, text ) ) {
slouken@9889
   644
                SDL_SendKeyboardText( text );
slouken@9889
   645
            }
slouken@9889
   646
        }
slouken@9889
   647
        returnCode = 0;
slouken@8143
   648
        break;
slouken@8143
   649
slouken@5086
   650
#ifdef WM_INPUTLANGCHANGE
slouken@2311
   651
    case WM_INPUTLANGCHANGE:
slouken@2311
   652
        {
slouken@4465
   653
            WIN_UpdateKeymap();
slouken@9898
   654
            SDL_SendKeymapChangedEvent();
slouken@2311
   655
        }
slouken@3566
   656
        returnCode = 1;
slouken@3566
   657
        break;
slouken@5086
   658
#endif /* WM_INPUTLANGCHANGE */
slouken@2311
   659
slouken@8253
   660
    case WM_NCLBUTTONDOWN:
slouken@8253
   661
        {
slouken@8253
   662
            data->in_title_click = SDL_TRUE;
slouken@8253
   663
        }
slouken@8253
   664
        break;
slouken@8253
   665
slouken@8916
   666
    case WM_CAPTURECHANGED:
slouken@8253
   667
        {
slouken@8253
   668
            data->in_title_click = SDL_FALSE;
slouken@8253
   669
slouken@8916
   670
            /* The mouse may have been released during a modal loop */
slouken@8212
   671
            WIN_CheckAsyncMouseRelease(data);
slouken@8036
   672
        }
slouken@8036
   673
        break;
slouken@8036
   674
slouken@5086
   675
#ifdef WM_GETMINMAXINFO
slouken@1895
   676
    case WM_GETMINMAXINFO:
slouken@1895
   677
        {
slouken@1895
   678
            MINMAXINFO *info;
slouken@1895
   679
            RECT size;
slouken@1895
   680
            int x, y;
slouken@1895
   681
            int w, h;
stopiccot@6682
   682
            int min_w, min_h;
slouken@6788
   683
            int max_w, max_h;
slouken@1895
   684
            int style;
slouken@3168
   685
            BOOL menu;
slouken@7191
   686
            BOOL constrain_max_size;
slouken@1895
   687
stopiccot@6682
   688
            if (SDL_IsShapedWindow(data->window))
eligottlieb@4815
   689
                Win32_ResizeWindowShape(data->window);
slouken@1895
   690
slouken@7941
   691
            /* If this is an expected size change, allow it */
slouken@7941
   692
            if (data->expected_resize) {
slouken@7941
   693
                break;
slouken@7941
   694
            }
slouken@7941
   695
slouken@1895
   696
            /* Get the current position of our window */
slouken@1895
   697
            GetWindowRect(hwnd, &size);
slouken@1895
   698
            x = size.left;
slouken@1895
   699
            y = size.top;
slouken@1895
   700
slouken@1895
   701
            /* Calculate current size of our window */
slouken@3685
   702
            SDL_GetWindowSize(data->window, &w, &h);
stopiccot@6682
   703
            SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
slouken@6788
   704
            SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
stopiccot@6682
   705
slouken@7191
   706
            /* Store in min_w and min_h difference between current size and minimal
stopiccot@6682
   707
               size so we don't need to call AdjustWindowRectEx twice */
stopiccot@6682
   708
            min_w -= w;
stopiccot@6682
   709
            min_h -= h;
slouken@6837
   710
            if (max_w && max_h) {
slouken@6837
   711
                max_w -= w;
slouken@6837
   712
                max_h -= h;
slouken@6862
   713
                constrain_max_size = TRUE;
slouken@6862
   714
            } else {
slouken@6862
   715
                constrain_max_size = FALSE;
slouken@6837
   716
            }
stopiccot@6682
   717
slouken@1895
   718
            size.top = 0;
slouken@1895
   719
            size.left = 0;
slouken@1895
   720
            size.bottom = h;
slouken@1895
   721
            size.right = w;
slouken@1895
   722
slouken@3168
   723
            style = GetWindowLong(hwnd, GWL_STYLE);
slouken@1895
   724
            /* DJM - according to the docs for GetMenu(), the
slouken@1895
   725
               return value is undefined if hwnd is a child window.
slouken@8817
   726
               Apparently it's too difficult for MS to check
slouken@1895
   727
               inside their function, so I have to do it here.
slouken@1895
   728
             */
slouken@3168
   729
            menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
slouken@3168
   730
            AdjustWindowRectEx(&size, style, menu, 0);
slouken@1895
   731
            w = size.right - size.left;
slouken@1895
   732
            h = size.bottom - size.top;
slouken@1895
   733
slouken@1895
   734
            /* Fix our size to the current size */
slouken@1895
   735
            info = (MINMAXINFO *) lParam;
stopiccot@6682
   736
            if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
stopiccot@6682
   737
                info->ptMinTrackSize.x = w + min_w;
stopiccot@6682
   738
                info->ptMinTrackSize.y = h + min_h;
slouken@6862
   739
                if (constrain_max_size) {
slouken@6862
   740
                    info->ptMaxTrackSize.x = w + max_w;
slouken@6862
   741
                    info->ptMaxTrackSize.y = h + max_h;
slouken@6862
   742
                }
stopiccot@6682
   743
            } else {
stopiccot@6682
   744
                info->ptMaxSize.x = w;
stopiccot@6682
   745
                info->ptMaxSize.y = h;
stopiccot@6682
   746
                info->ptMaxPosition.x = x;
stopiccot@6682
   747
                info->ptMaxPosition.y = y;
stopiccot@6682
   748
                info->ptMinTrackSize.x = w;
stopiccot@6682
   749
                info->ptMinTrackSize.y = h;
stopiccot@6682
   750
                info->ptMaxTrackSize.x = w;
stopiccot@6682
   751
                info->ptMaxTrackSize.y = h;
stopiccot@6682
   752
            }
slouken@1895
   753
        }
slouken@3566
   754
        returnCode = 0;
slouken@3566
   755
        break;
slouken@5086
   756
#endif /* WM_GETMINMAXINFO */
slouken@1895
   757
icculus@10387
   758
    case WM_WINDOWPOSCHANGING:
icculus@10387
   759
icculus@10387
   760
        if (data->expected_resize) {
icculus@10387
   761
            returnCode = 0;
icculus@10387
   762
        }
icculus@10387
   763
        break;
icculus@10387
   764
slouken@1895
   765
    case WM_WINDOWPOSCHANGED:
slouken@1895
   766
        {
slouken@1895
   767
            RECT rect;
slouken@1895
   768
            int x, y;
slouken@1895
   769
            int w, h;
slouken@11300
   770
slouken@9888
   771
            if (data->initializing || data->in_border_change) {
slouken@8817
   772
                break;
slouken@8817
   773
            }
slouken@1895
   774
slouken@8036
   775
            if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) {
slouken@3256
   776
                break;
slouken@3256
   777
            }
slouken@1895
   778
            ClientToScreen(hwnd, (LPPOINT) & rect);
slouken@1895
   779
            ClientToScreen(hwnd, (LPPOINT) & rect + 1);
slouken@1895
   780
slouken@8036
   781
            WIN_UpdateClipCursor(data->window);
slouken@1895
   782
slouken@1895
   783
            x = rect.left;
slouken@1895
   784
            y = rect.top;
slouken@3685
   785
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@1895
   786
slouken@1895
   787
            w = rect.right - rect.left;
slouken@1895
   788
            h = rect.bottom - rect.top;
slouken@3685
   789
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
slouken@1895
   790
                                h);
flibitijibibo@10417
   791
flibitijibibo@10417
   792
            /* Forces a WM_PAINT event */
flibitijibibo@10417
   793
            InvalidateRect(hwnd, NULL, FALSE);
slouken@1895
   794
        }
slouken@1895
   795
        break;
slouken@1895
   796
slouken@7941
   797
    case WM_SIZE:
slouken@7941
   798
        {
slouken@8813
   799
            switch (wParam) {
slouken@7941
   800
            case SIZE_MAXIMIZED:
slouken@7941
   801
                SDL_SendWindowEvent(data->window,
slouken@11007
   802
                    SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@11007
   803
                SDL_SendWindowEvent(data->window,
slouken@7941
   804
                    SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
slouken@7941
   805
                break;
slouken@7941
   806
            case SIZE_MINIMIZED:
slouken@7941
   807
                SDL_SendWindowEvent(data->window,
slouken@7941
   808
                    SDL_WINDOWEVENT_MINIMIZED, 0, 0);
slouken@7941
   809
                break;
slouken@7941
   810
            default:
slouken@7941
   811
                SDL_SendWindowEvent(data->window,
slouken@7941
   812
                    SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@7941
   813
                break;
slouken@7941
   814
            }
slouken@7941
   815
        }
slouken@7941
   816
        break;
slouken@7941
   817
slouken@1895
   818
    case WM_SETCURSOR:
slouken@1895
   819
        {
slouken@3076
   820
            Uint16 hittest;
slouken@1895
   821
slouken@3076
   822
            hittest = LOWORD(lParam);
slouken@3076
   823
            if (hittest == HTCLIENT) {
slouken@5421
   824
                SetCursor(SDL_cursor);
slouken@3566
   825
                returnCode = TRUE;
slouken@8813
   826
            } else if (!g_WindowFrameUsableWhileCursorHidden && !SDL_cursor) {
slouken@8813
   827
                SetCursor(NULL);
slouken@8813
   828
                returnCode = TRUE;
slouken@3076
   829
            }
slouken@1895
   830
        }
slouken@1895
   831
        break;
slouken@1895
   832
slouken@1895
   833
        /* We were occluded, refresh our display */
slouken@1895
   834
    case WM_PAINT:
slouken@1895
   835
        {
slouken@1895
   836
            RECT rect;
slouken@1895
   837
            if (GetUpdateRect(hwnd, &rect, FALSE)) {
slouken@7295
   838
                ValidateRect(hwnd, NULL);
slouken@3685
   839
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
slouken@1895
   840
                                    0, 0);
slouken@1895
   841
            }
slouken@1895
   842
        }
slouken@3566
   843
        returnCode = 0;
slouken@3566
   844
        break;
slouken@3095
   845
slouken@1895
   846
        /* We'll do our own drawing, prevent flicker */
slouken@1895
   847
    case WM_ERASEBKGND:
slouken@1895
   848
        {
slouken@1895
   849
        }
slouken@1895
   850
        return (1);
slouken@1895
   851
slouken@1895
   852
    case WM_SYSCOMMAND:
slouken@1895
   853
        {
slouken@9889
   854
            if ((wParam & 0xFFF0) == SC_KEYMENU) {
slouken@9889
   855
                return (0);
slouken@9889
   856
            }
icculus@9624
   857
icculus@9624
   858
#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
slouken@1895
   859
            /* Don't start the screensaver or blank the monitor in fullscreen apps */
slouken@1895
   860
            if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
slouken@1895
   861
                (wParam & 0xFFF0) == SC_MONITORPOWER) {
slouken@3032
   862
                if (SDL_GetVideoDevice()->suspend_screensaver) {
slouken@1895
   863
                    return (0);
slouken@1895
   864
                }
slouken@1895
   865
            }
icculus@9624
   866
#endif /* System has screensaver support */
slouken@1895
   867
        }
slouken@1895
   868
        break;
slouken@1895
   869
slouken@1895
   870
    case WM_CLOSE:
slouken@1895
   871
        {
slouken@3685
   872
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
slouken@1895
   873
        }
slouken@3566
   874
        returnCode = 0;
slouken@3566
   875
        break;
slouken@4919
   876
slouken@7191
   877
    case WM_TOUCH:
slouken@11215
   878
        if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
slouken@7191
   879
            UINT i, num_inputs = LOWORD(wParam);
slouken@7191
   880
            PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
slouken@7191
   881
            if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
slouken@7191
   882
                RECT rect;
slouken@7191
   883
                float x, y;
slouken@4919
   884
slouken@7191
   885
                if (!GetClientRect(hwnd, &rect) ||
slouken@7191
   886
                    (rect.right == rect.left && rect.bottom == rect.top)) {
philipp@7631
   887
                    if (inputs) {
philipp@7631
   888
                        SDL_stack_free(inputs);
philipp@7631
   889
                    }
slouken@7191
   890
                    break;
slouken@7191
   891
                }
slouken@7191
   892
                ClientToScreen(hwnd, (LPPOINT) & rect);
slouken@7191
   893
                ClientToScreen(hwnd, (LPPOINT) & rect + 1);
slouken@7191
   894
                rect.top *= 100;
slouken@7191
   895
                rect.left *= 100;
slouken@7191
   896
                rect.bottom *= 100;
slouken@7191
   897
                rect.right *= 100;
slouken@4932
   898
slouken@7191
   899
                for (i = 0; i < num_inputs; ++i) {
slouken@7191
   900
                    PTOUCHINPUT input = &inputs[i];
slouken@4919
   901
icculus@7543
   902
                    const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource);
slouken@9679
   903
                    if (SDL_AddTouch(touchId, "") < 0) {
slouken@9679
   904
                        continue;
slouken@7191
   905
                    }
slouken@4932
   906
slouken@7191
   907
                    /* Get the normalized coordinates for the window */
slouken@7191
   908
                    x = (float)(input->x - rect.left)/(rect.right - rect.left);
slouken@7191
   909
                    y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
slouken@4932
   910
slouken@7191
   911
                    if (input->dwFlags & TOUCHEVENTF_DOWN) {
slouken@7191
   912
                        SDL_SendTouch(touchId, input->dwID, SDL_TRUE, x, y, 1.0f);
slouken@7191
   913
                    }
slouken@7191
   914
                    if (input->dwFlags & TOUCHEVENTF_MOVE) {
slouken@7191
   915
                        SDL_SendTouchMotion(touchId, input->dwID, x, y, 1.0f);
slouken@7191
   916
                    }
slouken@7191
   917
                    if (input->dwFlags & TOUCHEVENTF_UP) {
slouken@7191
   918
                        SDL_SendTouch(touchId, input->dwID, SDL_FALSE, x, y, 1.0f);
slouken@7191
   919
                    }
slouken@7191
   920
                }
slouken@7191
   921
            }
slouken@7191
   922
            SDL_stack_free(inputs);
slouken@4932
   923
slouken@7191
   924
            data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
slouken@7191
   925
            return 0;
slouken@7191
   926
        }
slouken@7191
   927
        break;
slouken@6523
   928
slouken@6523
   929
    case WM_DROPFILES:
slouken@6523
   930
        {
slouken@6523
   931
            UINT i;
slouken@6523
   932
            HDROP drop = (HDROP) wParam;
slouken@6523
   933
            UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
slouken@6523
   934
            for (i = 0; i < count; ++i) {
slouken@6523
   935
                UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
slouken@6523
   936
                LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
slouken@6523
   937
                if (buffer) {
slouken@6523
   938
                    if (DragQueryFile(drop, i, buffer, size)) {
slouken@6523
   939
                        char *file = WIN_StringToUTF8(buffer);
icculus@10022
   940
                        SDL_SendDropFile(data->window, file);
slouken@6523
   941
                        SDL_free(file);
slouken@6523
   942
                    }
slouken@6523
   943
                    SDL_stack_free(buffer);
slouken@6523
   944
                }
slouken@6523
   945
            }
icculus@10022
   946
            SDL_SendDropComplete(data->window);
slouken@6523
   947
            DragFinish(drop);
slouken@6523
   948
            return 0;
slouken@6523
   949
        }
slouken@6523
   950
        break;
icculus@8938
   951
icculus@8938
   952
    case WM_NCHITTEST:
icculus@8938
   953
        {
icculus@8938
   954
            SDL_Window *window = data->window;
icculus@8938
   955
            if (window->hit_test) {
icculus@8941
   956
                POINT winpoint = { (int) LOWORD(lParam), (int) HIWORD(lParam) };
slouken@8976
   957
                if (ScreenToClient(hwnd, &winpoint)) {
icculus@8941
   958
                    const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
icculus@8941
   959
                    const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
icculus@8948
   960
                    switch (rc) {
icculus@10028
   961
                        #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
icculus@10028
   962
                        case SDL_HITTEST_DRAGGABLE: POST_HIT_TEST(HTCAPTION);
icculus@10028
   963
                        case SDL_HITTEST_RESIZE_TOPLEFT: POST_HIT_TEST(HTTOPLEFT);
icculus@10028
   964
                        case SDL_HITTEST_RESIZE_TOP: POST_HIT_TEST(HTTOP);
icculus@10028
   965
                        case SDL_HITTEST_RESIZE_TOPRIGHT: POST_HIT_TEST(HTTOPRIGHT);
icculus@10028
   966
                        case SDL_HITTEST_RESIZE_RIGHT: POST_HIT_TEST(HTRIGHT);
icculus@10028
   967
                        case SDL_HITTEST_RESIZE_BOTTOMRIGHT: POST_HIT_TEST(HTBOTTOMRIGHT);
icculus@10028
   968
                        case SDL_HITTEST_RESIZE_BOTTOM: POST_HIT_TEST(HTBOTTOM);
icculus@10028
   969
                        case SDL_HITTEST_RESIZE_BOTTOMLEFT: POST_HIT_TEST(HTBOTTOMLEFT);
icculus@10028
   970
                        case SDL_HITTEST_RESIZE_LEFT: POST_HIT_TEST(HTLEFT);
icculus@10028
   971
                        #undef POST_HIT_TEST
slouken@8976
   972
                        case SDL_HITTEST_NORMAL: return HTCLIENT;
icculus@8941
   973
                    }
icculus@8938
   974
                }
icculus@8948
   975
                /* If we didn't return, this will call DefWindowProc below. */
icculus@8938
   976
            }
icculus@8938
   977
        }
icculus@8938
   978
        break;
icculus@8938
   979
slouken@6523
   980
    }
slouken@3566
   981
slouken@3566
   982
    /* If there's a window proc, assume it's going to handle messages */
slouken@3566
   983
    if (data->wndproc) {
slouken@3566
   984
        return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
slouken@3566
   985
    } else if (returnCode >= 0) {
slouken@3566
   986
        return returnCode;
slouken@3566
   987
    } else {
slouken@3566
   988
        return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
slouken@3566
   989
    }
slouken@1895
   990
}
slouken@1895
   991
slouken@9597
   992
/* A message hook called before TranslateMessage() */
slouken@9597
   993
static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
slouken@9599
   994
static void *g_WindowsMessageHookData = NULL;
slouken@9597
   995
slouken@9599
   996
void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
slouken@9597
   997
{
slouken@9597
   998
    g_WindowsMessageHook = callback;
slouken@9599
   999
    g_WindowsMessageHookData = userdata;
slouken@9597
  1000
}
slouken@9597
  1001
slouken@1895
  1002
void
slouken@1895
  1003
WIN_PumpEvents(_THIS)
slouken@1895
  1004
{
icculus@7561
  1005
    const Uint8 *keystate;
slouken@1895
  1006
    MSG msg;
slouken@8218
  1007
    DWORD start_ticks = GetTickCount();
slouken@8218
  1008
slouken@8814
  1009
    if (g_WindowsEnableMessageLoop) {
slouken@8814
  1010
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
slouken@9597
  1011
            if (g_WindowsMessageHook) {
slouken@9599
  1012
                g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
slouken@9597
  1013
            }
slouken@9597
  1014
slouken@8814
  1015
            /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
slouken@8814
  1016
            TranslateMessage(&msg);
slouken@8814
  1017
            DispatchMessage(&msg);
slouken@8218
  1018
slouken@8814
  1019
            /* Make sure we don't busy loop here forever if there are lots of events coming in */
slouken@8814
  1020
            if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
slouken@8814
  1021
                break;
slouken@8814
  1022
            }
slouken@8218
  1023
        }
slouken@1895
  1024
    }
icculus@7561
  1025
icculus@7561
  1026
    /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one.
icculus@7561
  1027
       You won't get a KEYUP until both are released, and that keyup will only be for the second
icculus@7561
  1028
       key you released. Take heroic measures and check the keystate as of the last handled event,
icculus@7561
  1029
       and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */
icculus@7561
  1030
    keystate = SDL_GetKeyboardState(NULL);
icculus@7561
  1031
    if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
icculus@7561
  1032
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
icculus@7561
  1033
    }
icculus@7561
  1034
    if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
icculus@7561
  1035
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
icculus@7561
  1036
    }
slouken@1895
  1037
}
slouken@1895
  1038
slouken@1895
  1039
static int app_registered = 0;
slouken@1895
  1040
LPTSTR SDL_Appname = NULL;
slouken@1895
  1041
Uint32 SDL_Appstyle = 0;
slouken@1895
  1042
HINSTANCE SDL_Instance = NULL;
slouken@1895
  1043
slouken@1895
  1044
/* Register the class for this application */
slouken@1895
  1045
int
slouken@1895
  1046
SDL_RegisterApp(char *name, Uint32 style, void *hInst)
slouken@1895
  1047
{
slouken@11261
  1048
    const char *hint;
slouken@10426
  1049
    WNDCLASSEX wcex;
slouken@10426
  1050
    TCHAR path[MAX_PATH];
slouken@1895
  1051
slouken@1895
  1052
    /* Only do this once... */
slouken@1895
  1053
    if (app_registered) {
slouken@1895
  1054
        ++app_registered;
slouken@1895
  1055
        return (0);
slouken@1895
  1056
    }
slouken@1895
  1057
    if (!name && !SDL_Appname) {
slouken@1895
  1058
        name = "SDL_app";
slouken@5086
  1059
#if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
slouken@1895
  1060
        SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
slouken@5086
  1061
#endif
slouken@1895
  1062
        SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
slouken@1895
  1063
    }
slouken@1895
  1064
slouken@1895
  1065
    if (name) {
slouken@1895
  1066
        SDL_Appname = WIN_UTF8ToString(name);
slouken@1895
  1067
        SDL_Appstyle = style;
slouken@1895
  1068
        SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
slouken@1895
  1069
    }
slouken@1895
  1070
slouken@1895
  1071
    /* Register the application class */
slouken@10427
  1072
    wcex.cbSize         = sizeof(WNDCLASSEX);
slouken@10427
  1073
    wcex.hCursor        = NULL;
slouken@10427
  1074
    wcex.hIcon          = NULL;
slouken@10427
  1075
    wcex.hIconSm        = NULL;
slouken@10427
  1076
    wcex.lpszMenuName   = NULL;
slouken@10427
  1077
    wcex.lpszClassName  = SDL_Appname;
slouken@10427
  1078
    wcex.style          = SDL_Appstyle;
slouken@10427
  1079
    wcex.hbrBackground  = NULL;
slouken@10427
  1080
    wcex.lpfnWndProc    = WIN_WindowProc;
slouken@10427
  1081
    wcex.hInstance      = SDL_Instance;
slouken@10427
  1082
    wcex.cbClsExtra     = 0;
slouken@10427
  1083
    wcex.cbWndExtra     = 0;
slouken@10427
  1084
slouken@11261
  1085
    hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON);
slouken@11261
  1086
    if (hint && *hint) {
slouken@11261
  1087
        wcex.hIcon = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
slouken@11261
  1088
slouken@11261
  1089
        hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL);
slouken@11261
  1090
        if (hint && *hint) {
slouken@11261
  1091
            wcex.hIconSm = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
slouken@11261
  1092
        }
slouken@11261
  1093
    } else {
slouken@11261
  1094
        /* Use the first icon as a default icon, like in the Explorer */
slouken@11261
  1095
        GetModuleFileName(SDL_Instance, path, MAX_PATH);
slouken@11261
  1096
        ExtractIconEx(path, 0, &wcex.hIcon, &wcex.hIconSm, 1);
slouken@11261
  1097
    }
slouken@10427
  1098
slouken@10426
  1099
    if (!RegisterClassEx(&wcex)) {
icculus@7037
  1100
        return SDL_SetError("Couldn't register application class");
slouken@1895
  1101
    }
slouken@1895
  1102
slouken@1895
  1103
    app_registered = 1;
icculus@7037
  1104
    return 0;
slouken@1895
  1105
}
slouken@1895
  1106
slouken@1895
  1107
/* Unregisters the windowclass registered in SDL_RegisterApp above. */
slouken@1895
  1108
void
slouken@1895
  1109
SDL_UnregisterApp()
slouken@1895
  1110
{
slouken@10426
  1111
    WNDCLASSEX wcex;
slouken@1895
  1112
slouken@1895
  1113
    /* SDL_RegisterApp might not have been called before */
slouken@1895
  1114
    if (!app_registered) {
slouken@1895
  1115
        return;
slouken@1895
  1116
    }
slouken@1895
  1117
    --app_registered;
slouken@1895
  1118
    if (app_registered == 0) {
slouken@1895
  1119
        /* Check for any registered window classes. */
slouken@10426
  1120
        if (GetClassInfoEx(SDL_Instance, SDL_Appname, &wcex)) {
slouken@1895
  1121
            UnregisterClass(SDL_Appname, SDL_Instance);
slouken@10426
  1122
            if (wcex.hIcon) DestroyIcon(wcex.hIcon);
slouken@10426
  1123
            if (wcex.hIconSm) DestroyIcon(wcex.hIconSm);
slouken@1895
  1124
        }
slouken@1895
  1125
        SDL_free(SDL_Appname);
slouken@1895
  1126
        SDL_Appname = NULL;
slouken@1895
  1127
    }
slouken@1895
  1128
}
slouken@1895
  1129
slouken@6044
  1130
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
slouken@6044
  1131
slouken@1895
  1132
/* vi: set ts=4 sw=4 expandtab: */