zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

win32_init.c (23394B)


      1 //========================================================================
      2 // GLFW 3.3 Win32 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2019 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 // Please use C89 style variable declarations in this file because VS 2010
     28 //========================================================================
     29 
     30 #include "internal.h"
     31 
     32 #include <stdlib.h>
     33 #include <malloc.h>
     34 
     35 static const GUID _glfw_GUID_DEVINTERFACE_HID =
     36     {0x4d1e55b2,0xf16f,0x11cf,{0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30}};
     37 
     38 #define GUID_DEVINTERFACE_HID _glfw_GUID_DEVINTERFACE_HID
     39 
     40 #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
     41 
     42 #if defined(_GLFW_BUILD_DLL)
     43  #warning "These symbols must be exported by the executable and have no effect in a DLL"
     44 #endif
     45 
     46 // Executables (but not DLLs) exporting this symbol with this value will be
     47 // automatically directed to the high-performance GPU on Nvidia Optimus systems
     48 // with up-to-date drivers
     49 //
     50 __declspec(dllexport) DWORD NvOptimusEnablement = 1;
     51 
     52 // Executables (but not DLLs) exporting this symbol with this value will be
     53 // automatically directed to the high-performance GPU on AMD PowerXpress systems
     54 // with up-to-date drivers
     55 //
     56 __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
     57 
     58 #endif // _GLFW_USE_HYBRID_HPG
     59 
     60 #if defined(_GLFW_BUILD_DLL)
     61 
     62 // GLFW DLL entry point
     63 //
     64 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
     65 {
     66     return TRUE;
     67 }
     68 
     69 #endif // _GLFW_BUILD_DLL
     70 
     71 // Load necessary libraries (DLLs)
     72 //
     73 static GLFWbool loadLibraries(void)
     74 {
     75     _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll");
     76     if (!_glfw.win32.winmm.instance)
     77     {
     78         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
     79                              "Win32: Failed to load winmm.dll");
     80         return GLFW_FALSE;
     81     }
     82 
     83     _glfw.win32.winmm.GetTime = (PFN_timeGetTime)
     84         GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime");
     85 
     86     _glfw.win32.user32.instance = LoadLibraryA("user32.dll");
     87     if (!_glfw.win32.user32.instance)
     88     {
     89         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
     90                              "Win32: Failed to load user32.dll");
     91         return GLFW_FALSE;
     92     }
     93 
     94     _glfw.win32.user32.SetProcessDPIAware_ = (PFN_SetProcessDPIAware)
     95         GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
     96     _glfw.win32.user32.ChangeWindowMessageFilterEx_ = (PFN_ChangeWindowMessageFilterEx)
     97         GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
     98     _glfw.win32.user32.EnableNonClientDpiScaling_ = (PFN_EnableNonClientDpiScaling)
     99         GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling");
    100     _glfw.win32.user32.SetProcessDpiAwarenessContext_ = (PFN_SetProcessDpiAwarenessContext)
    101         GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext");
    102     _glfw.win32.user32.GetDpiForWindow_ = (PFN_GetDpiForWindow)
    103         GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow");
    104     _glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
    105         GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
    106 
    107     _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
    108     if (_glfw.win32.dinput8.instance)
    109     {
    110         _glfw.win32.dinput8.Create = (PFN_DirectInput8Create)
    111             GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create");
    112     }
    113 
    114     {
    115         int i;
    116         const char* names[] =
    117         {
    118             "xinput1_4.dll",
    119             "xinput1_3.dll",
    120             "xinput9_1_0.dll",
    121             "xinput1_2.dll",
    122             "xinput1_1.dll",
    123             NULL
    124         };
    125 
    126         for (i = 0;  names[i];  i++)
    127         {
    128             _glfw.win32.xinput.instance = LoadLibraryA(names[i]);
    129             if (_glfw.win32.xinput.instance)
    130             {
    131                 _glfw.win32.xinput.GetCapabilities = (PFN_XInputGetCapabilities)
    132                     GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
    133                 _glfw.win32.xinput.GetState = (PFN_XInputGetState)
    134                     GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
    135 
    136                 break;
    137             }
    138         }
    139     }
    140 
    141     _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll");
    142     if (_glfw.win32.dwmapi.instance)
    143     {
    144         _glfw.win32.dwmapi.IsCompositionEnabled = (PFN_DwmIsCompositionEnabled)
    145             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
    146         _glfw.win32.dwmapi.Flush = (PFN_DwmFlush)
    147             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
    148         _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow)
    149             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
    150         _glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor)
    151             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor");
    152     }
    153 
    154     _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");
    155     if (_glfw.win32.shcore.instance)
    156     {
    157         _glfw.win32.shcore.SetProcessDpiAwareness_ = (PFN_SetProcessDpiAwareness)
    158             GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness");
    159         _glfw.win32.shcore.GetDpiForMonitor_ = (PFN_GetDpiForMonitor)
    160             GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor");
    161     }
    162 
    163     _glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll");
    164     if (_glfw.win32.ntdll.instance)
    165     {
    166         _glfw.win32.ntdll.RtlVerifyVersionInfo_ = (PFN_RtlVerifyVersionInfo)
    167             GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
    168     }
    169 
    170     return GLFW_TRUE;
    171 }
    172 
    173 // Unload used libraries (DLLs)
    174 //
    175 static void freeLibraries(void)
    176 {
    177     if (_glfw.win32.xinput.instance)
    178         FreeLibrary(_glfw.win32.xinput.instance);
    179 
    180     if (_glfw.win32.dinput8.instance)
    181         FreeLibrary(_glfw.win32.dinput8.instance);
    182 
    183     if (_glfw.win32.winmm.instance)
    184         FreeLibrary(_glfw.win32.winmm.instance);
    185 
    186     if (_glfw.win32.user32.instance)
    187         FreeLibrary(_glfw.win32.user32.instance);
    188 
    189     if (_glfw.win32.dwmapi.instance)
    190         FreeLibrary(_glfw.win32.dwmapi.instance);
    191 
    192     if (_glfw.win32.shcore.instance)
    193         FreeLibrary(_glfw.win32.shcore.instance);
    194 
    195     if (_glfw.win32.ntdll.instance)
    196         FreeLibrary(_glfw.win32.ntdll.instance);
    197 }
    198 
    199 // Create key code translation tables
    200 //
    201 static void createKeyTables(void)
    202 {
    203     int scancode;
    204 
    205     memset(_glfw.win32.keycodes, -1, sizeof(_glfw.win32.keycodes));
    206     memset(_glfw.win32.scancodes, -1, sizeof(_glfw.win32.scancodes));
    207 
    208     _glfw.win32.keycodes[0x00B] = GLFW_KEY_0;
    209     _glfw.win32.keycodes[0x002] = GLFW_KEY_1;
    210     _glfw.win32.keycodes[0x003] = GLFW_KEY_2;
    211     _glfw.win32.keycodes[0x004] = GLFW_KEY_3;
    212     _glfw.win32.keycodes[0x005] = GLFW_KEY_4;
    213     _glfw.win32.keycodes[0x006] = GLFW_KEY_5;
    214     _glfw.win32.keycodes[0x007] = GLFW_KEY_6;
    215     _glfw.win32.keycodes[0x008] = GLFW_KEY_7;
    216     _glfw.win32.keycodes[0x009] = GLFW_KEY_8;
    217     _glfw.win32.keycodes[0x00A] = GLFW_KEY_9;
    218     _glfw.win32.keycodes[0x01E] = GLFW_KEY_A;
    219     _glfw.win32.keycodes[0x030] = GLFW_KEY_B;
    220     _glfw.win32.keycodes[0x02E] = GLFW_KEY_C;
    221     _glfw.win32.keycodes[0x020] = GLFW_KEY_D;
    222     _glfw.win32.keycodes[0x012] = GLFW_KEY_E;
    223     _glfw.win32.keycodes[0x021] = GLFW_KEY_F;
    224     _glfw.win32.keycodes[0x022] = GLFW_KEY_G;
    225     _glfw.win32.keycodes[0x023] = GLFW_KEY_H;
    226     _glfw.win32.keycodes[0x017] = GLFW_KEY_I;
    227     _glfw.win32.keycodes[0x024] = GLFW_KEY_J;
    228     _glfw.win32.keycodes[0x025] = GLFW_KEY_K;
    229     _glfw.win32.keycodes[0x026] = GLFW_KEY_L;
    230     _glfw.win32.keycodes[0x032] = GLFW_KEY_M;
    231     _glfw.win32.keycodes[0x031] = GLFW_KEY_N;
    232     _glfw.win32.keycodes[0x018] = GLFW_KEY_O;
    233     _glfw.win32.keycodes[0x019] = GLFW_KEY_P;
    234     _glfw.win32.keycodes[0x010] = GLFW_KEY_Q;
    235     _glfw.win32.keycodes[0x013] = GLFW_KEY_R;
    236     _glfw.win32.keycodes[0x01F] = GLFW_KEY_S;
    237     _glfw.win32.keycodes[0x014] = GLFW_KEY_T;
    238     _glfw.win32.keycodes[0x016] = GLFW_KEY_U;
    239     _glfw.win32.keycodes[0x02F] = GLFW_KEY_V;
    240     _glfw.win32.keycodes[0x011] = GLFW_KEY_W;
    241     _glfw.win32.keycodes[0x02D] = GLFW_KEY_X;
    242     _glfw.win32.keycodes[0x015] = GLFW_KEY_Y;
    243     _glfw.win32.keycodes[0x02C] = GLFW_KEY_Z;
    244 
    245     _glfw.win32.keycodes[0x028] = GLFW_KEY_APOSTROPHE;
    246     _glfw.win32.keycodes[0x02B] = GLFW_KEY_BACKSLASH;
    247     _glfw.win32.keycodes[0x033] = GLFW_KEY_COMMA;
    248     _glfw.win32.keycodes[0x00D] = GLFW_KEY_EQUAL;
    249     _glfw.win32.keycodes[0x029] = GLFW_KEY_GRAVE_ACCENT;
    250     _glfw.win32.keycodes[0x01A] = GLFW_KEY_LEFT_BRACKET;
    251     _glfw.win32.keycodes[0x00C] = GLFW_KEY_MINUS;
    252     _glfw.win32.keycodes[0x034] = GLFW_KEY_PERIOD;
    253     _glfw.win32.keycodes[0x01B] = GLFW_KEY_RIGHT_BRACKET;
    254     _glfw.win32.keycodes[0x027] = GLFW_KEY_SEMICOLON;
    255     _glfw.win32.keycodes[0x035] = GLFW_KEY_SLASH;
    256     _glfw.win32.keycodes[0x056] = GLFW_KEY_WORLD_2;
    257 
    258     _glfw.win32.keycodes[0x00E] = GLFW_KEY_BACKSPACE;
    259     _glfw.win32.keycodes[0x153] = GLFW_KEY_DELETE;
    260     _glfw.win32.keycodes[0x14F] = GLFW_KEY_END;
    261     _glfw.win32.keycodes[0x01C] = GLFW_KEY_ENTER;
    262     _glfw.win32.keycodes[0x001] = GLFW_KEY_ESCAPE;
    263     _glfw.win32.keycodes[0x147] = GLFW_KEY_HOME;
    264     _glfw.win32.keycodes[0x152] = GLFW_KEY_INSERT;
    265     _glfw.win32.keycodes[0x15D] = GLFW_KEY_MENU;
    266     _glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN;
    267     _glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP;
    268     _glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;
    269     _glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE;
    270     _glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE;
    271     _glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB;
    272     _glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;
    273     _glfw.win32.keycodes[0x145] = GLFW_KEY_NUM_LOCK;
    274     _glfw.win32.keycodes[0x046] = GLFW_KEY_SCROLL_LOCK;
    275     _glfw.win32.keycodes[0x03B] = GLFW_KEY_F1;
    276     _glfw.win32.keycodes[0x03C] = GLFW_KEY_F2;
    277     _glfw.win32.keycodes[0x03D] = GLFW_KEY_F3;
    278     _glfw.win32.keycodes[0x03E] = GLFW_KEY_F4;
    279     _glfw.win32.keycodes[0x03F] = GLFW_KEY_F5;
    280     _glfw.win32.keycodes[0x040] = GLFW_KEY_F6;
    281     _glfw.win32.keycodes[0x041] = GLFW_KEY_F7;
    282     _glfw.win32.keycodes[0x042] = GLFW_KEY_F8;
    283     _glfw.win32.keycodes[0x043] = GLFW_KEY_F9;
    284     _glfw.win32.keycodes[0x044] = GLFW_KEY_F10;
    285     _glfw.win32.keycodes[0x057] = GLFW_KEY_F11;
    286     _glfw.win32.keycodes[0x058] = GLFW_KEY_F12;
    287     _glfw.win32.keycodes[0x064] = GLFW_KEY_F13;
    288     _glfw.win32.keycodes[0x065] = GLFW_KEY_F14;
    289     _glfw.win32.keycodes[0x066] = GLFW_KEY_F15;
    290     _glfw.win32.keycodes[0x067] = GLFW_KEY_F16;
    291     _glfw.win32.keycodes[0x068] = GLFW_KEY_F17;
    292     _glfw.win32.keycodes[0x069] = GLFW_KEY_F18;
    293     _glfw.win32.keycodes[0x06A] = GLFW_KEY_F19;
    294     _glfw.win32.keycodes[0x06B] = GLFW_KEY_F20;
    295     _glfw.win32.keycodes[0x06C] = GLFW_KEY_F21;
    296     _glfw.win32.keycodes[0x06D] = GLFW_KEY_F22;
    297     _glfw.win32.keycodes[0x06E] = GLFW_KEY_F23;
    298     _glfw.win32.keycodes[0x076] = GLFW_KEY_F24;
    299     _glfw.win32.keycodes[0x038] = GLFW_KEY_LEFT_ALT;
    300     _glfw.win32.keycodes[0x01D] = GLFW_KEY_LEFT_CONTROL;
    301     _glfw.win32.keycodes[0x02A] = GLFW_KEY_LEFT_SHIFT;
    302     _glfw.win32.keycodes[0x15B] = GLFW_KEY_LEFT_SUPER;
    303     _glfw.win32.keycodes[0x137] = GLFW_KEY_PRINT_SCREEN;
    304     _glfw.win32.keycodes[0x138] = GLFW_KEY_RIGHT_ALT;
    305     _glfw.win32.keycodes[0x11D] = GLFW_KEY_RIGHT_CONTROL;
    306     _glfw.win32.keycodes[0x036] = GLFW_KEY_RIGHT_SHIFT;
    307     _glfw.win32.keycodes[0x15C] = GLFW_KEY_RIGHT_SUPER;
    308     _glfw.win32.keycodes[0x150] = GLFW_KEY_DOWN;
    309     _glfw.win32.keycodes[0x14B] = GLFW_KEY_LEFT;
    310     _glfw.win32.keycodes[0x14D] = GLFW_KEY_RIGHT;
    311     _glfw.win32.keycodes[0x148] = GLFW_KEY_UP;
    312 
    313     _glfw.win32.keycodes[0x052] = GLFW_KEY_KP_0;
    314     _glfw.win32.keycodes[0x04F] = GLFW_KEY_KP_1;
    315     _glfw.win32.keycodes[0x050] = GLFW_KEY_KP_2;
    316     _glfw.win32.keycodes[0x051] = GLFW_KEY_KP_3;
    317     _glfw.win32.keycodes[0x04B] = GLFW_KEY_KP_4;
    318     _glfw.win32.keycodes[0x04C] = GLFW_KEY_KP_5;
    319     _glfw.win32.keycodes[0x04D] = GLFW_KEY_KP_6;
    320     _glfw.win32.keycodes[0x047] = GLFW_KEY_KP_7;
    321     _glfw.win32.keycodes[0x048] = GLFW_KEY_KP_8;
    322     _glfw.win32.keycodes[0x049] = GLFW_KEY_KP_9;
    323     _glfw.win32.keycodes[0x04E] = GLFW_KEY_KP_ADD;
    324     _glfw.win32.keycodes[0x053] = GLFW_KEY_KP_DECIMAL;
    325     _glfw.win32.keycodes[0x135] = GLFW_KEY_KP_DIVIDE;
    326     _glfw.win32.keycodes[0x11C] = GLFW_KEY_KP_ENTER;
    327     _glfw.win32.keycodes[0x059] = GLFW_KEY_KP_EQUAL;
    328     _glfw.win32.keycodes[0x037] = GLFW_KEY_KP_MULTIPLY;
    329     _glfw.win32.keycodes[0x04A] = GLFW_KEY_KP_SUBTRACT;
    330 
    331     for (scancode = 0;  scancode < 512;  scancode++)
    332     {
    333         if (_glfw.win32.keycodes[scancode] > 0)
    334             _glfw.win32.scancodes[_glfw.win32.keycodes[scancode]] = scancode;
    335     }
    336 }
    337 
    338 // Creates a dummy window for behind-the-scenes work
    339 //
    340 static GLFWbool createHelperWindow(void)
    341 {
    342     MSG msg;
    343 
    344     _glfw.win32.helperWindowHandle =
    345         CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
    346                         _GLFW_WNDCLASSNAME,
    347                         L"GLFW message window",
    348                         WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
    349                         0, 0, 1, 1,
    350                         NULL, NULL,
    351                         GetModuleHandleW(NULL),
    352                         NULL);
    353 
    354     if (!_glfw.win32.helperWindowHandle)
    355     {
    356         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    357                              "Win32: Failed to create helper window");
    358         return GLFW_FALSE;
    359     }
    360 
    361     // HACK: The command to the first ShowWindow call is ignored if the parent
    362     //       process passed along a STARTUPINFO, so clear that with a no-op call
    363     ShowWindow(_glfw.win32.helperWindowHandle, SW_HIDE);
    364 
    365     // Register for HID device notifications
    366     {
    367         DEV_BROADCAST_DEVICEINTERFACE_W dbi;
    368         ZeroMemory(&dbi, sizeof(dbi));
    369         dbi.dbcc_size = sizeof(dbi);
    370         dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    371         dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
    372 
    373         _glfw.win32.deviceNotificationHandle =
    374             RegisterDeviceNotificationW(_glfw.win32.helperWindowHandle,
    375                                         (DEV_BROADCAST_HDR*) &dbi,
    376                                         DEVICE_NOTIFY_WINDOW_HANDLE);
    377     }
    378 
    379     while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE))
    380     {
    381         TranslateMessage(&msg);
    382         DispatchMessageW(&msg);
    383     }
    384 
    385    return GLFW_TRUE;
    386 }
    387 
    388 
    389 //////////////////////////////////////////////////////////////////////////
    390 //////                       GLFW internal API                      //////
    391 //////////////////////////////////////////////////////////////////////////
    392 
    393 // Returns a wide string version of the specified UTF-8 string
    394 //
    395 WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source)
    396 {
    397     WCHAR* target;
    398     int count;
    399 
    400     count = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0);
    401     if (!count)
    402     {
    403         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    404                              "Win32: Failed to convert string from UTF-8");
    405         return NULL;
    406     }
    407 
    408     target = calloc(count, sizeof(WCHAR));
    409 
    410     if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count))
    411     {
    412         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    413                              "Win32: Failed to convert string from UTF-8");
    414         free(target);
    415         return NULL;
    416     }
    417 
    418     return target;
    419 }
    420 
    421 // Returns a UTF-8 string version of the specified wide string
    422 //
    423 char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source)
    424 {
    425     char* target;
    426     int size;
    427 
    428     size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
    429     if (!size)
    430     {
    431         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    432                              "Win32: Failed to convert string to UTF-8");
    433         return NULL;
    434     }
    435 
    436     target = calloc(size, 1);
    437 
    438     if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL))
    439     {
    440         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    441                              "Win32: Failed to convert string to UTF-8");
    442         free(target);
    443         return NULL;
    444     }
    445 
    446     return target;
    447 }
    448 
    449 // Reports the specified error, appending information about the last Win32 error
    450 //
    451 void _glfwInputErrorWin32(int error, const char* description)
    452 {
    453     WCHAR buffer[_GLFW_MESSAGE_SIZE] = L"";
    454     char message[_GLFW_MESSAGE_SIZE] = "";
    455 
    456     FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
    457                        FORMAT_MESSAGE_IGNORE_INSERTS |
    458                        FORMAT_MESSAGE_MAX_WIDTH_MASK,
    459                    NULL,
    460                    GetLastError() & 0xffff,
    461                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    462                    buffer,
    463                    sizeof(buffer) / sizeof(WCHAR),
    464                    NULL);
    465     WideCharToMultiByte(CP_UTF8, 0, buffer, -1, message, sizeof(message), NULL, NULL);
    466 
    467     _glfwInputError(error, "%s: %s", description, message);
    468 }
    469 
    470 // Updates key names according to the current keyboard layout
    471 //
    472 void _glfwUpdateKeyNamesWin32(void)
    473 {
    474     int key;
    475     BYTE state[256] = {0};
    476 
    477     memset(_glfw.win32.keynames, 0, sizeof(_glfw.win32.keynames));
    478 
    479     for (key = GLFW_KEY_SPACE;  key <= GLFW_KEY_LAST;  key++)
    480     {
    481         UINT vk;
    482         int scancode, length;
    483         WCHAR chars[16];
    484 
    485         scancode = _glfw.win32.scancodes[key];
    486         if (scancode == -1)
    487             continue;
    488 
    489         if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
    490         {
    491             const UINT vks[] = {
    492                 VK_NUMPAD0,  VK_NUMPAD1,  VK_NUMPAD2, VK_NUMPAD3,
    493                 VK_NUMPAD4,  VK_NUMPAD5,  VK_NUMPAD6, VK_NUMPAD7,
    494                 VK_NUMPAD8,  VK_NUMPAD9,  VK_DECIMAL, VK_DIVIDE,
    495                 VK_MULTIPLY, VK_SUBTRACT, VK_ADD
    496             };
    497 
    498             vk = vks[key - GLFW_KEY_KP_0];
    499         }
    500         else
    501             vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
    502 
    503         length = ToUnicode(vk, scancode, state,
    504                            chars, sizeof(chars) / sizeof(WCHAR),
    505                            0);
    506 
    507         if (length == -1)
    508         {
    509             length = ToUnicode(vk, scancode, state,
    510                                chars, sizeof(chars) / sizeof(WCHAR),
    511                                0);
    512         }
    513 
    514         if (length < 1)
    515             continue;
    516 
    517         WideCharToMultiByte(CP_UTF8, 0, chars, 1,
    518                             _glfw.win32.keynames[key],
    519                             sizeof(_glfw.win32.keynames[key]),
    520                             NULL, NULL);
    521     }
    522 }
    523 
    524 // Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
    525 //
    526 BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
    527 {
    528     OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
    529     DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
    530     ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
    531     cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
    532     cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
    533     // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
    534     //       latter lies unless the user knew to embed a non-default manifest
    535     //       announcing support for Windows 10 via supportedOS GUID
    536     return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
    537 }
    538 
    539 // Checks whether we are on at least the specified build of Windows 10
    540 //
    541 BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build)
    542 {
    543     OSVERSIONINFOEXW osvi = { sizeof(osvi), 10, 0, build };
    544     DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
    545     ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
    546     cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
    547     cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
    548     // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
    549     //       latter lies unless the user knew to embed a non-default manifest
    550     //       announcing support for Windows 10 via supportedOS GUID
    551     return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
    552 }
    553 
    554 
    555 //////////////////////////////////////////////////////////////////////////
    556 //////                       GLFW platform API                      //////
    557 //////////////////////////////////////////////////////////////////////////
    558 
    559 int _glfwPlatformInit(void)
    560 {
    561     // To make SetForegroundWindow work as we want, we need to fiddle
    562     // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early
    563     // as possible in the hope of still being the foreground process)
    564     SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0,
    565                           &_glfw.win32.foregroundLockTimeout, 0);
    566     SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0),
    567                           SPIF_SENDCHANGE);
    568 
    569     if (!loadLibraries())
    570         return GLFW_FALSE;
    571 
    572     createKeyTables();
    573     _glfwUpdateKeyNamesWin32();
    574 
    575     if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
    576         SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
    577     else if (IsWindows8Point1OrGreater())
    578         SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
    579     else if (IsWindowsVistaOrGreater())
    580         SetProcessDPIAware();
    581 
    582     if (!_glfwRegisterWindowClassWin32())
    583         return GLFW_FALSE;
    584 
    585     if (!createHelperWindow())
    586         return GLFW_FALSE;
    587 
    588     _glfwInitTimerWin32();
    589     _glfwInitJoysticksWin32();
    590 
    591     _glfwPollMonitorsWin32();
    592     return GLFW_TRUE;
    593 }
    594 
    595 void _glfwPlatformTerminate(void)
    596 {
    597     if (_glfw.win32.deviceNotificationHandle)
    598         UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
    599 
    600     if (_glfw.win32.helperWindowHandle)
    601         DestroyWindow(_glfw.win32.helperWindowHandle);
    602 
    603     _glfwUnregisterWindowClassWin32();
    604 
    605     // Restore previous foreground lock timeout system setting
    606     SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
    607                           UIntToPtr(_glfw.win32.foregroundLockTimeout),
    608                           SPIF_SENDCHANGE);
    609 
    610     free(_glfw.win32.clipboardString);
    611     free(_glfw.win32.rawInput);
    612 
    613     _glfwTerminateWGL();
    614     _glfwTerminateEGL();
    615 
    616     _glfwTerminateJoysticksWin32();
    617 
    618     freeLibraries();
    619 }
    620 
    621 const char* _glfwPlatformGetVersionString(void)
    622 {
    623     return _GLFW_VERSION_NUMBER " Win32 WGL EGL OSMesa"
    624 #if defined(__MINGW32__)
    625         " MinGW"
    626 #elif defined(_MSC_VER)
    627         " VisualC"
    628 #endif
    629 #if defined(_GLFW_USE_HYBRID_HPG) || defined(_GLFW_USE_OPTIMUS_HPG)
    630         " hybrid-GPU"
    631 #endif
    632 #if defined(_GLFW_BUILD_DLL)
    633         " DLL"
    634 #endif
    635         ;
    636 }
    637