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