src/video/windows/SDL_windowsevents.c
author Cameron Gutman <aicommander@gmail.com>
Sun, 07 Jul 2019 11:23:16 -0700
changeset 12930 92e72926b7f5
parent 12824 2f882d435abf
child 12943 49190e92b7d1
permissions -rw-r--r--
Ignore synthetic mouse events generated for touchscreens

Windows generates fake raw mouse events for touchscreens for compatibility
with legacy apps that predate touch support in Windows. We already handle
touch events explicitly, so drop the synthetic events to avoid duplicates.
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 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) {
slouken@12770
    89
/* Windows generates this virtual keycode for Keypad 5 when NumLock is off.
michael@11241
    90
    case VK_CLEAR: return SDL_SCANCODE_CLEAR;
slouken@12770
    91
*/
michael@11241
    92
    case VK_MODECHANGE: return SDL_SCANCODE_MODE;
michael@11241
    93
    case VK_SELECT: return SDL_SCANCODE_SELECT;
michael@11241
    94
    case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
michael@11241
    95
    case VK_HELP: return SDL_SCANCODE_HELP;
michael@11241
    96
    case VK_PAUSE: return SDL_SCANCODE_PAUSE;
michael@11241
    97
    case VK_NUMLOCK: return SDL_SCANCODE_NUMLOCKCLEAR;
michael@11241
    98
michael@11241
    99
    case VK_F13: return SDL_SCANCODE_F13;
michael@11241
   100
    case VK_F14: return SDL_SCANCODE_F14;
michael@11241
   101
    case VK_F15: return SDL_SCANCODE_F15;
michael@11241
   102
    case VK_F16: return SDL_SCANCODE_F16;
michael@11241
   103
    case VK_F17: return SDL_SCANCODE_F17;
michael@11241
   104
    case VK_F18: return SDL_SCANCODE_F18;
michael@11241
   105
    case VK_F19: return SDL_SCANCODE_F19;
michael@11241
   106
    case VK_F20: return SDL_SCANCODE_F20;
michael@11241
   107
    case VK_F21: return SDL_SCANCODE_F21;
michael@11241
   108
    case VK_F22: return SDL_SCANCODE_F22;
michael@11241
   109
    case VK_F23: return SDL_SCANCODE_F23;
michael@11241
   110
    case VK_F24: return SDL_SCANCODE_F24;
michael@11241
   111
michael@11241
   112
    case VK_OEM_NEC_EQUAL: return SDL_SCANCODE_KP_EQUALS;
michael@11241
   113
    case VK_BROWSER_BACK: return SDL_SCANCODE_AC_BACK;
michael@11241
   114
    case VK_BROWSER_FORWARD: return SDL_SCANCODE_AC_FORWARD;
michael@11241
   115
    case VK_BROWSER_REFRESH: return SDL_SCANCODE_AC_REFRESH;
michael@11241
   116
    case VK_BROWSER_STOP: return SDL_SCANCODE_AC_STOP;
michael@11241
   117
    case VK_BROWSER_SEARCH: return SDL_SCANCODE_AC_SEARCH;
michael@11241
   118
    case VK_BROWSER_FAVORITES: return SDL_SCANCODE_AC_BOOKMARKS;
michael@11241
   119
    case VK_BROWSER_HOME: return SDL_SCANCODE_AC_HOME;
michael@11241
   120
    case VK_VOLUME_MUTE: return SDL_SCANCODE_AUDIOMUTE;
michael@11241
   121
    case VK_VOLUME_DOWN: return SDL_SCANCODE_VOLUMEDOWN;
michael@11241
   122
    case VK_VOLUME_UP: return SDL_SCANCODE_VOLUMEUP;
michael@11241
   123
michael@11241
   124
    case VK_MEDIA_NEXT_TRACK: return SDL_SCANCODE_AUDIONEXT;
michael@11241
   125
    case VK_MEDIA_PREV_TRACK: return SDL_SCANCODE_AUDIOPREV;
michael@11241
   126
    case VK_MEDIA_STOP: return SDL_SCANCODE_AUDIOSTOP;
michael@11241
   127
    case VK_MEDIA_PLAY_PAUSE: return SDL_SCANCODE_AUDIOPLAY;
michael@11241
   128
    case VK_LAUNCH_MAIL: return SDL_SCANCODE_MAIL;
michael@11241
   129
    case VK_LAUNCH_MEDIA_SELECT: return SDL_SCANCODE_MEDIASELECT;
michael@11241
   130
michael@11241
   131
    case VK_OEM_102: return SDL_SCANCODE_NONUSBACKSLASH;
michael@11241
   132
michael@11241
   133
    case VK_ATTN: return SDL_SCANCODE_SYSREQ;
michael@11241
   134
    case VK_CRSEL: return SDL_SCANCODE_CRSEL;
michael@11241
   135
    case VK_EXSEL: return SDL_SCANCODE_EXSEL;
michael@11241
   136
    case VK_OEM_CLEAR: return SDL_SCANCODE_CLEAR;
michael@11241
   137
michael@11241
   138
    case VK_LAUNCH_APP1: return SDL_SCANCODE_APP1;
michael@11241
   139
    case VK_LAUNCH_APP2: return SDL_SCANCODE_APP2;
michael@11241
   140
michael@11241
   141
    default: return SDL_SCANCODE_UNKNOWN;
michael@11241
   142
    }
michael@11241
   143
}
michael@11241
   144
michael@11241
   145
static SDL_Scancode
slouken@8813
   146
WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam)
jorgen@6922
   147
{
slouken@7191
   148
    SDL_Scancode code;
slouken@8813
   149
    int nScanCode = (lParam >> 16) & 0xFF;
slouken@11242
   150
    SDL_bool bIsExtended = (lParam & (1 << 24)) != 0;
jorgen@6922
   151
slouken@11242
   152
    code = VKeytoScancode(wParam);
jorgen@6922
   153
slouken@11242
   154
    if (code == SDL_SCANCODE_UNKNOWN && nScanCode <= 127) {
slouken@11242
   155
        code = windows_scancode_table[nScanCode];
slouken@7191
   156
slouken@11242
   157
        if (bIsExtended) {
slouken@11242
   158
            switch (code) {
slouken@11242
   159
            case SDL_SCANCODE_RETURN:
slouken@11242
   160
                code = SDL_SCANCODE_KP_ENTER;
slouken@11242
   161
                break;
slouken@11242
   162
            case SDL_SCANCODE_LALT:
slouken@11242
   163
                code = SDL_SCANCODE_RALT;
slouken@11242
   164
                break;
slouken@11242
   165
            case SDL_SCANCODE_LCTRL:
slouken@11242
   166
                code = SDL_SCANCODE_RCTRL;
slouken@11242
   167
                break;
slouken@11242
   168
            case SDL_SCANCODE_SLASH:
slouken@11242
   169
                code = SDL_SCANCODE_KP_DIVIDE;
slouken@11242
   170
                break;
slouken@11242
   171
            case SDL_SCANCODE_CAPSLOCK:
slouken@11242
   172
                code = SDL_SCANCODE_KP_PLUS;
slouken@11242
   173
                break;
slouken@11242
   174
            default:
slouken@11242
   175
                break;
slouken@11242
   176
            }
michael@11241
   177
        } else {
michael@11241
   178
            switch (code) {
slouken@11242
   179
            case SDL_SCANCODE_HOME:
slouken@11242
   180
                code = SDL_SCANCODE_KP_7;
slouken@11242
   181
                break;
slouken@11242
   182
            case SDL_SCANCODE_UP:
slouken@11242
   183
                code = SDL_SCANCODE_KP_8;
slouken@11242
   184
                break;
slouken@11242
   185
            case SDL_SCANCODE_PAGEUP:
slouken@11242
   186
                code = SDL_SCANCODE_KP_9;
slouken@11242
   187
                break;
slouken@11242
   188
            case SDL_SCANCODE_LEFT:
slouken@11242
   189
                code = SDL_SCANCODE_KP_4;
slouken@11242
   190
                break;
slouken@11242
   191
            case SDL_SCANCODE_RIGHT:
slouken@11242
   192
                code = SDL_SCANCODE_KP_6;
slouken@11242
   193
                break;
slouken@11242
   194
            case SDL_SCANCODE_END:
slouken@11242
   195
                code = SDL_SCANCODE_KP_1;
slouken@11242
   196
                break;
slouken@11242
   197
            case SDL_SCANCODE_DOWN:
slouken@11242
   198
                code = SDL_SCANCODE_KP_2;
slouken@11242
   199
                break;
slouken@11242
   200
            case SDL_SCANCODE_PAGEDOWN:
slouken@11242
   201
                code = SDL_SCANCODE_KP_3;
slouken@11242
   202
                break;
slouken@11242
   203
            case SDL_SCANCODE_INSERT:
slouken@11242
   204
                code = SDL_SCANCODE_KP_0;
slouken@11242
   205
                break;
slouken@11242
   206
            case SDL_SCANCODE_DELETE:
slouken@11242
   207
                code = SDL_SCANCODE_KP_PERIOD;
slouken@11242
   208
                break;
slouken@11242
   209
            case SDL_SCANCODE_PRINTSCREEN:
slouken@11242
   210
                code = SDL_SCANCODE_KP_MULTIPLY;
slouken@11242
   211
                break;
michael@11241
   212
            default:
michael@11241
   213
                break;
michael@11241
   214
            }
slouken@7191
   215
        }
slouken@7191
   216
    }
slouken@7191
   217
    return code;
jorgen@6922
   218
}
jorgen@6922
   219
slouken@10379
   220
static SDL_bool
slouken@10379
   221
WIN_ShouldIgnoreFocusClick()
slouken@10379
   222
{
slouken@10499
   223
    return !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE);
slouken@10379
   224
}
jorgen@6922
   225
philipp@10982
   226
static void
dludwig@9668
   227
WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID)
slouken@6943
   228
{
slouken@10377
   229
    if (data->focus_click_pending & SDL_BUTTON(button)) {
slouken@10377
   230
        /* Ignore the button click for activation */
slouken@10377
   231
        if (!bwParamMousePressed) {
slouken@10377
   232
            data->focus_click_pending &= ~SDL_BUTTON(button);
slouken@12153
   233
            WIN_UpdateClipCursor(data->window);
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@11959
   362
/* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
slouken@11959
   363
   doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
slouken@11959
   364
   This is used to implement a workaround.. */
slouken@11959
   365
static SDL_bool isWin10FCUorNewer = SDL_FALSE;
slouken@11959
   366
slouken@1895
   367
LRESULT CALLBACK
slouken@1895
   368
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
slouken@1895
   369
{
slouken@1895
   370
    SDL_WindowData *data;
slouken@3566
   371
    LRESULT returnCode = -1;
slouken@1895
   372
slouken@1951
   373
    /* Send a SDL_SYSWMEVENT if the application wants them */
slouken@4429
   374
    if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
slouken@1951
   375
        SDL_SysWMmsg wmmsg;
slouken@1951
   376
slouken@1951
   377
        SDL_VERSION(&wmmsg.version);
slouken@4900
   378
        wmmsg.subsystem = SDL_SYSWM_WINDOWS;
slouken@5056
   379
        wmmsg.msg.win.hwnd = hwnd;
slouken@5056
   380
        wmmsg.msg.win.msg = msg;
slouken@5056
   381
        wmmsg.msg.win.wParam = wParam;
slouken@5056
   382
        wmmsg.msg.win.lParam = lParam;
slouken@1951
   383
        SDL_SendSysWMEvent(&wmmsg);
slouken@1951
   384
    }
slouken@1951
   385
slouken@1895
   386
    /* Get the window data for the window */
slouken@1895
   387
    data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
slouken@1895
   388
    if (!data) {
slouken@1895
   389
        return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
slouken@1895
   390
    }
jimtla@4650
   391
slouken@1895
   392
#ifdef WMMSG_DEBUG
slouken@7941
   393
    {
slouken@7941
   394
        char message[1024];
slouken@7941
   395
        if (msg > MAX_WMMSG) {
slouken@7941
   396
            SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam);
slouken@7941
   397
        } else {
slouken@7941
   398
            SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam);
slouken@7941
   399
        }
slouken@7941
   400
        OutputDebugStringA(message);
slouken@7941
   401
    }
slouken@7816
   402
#endif /* WMMSG_DEBUG */
slouken@2710
   403
dewyatt@4752
   404
    if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
dewyatt@4752
   405
        return 0;
slouken@1895
   406
slouken@1895
   407
    switch (msg) {
slouken@1895
   408
slouken@1895
   409
    case WM_SHOWWINDOW:
slouken@1895
   410
        {
slouken@1895
   411
            if (wParam) {
slouken@3685
   412
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
slouken@1895
   413
            } else {
slouken@3685
   414
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
slouken@1895
   415
            }
slouken@1895
   416
        }
slouken@1895
   417
        break;
slouken@1895
   418
slouken@12231
   419
    case WM_NCACTIVATE:
slouken@12231
   420
        {
slouken@12231
   421
            /* Don't immediately clip the cursor in case we're clicking minimize/maximize buttons */
slouken@12231
   422
            data->skip_update_clipcursor = SDL_TRUE;
slouken@12231
   423
        }
slouken@12231
   424
        break;
slouken@12231
   425
slouken@1895
   426
    case WM_ACTIVATE:
slouken@1895
   427
        {
slouken@8796
   428
            POINT cursorPos;
slouken@1895
   429
            BOOL minimized;
slouken@1895
   430
slouken@1895
   431
            minimized = HIWORD(wParam);
slouken@1895
   432
            if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
icculus@12824
   433
                /* Don't mark the window as shown if it's activated before being shown */
icculus@12824
   434
                if (!IsWindowVisible(hwnd)) {
icculus@12824
   435
                    break;
icculus@12824
   436
                }
slouken@10539
   437
                if (LOWORD(wParam) == WA_CLICKACTIVE) {
slouken@10539
   438
                    if (GetAsyncKeyState(VK_LBUTTON)) {
slouken@10539
   439
                        data->focus_click_pending |= SDL_BUTTON_LMASK;
slouken@10539
   440
                    }
slouken@10539
   441
                    if (GetAsyncKeyState(VK_RBUTTON)) {
slouken@10539
   442
                        data->focus_click_pending |= SDL_BUTTON_RMASK;
slouken@10539
   443
                    }
slouken@10539
   444
                    if (GetAsyncKeyState(VK_MBUTTON)) {
slouken@10539
   445
                        data->focus_click_pending |= SDL_BUTTON_MMASK;
slouken@10539
   446
                    }
slouken@10539
   447
                    if (GetAsyncKeyState(VK_XBUTTON1)) {
slouken@10539
   448
                        data->focus_click_pending |= SDL_BUTTON_X1MASK;
slouken@10539
   449
                    }
slouken@10539
   450
                    if (GetAsyncKeyState(VK_XBUTTON2)) {
slouken@10539
   451
                        data->focus_click_pending |= SDL_BUTTON_X2MASK;
slouken@10539
   452
                    }
slouken@10377
   453
                }
slouken@10377
   454
                
slouken@3685
   455
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
slouken@4465
   456
                if (SDL_GetKeyboardFocus() != data->window) {
slouken@4465
   457
                    SDL_SetKeyboardFocus(data->window);
slouken@1895
   458
                }
slouken@11300
   459
slouken@8796
   460
                GetCursorPos(&cursorPos);
slouken@8796
   461
                ScreenToClient(hwnd, &cursorPos);
slouken@8796
   462
                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
slouken@11300
   463
slouken@8212
   464
                WIN_CheckAsyncMouseRelease(data);
slouken@6350
   465
slouken@4504
   466
                /*
slouken@4504
   467
                 * FIXME: Update keyboard state
slouken@4504
   468
                 */
slouken@4504
   469
                WIN_CheckClipboardUpdate(data->videodata);
icculus@9974
   470
icculus@9974
   471
                SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
icculus@9974
   472
                SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
slouken@1895
   473
            } else {
slouken@12153
   474
                RECT rect;
slouken@12153
   475
dludwig@9990
   476
                data->in_window_deactivation = SDL_TRUE;
dludwig@9990
   477
slouken@4465
   478
                if (SDL_GetKeyboardFocus() == data->window) {
slouken@4465
   479
                    SDL_SetKeyboardFocus(NULL);
slouken@10411
   480
                    WIN_ResetDeadKeys();
slouken@1895
   481
                }
slouken@8050
   482
slouken@12153
   483
                if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect) == 0)) {
slouken@12153
   484
                    ClipCursor(NULL);
slouken@12153
   485
                    SDL_zero(data->cursor_clipped_rect);
slouken@12153
   486
                }
