src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 May 2014 14:03:04 -0700
changeset 8796 9159d5c47819
parent 8713 e3a80970cf0b
child 8813 beae556efafc
permissions -rw-r--r--
Fixed bug 2520 - Held double-click app startup creates a stuck MOUSEBUTTONDOWN event

snake5creator

When starting application with the usual "double click on file" method on Windows, only holding the last click, an unnecessary MOUSEBUTTONDOWN event is sent before the initial MOUSEMOTION event, and mouse button state is stuck in the sense that it takes a subsequent button release, followed by another press for the system to resume sending events (beginning with the next button release / MOUSEBUTTONUP event).

Input event log with held double-click startup: http://i.imgur.com/nypGKR2.png

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