medfall

A super great game engine
Log | Files | Refs

win32_window.cc (54730B)


      1 //========================================================================
      2 // GLFW 3.3 Win32 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
      6 //
      7 // This software is provided 'as-is', without any express or implied
      8 // warranty. In no event will the authors be held liable for any damages
      9 // arising from the use of this software.
     10 //
     11 // Permission is granted to anyone to use this software for any purpose,
     12 // including commercial applications, and to alter it and redistribute it
     13 // freely, subject to the following restrictions:
     14 //
     15 // 1. The origin of this software must not be misrepresented; you must not
     16 //    claim that you wrote the original software. If you use this software
     17 //    in a product, an acknowledgment in the product documentation would
     18 //    be appreciated but is not required.
     19 //
     20 // 2. Altered source versions must be plainly marked as such, and must not
     21 //    be misrepresented as being the original software.
     22 //
     23 // 3. This notice may not be removed or altered from any source
     24 //    distribution.
     25 //
     26 //========================================================================
     27 
     28 #include "internal.h"
     29 
     30 #include <limits.h>
     31 #include <stdlib.h>
     32 #include <malloc.h>
     33 #include <string.h>
     34 #include <windowsx.h>
     35 #include <shellapi.h>
     36 
     37 #define _GLFW_KEY_INVALID -2
     38 
     39 // Returns the window style for the specified window
     40 //
     41 static DWORD getWindowStyle(const _GLFWwindow* window)
     42 {
     43     DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
     44 
     45     if (window->monitor)
     46         style |= WS_POPUP;
     47     else
     48     {
     49         style |= WS_SYSMENU | WS_MINIMIZEBOX;
     50 
     51         if (window->decorated)
     52         {
     53             style |= WS_CAPTION;
     54 
     55             if (window->resizable)
     56                 style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
     57         }
     58         else
     59             style |= WS_POPUP;
     60     }
     61 
     62     return style;
     63 }
     64 
     65 // Returns the extended window style for the specified window
     66 //
     67 static DWORD getWindowExStyle(const _GLFWwindow* window)
     68 {
     69     DWORD style = WS_EX_APPWINDOW;
     70 
     71     if (window->monitor || window->floating)
     72         style |= WS_EX_TOPMOST;
     73 
     74     return style;
     75 }
     76 
     77 // Returns the image whose area most closely matches the desired one
     78 //
     79 static const GLFWimage* chooseImage(int count, const GLFWimage* images,
     80                                     int width, int height)
     81 {
     82     int i, leastDiff = INT_MAX;
     83     const GLFWimage* closest = NULL;
     84 
     85     for (i = 0;  i < count;  i++)
     86     {
     87         const int currDiff = abs(images[i].width * images[i].height -
     88                                  width * height);
     89         if (currDiff < leastDiff)
     90         {
     91             closest = images + i;
     92             leastDiff = currDiff;
     93         }
     94     }
     95 
     96     return closest;
     97 }
     98 
     99 // Creates an RGBA icon or cursor
    100 //
    101 static HICON createIcon(const GLFWimage* image,
    102                         int xhot, int yhot, GLFWbool icon)
    103 {
    104     int i;
    105     HDC dc;
    106     HICON handle;
    107     HBITMAP color, mask;
    108     BITMAPV5HEADER bi;
    109     ICONINFO ii;
    110     unsigned char* target = NULL;
    111     unsigned char* source = image->pixels;
    112 
    113     ZeroMemory(&bi, sizeof(bi));
    114     bi.bV5Size        = sizeof(BITMAPV5HEADER);
    115     bi.bV5Width       = image->width;
    116     bi.bV5Height      = -image->height;
    117     bi.bV5Planes      = 1;
    118     bi.bV5BitCount    = 32;
    119     bi.bV5Compression = BI_BITFIELDS;
    120     bi.bV5RedMask     = 0x00ff0000;
    121     bi.bV5GreenMask   = 0x0000ff00;
    122     bi.bV5BlueMask    = 0x000000ff;
    123     bi.bV5AlphaMask   = 0xff000000;
    124 
    125     dc = GetDC(NULL);
    126     color = CreateDIBSection(dc,
    127                              (BITMAPINFO*) &bi,
    128                              DIB_RGB_COLORS,
    129                              (void**) &target,
    130                              NULL,
    131                              (DWORD) 0);
    132     ReleaseDC(NULL, dc);
    133 
    134     if (!color)
    135     {
    136         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    137                              "Win32: Failed to create RGBA bitmap");
    138         return NULL;
    139     }
    140 
    141     mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
    142     if (!mask)
    143     {
    144         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    145                              "Win32: Failed to create mask bitmap");
    146         DeleteObject(color);
    147         return NULL;
    148     }
    149 
    150     for (i = 0;  i < image->width * image->height;  i++)
    151     {
    152         target[0] = source[2];
    153         target[1] = source[1];
    154         target[2] = source[0];
    155         target[3] = source[3];
    156         target += 4;
    157         source += 4;
    158     }
    159 
    160     ZeroMemory(&ii, sizeof(ii));
    161     ii.fIcon    = icon;
    162     ii.xHotspot = xhot;
    163     ii.yHotspot = yhot;
    164     ii.hbmMask  = mask;
    165     ii.hbmColor = color;
    166 
    167     handle = CreateIconIndirect(&ii);
    168 
    169     DeleteObject(color);
    170     DeleteObject(mask);
    171 
    172     if (!handle)
    173     {
    174         if (icon)
    175         {
    176             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    177                                  "Win32: Failed to create icon");
    178         }
    179         else
    180         {
    181             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    182                                  "Win32: Failed to create cursor");
    183         }
    184     }
    185 
    186     return handle;
    187 }
    188 
    189 // Translate client window size to full window size according to styles
    190 //
    191 static void getFullWindowSize(DWORD style, DWORD exStyle,
    192                               int clientWidth, int clientHeight,
    193                               int* fullWidth, int* fullHeight)
    194 {
    195     RECT rect = { 0, 0, clientWidth, clientHeight };
    196     AdjustWindowRectEx(&rect, style, FALSE, exStyle);
    197     *fullWidth = rect.right - rect.left;
    198     *fullHeight = rect.bottom - rect.top;
    199 }
    200 
    201 // Enforce the client rect aspect ratio based on which edge is being dragged
    202 //
    203 static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
    204 {
    205     int xoff, yoff;
    206     const float ratio = (float) window->numer / (float) window->denom;
    207 
    208     getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
    209                       0, 0, &xoff, &yoff);
    210 
    211     if (edge == WMSZ_LEFT  || edge == WMSZ_BOTTOMLEFT ||
    212         edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
    213     {
    214         area->bottom = area->top + yoff +
    215             (int) ((area->right - area->left - xoff) / ratio);
    216     }
    217     else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT)
    218     {
    219         area->top = area->bottom - yoff -
    220             (int) ((area->right - area->left - xoff) / ratio);
    221     }
    222     else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM)
    223     {
    224         area->right = area->left + xoff +
    225             (int) ((area->bottom - area->top - yoff) * ratio);
    226     }
    227 }
    228 
    229 // Centers the cursor over the window client area
    230 //
    231 static void centerCursor(_GLFWwindow* window)
    232 {
    233     int width, height;
    234     _glfwPlatformGetWindowSize(window, &width, &height);
    235     _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
    236 }
    237 
    238 // Returns whether the cursor is in the client area of the specified window
    239 //
    240 static GLFWbool cursorInClientArea(_GLFWwindow* window)
    241 {
    242     RECT area;
    243     POINT pos;
    244 
    245     if (!GetCursorPos(&pos))
    246         return GLFW_FALSE;
    247 
    248     if (WindowFromPoint(pos) != window->win32.handle)
    249         return GLFW_FALSE;
    250 
    251     GetClientRect(window->win32.handle, &area);
    252     ClientToScreen(window->win32.handle, (POINT*) &area.left);
    253     ClientToScreen(window->win32.handle, (POINT*) &area.right);
    254 
    255     return PtInRect(&area, pos);
    256 }
    257 
    258 // Updates the cursor image according to its cursor mode
    259 //
    260 static void updateCursorImage(_GLFWwindow* window)
    261 {
    262     if (window->cursorMode == GLFW_CURSOR_NORMAL)
    263     {
    264         if (window->cursor)
    265             SetCursor(window->cursor->win32.handle);
    266         else
    267             SetCursor(LoadCursorW(NULL, IDC_ARROW));
    268     }
    269     else
    270         SetCursor(NULL);
    271 }
    272 
    273 // Updates the cursor clip rect
    274 //
    275 static void updateClipRect(_GLFWwindow* window)
    276 {
    277     if (window)
    278     {
    279         RECT clipRect;
    280         GetClientRect(window->win32.handle, &clipRect);
    281         ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
    282         ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
    283         ClipCursor(&clipRect);
    284     }
    285     else
    286         ClipCursor(NULL);
    287 }
    288 
    289 // Update native window styles to match attributes
    290 //
    291 static void updateWindowStyles(const _GLFWwindow* window)
    292 {
    293     RECT rect;
    294     DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
    295     style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP);
    296     style |= getWindowStyle(window);
    297 
    298     GetClientRect(window->win32.handle, &rect);
    299     AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
    300     ClientToScreen(window->win32.handle, (POINT*) &rect.left);
    301     ClientToScreen(window->win32.handle, (POINT*) &rect.right);
    302     SetWindowLongW(window->win32.handle, GWL_STYLE, style);
    303     SetWindowPos(window->win32.handle, HWND_TOP,
    304                  rect.left, rect.top,
    305                  rect.right - rect.left, rect.bottom - rect.top,
    306                  SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
    307 }
    308 
    309 // Translates a GLFW standard cursor to a resource ID
    310 //
    311 static LPWSTR translateCursorShape(int shape)
    312 {
    313     switch (shape)
    314     {
    315         case GLFW_ARROW_CURSOR:
    316             return IDC_ARROW;
    317         case GLFW_IBEAM_CURSOR:
    318             return IDC_IBEAM;
    319         case GLFW_CROSSHAIR_CURSOR:
    320             return IDC_CROSS;
    321         case GLFW_HAND_CURSOR:
    322             return IDC_HAND;
    323         case GLFW_HRESIZE_CURSOR:
    324             return IDC_SIZEWE;
    325         case GLFW_VRESIZE_CURSOR:
    326             return IDC_SIZENS;
    327     }
    328 
    329     return NULL;
    330 }
    331 
    332 // Retrieves and translates modifier keys
    333 //
    334 static int getKeyMods(void)
    335 {
    336     int mods = 0;
    337 
    338     if (GetKeyState(VK_SHIFT) & (1 << 31))
    339         mods |= GLFW_MOD_SHIFT;
    340     if (GetKeyState(VK_CONTROL) & (1 << 31))
    341         mods |= GLFW_MOD_CONTROL;
    342     if (GetKeyState(VK_MENU) & (1 << 31))
    343         mods |= GLFW_MOD_ALT;
    344     if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31))
    345         mods |= GLFW_MOD_SUPER;
    346 
    347     return mods;
    348 }
    349 
    350 // Retrieves and translates modifier keys
    351 //
    352 static int getAsyncKeyMods(void)
    353 {
    354     int mods = 0;
    355 
    356     if (GetAsyncKeyState(VK_SHIFT) & (1 << 31))
    357         mods |= GLFW_MOD_SHIFT;
    358     if (GetAsyncKeyState(VK_CONTROL) & (1 << 31))
    359         mods |= GLFW_MOD_CONTROL;
    360     if (GetAsyncKeyState(VK_MENU) & (1 << 31))
    361         mods |= GLFW_MOD_ALT;
    362     if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31))
    363         mods |= GLFW_MOD_SUPER;
    364 
    365     return mods;
    366 }
    367 
    368 // Translates a Windows key to the corresponding GLFW key
    369 //
    370 static int translateKey(WPARAM wParam, LPARAM lParam)
    371 {
    372     // The Ctrl keys require special handling
    373     if (wParam == VK_CONTROL)
    374     {
    375         MSG next;
    376         DWORD time;
    377 
    378         // Right side keys have the extended key bit set
    379         if (lParam & 0x01000000)
    380             return GLFW_KEY_RIGHT_CONTROL;
    381 
    382         // HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence
    383         //       We only want the Right Alt message, so if the next message is
    384         //       Right Alt we ignore this (synthetic) Left Ctrl message
    385         time = GetMessageTime();
    386 
    387         if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
    388         {
    389             if (next.message == WM_KEYDOWN ||
    390                 next.message == WM_SYSKEYDOWN ||
    391                 next.message == WM_KEYUP ||
    392                 next.message == WM_SYSKEYUP)
    393             {
    394                 if (next.wParam == VK_MENU &&
    395                     (next.lParam & 0x01000000) &&
    396                     next.time == time)
    397                 {
    398                     // Next message is Right Alt down so discard this
    399                     return _GLFW_KEY_INVALID;
    400                 }
    401             }
    402         }
    403 
    404         return GLFW_KEY_LEFT_CONTROL;
    405     }
    406 
    407     if (wParam == VK_PROCESSKEY)
    408     {
    409         // IME notifies that keys have been filtered by setting the virtual
    410         // key-code to VK_PROCESSKEY
    411         return _GLFW_KEY_INVALID;
    412     }
    413 
    414     return _glfw.win32.keycodes[HIWORD(lParam) & 0x1FF];
    415 }
    416 
    417 // Make the specified window and its video mode active on its monitor
    418 //
    419 static GLFWbool acquireMonitor(_GLFWwindow* window)
    420 {
    421     GLFWvidmode mode;
    422     GLFWbool status;
    423     int xpos, ypos;
    424 
    425     if (!_glfw.win32.acquiredMonitorCount)
    426         SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
    427     if (!window->monitor->window)
    428         _glfw.win32.acquiredMonitorCount++;
    429 
    430     status = _glfwSetVideoModeWin32(window->monitor, &window->videoMode);
    431 
    432     _glfwPlatformGetVideoMode(window->monitor, &mode);
    433     _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
    434 
    435     SetWindowPos(window->win32.handle, HWND_TOPMOST,
    436                  xpos, ypos, mode.width, mode.height,
    437                  SWP_NOACTIVATE | SWP_NOCOPYBITS);
    438 
    439     _glfwInputMonitorWindow(window->monitor, window);
    440     return status;
    441 }
    442 
    443 // Remove the window and restore the original video mode
    444 //
    445 static void releaseMonitor(_GLFWwindow* window)
    446 {
    447     if (window->monitor->window != window)
    448         return;
    449 
    450     _glfw.win32.acquiredMonitorCount--;
    451     if (!_glfw.win32.acquiredMonitorCount)
    452         SetThreadExecutionState(ES_CONTINUOUS);
    453 
    454     _glfwInputMonitorWindow(window->monitor, NULL);
    455     _glfwRestoreVideoModeWin32(window->monitor);
    456 }
    457 
    458 // Window callback function (handles window messages)
    459 //
    460 static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
    461                                    WPARAM wParam, LPARAM lParam)
    462 {
    463     _GLFWwindow* window = GetPropW(hWnd, L"GLFW");
    464     if (!window)
    465     {
    466         // This is the message handling for the hidden helper window
    467 
    468         switch (uMsg)
    469         {
    470             case WM_DISPLAYCHANGE:
    471                 _glfwPollMonitorsWin32();
    472                 break;
    473 
    474             case WM_DEVICECHANGE:
    475             {
    476                 if (wParam == DBT_DEVICEARRIVAL)
    477                 {
    478                     DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
    479                     if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
    480                         _glfwDetectJoystickConnectionWin32();
    481                 }
    482                 else if (wParam == DBT_DEVICEREMOVECOMPLETE)
    483                 {
    484                     DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
    485                     if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
    486                         _glfwDetectJoystickDisconnectionWin32();
    487                 }
    488 
    489                 break;
    490             }
    491         }
    492 
    493         return DefWindowProcW(hWnd, uMsg, wParam, lParam);
    494     }
    495 
    496     switch (uMsg)
    497     {
    498         case WM_SETFOCUS:
    499         {
    500             _glfwInputWindowFocus(window, GLFW_TRUE);
    501 
    502             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    503                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
    504 
    505             return 0;
    506         }
    507 
    508         case WM_KILLFOCUS:
    509         {
    510             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    511                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
    512 
    513             if (window->monitor && window->autoIconify)
    514                 _glfwPlatformIconifyWindow(window);
    515 
    516             _glfwInputWindowFocus(window, GLFW_FALSE);
    517             return 0;
    518         }
    519 
    520         case WM_SYSCOMMAND:
    521         {
    522             switch (wParam & 0xfff0)
    523             {
    524                 case SC_SCREENSAVE:
    525                 case SC_MONITORPOWER:
    526                 {
    527                     if (window->monitor)
    528                     {
    529                         // We are running in full screen mode, so disallow
    530                         // screen saver and screen blanking
    531                         return 0;
    532                     }
    533                     else
    534                         break;
    535                 }
    536 
    537                 // User trying to access application menu using ALT?
    538                 case SC_KEYMENU:
    539                     return 0;
    540             }
    541             break;
    542         }
    543 
    544         case WM_CLOSE:
    545         {
    546             _glfwInputWindowCloseRequest(window);
    547             return 0;
    548         }
    549 
    550         case WM_CHAR:
    551         case WM_SYSCHAR:
    552         case WM_UNICHAR:
    553         {
    554             const GLFWbool plain = (uMsg != WM_SYSCHAR);
    555 
    556             if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR)
    557             {
    558                 // WM_UNICHAR is not sent by Windows, but is sent by some
    559                 // third-party input method engine
    560                 // Returning TRUE here announces support for this message
    561                 return TRUE;
    562             }
    563 
    564             _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain);
    565             return 0;
    566         }
    567 
    568         case WM_KEYDOWN:
    569         case WM_SYSKEYDOWN:
    570         case WM_KEYUP:
    571         case WM_SYSKEYUP:
    572         {
    573             const int key = translateKey(wParam, lParam);
    574             const int scancode = (lParam >> 16) & 0x1ff;
    575             const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS;
    576             const int mods = getKeyMods();
    577 
    578             if (key == _GLFW_KEY_INVALID)
    579                 break;
    580 
    581             if (action == GLFW_RELEASE && wParam == VK_SHIFT)
    582             {
    583                 // HACK: Release both Shift keys on Shift up event, as when both
    584                 //       are pressed the first release does not emit any event
    585                 // NOTE: The other half of this is in _glfwPlatformPollEvents
    586                 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods);
    587                 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods);
    588             }
    589             else if (wParam == VK_SNAPSHOT)
    590             {
    591                 // HACK: Key down is not reported for the Print Screen key
    592                 _glfwInputKey(window, key, scancode, GLFW_PRESS, mods);
    593                 _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
    594             }
    595             else
    596                 _glfwInputKey(window, key, scancode, action, mods);
    597 
    598             break;
    599         }
    600 
    601         case WM_LBUTTONDOWN:
    602         case WM_RBUTTONDOWN:
    603         case WM_MBUTTONDOWN:
    604         case WM_XBUTTONDOWN:
    605         case WM_LBUTTONUP:
    606         case WM_RBUTTONUP:
    607         case WM_MBUTTONUP:
    608         case WM_XBUTTONUP:
    609         {
    610             int i, button, action;
    611 
    612             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
    613                 button = GLFW_MOUSE_BUTTON_LEFT;
    614             else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP)
    615                 button = GLFW_MOUSE_BUTTON_RIGHT;
    616             else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
    617                 button = GLFW_MOUSE_BUTTON_MIDDLE;
    618             else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
    619                 button = GLFW_MOUSE_BUTTON_4;
    620             else
    621                 button = GLFW_MOUSE_BUTTON_5;
    622 
    623             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN ||
    624                 uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN)
    625             {
    626                 action = GLFW_PRESS;
    627             }
    628             else
    629                 action = GLFW_RELEASE;
    630 
    631             for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
    632             {
    633                 if (window->mouseButtons[i] == GLFW_PRESS)
    634                     break;
    635             }
    636 
    637             if (i > GLFW_MOUSE_BUTTON_LAST)
    638                 SetCapture(hWnd);
    639 
    640             _glfwInputMouseClick(window, button, action, getKeyMods());
    641 
    642             for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
    643             {
    644                 if (window->mouseButtons[i] == GLFW_PRESS)
    645                     break;
    646             }
    647 
    648             if (i > GLFW_MOUSE_BUTTON_LAST)
    649                 ReleaseCapture();
    650 
    651             if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
    652                 return TRUE;
    653 
    654             return 0;
    655         }
    656 
    657         case WM_MOUSEMOVE:
    658         {
    659             const int x = GET_X_LPARAM(lParam);
    660             const int y = GET_Y_LPARAM(lParam);
    661 
    662             // Disabled cursor motion input is provided by WM_INPUT
    663             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    664                 break;
    665 
    666             _glfwInputCursorPos(window, x, y);
    667 
    668             window->win32.lastCursorPosX = x;
    669             window->win32.lastCursorPosY = y;
    670 
    671             if (!window->win32.cursorTracked)
    672             {
    673                 TRACKMOUSEEVENT tme;
    674                 ZeroMemory(&tme, sizeof(tme));
    675                 tme.cbSize = sizeof(tme);
    676                 tme.dwFlags = TME_LEAVE;
    677                 tme.hwndTrack = window->win32.handle;
    678                 TrackMouseEvent(&tme);
    679 
    680                 window->win32.cursorTracked = GLFW_TRUE;
    681                 _glfwInputCursorEnter(window, GLFW_TRUE);
    682             }
    683 
    684             return 0;
    685         }
    686 
    687         case WM_INPUT:
    688         {
    689             UINT size;
    690             HRAWINPUT ri = (HRAWINPUT) lParam;
    691             RAWINPUT* data;
    692             int dx, dy;
    693 
    694             // Only process input when disabled cursor mode is applied
    695             if (_glfw.win32.disabledCursorWindow != window)
    696                 break;
    697 
    698             GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
    699             if (size > (UINT) _glfw.win32.rawInputSize)
    700             {
    701                 free(_glfw.win32.rawInput);
    702                 _glfw.win32.rawInput = calloc(size, 1);
    703                 _glfw.win32.rawInputSize = size;
    704             }
    705 
    706             size = _glfw.win32.rawInputSize;
    707             if (GetRawInputData(ri, RID_INPUT,
    708                                 _glfw.win32.rawInput, &size,
    709                                 sizeof(RAWINPUTHEADER)) == (UINT) -1)
    710             {
    711                 _glfwInputError(GLFW_PLATFORM_ERROR,
    712                                 "Win32: Failed to retrieve raw input data");
    713                 break;
    714             }
    715 
    716             data = _glfw.win32.rawInput;
    717             if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
    718             {
    719                 dx = data->data.mouse.lLastX - window->win32.lastCursorPosX;
    720                 dy = data->data.mouse.lLastY - window->win32.lastCursorPosY;
    721             }
    722             else
    723             {
    724                 dx = data->data.mouse.lLastX;
    725                 dy = data->data.mouse.lLastY;
    726             }
    727 
    728             _glfwInputCursorPos(window,
    729                                 window->virtualCursorPosX + dx,
    730                                 window->virtualCursorPosY + dy);
    731 
    732             window->win32.lastCursorPosX += dx;
    733             window->win32.lastCursorPosY += dy;
    734             break;
    735         }
    736 
    737         case WM_MOUSELEAVE:
    738         {
    739             window->win32.cursorTracked = GLFW_FALSE;
    740             _glfwInputCursorEnter(window, GLFW_FALSE);
    741             return 0;
    742         }
    743 
    744         case WM_MOUSEWHEEL:
    745         {
    746             _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA);
    747             return 0;
    748         }
    749 
    750         case WM_MOUSEHWHEEL:
    751         {
    752             // This message is only sent on Windows Vista and later
    753             // NOTE: The X-axis is inverted for consistency with macOS and X11
    754             _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
    755             return 0;
    756         }
    757 
    758         case WM_ENTERSIZEMOVE:
    759         case WM_ENTERMENULOOP:
    760         {
    761             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    762                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
    763 
    764             break;
    765         }
    766 
    767         case WM_EXITSIZEMOVE:
    768         case WM_EXITMENULOOP:
    769         {
    770             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    771                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
    772 
    773             break;
    774         }
    775 
    776         case WM_SIZE:
    777         {
    778             const GLFWbool iconified = wParam == SIZE_MINIMIZED;
    779             const GLFWbool maximized = wParam == SIZE_MAXIMIZED ||
    780                                        (window->win32.maximized &&
    781                                         wParam != SIZE_RESTORED);
    782 
    783             if (_glfw.win32.disabledCursorWindow == window)
    784                 updateClipRect(window);
    785 
    786             if (window->win32.iconified != iconified)
    787                 _glfwInputWindowIconify(window, iconified);
    788 
    789             if (window->win32.maximized != maximized)
    790                 _glfwInputWindowMaximize(window, maximized);
    791 
    792             _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam));
    793             _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam));
    794 
    795             if (window->monitor && window->win32.iconified != iconified)
    796             {
    797                 if (iconified)
    798                     releaseMonitor(window);
    799                 else
    800                     acquireMonitor(window);
    801             }
    802 
    803             window->win32.iconified = iconified;
    804             window->win32.maximized = maximized;
    805             return 0;
    806         }
    807 
    808         case WM_MOVE:
    809         {
    810             if (_glfw.win32.disabledCursorWindow == window)
    811                 updateClipRect(window);
    812 
    813             // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
    814             // those macros do not handle negative window positions correctly
    815             _glfwInputWindowPos(window,
    816                                 GET_X_LPARAM(lParam),
    817                                 GET_Y_LPARAM(lParam));
    818             return 0;
    819         }
    820 
    821         case WM_SIZING:
    822         {
    823             if (window->numer == GLFW_DONT_CARE ||
    824                 window->denom == GLFW_DONT_CARE)
    825             {
    826                 break;
    827             }
    828 
    829             applyAspectRatio(window, (int) wParam, (RECT*) lParam);
    830             return TRUE;
    831         }
    832 
    833         case WM_GETMINMAXINFO:
    834         {
    835             int xoff, yoff;
    836             MINMAXINFO* mmi = (MINMAXINFO*) lParam;
    837 
    838             if (window->monitor)
    839                 break;
    840 
    841             getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
    842                               0, 0, &xoff, &yoff);
    843 
    844             if (window->minwidth != GLFW_DONT_CARE &&
    845                 window->minheight != GLFW_DONT_CARE)
    846             {
    847                 mmi->ptMinTrackSize.x = window->minwidth + xoff;
    848                 mmi->ptMinTrackSize.y = window->minheight + yoff;
    849             }
    850 
    851             if (window->maxwidth != GLFW_DONT_CARE &&
    852                 window->maxheight != GLFW_DONT_CARE)
    853             {
    854                 mmi->ptMaxTrackSize.x = window->maxwidth + xoff;
    855                 mmi->ptMaxTrackSize.y = window->maxheight + yoff;
    856             }
    857 
    858             return 0;
    859         }
    860 
    861         case WM_PAINT:
    862         {
    863             _glfwInputWindowDamage(window);
    864             break;
    865         }
    866 
    867         case WM_ERASEBKGND:
    868         {
    869             return TRUE;
    870         }
    871 
    872         case WM_SETCURSOR:
    873         {
    874             if (LOWORD(lParam) == HTCLIENT)
    875             {
    876                 updateCursorImage(window);
    877                 return TRUE;
    878             }
    879 
    880             break;
    881         }
    882 
    883         case WM_DPICHANGED:
    884         {
    885             RECT* rect = (RECT*) lParam;
    886             SetWindowPos(window->win32.handle,
    887                          HWND_TOP,
    888                          rect->left,
    889                          rect->top,
    890                          rect->right - rect->left,
    891                          rect->bottom - rect->top,
    892                          SWP_NOACTIVATE | SWP_NOZORDER);
    893             break;
    894         }
    895 
    896         case WM_DROPFILES:
    897         {
    898             HDROP drop = (HDROP) wParam;
    899             POINT pt;
    900             int i;
    901 
    902             const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
    903             char** paths = calloc(count, sizeof(char*));
    904 
    905             // Move the mouse to the position of the drop
    906             DragQueryPoint(drop, &pt);
    907             _glfwInputCursorPos(window, pt.x, pt.y);
    908 
    909             for (i = 0;  i < count;  i++)
    910             {
    911                 const UINT length = DragQueryFileW(drop, i, NULL, 0);
    912                 WCHAR* buffer = calloc(length + 1, sizeof(WCHAR));
    913 
    914                 DragQueryFileW(drop, i, buffer, length + 1);
    915                 paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
    916 
    917                 free(buffer);
    918             }
    919 
    920             _glfwInputDrop(window, count, (const char**) paths);
    921 
    922             for (i = 0;  i < count;  i++)
    923                 free(paths[i]);
    924             free(paths);
    925 
    926             DragFinish(drop);
    927             return 0;
    928         }
    929     }
    930 
    931     return DefWindowProcW(hWnd, uMsg, wParam, lParam);
    932 }
    933 
    934 // Creates the GLFW window
    935 //
    936 static int createNativeWindow(_GLFWwindow* window,
    937                               const _GLFWwndconfig* wndconfig)
    938 {
    939     int xpos, ypos, fullWidth, fullHeight;
    940     WCHAR* wideTitle;
    941     DWORD style = getWindowStyle(window);
    942     DWORD exStyle = getWindowExStyle(window);
    943 
    944     if (window->monitor)
    945     {
    946         GLFWvidmode mode;
    947 
    948         // NOTE: This window placement is temporary and approximate, as the
    949         //       correct position and size cannot be known until the monitor
    950         //       video mode has been picked in _glfwSetVideoModeWin32
    951         _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
    952         _glfwPlatformGetVideoMode(window->monitor, &mode);
    953         fullWidth  = mode.width;
    954         fullHeight = mode.height;
    955     }
    956     else
    957     {
    958         xpos = CW_USEDEFAULT;
    959         ypos = CW_USEDEFAULT;
    960 
    961         if (wndconfig->maximized)
    962             style |= WS_MAXIMIZE;
    963 
    964         getFullWindowSize(style, exStyle,
    965                           wndconfig->width, wndconfig->height,
    966                           &fullWidth, &fullHeight);
    967     }
    968 
    969     wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
    970     if (!wideTitle)
    971         return GLFW_FALSE;
    972 
    973     window->win32.handle = CreateWindowExW(exStyle,
    974                                            _GLFW_WNDCLASSNAME,
    975                                            wideTitle,
    976                                            style,
    977                                            xpos, ypos,
    978                                            fullWidth, fullHeight,
    979                                            NULL, // No parent window
    980                                            NULL, // No window menu
    981                                            GetModuleHandleW(NULL),
    982                                            NULL);
    983 
    984     free(wideTitle);
    985 
    986     if (!window->win32.handle)
    987     {
    988         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    989                              "Win32: Failed to create window");
    990         return GLFW_FALSE;
    991     }
    992 
    993     SetPropW(window->win32.handle, L"GLFW", window);
    994 
    995     if (_glfw_ChangeWindowMessageFilterEx)
    996     {
    997         _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
    998                                           WM_DROPFILES, MSGFLT_ALLOW, NULL);
    999         _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
   1000                                           WM_COPYDATA, MSGFLT_ALLOW, NULL);
   1001         _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
   1002                                           WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
   1003     }
   1004 
   1005     DragAcceptFiles(window->win32.handle, TRUE);
   1006 
   1007     return GLFW_TRUE;
   1008 }
   1009 
   1010 
   1011 //////////////////////////////////////////////////////////////////////////
   1012 //////                       GLFW internal API                      //////
   1013 //////////////////////////////////////////////////////////////////////////
   1014 
   1015 // Registers the GLFW window class
   1016 //
   1017 GLFWbool _glfwRegisterWindowClassWin32(void)
   1018 {
   1019     WNDCLASSEXW wc;
   1020 
   1021     ZeroMemory(&wc, sizeof(wc));
   1022     wc.cbSize        = sizeof(wc);
   1023     wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
   1024     wc.lpfnWndProc   = (WNDPROC) windowProc;
   1025     wc.hInstance     = GetModuleHandleW(NULL);
   1026     wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);
   1027     wc.lpszClassName = _GLFW_WNDCLASSNAME;
   1028 
   1029     // Load user-provided icon if available
   1030     wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
   1031                           L"GLFW_ICON", IMAGE_ICON,
   1032                           0, 0, LR_DEFAULTSIZE | LR_SHARED);
   1033     if (!wc.hIcon)
   1034     {
   1035         // No user-provided icon found, load default icon
   1036         wc.hIcon = LoadImageW(NULL,
   1037                               IDI_APPLICATION, IMAGE_ICON,
   1038                               0, 0, LR_DEFAULTSIZE | LR_SHARED);
   1039     }
   1040 
   1041     if (!RegisterClassExW(&wc))
   1042     {
   1043         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1044                              "Win32: Failed to register window class");
   1045         return GLFW_FALSE;
   1046     }
   1047 
   1048     return GLFW_TRUE;
   1049 }
   1050 
   1051 // Unregisters the GLFW window class
   1052 //
   1053 void _glfwUnregisterWindowClassWin32(void)
   1054 {
   1055     UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
   1056 }
   1057 
   1058 
   1059 //////////////////////////////////////////////////////////////////////////
   1060 //////                       GLFW platform API                      //////
   1061 //////////////////////////////////////////////////////////////////////////
   1062 
   1063 int _glfwPlatformCreateWindow(_GLFWwindow* window,
   1064                               const _GLFWwndconfig* wndconfig,
   1065                               const _GLFWctxconfig* ctxconfig,
   1066                               const _GLFWfbconfig* fbconfig)
   1067 {
   1068     if (!createNativeWindow(window, wndconfig))
   1069         return GLFW_FALSE;
   1070 
   1071     if (ctxconfig->client != GLFW_NO_API)
   1072     {
   1073         if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
   1074         {
   1075             if (!_glfwInitWGL())
   1076                 return GLFW_FALSE;
   1077             if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
   1078                 return GLFW_FALSE;
   1079         }
   1080         else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
   1081         {
   1082             if (!_glfwInitEGL())
   1083                 return GLFW_FALSE;
   1084             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
   1085                 return GLFW_FALSE;
   1086         }
   1087         else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
   1088         {
   1089             if (!_glfwInitOSMesa())
   1090                 return GLFW_FALSE;
   1091             if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
   1092                 return GLFW_FALSE;
   1093         }
   1094     }
   1095 
   1096     if (window->monitor)
   1097     {
   1098         _glfwPlatformShowWindow(window);
   1099         _glfwPlatformFocusWindow(window);
   1100         if (!acquireMonitor(window))
   1101             return GLFW_FALSE;
   1102 
   1103         if (wndconfig->centerCursor)
   1104             centerCursor(window);
   1105     }
   1106 
   1107     return GLFW_TRUE;
   1108 }
   1109 
   1110 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
   1111 {
   1112     if (window->monitor)
   1113         releaseMonitor(window);
   1114 
   1115     if (window->context.destroy)
   1116         window->context.destroy(window);
   1117 
   1118     if (_glfw.win32.disabledCursorWindow == window)
   1119         _glfw.win32.disabledCursorWindow = NULL;
   1120 
   1121     if (window->win32.handle)
   1122     {
   1123         RemovePropW(window->win32.handle, L"GLFW");
   1124         DestroyWindow(window->win32.handle);
   1125         window->win32.handle = NULL;
   1126     }
   1127 
   1128     if (window->win32.bigIcon)
   1129         DestroyIcon(window->win32.bigIcon);
   1130 
   1131     if (window->win32.smallIcon)
   1132         DestroyIcon(window->win32.smallIcon);
   1133 }
   1134 
   1135 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
   1136 {
   1137     WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title);
   1138     if (!wideTitle)
   1139         return;
   1140 
   1141     SetWindowTextW(window->win32.handle, wideTitle);
   1142     free(wideTitle);
   1143 }
   1144 
   1145 void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
   1146                                 int count, const GLFWimage* images)
   1147 {
   1148     HICON bigIcon = NULL, smallIcon = NULL;
   1149 
   1150     if (count)
   1151     {
   1152         const GLFWimage* bigImage = chooseImage(count, images,
   1153                                                 GetSystemMetrics(SM_CXICON),
   1154                                                 GetSystemMetrics(SM_CYICON));
   1155         const GLFWimage* smallImage = chooseImage(count, images,
   1156                                                   GetSystemMetrics(SM_CXSMICON),
   1157                                                   GetSystemMetrics(SM_CYSMICON));
   1158 
   1159         bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE);
   1160         smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE);
   1161     }
   1162     else
   1163     {
   1164         bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON);
   1165         smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
   1166     }
   1167 
   1168     SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
   1169     SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
   1170 
   1171     if (window->win32.bigIcon)
   1172         DestroyIcon(window->win32.bigIcon);
   1173 
   1174     if (window->win32.smallIcon)
   1175         DestroyIcon(window->win32.smallIcon);
   1176 
   1177     if (count)
   1178     {
   1179         window->win32.bigIcon = bigIcon;
   1180         window->win32.smallIcon = smallIcon;
   1181     }
   1182 }
   1183 
   1184 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
   1185 {
   1186     POINT pos = { 0, 0 };
   1187     ClientToScreen(window->win32.handle, &pos);
   1188 
   1189     if (xpos)
   1190         *xpos = pos.x;
   1191     if (ypos)
   1192         *ypos = pos.y;
   1193 }
   1194 
   1195 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
   1196 {
   1197     RECT rect = { xpos, ypos, xpos, ypos };
   1198     AdjustWindowRectEx(&rect, getWindowStyle(window),
   1199                        FALSE, getWindowExStyle(window));
   1200     SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
   1201                  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
   1202 }
   1203 
   1204 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
   1205 {
   1206     RECT area;
   1207     GetClientRect(window->win32.handle, &area);
   1208 
   1209     if (width)
   1210         *width = area.right;
   1211     if (height)
   1212         *height = area.bottom;
   1213 }
   1214 
   1215 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
   1216 {
   1217     if (window->monitor)
   1218     {
   1219         if (window->monitor->window == window)
   1220             acquireMonitor(window);
   1221     }
   1222     else
   1223     {
   1224         RECT rect = { 0, 0, width, height };
   1225         AdjustWindowRectEx(&rect, getWindowStyle(window),
   1226                            FALSE, getWindowExStyle(window));
   1227         SetWindowPos(window->win32.handle, HWND_TOP,
   1228                      0, 0, rect.right - rect.left, rect.bottom - rect.top,
   1229                      SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
   1230     }
   1231 }
   1232 
   1233 void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
   1234                                       int minwidth, int minheight,
   1235                                       int maxwidth, int maxheight)
   1236 {
   1237     RECT area;
   1238 
   1239     if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) &&
   1240         (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE))
   1241     {
   1242         return;
   1243     }
   1244 
   1245     GetWindowRect(window->win32.handle, &area);
   1246     MoveWindow(window->win32.handle,
   1247                area.left, area.top,
   1248                area.right - area.left,
   1249                area.bottom - area.top, TRUE);
   1250 }
   1251 
   1252 void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
   1253 {
   1254     RECT area;
   1255 
   1256     if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
   1257         return;
   1258 
   1259     GetWindowRect(window->win32.handle, &area);
   1260     applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area);
   1261     MoveWindow(window->win32.handle,
   1262                area.left, area.top,
   1263                area.right - area.left,
   1264                area.bottom - area.top, TRUE);
   1265 }
   1266 
   1267 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
   1268 {
   1269     _glfwPlatformGetWindowSize(window, width, height);
   1270 }
   1271 
   1272 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
   1273                                      int* left, int* top,
   1274                                      int* right, int* bottom)
   1275 {
   1276     RECT rect;
   1277     int width, height;
   1278 
   1279     _glfwPlatformGetWindowSize(window, &width, &height);
   1280     SetRect(&rect, 0, 0, width, height);
   1281     AdjustWindowRectEx(&rect, getWindowStyle(window),
   1282                        FALSE, getWindowExStyle(window));
   1283 
   1284     if (left)
   1285         *left = -rect.left;
   1286     if (top)
   1287         *top = -rect.top;
   1288     if (right)
   1289         *right = rect.right - width;
   1290     if (bottom)
   1291         *bottom = rect.bottom - height;
   1292 }
   1293 
   1294 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
   1295 {
   1296     ShowWindow(window->win32.handle, SW_MINIMIZE);
   1297 }
   1298 
   1299 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
   1300 {
   1301     ShowWindow(window->win32.handle, SW_RESTORE);
   1302 }
   1303 
   1304 void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
   1305 {
   1306     ShowWindow(window->win32.handle, SW_MAXIMIZE);
   1307 }
   1308 
   1309 void _glfwPlatformShowWindow(_GLFWwindow* window)
   1310 {
   1311     ShowWindow(window->win32.handle, SW_SHOW);
   1312 }
   1313 
   1314 void _glfwPlatformHideWindow(_GLFWwindow* window)
   1315 {
   1316     ShowWindow(window->win32.handle, SW_HIDE);
   1317 }
   1318 
   1319 void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
   1320 {
   1321     FlashWindow(window->win32.handle, TRUE);
   1322 }
   1323 
   1324 void _glfwPlatformFocusWindow(_GLFWwindow* window)
   1325 {
   1326     BringWindowToTop(window->win32.handle);
   1327     SetForegroundWindow(window->win32.handle);
   1328     SetFocus(window->win32.handle);
   1329 }
   1330 
   1331 void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
   1332                                    _GLFWmonitor* monitor,
   1333                                    int xpos, int ypos,
   1334                                    int width, int height,
   1335                                    int refreshRate)
   1336 {
   1337     if (window->monitor == monitor)
   1338     {
   1339         if (monitor)
   1340         {
   1341             if (monitor->window == window)
   1342                 acquireMonitor(window);
   1343         }
   1344         else
   1345         {
   1346             RECT rect = { xpos, ypos, xpos + width, ypos + height };
   1347             AdjustWindowRectEx(&rect, getWindowStyle(window),
   1348                                FALSE, getWindowExStyle(window));
   1349             SetWindowPos(window->win32.handle, HWND_TOP,
   1350                          rect.left, rect.top,
   1351                          rect.right - rect.left, rect.bottom - rect.top,
   1352                          SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER);
   1353         }
   1354 
   1355         return;
   1356     }
   1357 
   1358     if (window->monitor)
   1359         releaseMonitor(window);
   1360 
   1361     _glfwInputWindowMonitorChange(window, monitor);
   1362 
   1363     if (monitor)
   1364     {
   1365         GLFWvidmode mode;
   1366         DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
   1367         UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
   1368 
   1369         if (window->decorated)
   1370         {
   1371             style &= ~WS_OVERLAPPEDWINDOW;
   1372             style |= getWindowStyle(window);
   1373             SetWindowLongW(window->win32.handle, GWL_STYLE, style);
   1374 
   1375             flags |= SWP_FRAMECHANGED;
   1376         }
   1377 
   1378         _glfwPlatformGetVideoMode(monitor, &mode);
   1379         _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos);
   1380 
   1381         SetWindowPos(window->win32.handle, HWND_TOPMOST,
   1382                      xpos, ypos, mode.width, mode.height,
   1383                      flags);
   1384 
   1385         acquireMonitor(window);
   1386     }
   1387     else
   1388     {
   1389         HWND after;
   1390         RECT rect = { xpos, ypos, xpos + width, ypos + height };
   1391         DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
   1392         UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
   1393 
   1394         if (window->decorated)
   1395         {
   1396             style &= ~WS_POPUP;
   1397             style |= getWindowStyle(window);
   1398             SetWindowLongW(window->win32.handle, GWL_STYLE, style);
   1399 
   1400             flags |= SWP_FRAMECHANGED;
   1401         }
   1402 
   1403         if (window->floating)
   1404             after = HWND_TOPMOST;
   1405         else
   1406             after = HWND_NOTOPMOST;
   1407 
   1408         AdjustWindowRectEx(&rect, getWindowStyle(window),
   1409                            FALSE, getWindowExStyle(window));
   1410         SetWindowPos(window->win32.handle, after,
   1411                      rect.left, rect.top,
   1412                      rect.right - rect.left, rect.bottom - rect.top,
   1413                      flags);
   1414     }
   1415 }
   1416 
   1417 int _glfwPlatformWindowFocused(_GLFWwindow* window)
   1418 {
   1419     return window->win32.handle == GetActiveWindow();
   1420 }
   1421 
   1422 int _glfwPlatformWindowIconified(_GLFWwindow* window)
   1423 {
   1424     return IsIconic(window->win32.handle);
   1425 }
   1426 
   1427 int _glfwPlatformWindowVisible(_GLFWwindow* window)
   1428 {
   1429     return IsWindowVisible(window->win32.handle);
   1430 }
   1431 
   1432 int _glfwPlatformWindowMaximized(_GLFWwindow* window)
   1433 {
   1434     return IsZoomed(window->win32.handle);
   1435 }
   1436 
   1437 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
   1438 {
   1439     updateWindowStyles(window);
   1440 }
   1441 
   1442 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
   1443 {
   1444     updateWindowStyles(window);
   1445 }
   1446 
   1447 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
   1448 {
   1449     const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST;
   1450     SetWindowPos(window->win32.handle, after, 0, 0, 0, 0,
   1451                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
   1452 }
   1453 
   1454 void _glfwPlatformPollEvents(void)
   1455 {
   1456     MSG msg;
   1457     HWND handle;
   1458     _GLFWwindow* window;
   1459 
   1460     while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
   1461     {
   1462         if (msg.message == WM_QUIT)
   1463         {
   1464             // NOTE: While GLFW does not itself post WM_QUIT, other processes
   1465             //       may post it to this one, for example Task Manager
   1466             // HACK: Treat WM_QUIT as a close on all windows
   1467 
   1468             window = _glfw.windowListHead;
   1469             while (window)
   1470             {
   1471                 _glfwInputWindowCloseRequest(window);
   1472                 window = window->next;
   1473             }
   1474         }
   1475         else
   1476         {
   1477             TranslateMessage(&msg);
   1478             DispatchMessageW(&msg);
   1479         }
   1480     }
   1481 
   1482     handle = GetActiveWindow();
   1483     if (handle)
   1484     {
   1485         // NOTE: Shift keys on Windows tend to "stick" when both are pressed as
   1486         //       no key up message is generated by the first key release
   1487         //       The other half of this is in the handling of WM_KEYUP
   1488         // HACK: Query actual key state and synthesize release events as needed
   1489         window = GetPropW(handle, L"GLFW");
   1490         if (window)
   1491         {
   1492             const GLFWbool lshift = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
   1493             const GLFWbool rshift = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
   1494 
   1495             if (!lshift && window->keys[GLFW_KEY_LEFT_SHIFT] == GLFW_PRESS)
   1496             {
   1497                 const int mods = getAsyncKeyMods();
   1498                 const int scancode = _glfw.win32.scancodes[GLFW_KEY_LEFT_SHIFT];
   1499                 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods);
   1500             }
   1501             else if (!rshift && window->keys[GLFW_KEY_RIGHT_SHIFT] == GLFW_PRESS)
   1502             {
   1503                 const int mods = getAsyncKeyMods();
   1504                 const int scancode = _glfw.win32.scancodes[GLFW_KEY_RIGHT_SHIFT];
   1505                 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods);
   1506             }
   1507         }
   1508     }
   1509 
   1510     window = _glfw.win32.disabledCursorWindow;
   1511     if (window)
   1512     {
   1513         int width, height;
   1514         _glfwPlatformGetWindowSize(window, &width, &height);
   1515 
   1516         // NOTE: Re-center the cursor only if it has moved since the last call,
   1517         //       to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
   1518         if (window->win32.lastCursorPosX != width / 2 ||
   1519             window->win32.lastCursorPosY != height / 2)
   1520         {
   1521             _glfwPlatformSetCursorPos(window, width / 2, height / 2);
   1522         }
   1523     }
   1524 }
   1525 
   1526 void _glfwPlatformWaitEvents(void)
   1527 {
   1528     WaitMessage();
   1529 
   1530     _glfwPlatformPollEvents();
   1531 }
   1532 
   1533 void _glfwPlatformWaitEventsTimeout(double timeout)
   1534 {
   1535     MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS);
   1536 
   1537     _glfwPlatformPollEvents();
   1538 }
   1539 
   1540 void _glfwPlatformPostEmptyEvent(void)
   1541 {
   1542     PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
   1543 }
   1544 
   1545 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
   1546 {
   1547     POINT pos;
   1548 
   1549     if (GetCursorPos(&pos))
   1550     {
   1551         ScreenToClient(window->win32.handle, &pos);
   1552 
   1553         if (xpos)
   1554             *xpos = pos.x;
   1555         if (ypos)
   1556             *ypos = pos.y;
   1557     }
   1558 }
   1559 
   1560 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
   1561 {
   1562     POINT pos = { (int) xpos, (int) ypos };
   1563 
   1564     // Store the new position so it can be recognized later
   1565     window->win32.lastCursorPosX = pos.x;
   1566     window->win32.lastCursorPosY = pos.y;
   1567 
   1568     ClientToScreen(window->win32.handle, &pos);
   1569     SetCursorPos(pos.x, pos.y);
   1570 }
   1571 
   1572 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
   1573 {
   1574     if (mode == GLFW_CURSOR_DISABLED)
   1575     {
   1576         const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle };
   1577 
   1578         _glfw.win32.disabledCursorWindow = window;
   1579         _glfwPlatformGetCursorPos(window,
   1580                                   &_glfw.win32.restoreCursorPosX,
   1581                                   &_glfw.win32.restoreCursorPosY);
   1582         centerCursor(window);
   1583         updateClipRect(window);
   1584 
   1585         if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
   1586         {
   1587             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1588                                  "Win32: Failed to register raw input device");
   1589         }
   1590     }
   1591     else if (_glfw.win32.disabledCursorWindow == window)
   1592     {
   1593         const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL };
   1594 
   1595         _glfw.win32.disabledCursorWindow = NULL;
   1596         updateClipRect(NULL);
   1597         _glfwPlatformSetCursorPos(window,
   1598                                   _glfw.win32.restoreCursorPosX,
   1599                                   _glfw.win32.restoreCursorPosY);
   1600 
   1601         if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
   1602         {
   1603             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1604                                  "Win32: Failed to remove raw input device");
   1605         }
   1606     }
   1607 
   1608     if (cursorInClientArea(window))
   1609         updateCursorImage(window);
   1610 }
   1611 
   1612 const char* _glfwPlatformGetScancodeName(int scancode)
   1613 {
   1614     WCHAR name[16];
   1615 
   1616     if (!GetKeyNameTextW(scancode << 16, name, sizeof(name) / sizeof(WCHAR)))
   1617         return NULL;
   1618 
   1619     if (!WideCharToMultiByte(CP_UTF8, 0, name, -1,
   1620                              _glfw.win32.keyName,
   1621                              sizeof(_glfw.win32.keyName),
   1622                              NULL, NULL))
   1623     {
   1624         return NULL;
   1625     }
   1626 
   1627     return _glfw.win32.keyName;
   1628 }
   1629 
   1630 int _glfwPlatformGetKeyScancode(int key)
   1631 {
   1632     return _glfw.win32.scancodes[key];
   1633 }
   1634 
   1635 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
   1636                               const GLFWimage* image,
   1637                               int xhot, int yhot)
   1638 {
   1639     cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
   1640     if (!cursor->win32.handle)
   1641         return GLFW_FALSE;
   1642 
   1643     return GLFW_TRUE;
   1644 }
   1645 
   1646 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
   1647 {
   1648     cursor->win32.handle =
   1649         CopyCursor(LoadCursorW(NULL, translateCursorShape(shape)));
   1650     if (!cursor->win32.handle)
   1651     {
   1652         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1653                              "Win32: Failed to create standard cursor");
   1654         return GLFW_FALSE;
   1655     }
   1656 
   1657     return GLFW_TRUE;
   1658 }
   1659 
   1660 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
   1661 {
   1662     if (cursor->win32.handle)
   1663         DestroyIcon((HICON) cursor->win32.handle);
   1664 }
   1665 
   1666 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
   1667 {
   1668     if (cursorInClientArea(window))
   1669         updateCursorImage(window);
   1670 }
   1671 
   1672 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
   1673 {
   1674     int characterCount;
   1675     HANDLE object;
   1676     WCHAR* buffer;
   1677 
   1678     characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
   1679     if (!characterCount)
   1680         return;
   1681 
   1682     object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR));
   1683     if (!object)
   1684     {
   1685         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1686                              "Win32: Failed to allocate global handle for clipboard");
   1687         return;
   1688     }
   1689 
   1690     buffer = GlobalLock(object);
   1691     if (!buffer)
   1692     {
   1693         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1694                              "Win32: Failed to lock global handle");
   1695         GlobalFree(object);
   1696         return;
   1697     }
   1698 
   1699     MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount);
   1700     GlobalUnlock(object);
   1701 
   1702     if (!OpenClipboard(_glfw.win32.helperWindowHandle))
   1703     {
   1704         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1705                              "Win32: Failed to open clipboard");
   1706         GlobalFree(object);
   1707         return;
   1708     }
   1709 
   1710     EmptyClipboard();
   1711     SetClipboardData(CF_UNICODETEXT, object);
   1712     CloseClipboard();
   1713 }
   1714 
   1715 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
   1716 {
   1717     HANDLE object;
   1718     WCHAR* buffer;
   1719 
   1720     if (!OpenClipboard(_glfw.win32.helperWindowHandle))
   1721     {
   1722         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1723                              "Win32: Failed to open clipboard");
   1724         return NULL;
   1725     }
   1726 
   1727     object = GetClipboardData(CF_UNICODETEXT);
   1728     if (!object)
   1729     {
   1730         _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE,
   1731                              "Win32: Failed to convert clipboard to string");
   1732         CloseClipboard();
   1733         return NULL;
   1734     }
   1735 
   1736     buffer = GlobalLock(object);
   1737     if (!buffer)
   1738     {
   1739         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1740                              "Win32: Failed to lock global handle");
   1741         CloseClipboard();
   1742         return NULL;
   1743     }
   1744 
   1745     free(_glfw.win32.clipboardString);
   1746     _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer);
   1747 
   1748     GlobalUnlock(object);
   1749     CloseClipboard();
   1750 
   1751     return _glfw.win32.clipboardString;
   1752 }
   1753 
   1754 void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
   1755 {
   1756     if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface)
   1757         return;
   1758 
   1759     extensions[0] = "VK_KHR_surface";
   1760     extensions[1] = "VK_KHR_win32_surface";
   1761 }
   1762 
   1763 int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
   1764                                                       VkPhysicalDevice device,
   1765                                                       uint32_t queuefamily)
   1766 {
   1767     PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR =
   1768         (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
   1769         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
   1770     if (!vkGetPhysicalDeviceWin32PresentationSupportKHR)
   1771     {
   1772         _glfwInputError(GLFW_API_UNAVAILABLE,
   1773                         "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
   1774         return GLFW_FALSE;
   1775     }
   1776 
   1777     return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily);
   1778 }
   1779 
   1780 VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
   1781                                           _GLFWwindow* window,
   1782                                           const VkAllocationCallbacks* allocator,
   1783                                           VkSurfaceKHR* surface)
   1784 {
   1785     VkResult err;
   1786     VkWin32SurfaceCreateInfoKHR sci;
   1787     PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
   1788 
   1789     vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
   1790         vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
   1791     if (!vkCreateWin32SurfaceKHR)
   1792     {
   1793         _glfwInputError(GLFW_API_UNAVAILABLE,
   1794                         "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
   1795         return VK_ERROR_EXTENSION_NOT_PRESENT;
   1796     }
   1797 
   1798     memset(&sci, 0, sizeof(sci));
   1799     sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
   1800     sci.hinstance = GetModuleHandle(NULL);
   1801     sci.hwnd = window->win32.handle;
   1802 
   1803     err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
   1804     if (err)
   1805     {
   1806         _glfwInputError(GLFW_PLATFORM_ERROR,
   1807                         "Win32: Failed to create Vulkan surface: %s",
   1808                         _glfwGetVulkanResultString(err));
   1809     }
   1810 
   1811     return err;
   1812 }
   1813 
   1814 
   1815 //////////////////////////////////////////////////////////////////////////
   1816 //////                        GLFW native API                       //////
   1817 //////////////////////////////////////////////////////////////////////////
   1818 
   1819 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
   1820 {
   1821     _GLFWwindow* window = (_GLFWwindow*) handle;
   1822     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   1823     return window->win32.handle;
   1824 }
   1825