1 /// Translated from C to D
2 module glfw3.win32_init;
3 
4 extern(C): @nogc: nothrow: __gshared:
5 
6 //========================================================================
7 // GLFW 3.3 Win32 - www.glfw.org
8 //------------------------------------------------------------------------
9 // Copyright (c) 2002-2006 Marcus Geelnard
10 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
11 //
12 // This software is provided 'as-is', without any express or implied
13 // warranty. In no event will the authors be held liable for any damages
14 // arising from the use of this software.
15 //
16 // Permission is granted to anyone to use this software for any purpose,
17 // including commercial applications, and to alter it and redistribute it
18 // freely, subject to the following restrictions:
19 //
20 // 1. The origin of this software must not be misrepresented; you must not
21 //    claim that you wrote the original software. If you use this software
22 //    in a product, an acknowledgment in the product documentation would
23 //    be appreciated but is not required.
24 //
25 // 2. Altered source versions must be plainly marked as such, and must not
26 //    be misrepresented as being the original software.
27 //
28 // 3. This notice may not be removed or altered from any source
29 //    distribution.
30 //
31 //========================================================================
32 // Please use C89 style variable declarations in this file because VS 2010
33 //========================================================================
34 
35 import glfw3.internal;
36 
37 import core.stdc.stdlib;
38 import core.stdc.string;
39 
40 private const(GUID) _glfw_GUID_DEVINTERFACE_HID = GUID(0x4d1e55b2,0xf16f,0x11cf,[0x88,0xcb,0x00,0x11,0x11,0x00,0x00,0x30]);
41 
42 package:
43 
44 enum GUID_DEVINTERFACE_HID = _glfw_GUID_DEVINTERFACE_HID;
45 
46 version(_GLFW_USE_HYBRID_HPG) version = _GLFW_USE_HPG;
47 version(_GLFW_USE_OPTIMUS_HPG) version = _GLFW_USE_HPG;
48 
49 version(_GLFW_USE_HPG) {
50 
51 // Executables (but not DLLs) exporting this symbol with this value will be
52 // automatically directed to the high-performance GPU on Nvidia Optimus systems
53 // with up-to-date drivers
54 //
55 DWORD NvOptimusEnablement = 1;
56 
57 // Executables (but not DLLs) exporting this symbol with this value will be
58 // automatically directed to the high-performance GPU on AMD PowerXpress systems
59 // with up-to-date drivers
60 //
61 int AmdPowerXpressRequestHighPerformance = 1;
62 
63 }
64 
65 version (_GLFW_BUILD_DLL) {
66 
67 // GLFW DLL entry point
68 //
69 extern(Windows) BOOL DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
70     return TRUE;
71 }
72 
73 }
74 
75 // Load necessary libraries (DLLs)
76 //
77 private GLFWbool loadLibraries() {
78     _glfw.win32.winmm.instance = LoadLibraryA("winmm.dll");
79     if (!_glfw.win32.winmm.instance)
80     {
81         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
82                              "Win32: Failed to load winmm.dll");
83         return GLFW_FALSE;
84     }
85 
86     _glfw.win32.winmm.GetTime = cast(PFN_timeGetTime)
87         GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime");
88 
89     _glfw.win32.user32.instance = LoadLibraryA("user32.dll");
90     if (!_glfw.win32.user32.instance)
91     {
92         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
93                              "Win32: Failed to load user32.dll");
94         return GLFW_FALSE;
95     }
96 
97     _glfw.win32.user32.SetProcessDPIAware_ = cast(PFN_SetProcessDPIAware)
98         GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware");
99     _glfw.win32.user32.ChangeWindowMessageFilterEx_ = cast(PFN_ChangeWindowMessageFilterEx)
100         GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx");
101     _glfw.win32.user32.EnableNonClientDpiScaling_ = cast(PFN_EnableNonClientDpiScaling)
102         GetProcAddress(_glfw.win32.user32.instance, "EnableNonClientDpiScaling");
103     _glfw.win32.user32.SetProcessDpiAwarenessContext_ = cast(PFN_SetProcessDpiAwarenessContext)
104         GetProcAddress(_glfw.win32.user32.instance, "SetProcessDpiAwarenessContext");
105     _glfw.win32.user32.GetDpiForWindow_ = cast(PFN_GetDpiForWindow)
106         GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow");
107     _glfw.win32.user32.AdjustWindowRectExForDpi_ = cast(PFN_AdjustWindowRectExForDpi)
108         GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
109 
110     _glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
111     if (_glfw.win32.dinput8.instance)
112     {
113         _glfw.win32.dinput8.Create = cast(PFN_DirectInput8Create)
114             GetProcAddress(_glfw.win32.dinput8.instance, "DirectInput8Create");
115     }
116 
117     {
118         int i;
119         const(char)*[6] names = [
120             "xinput1_4.dll".ptr,
121             "xinput1_3.dll".ptr,
122             "xinput9_1_0.dll".ptr,
123             "xinput1_2.dll".ptr,
124             "xinput1_1.dll".ptr,
125             null
126         ];
127 
128         for (i = 0;  names[i];  i++)
129         {
130             _glfw.win32.xinput.instance = LoadLibraryA(names[i]);
131             if (_glfw.win32.xinput.instance)
132             {
133                 _glfw.win32.xinput.GetCapabilities = cast(PFN_XInputGetCapabilities)
134                     GetProcAddress(_glfw.win32.xinput.instance, "XInputGetCapabilities");
135                 _glfw.win32.xinput.GetState = cast(PFN_XInputGetState)
136                     GetProcAddress(_glfw.win32.xinput.instance, "XInputGetState");
137                 _glfw.win32.xinput.SetState = cast(PFN_XInputSetState)
138                     GetProcAddress(_glfw.win32.xinput.instance, "XInputSetState");
139 
140                 break;
141             }
142         }
143     }
144 
145     _glfw.win32.dwmapi.instance = LoadLibraryA("dwmapi.dll");
146     if (_glfw.win32.dwmapi.instance)
147     {
148         _glfw.win32.dwmapi.IsCompositionEnabled = cast(PFN_DwmIsCompositionEnabled)
149             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
150         _glfw.win32.dwmapi.Flush = cast(PFN_DwmFlush)
151             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
152         _glfw.win32.dwmapi.EnableBlurBehindWindow = cast(PFN_DwmEnableBlurBehindWindow)
153             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
154     }
155 
156     _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");
157     if (_glfw.win32.shcore.instance)
158     {
159         _glfw.win32.shcore.SetProcessDpiAwareness_ = cast(PFN_SetProcessDpiAwareness)
160             GetProcAddress(_glfw.win32.shcore.instance, "SetProcessDpiAwareness");
161         _glfw.win32.shcore.GetDpiForMonitor_ = cast(PFN_GetDpiForMonitor)
162             GetProcAddress(_glfw.win32.shcore.instance, "GetDpiForMonitor");
163     }
164 
165     _glfw.win32.ntdll.instance = LoadLibraryA("ntdll.dll");
166     if (_glfw.win32.ntdll.instance)
167     {
168         _glfw.win32.ntdll.RtlVerifyVersionInfo_ = cast(PFN_RtlVerifyVersionInfo)
169             GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
170     }
171 
172     return GLFW_TRUE;
173 }
174 
175 // Unload used libraries (DLLs)
176 //
177 private extern(D) void freeLibraries() {
178     if (_glfw.win32.xinput.instance)
179         FreeLibrary(_glfw.win32.xinput.instance);
180 
181     if (_glfw.win32.dinput8.instance)
182         FreeLibrary(_glfw.win32.dinput8.instance);
183 
184     if (_glfw.win32.winmm.instance)
185         FreeLibrary(_glfw.win32.winmm.instance);
186 
187     if (_glfw.win32.user32.instance)
188         FreeLibrary(_glfw.win32.user32.instance);
189 
190     if (_glfw.win32.dwmapi.instance)
191         FreeLibrary(_glfw.win32.dwmapi.instance);
192 
193     if (_glfw.win32.shcore.instance)
194         FreeLibrary(_glfw.win32.shcore.instance);
195 
196     if (_glfw.win32.ntdll.instance)
197         FreeLibrary(_glfw.win32.ntdll.instance);
198 }
199 
200 // Create key code translation tables
201 //
202 private extern(D) void createKeyTables() {
203     int scancode;
204 
205     memset(_glfw.win32.keycodes.ptr, -1, typeof(_glfw.win32.keycodes).sizeof);
206     memset(_glfw.win32.scancodes.ptr, -1, typeof(_glfw.win32.scancodes).sizeof);
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 private GLFWbool createHelperWindow() {
341     MSG msg;
342 
343     _glfw.win32.helperWindowHandle =
344         CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
345                         _GLFW_WNDCLASSNAME.ptr,
346                         "GLFW message window"w.ptr,
347                         WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
348                         0, 0, 1, 1,
349                         null, null,
350                         GetModuleHandleW(null),
351                         null);
352 
353     if (!_glfw.win32.helperWindowHandle)
354     {
355         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
356                              "Win32: Failed to create helper window");
357         return GLFW_FALSE;
358     }
359 
360     // HACK: The command to the first ShowWindow call is ignored if the parent
361     //       process passed along a STARTUPINFO, so clear that with a no-op call
362     ShowWindow(_glfw.win32.helperWindowHandle, SW_HIDE);
363 
364     // Register for HID device notifications
365     {
366         DEV_BROADCAST_DEVICEINTERFACE_W dbi;
367         memset(&dbi, 0, typeof(dbi).sizeof); //ZeroMemory(&dbi, typeof(dbi).sizeof);
368         dbi.dbcc_size = typeof(dbi).sizeof;
369         dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
370         dbi.dbcc_classguid = GUID_DEVINTERFACE_HID;
371 
372         _glfw.win32.deviceNotificationHandle =
373             RegisterDeviceNotificationW(_glfw.win32.helperWindowHandle,
374                                         cast(DEV_BROADCAST_HDR*) &dbi,
375                                         DEVICE_NOTIFY_WINDOW_HANDLE);
376     }
377 
378     while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE))
379     {
380         TranslateMessage(&msg);
381         DispatchMessageW(&msg);
382     }
383 
384    return GLFW_TRUE;
385 }
386 
387 
388 //////////////////////////////////////////////////////////////////////////
389 //////                       GLFW internal API                      //////
390 //////////////////////////////////////////////////////////////////////////
391 
392 // Returns a wide string version of the specified UTF-8 string
393 //
394 WCHAR* _glfwCreateWideStringFromUTF8Win32(const(char)* source) {
395     WCHAR* target;
396     int count;
397 
398     count = MultiByteToWideChar(CP_UTF8, 0, source, -1, null, 0);
399     if (!count)
400     {
401         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
402                              "Win32: Failed to convert string from UTF-8");
403         return null;
404     }
405 
406     target = cast(WCHAR*) calloc(count, WCHAR.sizeof);
407 
408     if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, count))
409     {
410         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
411                              "Win32: Failed to convert string from UTF-8");
412         free(target);
413         return null;
414     }
415 
416     return target;
417 }
418 
419 // Returns a UTF-8 string version of the specified wide string
420 //
421 char* _glfwCreateUTF8FromWideStringWin32(const(WCHAR)* source) {
422     char* target;
423     int size;
424 
425     size = WideCharToMultiByte(CP_UTF8, 0, source, -1, null, 0, null, null);
426     if (!size)
427     {
428         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
429                              "Win32: Failed to convert string to UTF-8");
430         return null;
431     }
432 
433     target = cast(char*) calloc(size, 1);
434 
435     if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, null, null))
436     {
437         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
438                              "Win32: Failed to convert string to UTF-8");
439         free(target);
440         return null;
441     }
442 
443     return target;
444 }
445 
446 // Reports the specified error, appending information about the last Win32 error
447 //
448 void _glfwInputErrorWin32(int error, const(char)* description) {
449     WCHAR[_GLFW_MESSAGE_SIZE] buffer = ""w;
450     char[_GLFW_MESSAGE_SIZE] message = "";
451 
452     FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
453                        FORMAT_MESSAGE_IGNORE_INSERTS |
454                        FORMAT_MESSAGE_MAX_WIDTH_MASK,
455                    null,
456                    GetLastError() & 0xffff,
457                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
458                    buffer.ptr,
459                    buffer.sizeof / WCHAR.sizeof,
460                    null);
461     WideCharToMultiByte(CP_UTF8, 0, buffer.ptr, -1, message.ptr, typeof(message).sizeof, null, null);
462 
463     _glfwInputError(error, "%s: %s", description, message.ptr);
464 }
465 
466 // Updates key names according to the current keyboard layout
467 //
468 void _glfwUpdateKeyNamesWin32() {
469     int key;
470     BYTE[256] state = 0;
471 
472     memset(_glfw.win32.keynames.ptr, 0, typeof(_glfw.win32.keynames).sizeof);
473 
474     for (key = GLFW_KEY_SPACE;  key <= GLFW_KEY_LAST;  key++)
475     {
476         UINT vk;
477         int scancode;int length;
478         WCHAR[16] chars;
479 
480         scancode = _glfw.win32.scancodes[key];
481         if (scancode == -1)
482             continue;
483 
484         if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
485         {
486             const(UINT)[15] vks = [
487                 VK_NUMPAD0,  VK_NUMPAD1,  VK_NUMPAD2, VK_NUMPAD3,
488                 VK_NUMPAD4,  VK_NUMPAD5,  VK_NUMPAD6, VK_NUMPAD7,
489                 VK_NUMPAD8,  VK_NUMPAD9,  VK_DECIMAL, VK_DIVIDE,
490                 VK_MULTIPLY, VK_SUBTRACT, VK_ADD
491             ];
492 
493             vk = vks[key - GLFW_KEY_KP_0];
494         }
495         else
496             vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
497 
498         length = ToUnicode(vk, scancode, state.ptr,
499                            chars.ptr, chars.sizeof / WCHAR.sizeof,
500                            0);
501 
502         if (length == -1)
503         {
504             length = ToUnicode(vk, scancode, state.ptr,
505                                chars.ptr, chars.sizeof / WCHAR.sizeof,
506                                0);
507         }
508 
509         if (length < 1)
510             continue;
511 
512         WideCharToMultiByte(CP_UTF8, 0, chars.ptr, 1,
513                             _glfw.win32.keynames[key].ptr,
514                             typeof(_glfw.win32.keynames[key]).sizeof,
515                             null, null);
516     }
517 }
518 
519 // Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
520 //
521 BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp) {
522     OSVERSIONINFOEXW osvi = OSVERSIONINFOEXW(OSVERSIONINFOEXW.sizeof, major, minor, 0, 0, (wchar[128]).init, sp);
523     DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
524     ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
525     cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
526     cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
527     // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
528     //       latter lies unless the user knew to embed a non-default manifest
529     //       announcing support for Windows 10 via supportedOS GUID
530     return _glfw.win32.ntdll.RtlVerifyVersionInfo_(&osvi, mask, cond) == 0;
531 }
532 
533 // Checks whether we are on at least the specified build of Windows 10
534 //
535 BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build) {
536     OSVERSIONINFOEXW osvi = OSVERSIONINFOEXW(OSVERSIONINFOEXW.sizeof, 10, 0, build);
537     DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
538     ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
539     cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
540     cond = VerSetConditionMask(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
541     // HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
542     //       latter lies unless the user knew to embed a non-default manifest
543     //       announcing support for Windows 10 via supportedOS GUID
544     return _glfw.win32.ntdll.RtlVerifyVersionInfo_(&osvi, mask, cond) == 0;
545 }
546 
547 
548 //////////////////////////////////////////////////////////////////////////
549 //////                       GLFW platform API                      //////
550 //////////////////////////////////////////////////////////////////////////
551 
552 int _glfwPlatformInit() {
553     // To make SetForegroundWindow work as we want, we need to fiddle
554     // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early
555     // as possible in the hope of still being the foreground process)
556     SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0,
557                           &_glfw.win32.foregroundLockTimeout, 0);
558     SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, null /*UIntToPtr(0)*/,
559                           SPIF_SENDCHANGE);
560 
561     if (!loadLibraries())
562         return GLFW_FALSE;
563 
564     createKeyTables();
565     _glfwUpdateKeyNamesWin32();
566 
567     if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
568         _glfw.win32.user32.SetProcessDpiAwarenessContext_(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
569     else if (IsWindows8Point1OrGreater())
570         _glfw.win32.shcore.SetProcessDpiAwareness_(PROCESS_DPI_AWARENESS.PROCESS_PER_MONITOR_DPI_AWARE);
571     else if (IsWindowsVistaOrGreater())
572         _glfw.win32.user32.SetProcessDPIAware_();
573 
574     if (!_glfwRegisterWindowClassWin32())
575         return GLFW_FALSE;
576 
577     if (!createHelperWindow())
578         return GLFW_FALSE;
579 
580     _glfwInitTimerWin32();
581     _glfwInitJoysticksWin32();
582 
583     _glfwPollMonitorsWin32();
584     return GLFW_TRUE;
585 }
586 
587 void _glfwPlatformTerminate() {
588     if (_glfw.win32.deviceNotificationHandle)
589         UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
590 
591     if (_glfw.win32.helperWindowHandle)
592         DestroyWindow(_glfw.win32.helperWindowHandle);
593 
594     _glfwUnregisterWindowClassWin32();
595 
596     // Restore previous foreground lock timeout system setting
597     SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
598                           cast(void*) cast(UINT_PTR) _glfw.win32.foregroundLockTimeout,
599                           SPIF_SENDCHANGE);
600 
601     free(_glfw.win32.clipboardString);
602     free(_glfw.win32.rawInput);
603 
604     _glfwTerminateWGL();
605     _glfwTerminateEGL();
606 
607     _glfwTerminateJoysticksWin32();
608 
609     freeLibraries();
610 }
611 
612 const(char)* _glfwPlatformGetVersionString() {
613     version (MinGW) {
614         enum clibPart = " MinGW";
615     } else version (CRuntime_Microsoft) {
616         enum clibPart = " VisualC";
617     } else {
618         enum clibPart = "";
619     }
620 
621     version(_GLFW_USE_HYBRID_HPG) {
622         enum optimusPart = " hybrid-GPU";
623     } else version(_GLFW_USE_OPTIMUS_HPG) {
624         enum optimusPart = " hybrid-GPU";
625     } else {
626         enum optimusPart = "";
627     }
628     version (_GLFW_BUILD_DLL) {
629         enum dllPart = " DLL";
630     } else {
631         enum dllPart = "";
632     }
633 
634     return _GLFW_VERSION_NUMBER ~ " Win32 WGL EGL OSMesa" ~ clibPart ~ optimusPart ~ dllPart;
635 }