src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 26 Aug 2018 10:34:23 -0700
changeset 12153 de4288fa5b0b
parent 11959 4cc8aad8d434
child 12154 2a9b4339468b
permissions -rw-r--r--
Only reset the clip rect if it's currently the rect we previously clipped.
This prevents us from clearing the clip rect globally when another application has set it.

There's also an experimental change to regularly update the clip rect for a window defensively, in case someone else has reset it. It works well, but I don't know if it's cheap enough to call as frequently as it would be called now, and might have other undesirable side effects.

Also fixed whitespace and SDL coding style
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 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@12153
   231
            WIN_UpdateClipCursor(data->window);
slouken@10377
   232
        }
slouken@10379
   233
        if (WIN_ShouldIgnoreFocusClick()) {
slouken@10379
   234
            return;
slouken@10379
   235
        }
slouken@8916
   236
    }
slouken@8916
   237
slouken@8813
   238
    if (bwParamMousePressed && !bSDLMousePressed) {
dludwig@9668
   239
        SDL_SendMouseButton(data->window, mouseID, SDL_PRESSED, button);
slouken@8813
   240
    } else if (!bwParamMousePressed && bSDLMousePressed) {
dludwig@9668
   241
        SDL_SendMouseButton(data->window, mouseID, SDL_RELEASED, button);
slouken@7191
   242
    }
slouken@6943
   243
}
slouken@6943
   244
slouken@6943
   245
/*
slouken@6943
   246
* Some windows systems fail to send a WM_LBUTTONDOWN sometimes, but each mouse move contains the current button state also
slouken@6943
   247
*  so this funciton reconciles our view of the world with the current buttons reported by windows
slouken@6943
   248
*/
philipp@10982
   249
static void
dludwig@9668
   250
WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mouseID)
slouken@6943
   251
{
slouken@8813
   252
    if (wParam != data->mouse_button_flags) {
slouken@8813
   253
        Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
dludwig@9668
   254
        WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, mouseID);
dludwig@9668
   255
        WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, mouseID);
dludwig@9668
   256
        WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, mouseID);
dludwig@9668
   257
        WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, mouseID);
dludwig@9668
   258
        WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, mouseID);
slouken@7191
   259
        data->mouse_button_flags = wParam;
slouken@7191
   260
    }
slouken@6943
   261
}
slouken@6943
   262
slouken@6943
   263
philipp@10982
   264
static void
slouken@8813
   265
WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data)
slouken@6943
   266
{
slouken@8813
   267
    if (rawButtons != data->mouse_button_flags) {
slouken@8813
   268
        Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
slouken@8813
   269
        if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN))
dludwig@9668
   270
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
slouken@8813
   271
        if ((rawButtons & RI_MOUSE_BUTTON_1_UP))
dludwig@9668
   272
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
slouken@8813
   273
        if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN))
dludwig@9668
   274
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
slouken@8813
   275
        if ((rawButtons & RI_MOUSE_BUTTON_2_UP))
dludwig@9668
   276
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
slouken@8813
   277
        if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN))
dludwig@9668
   278
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
slouken@8813
   279
        if ((rawButtons & RI_MOUSE_BUTTON_3_UP))
dludwig@9668
   280
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
slouken@8813
   281
        if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN))
dludwig@9668
   282
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
slouken@8813
   283
        if ((rawButtons & RI_MOUSE_BUTTON_4_UP))
dludwig@9668
   284
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
slouken@8813
   285
        if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN))
dludwig@9668
   286
            WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
slouken@8813
   287
        if ((rawButtons & RI_MOUSE_BUTTON_5_UP))
dludwig@9668
   288
            WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
slouken@7191
   289
        data->mouse_button_flags = rawButtons;
slouken@7191
   290
    }
slouken@6943
   291
}
slouken@6943
   292
philipp@10982
   293
static void
slouken@8813
   294
WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
slouken@8212
   295
{
slouken@8212
   296
    Uint32 mouseFlags;
slouken@8212
   297
    SHORT keyState;
slouken@8212
   298
slouken@8212
   299
    /* mouse buttons may have changed state here, we need to resync them,
slouken@8212
   300
       but we will get a WM_MOUSEMOVE right away which will fix things up if in non raw mode also
slouken@8212
   301
    */
slouken@8813
   302
    mouseFlags = SDL_GetMouseState(NULL, NULL);
slouken@8212
   303
slouken@8813
   304
    keyState = GetAsyncKeyState(VK_LBUTTON);
slouken@8796
   305
    if (!(keyState & 0x8000)) {
dludwig@9668
   306
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
slouken@8796
   307
    }
slouken@8796
   308
    keyState = GetAsyncKeyState(VK_RBUTTON);
slouken@8796
   309
    if (!(keyState & 0x8000)) {
dludwig@9668
   310
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
slouken@8796
   311
    }
slouken@8796
   312
    keyState = GetAsyncKeyState(VK_MBUTTON);
slouken@8796
   313
    if (!(keyState & 0x8000)) {
dludwig@9668
   314
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
slouken@8796
   315
    }
slouken@8796
   316
    keyState = GetAsyncKeyState(VK_XBUTTON1);
slouken@8796
   317
    if (!(keyState & 0x8000)) {
dludwig@9668
   318
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
slouken@8796
   319
    }
slouken@8796
   320
    keyState = GetAsyncKeyState(VK_XBUTTON2);
slouken@8796
   321
    if (!(keyState & 0x8000)) {
dludwig@9668
   322
        WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
slouken@8796
   323
    }
slouken@8212
   324
    data->mouse_button_flags = 0;
slouken@8212
   325
}
slouken@8212
   326
philipp@10982
   327
static BOOL
slouken@7645
   328
WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
slouken@7645
   329
{
slouken@7645
   330
    if (codepoint <= 0x7F) {
slouken@7645
   331
        text[0] = (char) codepoint;
slouken@7645
   332
        text[1] = '\0';
slouken@7645
   333
    } else if (codepoint <= 0x7FF) {
slouken@7645
   334
        text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
slouken@7645
   335
        text[1] = 0x80 | (char) (codepoint & 0x3F);
slouken@7645
   336
        text[2] = '\0';
slouken@7645
   337
    } else if (codepoint <= 0xFFFF) {
slouken@7645
   338
        text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
slouken@7645
   339
        text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
slouken@7645
   340
        text[2] = 0x80 | (char) (codepoint & 0x3F);
slouken@7645
   341
        text[3] = '\0';
slouken@7645
   342
    } else if (codepoint <= 0x10FFFF) {
slouken@7645
   343
        text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
slouken@7645
   344
        text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
slouken@7645
   345
        text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
slouken@7645
   346
        text[3] = 0x80 | (char) (codepoint & 0x3F);
slouken@7645
   347
        text[4] = '\0';
slouken@7645
   348
    } else {
slouken@7645
   349
        return SDL_FALSE;
slouken@7645
   350
    }
slouken@7645
   351
    return SDL_TRUE;
slouken@7645
   352
}
slouken@7645
   353