dludwig@9990
   487
dludwig@9990
   488
                data->in_window_deactivation = SDL_FALSE;
slouken@1895
   489
            }
slouken@1895
   490
        }
slouken@3566
   491
        returnCode = 0;
slouken@3566
   492
        break;
slouken@1895
   493
slouken@7191
   494
    case WM_MOUSEMOVE:
slouken@8071
   495
        {
slouken@8071
   496
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   497
            if (!mouse->relative_mode || mouse->relative_mode_warp) {
sylvain@12677
   498
                /* Only generate mouse events for real mouse */
sylvain@12677
   499
                if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) {
sylvain@12677
   500
                    SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
sylvain@12677
   501
                    if (isWin10FCUorNewer && mouse->relative_mode_warp) {
sylvain@12677
   502
                        /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
sylvain@12677
   503
                           SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
sylvain@12677
   504
                           after each windows mouse event generate a fake event for the middle of the window
sylvain@12677
   505
                           if relative_mode_warp is used */
sylvain@12677
   506
                        int center_x = 0, center_y = 0;
sylvain@12677
   507
                        SDL_GetWindowSize(data->window, &center_x, &center_y);
sylvain@12677
   508
                        center_x /= 2;
sylvain@12677
   509
                        center_y /= 2;
sylvain@12677
   510
                        SDL_SendMouseMotion(data->window, 0, 0, center_x, center_y);
sylvain@12677
   511
                    }
slouken@11959
   512
                }
slouken@8071
   513
            }
slouken@8071
   514
        }
slouken@7191
   515
        /* don't break here, fall through to check the wParam like the button presses */
slouken@7191
   516
    case WM_LBUTTONUP:
slouken@7191
   517
    case WM_RBUTTONUP:
slouken@7191
   518
    case WM_MBUTTONUP:
slouken@7191
   519
    case WM_XBUTTONUP:
slouken@7191
   520
    case WM_LBUTTONDOWN:
slouken@8713
   521
    case WM_LBUTTONDBLCLK:
slouken@7191
   522
    case WM_RBUTTONDOWN:
slouken@8713
   523
    case WM_RBUTTONDBLCLK:
slouken@7191
   524
    case WM_MBUTTONDOWN:
slouken@8713
   525
    case WM_MBUTTONDBLCLK:
slouken@7191
   526
    case WM_XBUTTONDOWN:
slouken@8713
   527
    case WM_XBUTTONDBLCLK:
slouken@8071
   528
        {
slouken@8071
   529
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   530
            if (!mouse->relative_mode || mouse->relative_mode_warp) {
sylvain@12677
   531
                if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) {
sylvain@12684
   532
                    WIN_CheckWParamMouseButtons(wParam, data, 0);
sylvain@12677
   533
                }
slouken@8071
   534
            }
slouken@8071
   535
        }
slouken@7191
   536
        break;
slouken@3139
   537
slouken@7191
   538
    case WM_INPUT:
slouken@8071
   539
        {
slouken@8071
   540
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   541
            HRAWINPUT hRawInput = (HRAWINPUT)lParam;
slouken@8071
   542
            RAWINPUT inp;
slouken@8071
   543
            UINT size = sizeof(inp);
icculus@8942
   544
            const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
icculus@8942
   545
            const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
slouken@6782
   546
icculus@8942
   547
            if (!isRelative || mouse->focus != data->window) {
icculus@8942
   548
                if (!isCapture) {
icculus@8942
   549
                    break;
icculus@8942
   550
                }
slouken@8071
   551
            }
slouken@6782
   552
slouken@8071
   553
            GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
slouken@6350
   554
aicommander@12930
   555
            /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
aicommander@12930
   556
            if (inp.header.dwType == RIM_TYPEMOUSE && (GetMessageExtraInfo() & 0x80) == 0) {
icculus@8942
   557
                if (isRelative) {
slouken@8976
   558
                    RAWMOUSE* rawmouse = &inp.data.mouse;
slouken@6350
   559
slouken@8976
   560
                    if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
slouken@8976
   561
                        SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
icculus@8942
   562
                    } else {
icculus@8942
   563
                        /* synthesize relative moves from the abs position */
icculus@8942
   564
                        static SDL_Point initialMousePoint;
icculus@8942
   565
                        if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
slouken@8976
   566
                            initialMousePoint.x = rawmouse->lLastX;
slouken@8976
   567
                            initialMousePoint.y = rawmouse->lLastY;
icculus@8942
   568
                        }
icculus@8942
   569
slouken@10864
   570
                        SDL_SendMouseMotion(data->window, 0, 1, (int)(rawmouse->lLastX-initialMousePoint.x), (int)(rawmouse->lLastY-initialMousePoint.y));
icculus@8942
   571
slouken@8976
   572
                        initialMousePoint.x = rawmouse->lLastX;
slouken@8976
   573
                        initialMousePoint.y = rawmouse->lLastY;
slouken@8071
   574
                    }
slouken@8976
   575
                    WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
icculus@8942
   576
                } else if (isCapture) {
icculus@8942
   577
                    /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
icculus@8942
   578
                    POINT pt;
slouken@10863
   579
                    RECT hwndRect;
slouken@10864
   580
                    HWND currentHnd;
slouken@10864
   581
icculus@8942
   582
                    GetCursorPos(&pt);
slouken@10864
   583
                    currentHnd = WindowFromPoint(pt);
slouken@10864
   584
                    ScreenToClient(hwnd, &pt);
slouken@10864
   585
                    GetClientRect(hwnd, &hwndRect);
slouken@10863
   586
slouken@10863
   587
                    /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
slouken@10864
   588
                    if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
slouken@10864
   589
                        SDL_SendMouseMotion(data->window, 0, 0, (int)pt.x, (int)pt.y);
icculus@8949
   590
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
icculus@8949
   591
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
icculus@8949
   592
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
icculus@8949
   593
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
icculus@8949
   594
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
icculus@8942
   595
                    }
icculus@8942
   596
                } else {
icculus@8942
   597
                    SDL_assert(0 && "Shouldn't happen");
slouken@7191
   598
                }
slouken@7191
   599
            }
slouken@7191
   600
        }
slouken@7191
   601
        break;
slouken@6350
   602
slouken@5049
   603
    case WM_MOUSEWHEEL:
slouken@7911
   604
    case WM_MOUSEHWHEEL:
slouken@7911
   605
        {
slouken@11300
   606
            short amount = GET_WHEEL_DELTA_WPARAM(wParam);
slouken@11300
   607
            float fAmount = (float) amount / WHEEL_DELTA;
slouken@11300
   608
            if (msg == WM_MOUSEWHEEL)
slouken@11300
   609
                SDL_SendMouseWheel(data->window, 0, 0.0f, fAmount, SDL_MOUSEWHEEL_NORMAL);
slouken@11300
   610
            else
slouken@11300
   611
                SDL_SendMouseWheel(data->window, 0, fAmount, 0.0f, SDL_MOUSEWHEEL_NORMAL);
slouken@7911
   612
        }
slouken@8071
   613
        break;
slouken@7911
   614
slouken@5086
   615
#ifdef WM_MOUSELEAVE
slouken@1895
   616
    case WM_MOUSELEAVE:
icculus@8942
   617
        if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
slouken@8035
   618
            if (!IsIconic(hwnd)) {
slouken@8035
   619
                POINT cursorPos;
slouken@8035
   620
                GetCursorPos(&cursorPos);
slouken@8035
   621
                ScreenToClient(hwnd, &cursorPos);
slouken@8035
   622
                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
slouken@8035
   623
            }
slouken@7191
   624
            SDL_SetMouseFocus(NULL);
slouken@1895
   625
        }
slouken@3566
   626
        returnCode = 0;
slouken@3566
   627
        break;
slouken@5086
   628
#endif /* WM_MOUSELEAVE */
slouken@1895
   629
slouken@7645
   630
    case WM_KEYDOWN:
slouken@7646
   631
    case WM_SYSKEYDOWN:
slouken@7645
   632
        {
slouken@8813
   633
            SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
icculus@9641
   634
            const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
icculus@9641
   635
icculus@9641
   636
            /* Detect relevant keyboard shortcuts */
icculus@9641
   637
            if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) {
icculus@9641
   638
                /* ALT+F4: Close window */
andrewb@9829
   639
                if (code == SDL_SCANCODE_F4 && ShouldGenerateWindowCloseOnAltF4()) {
icculus@9641
   640
                    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
icculus@9641
   641
                }
icculus@9641
   642
            }
icculus@9641
   643
slouken@8813
   644
            if (code != SDL_SCANCODE_UNKNOWN) {
slouken@8813
   645
                SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@7646
   646
            }
slouken@7646
   647
        }
slouken@11300
   648
slouken@3566
   649
        returnCode = 0;
slouken@3566
   650
        break;
slouken@1895
   651
slouken@1895
   652
    case WM_SYSKEYUP:
slouken@1895
   653
    case WM_KEYUP:
slouken@1895
   654
        {
slouken@8813
   655
            SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
gabomdq@7975
   656
            const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
gabomdq@7975
   657
slouken@8813
   658
            if (code != SDL_SCANCODE_UNKNOWN) {
slouken@6938
   659
                if (code == SDL_SCANCODE_PRINTSCREEN &&
gabomdq@7975
   660
                    keyboardState[code] == SDL_RELEASED) {
slouken@6938
   661
                    SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@6938
   662
                }
slouken@6938
   663
                SDL_SendKeyboardKey(SDL_RELEASED, code);
slouken@2308
   664
            }
slouken@1895
   665
        }
slouken@3566
   666
        returnCode = 0;
slouken@3566
   667
        break;
slouken@1895
   668
slouken@8143
   669
    case WM_UNICHAR:
slouken@12153
   670
        if (wParam == UNICODE_NOCHAR) {
slouken@9889
   671
            returnCode = 1;
slouken@9889
   672
            break;
slouken@9889
   673
        }
slouken@9889
   674
        /* otherwise fall through to below */
slouken@9889
   675
    case WM_CHAR:
slouken@9889
   676
        {
slouken@9889
   677
            char text[5];
slouken@12153
   678
            if (WIN_ConvertUTF32toUTF8((UINT32)wParam, text)) {
slouken@12153
   679
                SDL_SendKeyboardText(text);
slouken@9889
   680
            }
slouken@9889
   681
        }
slouken@9889
   682
        returnCode = 0;
slouken@8143
   683
        break;
slouken@8143
   684
slouken@5086
   685
#ifdef WM_INPUTLANGCHANGE
slouken@2311
   686
    case WM_INPUTLANGCHANGE:
slouken@2311
   687
        {
slouken@4465
   688
            WIN_UpdateKeymap();
slouken@9898
   689
            SDL_SendKeymapChangedEvent();
slouken@2311
   690
        }
slouken@3566
   691
        returnCode = 1;
slouken@3566
   692
        break;
slouken@5086
   693
#endif /* WM_INPUTLANGCHANGE */
slouken@2311
   694
slouken@8253
   695
    case WM_NCLBUTTONDOWN:
slouken@8253
   696
        {
slouken@8253
   697
            data->in_title_click = SDL_TRUE;
slouken@8253
   698
        }
slouken@8253
   699
        break;
slouken@8253
   700
slouken@8916
   701
    case WM_CAPTURECHANGED:
slouken@8253
   702
        {
slouken@8253
   703
            data->in_title_click = SDL_FALSE;
slouken@8253
   704
slouken@8916
   705
            /* The mouse may have been released during a modal loop */
slouken@8212
   706
            WIN_CheckAsyncMouseRelease(data);
slouken@8036
   707
        }
slouken@8036
   708
        break;
slouken@8036
   709
slouken@5086
   710
#ifdef WM_GETMINMAXINFO
slouken@1895
   711
    case WM_GETMINMAXINFO:
slouken@1895
   712
        {
slouken@1895
   713
            MINMAXINFO *info;
slouken@1895
   714
            RECT size;
slouken@1895
   715
            int x, y;
slouken@1895
   716
            int w, h;
stopiccot@6682
   717
            int min_w, min_h;
slouken@6788
   718
            int max_w, max_h;
slouken@7191
   719
            BOOL constrain_max_size;
slouken@1895
   720
stopiccot@6682
   721
            if (SDL_IsShapedWindow(data->window))
eligottlieb@4815
   722
                Win32_ResizeWindowShape(data->window);
slouken@1895
   723
slouken@7941
   724
            /* If this is an expected size change, allow it */
slouken@7941
   725
            if (data->expected_resize) {
slouken@7941
   726
                break;
slouken@7941
   727
            }
slouken@7941
   728
slouken@1895
   729
            /* Get the current position of our window */
slouken@1895
   730
            GetWindowRect(hwnd, &size);
slouken@1895
   731
            x = size.left;
slouken@1895
   732
            y = size.top;
slouken@1895
   733
slouken@1895
   734
            /* Calculate current size of our window */
slouken@3685
   735
            SDL_GetWindowSize(data->window, &w, &h);
stopiccot@6682
   736
            SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
slouken@6788
   737
            SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
stopiccot@6682
   738
slouken@7191
   739
            /* Store in min_w and min_h difference between current size and minimal
stopiccot@6682
   740
               size so we don't need to call AdjustWindowRectEx twice */
stopiccot@6682
   741
            min_w -= w;
stopiccot@6682
   742
            min_h -= h;
slouken@6837
   743
            if (max_w && max_h) {
slouken@6837
   744
                max_w -= w;
slouken@6837
   745
                max_h -= h;
slouken@6862
   746
                constrain_max_size = TRUE;
slouken@6862
   747
            } else {
slouken@6862
   748
                constrain_max_size = FALSE;
slouken@6837
   749
            }
stopiccot@6682
   750
slouken@11857
   751
            if (!(SDL_GetWindowFlags(data->window) & SDL_WINDOW_BORDERLESS)) {
slouken@11857
   752
                LONG style = GetWindowLong(hwnd, GWL_STYLE);
slouken@11857
   753
                /* DJM - according to the docs for GetMenu(), the
slouken@11857
   754
                   return value is undefined if hwnd is a child window.
slouken@11857
   755
                   Apparently it's too difficult for MS to check
slouken@11857
   756
                   inside their function, so I have to do it here.
slouken@11857
   757
                 */
slouken@11857
   758
                BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
slouken@11857
   759
                size.top = 0;
slouken@11857
   760
                size.left = 0;
slouken@11857
   761
                size.bottom = h;
slouken@11857
   762
                size.right = w;
slouken@1895
   763
slouken@11857
   764
                AdjustWindowRectEx(&size, style, menu, 0);
slouken@11857
   765
                w = size.right - size.left;
slouken@11857
   766
                h = size.bottom - size.top;
slouken@11857
   767
            }
slouken@1895
   768
slouken@1895
   769
            /* Fix our size to the current size */
slouken@1895
   770
            info = (MINMAXINFO *) lParam;
stopiccot@6682
   771
            if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
stopiccot@6682
   772
                info->ptMinTrackSize.x = w + min_w;
stopiccot@6682
   773
                info->ptMinTrackSize.y = h + min_h;
slouken@6862
   774
                if (constrain_max_size) {
slouken@6862
   775
                    info->ptMaxTrackSize.x = w + max_w;
slouken@6862
   776
                    info->ptMaxTrackSize.y = h + max_h;
slouken@6862
   777
                }
stopiccot@6682
   778
            } else {
stopiccot@6682
   779
                info->ptMaxSize.x = w;
stopiccot@6682
   780
                info->ptMaxSize.y = h;
stopiccot@6682
   781
                info->ptMaxPosition.x = x;
stopiccot@6682
   782
                info->ptMaxPosition.y = y;
stopiccot@6682
   783
                info->ptMinTrackSize.x = w;
stopiccot@6682
   784
                info->ptMinTrackSize.y = h;
stopiccot@6682
   785
                info->ptMaxTrackSize.x = w;
stopiccot@6682
   786
                info->ptMaxTrackSize.y = h;
stopiccot@6682
   787
            }
slouken@1895
   788
        }
slouken@3566
   789
        returnCode = 0;
slouken@3566
   790
        break;
slouken@5086
   791
#endif /* WM_GETMINMAXINFO */
slouken@1895
   792
icculus@10387
   793
    case WM_WINDOWPOSCHANGING:
icculus@10387
   794
icculus@10387
   795
        if (data->expected_resize) {
icculus@10387
   796
            returnCode = 0;
icculus@10387
   797
        }
icculus@10387
   798
        break;
icculus@10387
   799
slouken@1895
   800
    case WM_WINDOWPOSCHANGED:
slouken@1895
   801
        {
slouken@1895
   802
            RECT rect;
slouken@1895
   803
            int x, y;
slouken@1895
   804
            int w, h;
slouken@11300
   805
slouken@9888
   806
            if (data->initializing || data->in_border_change) {
slouken@8817
   807
                break;
slouken@8817
   808
            }
slouken@1895
   809
slouken@8036
   810
            if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) {
slouken@3256
   811
                break;
slouken@3256
   812
            }
slouken@1895
   813
            ClientToScreen(hwnd, (LPPOINT) & rect);
slouken@1895
   814
            ClientToScreen(hwnd, (LPPOINT) & rect + 1);
slouken@1895
   815
slouken@8036
   816
            WIN_UpdateClipCursor(data->window);
slouken@1895
   817
slouken@1895
   818
            x = rect.left;
slouken@1895
   819
            y = rect.top;
slouken@3685
   820
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@1895
   821
slouken@1895
   822
            w = rect.right - rect.left;
slouken@1895
   823
            h = rect.bottom - rect.top;
slouken@3685
   824
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
slouken@1895
   825
                                h);
flibitijibibo@10417
   826
flibitijibibo@10417
   827
            /* Forces a WM_PAINT event */
flibitijibibo@10417
   828
            InvalidateRect(hwnd, NULL, FALSE);
slouken@1895
   829
        }
slouken@1895
   830
        break;
slouken@1895
   831
slouken@7941
   832
    case WM_SIZE:
slouken@7941
   833
        {
slouken@8813
   834
            switch (wParam) {
slouken@7941
   835
            case SIZE_MAXIMIZED:
slouken@7941
   836
                SDL_SendWindowEvent(data->window,
slouken@11007
   837
                    SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@11007
   838
                SDL_SendWindowEvent(data->window,
slouken@7941
   839
                    SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
slouken@7941
   840
                break;
slouken@7941
   841
            case SIZE_MINIMIZED:
slouken@7941
   842
                SDL_SendWindowEvent(data->window,
slouken@7941
   843
                    SDL_WINDOWEVENT_MINIMIZED, 0, 0);
slouken@7941
   844
                break;
slouken@7941
   845
            default:
slouken@7941
   846
                SDL_SendWindowEvent(data->window,
slouken@7941
   847
                    SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@7941
   848
                break;
slouken@7941
   849
            }
slouken@7941
   850
        }
slouken@7941
   851
        break;
slouken@7941
   852
slouken@1895
   853
    case WM_SETCURSOR:
slouken@1895
   854
        {
slouken@3076
   855
            Uint16 hittest;
slouken@1895
   856
slouken@3076
   857
            hittest = LOWORD(lParam);
slouken@3076
   858
            if (hittest == HTCLIENT) {
slouken@5421
   859
                SetCursor(SDL_cursor);
slouken@3566
   860
                returnCode = TRUE;
slouken@8813
   861
            } else if (!g_WindowFrameUsableWhileCursorHidden && !SDL_cursor) {
slouken@8813
   862
                SetCursor(NULL);
slouken@8813
   863
                returnCode = TRUE;
slouken@3076
   864
            }
slouken@1895
   865
        }
slouken@1895
   866
        break;
slouken@1895
   867
slouken@1895
   868
        /* We were occluded, refresh our display */
slouken@1895
   869
    case WM_PAINT:
slouken@1895
   870
        {
slouken@1895
   871
            RECT rect;
slouken@1895
   872
            if (GetUpdateRect(hwnd, &rect, FALSE)) {
slouken@7295
   873
                ValidateRect(hwnd, NULL);
slouken@3685
   874
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
slouken@1895
   875
                                    0, 0);
slouken@1895
   876
            }
slouken@1895
   877
        }
slouken@3566
   878
        returnCode = 0;
slouken@3566
   879
        break;
slouken@3095
   880
slouken@1895
   881
        /* We'll do our own drawing, prevent flicker */
slouken@1895
   882
    case WM_ERASEBKGND:
slouken@1895
   883
        {
slouken@1895
   884
        }
slouken@1895
   885
        return (1);
slouken@1895
   886
slouken@1895
   887
    case WM_SYSCOMMAND:
slouken@1895
   888
        {
slouken@9889
   889
            if ((wParam & 0xFFF0) == SC_KEYMENU) {
slouken@9889
   890
                return (0);
slouken@9889
   891
            }
icculus@9624
   892
icculus@9624
   893
#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
slouken@1895
   894
            /* Don't start the screensaver or blank the monitor in fullscreen apps */
slouken@1895
   895
            if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
slouken@1895
   896
                (wParam & 0xFFF0) == SC_MONITORPOWER) {
slouken@3032
   897
                if (SDL_GetVideoDevice()->suspend_screensaver) {
slouken@1895
   898
                    return (0);
slouken@1895
   899
                }
slouken@1895
   900
            }
icculus@9624
   901
#endif /* System has screensaver support */
slouken@1895
   902
        }
slouken@1895
   903
        break;
slouken@1895
   904
slouken@1895
   905
    case WM_CLOSE:
slouken@1895
   906
        {
slouken@3685
   907
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
slouken@1895
   908
        }
slouken@3566
   909
        returnCode = 0;
slouken@3566
   910
        break;
slouken@4919
   911
slouken@7191
   912
    case WM_TOUCH:
slouken@11215
   913
        if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
slouken@7191
   914
            UINT i, num_inputs = LOWORD(wParam);
icculus@12349
   915
            SDL_bool isstack;
icculus@12349
   916
            PTOUCHINPUT inputs = SDL_small_alloc(TOUCHINPUT, num_inputs, &isstack);
slouken@7191
   917
            if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
slouken@7191
   918
                RECT rect;
slouken@7191
   919
                float x, y;
slouken@4919
   920
slouken@7191
   921
                if (!GetClientRect(hwnd, &rect) ||
slouken@7191
   922
                    (rect.right == rect.left && rect.bottom == rect.top)) {
philipp@7631
   923
                    if (inputs) {
icculus@12349
   924
                        SDL_small_free(inputs, isstack);
philipp@7631
   925
                    }
slouken@7191
   926
                    break;
slouken@7191
   927
                }
slouken@7191
   928
                ClientToScreen(hwnd, (LPPOINT) & rect);
slouken@7191
   929
                ClientToScreen(hwnd, (LPPOINT) & rect + 1);
slouken@7191
   930
                rect.top *= 100;
slouken@7191
   931
                rect.left *= 100;
slouken@7191
   932
                rect.bottom *= 100;
slouken@7191
   933
                rect.right *= 100;
slouken@4932
   934
slouken@7191
   935
                for (i = 0; i < num_inputs; ++i) {
slouken@7191
   936
                    PTOUCHINPUT input = &inputs[i];
slouken@4919
   937
icculus@7543
   938
                    const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource);
slime73@12404
   939
slime73@12404
   940
                    /* TODO: Can we use GetRawInputDeviceInfo and HID info to
slime73@12404
   941
                       determine if this is a direct or indirect touch device?
slime73@12404
   942
                     */
slime73@12404
   943
                    if (SDL_AddTouch(touchId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
slouken@9679
   944
                        continue;
slouken@7191
   945
                    }
slouken@4932
   946
slouken@7191
   947
                    /* Get the normalized coordinates for the window */
slouken@7191
   948
                    x = (float)(input->x - rect.left)/(rect.right - rect.left);
slouken@7191
   949
                    y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
slouken@4932
   950
slouken@7191
   951
                    if (input->dwFlags & TOUCHEVENTF_DOWN) {
slouken@7191
   952
                        SDL_SendTouch(touchId, input->dwID, SDL_TRUE, x, y, 1.0f);
slouken@7191
   953
                    }
slouken@7191
   954
                    if (input->dwFlags & TOUCHEVENTF_MOVE) {
slouken@7191
   955
                        SDL_SendTouchMotion(touchId, input->dwID, x, y, 1.0f);
slouken@7191
   956
                    }
slouken@7191
   957
                    if (input->dwFlags & TOUCHEVENTF_UP) {
slouken@7191
   958
                        SDL_SendTouch(touchId, input->dwID, SDL_FALSE, x, y, 1.0f);
slouken@7191
   959
                    }
slouken@7191
   960
                }
slouken@7191
   961
            }
icculus@12349
   962
            SDL_small_free(inputs, isstack);
slouken@4932
   963
slouken@7191
   964
            data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
slouken@7191
   965
            return 0;
slouken@7191
   966
        }
slouken@7191
   967
        break;
slouken@6523
   968
slouken@6523
   969
    case WM_DROPFILES:
slouken@6523
   970
        {
slouken@6523
   971
            UINT i;
slouken@6523
   972
            HDROP drop = (HDROP) wParam;
slouken@6523
   973
            UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
slouken@6523
   974
            for (i = 0; i < count; ++i) {
icculus@12349
   975
                SDL_bool isstack;
slouken@6523
   976
                UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
icculus@12349
   977
                LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
slouken@6523
   978
                if (buffer) {
slouken@6523
   979
                    if (DragQueryFile(drop, i, buffer, size)) {
slouken@6523
   980
                        char *file = WIN_StringToUTF8(buffer);
icculus@10022
   981
                        SDL_SendDropFile(data->window, file);
slouken@6523
   982
                        SDL_free(file);
slouken@6523
   983
                    }
icculus@12349
   984
                    SDL_small_free(buffer, isstack);
slouken@6523
   985
                }
slouken@6523
   986
            }
icculus@10022
   987
            SDL_SendDropComplete(data->window);
slouken@6523
   988
            DragFinish(drop);
slouken@6523
   989
            return 0;
slouken@6523
   990
        }
slouken@6523
   991
        break;
icculus@8938
   992
slouken@11528
   993
    case WM_NCCALCSIZE:
slouken@11528
   994
        {
slouken@11874
   995
            Uint32 window_flags = SDL_GetWindowFlags(data->window);
slouken@11874
   996
            if (wParam == TRUE && (window_flags & SDL_WINDOW_BORDERLESS) && !(window_flags & SDL_WINDOW_FULLSCREEN)) {
slouken@11716
   997
                /* When borderless, need to tell windows that the size of the non-client area is 0 */
slouken@11874
   998
                if (!(window_flags & SDL_WINDOW_RESIZABLE)) {
slouken@11716
   999
                    int w, h;
slouken@11716
  1000
                    NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam;
slouken@11874
  1001
                    w = data->window->windowed.w;
slouken@11874
  1002
                    h = data->window->windowed.h;
slouken@11716
  1003
                    params->rgrc[0].right = params->rgrc[0].left + w;
slouken@11716
  1004
                    params->rgrc[0].bottom = params->rgrc[0].top + h;
slouken@11716
  1005
                }
slouken@11528
  1006
                return 0;
slouken@11716
  1007
            }
slouken@11528
  1008
        }
slouken@11528
  1009
        break;
slouken@11528
  1010
icculus@8938
  1011
    case WM_NCHITTEST:
icculus@8938
  1012
        {
icculus@8938
  1013
            SDL_Window *window = data->window;
icculus@8938
  1014
            if (window->hit_test) {
slouken@11547
  1015
                POINT winpoint = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
slouken@8976
  1016
                if (ScreenToClient(hwnd, &winpoint)) {
icculus@8941
  1017
                    const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
icculus@8941
  1018
                    const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
icculus@8948
  1019
                    switch (rc) {
icculus@10028
  1020
                        #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
icculus@10028
  1021
                        case SDL_HITTEST_DRAGGABLE: POST_HIT_TEST(HTCAPTION);
icculus@10028
  1022
                        case SDL_HITTEST_RESIZE_TOPLEFT: POST_HIT_TEST(HTTOPLEFT);
icculus@10028
  1023
                        case SDL_HITTEST_RESIZE_TOP: POST_HIT_TEST(HTTOP);
icculus@10028
  1024
                        case SDL_HITTEST_RESIZE_TOPRIGHT: POST_HIT_TEST(HTTOPRIGHT);
icculus@10028
  1025
                        case SDL_HITTEST_RESIZE_RIGHT: POST_HIT_TEST(HTRIGHT);
icculus@10028
  1026
                        case SDL_HITTEST_RESIZE_BOTTOMRIGHT: POST_HIT_TEST(HTBOTTOMRIGHT);
icculus@10028
  1027
                        case SDL_HITTEST_RESIZE_BOTTOM: POST_HIT_TEST(HTBOTTOM);
icculus@10028
  1028
                        case SDL_HITTEST_RESIZE_BOTTOMLEFT: POST_HIT_TEST(HTBOTTOMLEFT);
icculus@10028
  1029
                        case SDL_HITTEST_RESIZE_LEFT: POST_HIT_TEST(HTLEFT);
icculus@10028
  1030
                        #undef POST_HIT_TEST
slouken@8976
  1031
                        case SDL_HITTEST_NORMAL: return HTCLIENT;
icculus@8941
  1032
                    }
icculus@8938
  1033
                }
icculus@8948
  1034
                /* If we didn't return, this will call DefWindowProc below. */
icculus@8938
  1035
            }
icculus@8938
  1036
        }
icculus@8938
  1037
        break;
slouken@6523
  1038
    }
slouken@3566
  1039
slouken@3566
  1040
    /* If there's a window proc, assume it's going to handle messages */
slouken@3566
  1041
    if (data->wndproc) {
slouken@3566
  1042
        return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
slouken@3566
  1043
    } else if (returnCode >= 0) {
slouken@3566
  1044
        return returnCode;
slouken@3566
  1045
    } else {
slouken@3566
  1046
        return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
slouken@3566
  1047
    }
slouken@1895
  1048
}
slouken@1895
  1049
slouken@12154
  1050
static void WIN_UpdateClipCursorForWindows()
slouken@12154
  1051
{
slouken@12154
  1052
    SDL_VideoDevice *_this = SDL_GetVideoDevice();
slouken@12154
  1053
    SDL_Window *window;
slouken@12154
  1054
slouken@12154
  1055
    if (_this) {
slouken@12154
  1056
        for (window = _this->windows; window; window = window->next) {
slouken@12154
  1057
            if (window->driverdata) {
slouken@12154
  1058
                WIN_UpdateClipCursor(window);
slouken@12154
  1059
            }
slouken@12154
  1060
        }
slouken@12154
  1061
    }
slouken@12154
  1062
}
slouken@12154
  1063
slouken@9597
  1064
/* A message hook called before TranslateMessage() */
slouken@9597
  1065
static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
slouken@9599
  1066
static void *g_WindowsMessageHookData = NULL;
slouken@9597
  1067
slouken@9599
  1068
void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
slouken@9597
  1069
{
slouken@9597
  1070
    g_WindowsMessageHook = callback;
slouken@9599
  1071
    g_WindowsMessageHookData = userdata;
slouken@9597
  1072
}
slouken@9597
  1073
slouken@1895
  1074
void
slouken@1895
  1075
WIN_PumpEvents(_THIS)
slouken@1895
  1076
{
icculus@7561
  1077
    const Uint8 *keystate;
slouken@1895
  1078
    MSG msg;
slouken@8218
  1079
    DWORD start_ticks = GetTickCount();
slouken@8218
  1080
slouken@8814
  1081
    if (g_WindowsEnableMessageLoop) {
slouken@8814
  1082
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
slouken@9597
  1083
            if (g_WindowsMessageHook) {
slouken@9599
  1084
                g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
slouken@9597
  1085
            }
slouken@9597
  1086
slouken@8814
  1087
            /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
slouken@8814
  1088
            TranslateMessage(&msg);
slouken@8814
  1089
            DispatchMessage(&msg);
slouken@8218
  1090
slouken@8814
  1091
            /* Make sure we don't busy loop here forever if there are lots of events coming in */
slouken@8814
  1092
            if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
slouken@8814
  1093
                break;
slouken@8814
  1094
            }
slouken@8218
  1095
        }
slouken@1895
  1096
    }
icculus@7561
  1097
icculus@7561
  1098
    /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one.
icculus@7561
  1099
       You won't get a KEYUP until both are released, and that keyup will only be for the second
icculus@7561
  1100
       key you released. Take heroic measures and check the keystate as of the last handled event,
icculus@7561
  1101
       and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */
icculus@7561
  1102
    keystate = SDL_GetKeyboardState(NULL);
icculus@7561
  1103
    if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
icculus@7561
  1104
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
icculus@7561
  1105
    }
icculus@7561
  1106
    if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
icculus@7561
  1107
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
icculus@7561
  1108
    }
slouken@12154
  1109
slouken@12154
  1110
    /* Update the clipping rect in case someone else has stolen it */
slouken@12154
  1111
    WIN_UpdateClipCursorForWindows();
slouken@1895
  1112
}
slouken@1895
  1113
slouken@11959
  1114
/* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
slouken@11959
  1115
   we need to detect the windows version. this struct and the function below does that.
slouken@11959
  1116
   usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
slouken@11959
  1117
   but here we just load it dynamically */