andrewb@9829
   354
static SDL_bool
andrewb@9829
   355
ShouldGenerateWindowCloseOnAltF4(void)
andrewb@9829
   356
{
slouken@10499
   357
    return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
andrewb@9829
   358
}
andrewb@9829
   359
slouken@11959
   360
/* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
slouken@11959
   361
   doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
slouken@11959
   362
   This is used to implement a workaround.. */
slouken@11959
   363
static SDL_bool isWin10FCUorNewer = SDL_FALSE;
slouken@11959
   364
slouken@1895
   365
LRESULT CALLBACK
slouken@1895
   366
WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
slouken@1895
   367
{
slouken@1895
   368
    SDL_WindowData *data;
slouken@3566
   369
    LRESULT returnCode = -1;
slouken@1895
   370
slouken@1951
   371
    /* Send a SDL_SYSWMEVENT if the application wants them */
slouken@4429
   372
    if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
slouken@1951
   373
        SDL_SysWMmsg wmmsg;
slouken@1951
   374
slouken@1951
   375
        SDL_VERSION(&wmmsg.version);
slouken@4900
   376
        wmmsg.subsystem = SDL_SYSWM_WINDOWS;
slouken@5056
   377
        wmmsg.msg.win.hwnd = hwnd;
slouken@5056
   378
        wmmsg.msg.win.msg = msg;
slouken@5056
   379
        wmmsg.msg.win.wParam = wParam;
slouken@5056
   380
        wmmsg.msg.win.lParam = lParam;
slouken@1951
   381
        SDL_SendSysWMEvent(&wmmsg);
slouken@1951
   382
    }
slouken@1951
   383
slouken@1895
   384
    /* Get the window data for the window */
slouken@1895
   385
    data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
slouken@1895
   386
    if (!data) {
slouken@1895
   387
        return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
slouken@1895
   388
    }
jimtla@4650
   389
slouken@1895
   390
#ifdef WMMSG_DEBUG
slouken@7941
   391
    {
slouken@7941
   392
        char message[1024];
slouken@7941
   393
        if (msg > MAX_WMMSG) {
slouken@7941
   394
            SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam);
slouken@7941
   395
        } else {
slouken@7941
   396
            SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam);
slouken@7941
   397
        }
slouken@7941
   398
        OutputDebugStringA(message);
slouken@7941
   399
    }
slouken@7816
   400
#endif /* WMMSG_DEBUG */
slouken@2710
   401
slouken@12153
   402
    /* Update the clipping rect in case someone else has stolen it */
slouken@12153
   403
    /* FIXME: Is this function cheap enough to call this frequently?
slouken@12153
   404
    WIN_UpdateClipCursor(data->window);
slouken@12153
   405
    */
slouken@12153
   406
dewyatt@4752
   407
    if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
dewyatt@4752
   408
        return 0;
slouken@1895
   409
slouken@1895
   410
    switch (msg) {
slouken@1895
   411
slouken@1895
   412
    case WM_SHOWWINDOW:
slouken@1895
   413
        {
slouken@1895
   414
            if (wParam) {
slouken@3685
   415
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
slouken@1895
   416
            } else {
slouken@3685
   417
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
slouken@1895
   418
            }
slouken@1895
   419
        }
slouken@1895
   420
        break;
slouken@1895
   421
slouken@1895
   422
    case WM_ACTIVATE:
slouken@1895
   423
        {
slouken@8796
   424
            POINT cursorPos;
slouken@1895
   425
            BOOL minimized;
slouken@1895
   426
slouken@11938
   427
            /* Don't mark the window as shown if it's activated before being shown */
slouken@11938
   428
            if (!IsWindowVisible(hwnd)) {
slouken@11938
   429
                break;
slouken@11938
   430
            }
slouken@11938
   431
slouken@1895
   432
            minimized = HIWORD(wParam);
slouken@1895
   433
            if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
slouken@10539
   434
                if (LOWORD(wParam) == WA_CLICKACTIVE) {
slouken@10539
   435
                    if (GetAsyncKeyState(VK_LBUTTON)) {
slouken@10539
   436
                        data->focus_click_pending |= SDL_BUTTON_LMASK;
slouken@10539
   437
                    }
slouken@10539
   438
                    if (GetAsyncKeyState(VK_RBUTTON)) {
slouken@10539
   439
                        data->focus_click_pending |= SDL_BUTTON_RMASK;
slouken@10539
   440
                    }
slouken@10539
   441
                    if (GetAsyncKeyState(VK_MBUTTON)) {
slouken@10539
   442
                        data->focus_click_pending |= SDL_BUTTON_MMASK;
slouken@10539
   443
                    }
slouken@10539
   444
                    if (GetAsyncKeyState(VK_XBUTTON1)) {
slouken@10539
   445
                        data->focus_click_pending |= SDL_BUTTON_X1MASK;
slouken@10539
   446
                    }
slouken@10539
   447
                    if (GetAsyncKeyState(VK_XBUTTON2)) {
slouken@10539
   448
                        data->focus_click_pending |= SDL_BUTTON_X2MASK;
slouken@10539
   449
                    }
slouken@10377
   450
                }
slouken@10377
   451
                
slouken@3685
   452
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
slouken@4465
   453
                if (SDL_GetKeyboardFocus() != data->window) {
slouken@4465
   454
                    SDL_SetKeyboardFocus(data->window);
slouken@1895
   455
                }
slouken@11300
   456
slouken@8796
   457
                GetCursorPos(&cursorPos);
slouken@8796
   458
                ScreenToClient(hwnd, &cursorPos);
slouken@8796
   459
                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
slouken@11300
   460
slouken@8212
   461
                WIN_CheckAsyncMouseRelease(data);
slouken@6350
   462
slouken@4504
   463
                /*
slouken@4504
   464
                 * FIXME: Update keyboard state
slouken@4504
   465
                 */
slouken@4504
   466
                WIN_CheckClipboardUpdate(data->videodata);
icculus@9974
   467
icculus@9974
   468
                SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
icculus@9974
   469
                SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
slouken@1895
   470
            } else {
slouken@12153
   471
                RECT rect;
slouken@12153
   472
dludwig@9990
   473
                data->in_window_deactivation = SDL_TRUE;
dludwig@9990
   474
slouken@4465
   475
                if (SDL_GetKeyboardFocus() == data->window) {
slouken@4465
   476
                    SDL_SetKeyboardFocus(NULL);
slouken@10411
   477
                    WIN_ResetDeadKeys();
slouken@1895
   478
                }
slouken@8050
   479
slouken@12153
   480
                if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect) == 0)) {
slouken@12153
   481
SDL_Log("Windows deactivate, ClipCursor(NULL)\n");
slouken@12153
   482
                    ClipCursor(NULL);
slouken@12153
   483
                    SDL_zero(data->cursor_clipped_rect);
slouken@12153
   484
                }