slouken@11959
  1118
struct SDL_WIN_OSVERSIONINFOW {
slouken@11959
  1119
    ULONG dwOSVersionInfoSize;
slouken@11959
  1120
    ULONG dwMajorVersion;
slouken@11959
  1121
    ULONG dwMinorVersion;
slouken@11959
  1122
    ULONG dwBuildNumber;
slouken@11959
  1123
    ULONG dwPlatformId;
slouken@11959
  1124
    WCHAR szCSDVersion[128];
slouken@11959
  1125
};
slouken@11959
  1126
slouken@11959
  1127
static SDL_bool
slouken@11959
  1128
IsWin10FCUorNewer(void)
slouken@11959
  1129
{
slouken@11959
  1130
    HMODULE handle = GetModuleHandleW(L"ntdll.dll");
slouken@11959
  1131
    if (handle) {
slouken@11959
  1132
        typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
slouken@11959
  1133
        RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
slouken@11959
  1134
        if (getVersionPtr != NULL) {
slouken@11959
  1135
            struct SDL_WIN_OSVERSIONINFOW info;
slouken@11959
  1136
            SDL_zero(info);
slouken@11959
  1137
            info.dwOSVersionInfoSize = sizeof(info);
slouken@11959
  1138
            if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
slouken@12153
  1139
                if ((info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299) ||
slouken@12153
  1140
                    (info.dwMajorVersion == 10 && info.dwMinorVersion > 0) ||
slouken@12153
  1141
                    (info.dwMajorVersion > 10))
slouken@11959
  1142
                {
slouken@11959
  1143
                    return SDL_TRUE;
slouken@11959
  1144
                }
slouken@11959
  1145
            }
slouken@11959
  1146
        }
slouken@11959
  1147
    }
slouken@11959
  1148
    return SDL_FALSE;
slouken@11959
  1149
}
slouken@11959
  1150
slouken@1895
  1151
static int app_registered = 0;
slouken@1895
  1152
LPTSTR SDL_Appname = NULL;
slouken@1895
  1153
Uint32 SDL_Appstyle = 0;
slouken@1895
  1154
HINSTANCE SDL_Instance = NULL;
slouken@1895
  1155
slouken@1895
  1156
/* Register the class for this application */
slouken@1895
  1157
int
slouken@1895
  1158
SDL_RegisterApp(char *name, Uint32 style, void *hInst)
slouken@1895
  1159
{
slouken@11261
  1160
    const char *hint;
slouken@10426
  1161
    WNDCLASSEX wcex;
slouken@10426
  1162
    TCHAR path[MAX_PATH];
slouken@1895
  1163
slouken@1895
  1164
    /* Only do this once... */
slouken@1895
  1165
    if (app_registered) {
slouken@1895
  1166
        ++app_registered;
slouken@1895
  1167
        return (0);
slouken@1895
  1168
    }
slouken@1895
  1169
    if (!name && !SDL_Appname) {
slouken@1895
  1170
        name = "SDL_app";
slouken@5086
  1171
#if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
slouken@1895
  1172
        SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
slouken@5086
  1173
#endif
slouken@1895
  1174
        SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
slouken@1895
  1175
    }
slouken@1895
  1176
slouken@1895
  1177
    if (name) {
slouken@1895
  1178
        SDL_Appname = WIN_UTF8ToString(name);
slouken@1895
  1179
        SDL_Appstyle = style;
slouken@1895
  1180
        SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
slouken@1895
  1181
    }
slouken@1895
  1182
slouken@1895
  1183
    /* Register the application class */
slouken@10427
  1184
    wcex.cbSize         = sizeof(WNDCLASSEX);
slouken@10427
  1185
    wcex.hCursor        = NULL;
slouken@10427
  1186
    wcex.hIcon          = NULL;
slouken@10427
  1187
    wcex.hIconSm        = NULL;
slouken@10427
  1188
    wcex.lpszMenuName   = NULL;
slouken@10427
  1189
    wcex.lpszClassName  = SDL_Appname;
slouken@10427
  1190
    wcex.style          = SDL_Appstyle;
slouken@10427
  1191
    wcex.hbrBackground  = NULL;
slouken@10427
  1192
    wcex.lpfnWndProc    = WIN_WindowProc;
slouken@10427
  1193
    wcex.hInstance      = SDL_Instance;
slouken@10427
  1194
    wcex.cbClsExtra     = 0;
slouken@10427
  1195
    wcex.cbWndExtra     = 0;
slouken@10427
  1196
slouken@11261
  1197
    hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON);
slouken@11261
  1198
    if (hint && *hint) {
slouken@11261
  1199
        wcex.hIcon = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
slouken@11261
  1200
slouken@11261
  1201
        hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL);
slouken@11261
  1202
        if (hint && *hint) {
slouken@11261
  1203
            wcex.hIconSm = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
slouken@11261
  1204
        }
slouken@11261
  1205
    } else {
slouken@11261
  1206
        /* Use the first icon as a default icon, like in the Explorer */
slouken@11261
  1207
        GetModuleFileName(SDL_Instance, path, MAX_PATH);
slouken@11261
  1208
        ExtractIconEx(path, 0, &wcex.hIcon, &wcex.hIconSm, 1);
slouken@11261
  1209
    }
slouken@10427
  1210
slouken@10426
  1211
    if (!RegisterClassEx(&wcex)) {
icculus@7037
  1212
        return SDL_SetError("Couldn't register application class");
slouken@1895
  1213
    }
slouken@1895
  1214
slouken@11959
  1215
    isWin10FCUorNewer = IsWin10FCUorNewer();
slouken@11959
  1216
slouken@1895
  1217
    app_registered = 1;
icculus@7037
  1218
    return 0;
slouken@1895
  1219
}
slouken@1895
  1220
slouken@1895
  1221
/* Unregisters the windowclass registered in SDL_RegisterApp above. */
slouken@1895
  1222
void
slouken@1895
  1223
SDL_UnregisterApp()
slouken@1895
  1224
{
slouken@10426
  1225
    WNDCLASSEX wcex;
slouken@1895
  1226
slouken@1895
  1227
    /* SDL_RegisterApp might not have been called before */
slouken@1895
  1228
    if (!app_registered) {
slouken@1895
  1229
        return;
slouken@1895
  1230
    }
slouken@1895
  1231
    --app_registered;
slouken@1895
  1232
    if (app_registered == 0) {
slouken@1895
  1233
        /* Check for any registered window classes. */
slouken@10426
  1234
        if (GetClassInfoEx(SDL_Instance, SDL_Appname, &wcex)) {
slouken@1895
  1235
            UnregisterClass(SDL_Appname, SDL_Instance);
slouken@10426
  1236
            if (wcex.hIcon) DestroyIcon(wcex.hIcon);
slouken@10426
  1237
            if (wcex.hIconSm) DestroyIcon(wcex.hIconSm);
slouken@1895
  1238
        }
slouken@1895
  1239
        SDL_free(SDL_Appname);
slouken@1895
  1240
        SDL_Appname = NULL;
slouken@1895
  1241
    }
slouken@1895
  1242
}
slouken@1895
  1243
slouken@6044
  1244
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
slouken@6044
  1245
slouken@1895
  1246
/* vi: set ts=4 sw=4 expandtab: */