dludwig@9990
   485
dludwig@9990
   486
                data->in_window_deactivation = SDL_FALSE;
slouken@1895
   487
            }
slouken@1895
   488
        }
slouken@3566
   489
        returnCode = 0;
slouken@3566
   490
        break;
slouken@1895
   491
slouken@7191
   492
    case WM_MOUSEMOVE:
slouken@8071
   493
        {
slouken@8071
   494
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   495
            if (!mouse->relative_mode || mouse->relative_mode_warp) {
dludwig@9668
   496
                SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
dludwig@9668
   497
                SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
slouken@11959
   498
                if (isWin10FCUorNewer && mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
slouken@11959
   499
                    /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
slouken@11959
   500
                       SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
slouken@11959
   501
                       after each windows mouse event generate a fake event for the middle of the window
slouken@11959
   502
                       if relative_mode_warp is used */
slouken@11959
   503
                    int center_x = 0, center_y = 0;
slouken@11959
   504
                    SDL_GetWindowSize(data->window, &center_x, &center_y);
slouken@11959
   505
                    center_x /= 2;
slouken@11959
   506
                    center_y /= 2;
slouken@11959
   507
                    SDL_SendMouseMotion(data->window, mouseID, 0, center_x, center_y);
slouken@11959
   508
                }
slouken@8071
   509
            }
slouken@8071
   510
        }
slouken@7191
   511
        /* don't break here, fall through to check the wParam like the button presses */
slouken@7191
   512
    case WM_LBUTTONUP:
slouken@7191
   513
    case WM_RBUTTONUP:
slouken@7191
   514
    case WM_MBUTTONUP:
slouken@7191
   515
    case WM_XBUTTONUP:
slouken@7191
   516
    case WM_LBUTTONDOWN:
slouken@8713
   517
    case WM_LBUTTONDBLCLK:
slouken@7191
   518
    case WM_RBUTTONDOWN:
slouken@8713
   519
    case WM_RBUTTONDBLCLK:
slouken@7191
   520
    case WM_MBUTTONDOWN:
slouken@8713
   521
    case WM_MBUTTONDBLCLK:
slouken@7191
   522
    case WM_XBUTTONDOWN:
slouken@8713
   523
    case WM_XBUTTONDBLCLK:
slouken@8071
   524
        {
slouken@8071
   525
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   526
            if (!mouse->relative_mode || mouse->relative_mode_warp) {
dludwig@9668
   527
                SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
dludwig@9668
   528
                WIN_CheckWParamMouseButtons(wParam, data, mouseID);
slouken@8071
   529
            }
slouken@8071
   530
        }
slouken@7191
   531
        break;
slouken@3139
   532
slouken@7191
   533
    case WM_INPUT:
slouken@8071
   534
        {
slouken@8071
   535
            SDL_Mouse *mouse = SDL_GetMouse();
slouken@8071
   536
            HRAWINPUT hRawInput = (HRAWINPUT)lParam;
slouken@8071
   537
            RAWINPUT inp;
slouken@8071
   538
            UINT size = sizeof(inp);
icculus@8942
   539
            const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
icculus@8942
   540
            const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
slouken@6782
   541
icculus@8942
   542
            if (!isRelative || mouse->focus != data->window) {
icculus@8942
   543
                if (!isCapture) {
icculus@8942
   544
                    break;
icculus@8942
   545
                }
slouken@8071
   546
            }
slouken@6782
   547
slouken@8071
   548
            GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
slouken@6350
   549
slouken@8071
   550
            /* Mouse data */
slouken@8071
   551
            if (inp.header.dwType == RIM_TYPEMOUSE) {
icculus@8942
   552
                if (isRelative) {
slouken@8976
   553
                    RAWMOUSE* rawmouse = &inp.data.mouse;
slouken@6350
   554
slouken@8976
   555
                    if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
slouken@8976
   556
                        SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
icculus@8942
   557
                    } else {
icculus@8942
   558
                        /* synthesize relative moves from the abs position */
icculus@8942
   559
                        static SDL_Point initialMousePoint;
icculus@8942
   560
                        if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
slouken@8976
   561
                            initialMousePoint.x = rawmouse->lLastX;
slouken@8976
   562
                            initialMousePoint.y = rawmouse->lLastY;
icculus@8942
   563
                        }
icculus@8942
   564
slouken@10864
   565
                        SDL_SendMouseMotion(data->window, 0, 1, (int)(rawmouse->lLastX-initialMousePoint.x), (int)(rawmouse->lLastY-initialMousePoint.y));
icculus@8942
   566
slouken@8976
   567
                        initialMousePoint.x = rawmouse->lLastX;
slouken@8976
   568
                        initialMousePoint.y = rawmouse->lLastY;
slouken@8071
   569
                    }
slouken@8976
   570
                    WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
icculus@8942
   571
                } else if (isCapture) {
icculus@8942
   572
                    /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
icculus@8942
   573
                    POINT pt;
slouken@10863
   574
                    RECT hwndRect;
slouken@10864
   575
                    HWND currentHnd;
slouken@10864
   576
icculus@8942
   577
                    GetCursorPos(&pt);
slouken@10864
   578
                    currentHnd = WindowFromPoint(pt);
slouken@10864
   579
                    ScreenToClient(hwnd, &pt);
slouken@10864
   580
                    GetClientRect(hwnd, &hwndRect);
slouken@10863
   581
slouken@10863
   582
                    /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
slouken@10864
   583
                    if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
slouken@10864
   584
                        SDL_SendMouseMotion(data->window, 0, 0, (int)pt.x, (int)pt.y);
icculus@8949
   585
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
icculus@8949
   586
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
icculus@8949
   587
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
icculus@8949
   588
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
icculus@8949
   589
                        SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
icculus@8942
   590
                    }
icculus@8942
   591
                } else {
icculus@8942
   592
                    SDL_assert(0 && "Shouldn't happen");
slouken@7191
   593
                }
slouken@7191
   594
            }
slouken@7191
   595
        }
slouken@7191
   596
        break;
slouken@6350
   597
slouken@5049
   598
    case WM_MOUSEWHEEL:
slouken@7911
   599
    case WM_MOUSEHWHEEL:
slouken@7911
   600
        {
slouken@11300
   601
            short amount = GET_WHEEL_DELTA_WPARAM(wParam);
slouken@11300
   602
            float fAmount = (float) amount / WHEEL_DELTA;
slouken@11300
   603
            if (msg == WM_MOUSEWHEEL)
slouken@11300
   604
                SDL_SendMouseWheel(data->window, 0, 0.0f, fAmount, SDL_MOUSEWHEEL_NORMAL);
slouken@11300
   605
            else
slouken@11300
   606
                SDL_SendMouseWheel(data->window, 0, fAmount, 0.0f, SDL_MOUSEWHEEL_NORMAL);
slouken@7911
   607
        }
slouken@8071
   608
        break;
slouken@7911
   609
slouken@5086
   610
#ifdef WM_MOUSELEAVE
slouken@1895
   611
    case WM_MOUSELEAVE:
icculus@8942
   612
        if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
slouken@8035
   613
            if (!IsIconic(hwnd)) {
slouken@8035
   614
                POINT cursorPos;
slouken@8035
   615
                GetCursorPos(&cursorPos);
slouken@8035
   616
                ScreenToClient(hwnd, &cursorPos);
slouken@8035
   617
                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
slouken@8035
   618
            }
slouken@7191
   619
            SDL_SetMouseFocus(NULL);
slouken@1895
   620
        }
slouken@3566
   621
        returnCode = 0;
slouken@3566
   622
        break;
slouken@5086
   623
#endif /* WM_MOUSELEAVE */
slouken@1895
   624
slouken@7645
   625
    case WM_KEYDOWN:
slouken@7646
   626
    case WM_SYSKEYDOWN:
slouken@7645
   627
        {
slouken@8813
   628
            SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
icculus@9641
   629
            const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
icculus@9641
   630
icculus@9641
   631
            /* Detect relevant keyboard shortcuts */
icculus@9641
   632
            if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) {
icculus@9641
   633
                /* ALT+F4: Close window */
andrewb@9829
   634
                if (code == SDL_SCANCODE_F4 && ShouldGenerateWindowCloseOnAltF4()) {
icculus@9641
   635
                    SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
icculus@9641
   636
                }
icculus@9641
   637
            }
icculus@9641
   638
slouken@8813
   639
            if (code != SDL_SCANCODE_UNKNOWN) {
slouken@8813
   640
                SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@7646
   641
            }
slouken@7646
   642
        }
slouken@11300
   643
slouken@3566
   644
        returnCode = 0;
slouken@3566
   645
        break;
slouken@1895
   646
slouken@1895
   647
    case WM_SYSKEYUP:
slouken@1895
   648
    case WM_KEYUP:
slouken@1895
   649
        {
slouken@8813
   650
            SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
gabomdq@7975
   651
            const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
gabomdq@7975
   652
slouken@8813
   653
            if (code != SDL_SCANCODE_UNKNOWN) {
slouken@6938
   654
                if (code == SDL_SCANCODE_PRINTSCREEN &&
gabomdq@7975
   655
                    keyboardState[code] == SDL_RELEASED) {
slouken@6938
   656
                    SDL_SendKeyboardKey(SDL_PRESSED, code);
slouken@6938
   657
                }
slouken@6938
   658
                SDL_SendKeyboardKey(SDL_RELEASED, code);
slouken@2308
   659
            }
slouken@1895
   660
        }
slouken@3566
   661
        returnCode = 0;
slouken@3566
   662
        break;
slouken@1895
   663
slouken@8143
   664
    case WM_UNICHAR:
slouken@12153
   665
        if (wParam == UNICODE_NOCHAR) {
slouken@9889
   666
            returnCode = 1;
slouken@9889
   667
            break;
slouken@9889
   668
        }
slouken@9889
   669
        /* otherwise fall through to below */
slouken@9889
   670
    case WM_CHAR:
slouken@9889
   671
        {
slouken@9889
   672
            char text[5];
slouken@12153
   673
            if (WIN_ConvertUTF32toUTF8((UINT32)wParam, text)) {
slouken@12153
   674
                SDL_SendKeyboardText(text);
slouken@9889
   675
            }
slouken@9889
   676
        }
slouken@9889
   677
        returnCode = 0;
slouken@8143
   678
        break;
slouken@8143
   679
slouken@5086
   680
#ifdef WM_INPUTLANGCHANGE
slouken@2311
   681
    case WM_INPUTLANGCHANGE:
slouken@2311
   682
        {
slouken@4465
   683
            WIN_UpdateKeymap();
slouken@9898
   684
            SDL_SendKeymapChangedEvent();
slouken@2311
   685
        }
slouken@3566
   686
        returnCode = 1;
slouken@3566
   687
        break;
slouken@5086
   688
#endif /* WM_INPUTLANGCHANGE */
slouken@2311
   689
slouken@8253
   690
    case WM_NCLBUTTONDOWN:
slouken@8253
   691
        {
slouken@8253
   692
            data->in_title_click = SDL_TRUE;
slouken@8253
   693
        }
slouken@8253
   694
        break;
slouken@8253
   695
slouken@8916
   696
    case WM_CAPTURECHANGED:
slouken@8253
   697
        {
slouken@8253
   698
            data->in_title_click = SDL_FALSE;
slouken@8253
   699
slouken@8916
   700
            /* The mouse may have been released during a modal loop */
slouken@8212
   701
            WIN_CheckAsyncMouseRelease(data);
slouken@8036
   702
        }
slouken@8036
   703
        break;
slouken@8036
   704
slouken@5086
   705
#ifdef WM_GETMINMAXINFO
slouken@1895
   706
    case WM_GETMINMAXINFO:
slouken@1895
   707
        {
slouken@1895
   708
            MINMAXINFO *info;
slouken@1895
   709
            RECT size;
slouken@1895
   710
            int x, y;
slouken@1895
   711
            int w, h;
stopiccot@6682
   712
            int min_w, min_h;
slouken@6788
   713
            int max_w, max_h;
slouken@7191
   714
            BOOL constrain_max_size;
slouken@1895
   715
stopiccot@6682
   716
            if (SDL_IsShapedWindow(data->window))
eligottlieb@4815
   717
                Win32_ResizeWindowShape(data->window);
slouken@1895
   718
slouken@7941
   719
            /* If this is an expected size change, allow it */
slouken@7941
   720
            if (data->expected_resize) {
slouken@7941
   721
                break;
slouken@7941
   722
            }
slouken@7941
   723
slouken@1895
   724
            /* Get the current position of our window */
slouken@1895
   725
            GetWindowRect(hwnd, &size);
slouken@1895
   726
            x = size.left;
slouken@1895
   727
            y = size.top;
slouken@1895
   728
slouken@1895
   729
            /* Calculate current size of our window */
slouken@3685
   730
            SDL_GetWindowSize(data->window, &w, &h);
stopiccot@6682
   731
            SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
slouken@6788
   732
            SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
stopiccot@6682
   733
slouken@7191
   734
            /* Store in min_w and min_h difference between current size and minimal
stopiccot@6682
   735
               size so we don't need to call AdjustWindowRectEx twice */
stopiccot@6682
   736
            min_w -= w;
stopiccot@6682
   737
            min_h -= h;
slouken@6837
   738
            if (max_w && max_h) {
slouken@6837
   739
                max_w -= w;
slouken@6837
   740
                max_h -= h;
slouken@6862
   741
                constrain_max_size = TRUE;
slouken@6862
   742
            } else {
slouken@6862
   743
                constrain_max_size = FALSE;
slouken@6837
   744
            }
stopiccot@6682
   745
slouken@11857
   746
            if (!(SDL_GetWindowFlags(data->window) & SDL_WINDOW_BORDERLESS)) {
slouken@11857
   747
                LONG style = GetWindowLong(hwnd, GWL_STYLE);
slouken@11857
   748
                /* DJM - according to the docs for GetMenu(), the
slouken@11857
   749
                   return value is undefined if hwnd is a child window.
slouken@11857
   750
                   Apparently it's too difficult for MS to check
slouken@11857
   751
                   inside their function, so I have to do it here.
slouken@11857
   752
                 */
slouken@11857
   753
                BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
slouken@11857
   754
                size.top = 0;
slouken@11857
   755
                size.left = 0;
slouken@11857
   756
                size.bottom = h;
slouken@11857
   757
                size.right = w;
slouken@1895
   758
slouken@11857
   759
                AdjustWindowRectEx(&size, style, menu, 0);
slouken@11857
   760
                w = size.right - size.left;
slouken@11857
   761
                h = size.bottom - size.top;
slouken@11857
   762
            }
slouken@1895
   763
slouken@1895
   764
            /* Fix our size to the current size */
slouken@1895
   765
            info = (MINMAXINFO *) lParam;
stopiccot@6682
   766
            if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
stopiccot@6682
   767
                info->ptMinTrackSize.x = w + min_w;
stopiccot@6682
   768
                info->ptMinTrackSize.y = h + min_h;
slouken@6862
   769
                if (constrain_max_size) {
slouken@6862
   770
                    info->ptMaxTrackSize.x = w + max_w;
slouken@6862
   771
                    info->ptMaxTrackSize.y = h + max_h;
slouken@6862
   772
                }
stopiccot@6682
   773
            } else {
stopiccot@6682
   774
                info->ptMaxSize.x = w;
stopiccot@6682
   775
                info->ptMaxSize.y = h;
stopiccot@6682
   776
                info->ptMaxPosition.x = x;
stopiccot@6682
   777
                info->ptMaxPosition.y = y;
stopiccot@6682
   778
                info->ptMinTrackSize.x = w;
stopiccot@6682
   779
                info->ptMinTrackSize.y = h;
stopiccot@6682
   780
                info->ptMaxTrackSize.x = w;
stopiccot@6682
   781
                info->ptMaxTrackSize.y = h;
stopiccot@6682
   782
            }
slouken@1895
   783
        }
slouken@3566
   784
        returnCode = 0;
slouken@3566
   785
        break;
slouken@5086
   786
#endif /* WM_GETMINMAXINFO */
slouken@1895
   787
icculus@10387
   788
    case WM_WINDOWPOSCHANGING:
icculus@10387
   789
icculus@10387
   790
        if (data->expected_resize) {
icculus@10387
   791
            returnCode = 0;
icculus@10387
   792
        }
icculus@10387
   793
        break;
icculus@10387
   794
slouken@1895
   795
    case WM_WINDOWPOSCHANGED:
slouken@1895
   796
        {
slouken@1895
   797
            RECT rect;
slouken@1895
   798
            int x, y;
slouken@1895
   799
            int w, h;
slouken@11300
   800
slouken@9888
   801
            if (data->initializing || data->in_border_change) {
slouken@8817
   802
                break;
slouken@8817
   803
            }
slouken@1895
   804
slouken@8036
   805
            if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) {
slouken@3256
   806
                break;
slouken@3256
   807
            }
slouken@1895
   808
            ClientToScreen(hwnd, (LPPOINT) & rect);
slouken@1895
   809
            ClientToScreen(hwnd, (LPPOINT) & rect + 1);
slouken@1895
   810
slouken@8036
   811
            WIN_UpdateClipCursor(data->window);
slouken@1895
   812
slouken@1895
   813
            x = rect.left;
slouken@1895
   814
            y = rect.top;
slouken@3685
   815
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@1895
   816
slouken@1895
   817
            w = rect.right - rect.left;
slouken@1895
   818
            h = rect.bottom - rect.top;
slouken@3685
   819
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
slouken@1895
   820
                                h);
flibitijibibo@10417
   821
flibitijibibo@10417
   822
            /* Forces a WM_PAINT event */
flibitijibibo@10417
   823
            InvalidateRect(hwnd, NULL, FALSE);
slouken@1895
   824
        }
slouken@1895
   825
        break;
slouken@1895
   826
slouken@7941
   827
    case WM_SIZE:
slouken@7941
   828
        {
slouken@8813
   829
            switch (wParam) {
slouken@7941
   830
            case SIZE_MAXIMIZED:
slouken@7941
   831
                SDL_SendWindowEvent(data->window,
slouken@11007
   832
                    SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@11007
   833
                SDL_SendWindowEvent(data->window,
slouken@7941
   834
                    SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
slouken@7941
   835
                break;
slouken@7941
   836
            case SIZE_MINIMIZED:
slouken@7941
   837
                SDL_SendWindowEvent(data->window,
slouken@7941
   838
                    SDL_WINDOWEVENT_MINIMIZED, 0, 0);
slouken@7941
   839
                break;
slouken@7941
   840
            default:
slouken@7941
   841
                SDL_SendWindowEvent(data->window,
slouken@7941
   842
                    SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@7941
   843
                break;
slouken@7941
   844
            }
slouken@7941
   845
        }
slouken@7941
   846
        break;
slouken@7941
   847
slouken@1895
   848
    case WM_SETCURSOR:
slouken@1895
   849
        {
slouken@3076
   850
            Uint16 hittest;
slouken@1895
   851
slouken@3076
   852
            hittest = LOWORD(lParam);
slouken@3076
   853
            if (hittest == HTCLIENT) {
slouken@5421
   854
                SetCursor(SDL_cursor);
slouken@3566
   855
                returnCode = TRUE;
slouken@8813
   856
            } else if (!g_WindowFrameUsableWhileCursorHidden && !SDL_cursor) {
slouken@8813
   857
                SetCursor(NULL);
slouken@8813
   858
                returnCode = TRUE;
slouken@3076
   859
            }
slouken@1895
   860
        }
slouken@1895
   861
        break;
slouken@1895
   862
slouken@1895
   863
        /* We were occluded, refresh our display */
slouken@1895
   864
    case WM_PAINT:
slouken@1895
   865
        {
slouken@1895
   866
            RECT rect;
slouken@1895
   867
            if (GetUpdateRect(hwnd, &rect, FALSE)) {
slouken@7295
   868
                ValidateRect(hwnd, NULL);
slouken@3685
   869
                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
slouken@1895
   870
                                    0, 0);
slouken@1895
   871
            }
slouken@1895
   872
        }
slouken@3566
   873
        returnCode = 0;
slouken@3566
   874
        break;
slouken@3095
   875
slouken@1895
   876
        /* We'll do our own drawing, prevent flicker */
slouken@1895
   877
    case WM_ERASEBKGND:
slouken@1895
   878
        {
slouken@1895
   879
        }
slouken@1895
   880
        return (1);
slouken@1895
   881
slouken@1895
   882
    case WM_SYSCOMMAND:
slouken@1895
   883
        {
slouken@9889
   884
            if ((wParam & 0xFFF0) == SC_KEYMENU) {
slouken@9889
   885
                return (0);
slouken@9889
   886
            }
icculus@9624
   887
icculus@9624
   888
#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
slouken@1895
   889
            /* Don't start the screensaver or blank the monitor in fullscreen apps */
slouken@1895
   890
            if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
slouken@1895
   891
                (wParam & 0xFFF0) == SC_MONITORPOWER) {
slouken@3032
   892
                if (SDL_GetVideoDevice()->suspend_screensaver) {
slouken@1895
   893
                    return (0);
slouken@1895
   894
                }
slouken@1895
   895
            }
icculus@9624
   896
#endif /* System has screensaver support */
slouken@1895
   897
        }
slouken@1895
   898
        break;
slouken@1895
   899
slouken@1895
   900
    case WM_CLOSE:
slouken@1895
   901
        {
slouken@3685
   902
            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
slouken@1895
   903
        }
slouken@3566
   904
        returnCode = 0;
slouken@3566
   905
        break;
slouken@4919
   906
slouken@7191
   907
    case WM_TOUCH:
slouken@11215
   908
        if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
slouken@7191
   909
            UINT i, num_inputs = LOWORD(wParam);
slouken@7191
   910
            PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
slouken@7191
   911
            if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
slouken@7191
   912
                RECT rect;
slouken@7191
   913
                float x, y;
slouken@4919
   914
slouken@7191
   915
                if (!GetClientRect(hwnd, &rect) ||
slouken@7191
   916
                    (rect.right == rect.left && rect.bottom == rect.top)) {
philipp@7631
   917
                    if (inputs) {
philipp@7631
   918
                        SDL_stack_free(inputs);
philipp@7631
   919
                    }
slouken@7191
   920
                    break;
slouken@7191
   921
                }
slouken@7191
   922
                ClientToScreen(hwnd, (LPPOINT) & rect);
slouken@7191
   923
                ClientToScreen(hwnd, (LPPOINT) & rect + 1);
slouken@7191
   924
                rect.top *= 100;
slouken@7191
   925
                rect.left *= 100;
slouken@7191
   926
                rect.bottom *= 100;
slouken@7191
   927
                rect.right *= 100;
slouken@4932
   928
slouken@7191
   929
                for (i = 0; i < num_inputs; ++i) {
slouken@7191
   930
                    PTOUCHINPUT input = &inputs[i];
slouken@4919
   931
icculus@7543
   932
                    const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource);
slouken@9679
   933
                    if (SDL_AddTouch(touchId, "") < 0) {
slouken@9679
   934
                        continue;
slouken@7191
   935
                    }
slouken@4932
   936
slouken@7191
   937
                    /* Get the normalized coordinates for the window */
slouken@7191
   938
                    x = (float)(input->x - rect.left)/(rect.right - rect.left);
slouken@7191
   939
                    y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
slouken@4932
   940
slouken@7191
   941
                    if (input->dwFlags & TOUCHEVENTF_DOWN) {
slouken@7191
   942
                        SDL_SendTouch(touchId, input->dwID, SDL_TRUE, x, y, 1.0f);
slouken@7191
   943
                    }
slouken@7191
   944
                    if (input->dwFlags & TOUCHEVENTF_MOVE) {
slouken@7191
   945
                        SDL_SendTouchMotion(touchId, input->dwID, x, y, 1.0f);
slouken@7191
   946
                    }
slouken@7191
   947
                    if (input->dwFlags & TOUCHEVENTF_UP) {
slouken@7191
   948
                        SDL_SendTouch(touchId, input->dwID, SDL_FALSE, x, y, 1.0f);
slouken@7191
   949
                    }
slouken@7191
   950
                }
slouken@7191
   951
            }
slouken@7191
   952
            SDL_stack_free(inputs);
slouken@4932
   953
slouken@7191
   954
            data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
slouken@7191
   955
            return 0;
slouken@7191
   956
        }
slouken@7191
   957
        break;
slouken@6523
   958
slouken@6523
   959
    case WM_DROPFILES:
slouken@6523
   960
        {
slouken@6523
   961
            UINT i;
slouken@6523
   962
            HDROP drop = (HDROP) wParam;
slouken@6523
   963
            UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
slouken@6523
   964
            for (i = 0; i < count; ++i) {
slouken@6523
   965
                UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
slouken@6523
   966
                LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
slouken@6523
   967
                if (buffer) {
slouken@6523
   968
                    if (DragQueryFile(drop, i, buffer, size)) {
slouken@6523
   969
                        char *file = WIN_StringToUTF8(buffer);
icculus@10022
   970
                        SDL_SendDropFile(data->window, file);
slouken@6523
   971
                        SDL_free(file);
slouken@6523
   972
                    }
slouken@6523
   973
                    SDL_stack_free(buffer);
slouken@6523
   974
                }
slouken@6523
   975
            }
icculus@10022
   976
            SDL_SendDropComplete(data->window);
slouken@6523
   977
            DragFinish(drop);
slouken@6523
   978
            return 0;
slouken@6523
   979
        }
slouken@6523
   980
        break;
icculus@8938
   981
slouken@11528
   982
    case WM_NCCALCSIZE:
slouken@11528
   983
        {
slouken@11874
   984
            Uint32 window_flags = SDL_GetWindowFlags(data->window);
slouken@11874
   985
            if (wParam == TRUE && (window_flags & SDL_WINDOW_BORDERLESS) && !(window_flags & SDL_WINDOW_FULLSCREEN)) {
slouken@11716
   986
                /* When borderless, need to tell windows that the size of the non-client area is 0 */
slouken@11874
   987
                if (!(window_flags & SDL_WINDOW_RESIZABLE)) {
slouken@11716
   988
                    int w, h;
slouken@11716
   989
                    NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam;
slouken@11874
   990
                    w = data->window->windowed.w;
slouken@11874
   991
                    h = data->window->windowed.h;
slouken@11716
   992
                    params->rgrc[0].right = params->rgrc[0].left + w;
slouken@11716
   993
                    params->rgrc[0].bottom = params->rgrc[0].top + h;
slouken@11716
   994
                }
slouken@11528
   995
                return 0;
slouken@11716
   996
            }
slouken@11528
   997
        }
slouken@11528
   998
        break;
slouken@11528
   999
icculus@8938
  1000
    case WM_NCHITTEST:
icculus@8938
  1001
        {
icculus@8938
  1002
            SDL_Window *window = data->window;
icculus@8938
  1003
            if (window->hit_test) {
slouken@11547
  1004
                POINT winpoint = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
slouken@8976
  1005
                if (ScreenToClient(hwnd, &winpoint)) {
icculus@8941
  1006
                    const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
icculus@8941
  1007
                    const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
icculus@8948
  1008
                    switch (rc) {
icculus@10028
  1009
                        #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
icculus@10028
  1010
                        case SDL_HITTEST_DRAGGABLE: POST_HIT_TEST(HTCAPTION);
icculus@10028
  1011
                        case SDL_HITTEST_RESIZE_TOPLEFT: POST_HIT_TEST(HTTOPLEFT);
icculus@10028
  1012
                        case SDL_HITTEST_RESIZE_TOP: POST_HIT_TEST(HTTOP);
icculus@10028
  1013
                        case SDL_HITTEST_RESIZE_TOPRIGHT: POST_HIT_TEST(HTTOPRIGHT);
icculus@10028
  1014
                        case SDL_HITTEST_RESIZE_RIGHT: POST_HIT_TEST(HTRIGHT);
icculus@10028
  1015
                        case SDL_HITTEST_RESIZE_BOTTOMRIGHT: POST_HIT_TEST(HTBOTTOMRIGHT);
icculus@10028
  1016
                        case SDL_HITTEST_RESIZE_BOTTOM: POST_HIT_TEST(HTBOTTOM);
icculus@10028
  1017
                        case SDL_HITTEST_RESIZE_BOTTOMLEFT: POST_HIT_TEST(HTBOTTOMLEFT);
icculus@10028
  1018
                        case SDL_HITTEST_RESIZE_LEFT: POST_HIT_TEST(HTLEFT);
icculus@10028
  1019
                        #undef POST_HIT_TEST
slouken@8976
  1020
                        case SDL_HITTEST_NORMAL: return HTCLIENT;
icculus@8941
  1021
                    }
icculus@8938
  1022
                }
icculus@8948
  1023
                /* If we didn't return, this will call DefWindowProc below. */
icculus@8938
  1024
            }
icculus@8938
  1025
        }
icculus@8938
  1026
        break;
slouken@6523
  1027
    }
slouken@3566
  1028
slouken@3566
  1029
    /* If there's a window proc, assume it's going to handle messages */
slouken@3566
  1030
    if (data->wndproc) {
slouken@3566
  1031
        return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
slouken@3566
  1032
    } else if (returnCode >= 0) {
slouken@3566
  1033
        return returnCode;
slouken@3566
  1034
    } else {
slouken@3566
  1035
        return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
slouken@3566
  1036
    }
slouken@1895
  1037
}
slouken@1895
  1038
slouken@9597
  1039
/* A message hook called before TranslateMessage() */
slouken@9597
  1040
static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
slouken@9599
  1041
static void *g_WindowsMessageHookData = NULL;
slouken@9597
  1042
slouken@9599
  1043
void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
slouken@9597
  1044
{
slouken@9597
  1045
    g_WindowsMessageHook = callback;
slouken@9599
  1046
    g_WindowsMessageHookData = userdata;
slouken@9597
  1047
}
slouken@9597
  1048
slouken@1895
  1049
void
slouken@1895
  1050
WIN_PumpEvents(_THIS)
slouken@1895
  1051
{
icculus@7561
  1052
    const Uint8 *keystate;
slouken@1895
  1053
    MSG msg;
slouken@8218
  1054
    DWORD start_ticks = GetTickCount();
slouken@8218
  1055
slouken@8814
  1056
    if (g_WindowsEnableMessageLoop) {
slouken@8814
  1057
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
slouken@9597
  1058
            if (g_WindowsMessageHook) {
slouken@9599
  1059
                g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
slouken@9597
  1060
            }
slouken@9597
  1061
slouken@8814
  1062
            /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
slouken@8814
  1063
            TranslateMessage(&msg);
slouken@8814
  1064
            DispatchMessage(&msg);
slouken@8218
  1065
slouken@8814
  1066
            /* Make sure we don't busy loop here forever if there are lots of events coming in */
slouken@8814
  1067
            if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
slouken@8814
  1068
                break;
slouken@8814
  1069
            }
slouken@8218
  1070
        }
slouken@1895
  1071
    }
icculus@7561
  1072
icculus@7561
  1073
    /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one.
icculus@7561
  1074
       You won't get a KEYUP until both are released, and that keyup will only be for the second
icculus@7561
  1075
       key you released. Take heroic measures and check the keystate as of the last handled event,
icculus@7561
  1076
       and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */
icculus@7561
  1077
    keystate = SDL_GetKeyboardState(NULL);
icculus@7561
  1078
    if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
icculus@7561
  1079
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
icculus@7561
  1080
    }
icculus@7561
  1081
    if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
icculus@7561
  1082
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
icculus@7561
  1083
    }
slouken@1895
  1084
}
slouken@1895
  1085
slouken@11959
  1086
/* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
slouken@11959
  1087
   we need to detect the windows version. this struct and the function below does that.
slouken@11959
  1088
   usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
slouken@11959
  1089
   but here we just load it dynamically */
slouken@11959
  1090
struct SDL_WIN_OSVERSIONINFOW {
slouken@11959
  1091
    ULONG dwOSVersionInfoSize;
slouken@11959
  1092
    ULONG dwMajorVersion;
slouken@11959
  1093
    ULONG dwMinorVersion;
slouken@11959
  1094
    ULONG dwBuildNumber;
slouken@11959
  1095
    ULONG dwPlatformId;
slouken@11959
  1096
    WCHAR szCSDVersion[128];
slouken@11959
  1097
};
slouken@11959
  1098
slouken@11959
  1099
static SDL_bool
slouken@11959
  1100
IsWin10FCUorNewer(void)
slouken@11959
  1101
{
slouken@11959
  1102
    HMODULE handle = GetModuleHandleW(L"ntdll.dll");
slouken@11959
  1103
    if (handle) {
slouken@11959
  1104
        typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
slouken@11959
  1105
        RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
slouken@11959
  1106
        if (getVersionPtr != NULL) {
slouken@11959
  1107
            struct SDL_WIN_OSVERSIONINFOW info;
slouken@11959
  1108
            SDL_zero(info);
slouken@11959
  1109
            info.dwOSVersionInfoSize = sizeof(info);
slouken@11959
  1110
            if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
slouken@12153
  1111
                if ((info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299) ||
slouken@12153
  1112
                    (info.dwMajorVersion == 10 && info.dwMinorVersion > 0) ||
slouken@12153
  1113
                    (info.dwMajorVersion > 10))
slouken@11959
  1114
                {
slouken@11959
  1115
                    return SDL_TRUE;
slouken@11959
  1116
                }
slouken@11959
  1117
            }
slouken@11959
  1118
        }
slouken@11959
  1119
    }
slouken@11959
  1120
    return SDL_FALSE;
slouken@11959
  1121
}
slouken@11959
  1122
slouken@1895
  1123
static int app_registered = 0;
slouken@1895
  1124
LPTSTR SDL_Appname = NULL;
slouken@1895
  1125
Uint32 SDL_Appstyle = 0;
slouken@1895
  1126
HINSTANCE SDL_Instance = NULL;
slouken@1895
  1127
slouken@1895
  1128
/* Register the class for this application */
slouken@1895
  1129
int
slouken@1895
  1130
SDL_RegisterApp(char *name, Uint32 style, void *hInst)
slouken@1895
  1131
{
slouken@11261
  1132
    const char *hint;
slouken@10426
  1133
    WNDCLASSEX wcex;
slouken@10426
  1134
    TCHAR path[MAX_PATH];
slouken@1895
  1135
slouken@1895
  1136
    /* Only do this once... */
slouken@1895
  1137
    if (app_registered) {
slouken@1895
  1138
        ++app_registered;
slouken@1895
  1139
        return (0);
slouken@1895
  1140
    }
slouken@1895
  1141
    if (!name && !SDL_Appname) {
slouken@1895
  1142
        name = "SDL_app";
slouken@5086
  1143
#if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
slouken@1895
  1144
        SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
slouken@5086
  1145
#endif
slouken@1895
  1146
        SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
slouken@1895
  1147
    }
slouken@1895
  1148
slouken@1895
  1149
    if (name) {
slouken@1895
  1150
        SDL_Appname = WIN_UTF8ToString(name);
slouken@1895
  1151
        SDL_Appstyle = style;
slouken@1895
  1152
        SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
slouken@1895
  1153
    }
slouken@1895
  1154
slouken@1895
  1155
    /* Register the application class */
slouken@10427
  1156
    wcex.cbSize         = sizeof(WNDCLASSEX);
slouken@10427
  1157
    wcex.hCursor        = NULL;
slouken@10427
  1158
    wcex.hIcon          = NULL;
slouken@10427
  1159
    wcex.hIconSm        = NULL;
slouken@10427
  1160
    wcex.lpszMenuName   = NULL;
slouken@10427
  1161
    wcex.lpszClassName  = SDL_Appname;
slouken@10427
  1162
    wcex.style          = SDL_Appstyle;
slouken@10427
  1163
    wcex.hbrBackground  = NULL;
slouken@10427
  1164
    wcex.lpfnWndProc    = WIN_WindowProc;
slouken@10427
  1165
    wcex.hInstance      = SDL_Instance;
slouken@10427
  1166
    wcex.cbClsExtra     = 0;
slouken@10427
  1167
    wcex.cbWndExtra     = 0;
slouken@10427
  1168
slouken@11261
  1169
    hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON);
slouken@11261
  1170
    if (hint && *hint) {
slouken@11261
  1171
        wcex.hIcon = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
slouken@11261
  1172
slouken@11261
  1173
        hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL);
slouken@11261
  1174
        if (hint && *hint) {
slouken@11261
  1175
            wcex.hIconSm = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
slouken@11261
  1176
        }
slouken@11261
  1177
    } else {
slouken@11261
  1178
        /* Use the first icon as a default icon, like in the Explorer */
slouken@11261
  1179
        GetModuleFileName(SDL_Instance, path, MAX_PATH);
slouken@11261
  1180
        ExtractIconEx(path, 0, &wcex.hIcon, &wcex.hIconSm, 1);
slouken@11261
  1181
    }
slouken@10427
  1182
slouken@10426
  1183
    if (!RegisterClassEx(&wcex)) {
icculus@7037
  1184
        return SDL_SetError("Couldn't register application class");
slouken@1895
  1185
    }
slouken@1895
  1186
slouken@11959
  1187
    isWin10FCUorNewer = IsWin10FCUorNewer();
slouken@11959
  1188
slouken@1895
  1189
    app_registered = 1;
icculus@7037
  1190
    return 0;
slouken@1895
  1191
}
slouken@1895
  1192
slouken@1895
  1193
/* Unregisters the windowclass registered in SDL_RegisterApp above. */
slouken@1895
  1194
void
slouken@1895
  1195
SDL_UnregisterApp()
slouken@1895
  1196
{
slouken@10426
  1197
    WNDCLASSEX wcex;
slouken@1895
  1198
slouken@1895
  1199
    /* SDL_RegisterApp might not have been called before */
slouken@1895
  1200
    if (!app_registered) {
slouken@1895
  1201
        return;
slouken@1895
  1202
    }
slouken@1895
  1203
    --app_registered;
slouken@1895
  1204
    if (app_registered == 0) {
slouken@1895
  1205
        /* Check for any registered window classes. */
slouken@10426
  1206
        if (GetClassInfoEx(SDL_Instance, SDL_Appname, &wcex)) {
slouken@1895
  1207
            UnregisterClass(SDL_Appname, SDL_Instance);
slouken@10426
  1208
            if (wcex.hIcon) DestroyIcon(wcex.hIcon);
slouken@10426
  1209
            if (wcex.hIconSm) DestroyIcon(wcex.hIconSm);
slouken@1895
  1210
        }
slouken@1895
  1211
        SDL_free(SDL_Appname);
slouken@1895
  1212
        SDL_Appname = NULL;
slouken@1895
  1213
    }
slouken@1895
  1214
}
slouken@1895
  1215
slouken@6044
  1216
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
slouken@6044
  1217
slouken@1895
  1218
/* vi: set ts=4 sw=4 expandtab: */