github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/external/glfw/src/win32_window.c (about) 1 //======================================================================== 2 // GLFW 3.4 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 <limits.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <windowsx.h> 36 #include <shellapi.h> 37 38 // Returns the window style for the specified window 39 // 40 static DWORD getWindowStyle(const _GLFWwindow* window) 41 { 42 DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 43 44 if (window->monitor) 45 style |= WS_POPUP; 46 else 47 { 48 style |= WS_SYSMENU | WS_MINIMIZEBOX; 49 50 if (window->decorated) 51 { 52 style |= WS_CAPTION; 53 54 if (window->resizable) 55 style |= WS_MAXIMIZEBOX | WS_THICKFRAME; 56 } 57 else 58 style |= WS_POPUP; 59 } 60 61 return style; 62 } 63 64 // Returns the extended window style for the specified window 65 // 66 static DWORD getWindowExStyle(const _GLFWwindow* window) 67 { 68 DWORD style = WS_EX_APPWINDOW; 69 70 if (window->monitor || window->floating) 71 style |= WS_EX_TOPMOST; 72 73 return style; 74 } 75 76 // Returns the image whose area most closely matches the desired one 77 // 78 static const GLFWimage* chooseImage(int count, const GLFWimage* images, 79 int width, int height) 80 { 81 int i, leastDiff = INT_MAX; 82 const GLFWimage* closest = NULL; 83 84 for (i = 0; i < count; i++) 85 { 86 const int currDiff = abs(images[i].width * images[i].height - 87 width * height); 88 if (currDiff < leastDiff) 89 { 90 closest = images + i; 91 leastDiff = currDiff; 92 } 93 } 94 95 return closest; 96 } 97 98 // Creates an RGBA icon or cursor 99 // 100 static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon) 101 { 102 int i; 103 HDC dc; 104 HICON handle; 105 HBITMAP color, mask; 106 BITMAPV5HEADER bi; 107 ICONINFO ii; 108 unsigned char* target = NULL; 109 unsigned char* source = image->pixels; 110 111 ZeroMemory(&bi, sizeof(bi)); 112 bi.bV5Size = sizeof(bi); 113 bi.bV5Width = image->width; 114 bi.bV5Height = -image->height; 115 bi.bV5Planes = 1; 116 bi.bV5BitCount = 32; 117 bi.bV5Compression = BI_BITFIELDS; 118 bi.bV5RedMask = 0x00ff0000; 119 bi.bV5GreenMask = 0x0000ff00; 120 bi.bV5BlueMask = 0x000000ff; 121 bi.bV5AlphaMask = 0xff000000; 122 123 dc = GetDC(NULL); 124 color = CreateDIBSection(dc, 125 (BITMAPINFO*) &bi, 126 DIB_RGB_COLORS, 127 (void**) &target, 128 NULL, 129 (DWORD) 0); 130 ReleaseDC(NULL, dc); 131 132 if (!color) 133 { 134 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 135 "Win32: Failed to create RGBA bitmap"); 136 return NULL; 137 } 138 139 mask = CreateBitmap(image->width, image->height, 1, 1, NULL); 140 if (!mask) 141 { 142 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 143 "Win32: Failed to create mask bitmap"); 144 DeleteObject(color); 145 return NULL; 146 } 147 148 for (i = 0; i < image->width * image->height; i++) 149 { 150 target[0] = source[2]; 151 target[1] = source[1]; 152 target[2] = source[0]; 153 target[3] = source[3]; 154 target += 4; 155 source += 4; 156 } 157 158 ZeroMemory(&ii, sizeof(ii)); 159 ii.fIcon = icon; 160 ii.xHotspot = xhot; 161 ii.yHotspot = yhot; 162 ii.hbmMask = mask; 163 ii.hbmColor = color; 164 165 handle = CreateIconIndirect(&ii); 166 167 DeleteObject(color); 168 DeleteObject(mask); 169 170 if (!handle) 171 { 172 if (icon) 173 { 174 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 175 "Win32: Failed to create icon"); 176 } 177 else 178 { 179 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 180 "Win32: Failed to create cursor"); 181 } 182 } 183 184 return handle; 185 } 186 187 // Translate content area size to full window size according to styles and DPI 188 // 189 static void getFullWindowSize(DWORD style, DWORD exStyle, 190 int contentWidth, int contentHeight, 191 int* fullWidth, int* fullHeight, 192 UINT dpi) 193 { 194 RECT rect = { 0, 0, contentWidth, contentHeight }; 195 196 if (_glfwIsWindows10Version1607OrGreaterWin32()) 197 AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); 198 else 199 AdjustWindowRectEx(&rect, style, FALSE, exStyle); 200 201 *fullWidth = rect.right - rect.left; 202 *fullHeight = rect.bottom - rect.top; 203 } 204 205 // Enforce the content area aspect ratio based on which edge is being dragged 206 // 207 static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) 208 { 209 int xoff, yoff; 210 UINT dpi = USER_DEFAULT_SCREEN_DPI; 211 const float ratio = (float) window->numer / (float) window->denom; 212 213 if (_glfwIsWindows10Version1607OrGreaterWin32()) 214 dpi = GetDpiForWindow(window->win32.handle); 215 216 getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 217 0, 0, &xoff, &yoff, dpi); 218 219 if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || 220 edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) 221 { 222 area->bottom = area->top + yoff + 223 (int) ((area->right - area->left - xoff) / ratio); 224 } 225 else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) 226 { 227 area->top = area->bottom - yoff - 228 (int) ((area->right - area->left - xoff) / ratio); 229 } 230 else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) 231 { 232 area->right = area->left + xoff + 233 (int) ((area->bottom - area->top - yoff) * ratio); 234 } 235 } 236 237 // Updates the cursor image according to its cursor mode 238 // 239 static void updateCursorImage(_GLFWwindow* window) 240 { 241 if (window->cursorMode == GLFW_CURSOR_NORMAL || 242 window->cursorMode == GLFW_CURSOR_CAPTURED) 243 { 244 if (window->cursor) 245 SetCursor(window->cursor->win32.handle); 246 else 247 SetCursor(LoadCursorW(NULL, IDC_ARROW)); 248 } 249 else 250 SetCursor(NULL); 251 } 252 253 // Sets the cursor clip rect to the window content area 254 // 255 static void captureCursor(_GLFWwindow* window) 256 { 257 RECT clipRect; 258 GetClientRect(window->win32.handle, &clipRect); 259 ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); 260 ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); 261 ClipCursor(&clipRect); 262 _glfw.win32.capturedCursorWindow = window; 263 } 264 265 // Disabled clip cursor 266 // 267 static void releaseCursor(void) 268 { 269 ClipCursor(NULL); 270 _glfw.win32.capturedCursorWindow = NULL; 271 } 272 273 // Enables WM_INPUT messages for the mouse for the specified window 274 // 275 static void enableRawMouseMotion(_GLFWwindow* window) 276 { 277 const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle }; 278 279 if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) 280 { 281 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 282 "Win32: Failed to register raw input device"); 283 } 284 } 285 286 // Disables WM_INPUT messages for the mouse 287 // 288 static void disableRawMouseMotion(_GLFWwindow* window) 289 { 290 const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL }; 291 292 if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) 293 { 294 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 295 "Win32: Failed to remove raw input device"); 296 } 297 } 298 299 // Apply disabled cursor mode to a focused window 300 // 301 static void disableCursor(_GLFWwindow* window) 302 { 303 _glfw.win32.disabledCursorWindow = window; 304 _glfwGetCursorPosWin32(window, 305 &_glfw.win32.restoreCursorPosX, 306 &_glfw.win32.restoreCursorPosY); 307 updateCursorImage(window); 308 _glfwCenterCursorInContentArea(window); 309 captureCursor(window); 310 311 if (window->rawMouseMotion) 312 enableRawMouseMotion(window); 313 } 314 315 // Exit disabled cursor mode for the specified window 316 // 317 static void enableCursor(_GLFWwindow* window) 318 { 319 if (window->rawMouseMotion) 320 disableRawMouseMotion(window); 321 322 _glfw.win32.disabledCursorWindow = NULL; 323 releaseCursor(); 324 _glfwSetCursorPosWin32(window, 325 _glfw.win32.restoreCursorPosX, 326 _glfw.win32.restoreCursorPosY); 327 updateCursorImage(window); 328 } 329 330 // Returns whether the cursor is in the content area of the specified window 331 // 332 static GLFWbool cursorInContentArea(_GLFWwindow* window) 333 { 334 RECT area; 335 POINT pos; 336 337 if (!GetCursorPos(&pos)) 338 return GLFW_FALSE; 339 340 if (WindowFromPoint(pos) != window->win32.handle) 341 return GLFW_FALSE; 342 343 GetClientRect(window->win32.handle, &area); 344 ClientToScreen(window->win32.handle, (POINT*) &area.left); 345 ClientToScreen(window->win32.handle, (POINT*) &area.right); 346 347 return PtInRect(&area, pos); 348 } 349 350 // Update native window styles to match attributes 351 // 352 static void updateWindowStyles(const _GLFWwindow* window) 353 { 354 RECT rect; 355 DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); 356 style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP); 357 style |= getWindowStyle(window); 358 359 GetClientRect(window->win32.handle, &rect); 360 361 if (_glfwIsWindows10Version1607OrGreaterWin32()) 362 { 363 AdjustWindowRectExForDpi(&rect, style, FALSE, 364 getWindowExStyle(window), 365 GetDpiForWindow(window->win32.handle)); 366 } 367 else 368 AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window)); 369 370 ClientToScreen(window->win32.handle, (POINT*) &rect.left); 371 ClientToScreen(window->win32.handle, (POINT*) &rect.right); 372 SetWindowLongW(window->win32.handle, GWL_STYLE, style); 373 SetWindowPos(window->win32.handle, HWND_TOP, 374 rect.left, rect.top, 375 rect.right - rect.left, rect.bottom - rect.top, 376 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER); 377 } 378 379 // Update window framebuffer transparency 380 // 381 static void updateFramebufferTransparency(const _GLFWwindow* window) 382 { 383 BOOL composition, opaque; 384 DWORD color; 385 386 if (!IsWindowsVistaOrGreater()) 387 return; 388 389 if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) 390 return; 391 392 if (IsWindows8OrGreater() || 393 (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque)) 394 { 395 HRGN region = CreateRectRgn(0, 0, -1, -1); 396 DWM_BLURBEHIND bb = {0}; 397 bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; 398 bb.hRgnBlur = region; 399 bb.fEnable = TRUE; 400 401 DwmEnableBlurBehindWindow(window->win32.handle, &bb); 402 DeleteObject(region); 403 } 404 else 405 { 406 // HACK: Disable framebuffer transparency on Windows 7 when the 407 // colorization color is opaque, because otherwise the window 408 // contents is blended additively with the previous frame instead 409 // of replacing it 410 DWM_BLURBEHIND bb = {0}; 411 bb.dwFlags = DWM_BB_ENABLE; 412 DwmEnableBlurBehindWindow(window->win32.handle, &bb); 413 } 414 } 415 416 // Retrieves and translates modifier keys 417 // 418 static int getKeyMods(void) 419 { 420 int mods = 0; 421 422 if (GetKeyState(VK_SHIFT) & 0x8000) 423 mods |= GLFW_MOD_SHIFT; 424 if (GetKeyState(VK_CONTROL) & 0x8000) 425 mods |= GLFW_MOD_CONTROL; 426 if (GetKeyState(VK_MENU) & 0x8000) 427 mods |= GLFW_MOD_ALT; 428 if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) 429 mods |= GLFW_MOD_SUPER; 430 if (GetKeyState(VK_CAPITAL) & 1) 431 mods |= GLFW_MOD_CAPS_LOCK; 432 if (GetKeyState(VK_NUMLOCK) & 1) 433 mods |= GLFW_MOD_NUM_LOCK; 434 435 return mods; 436 } 437 438 static void fitToMonitor(_GLFWwindow* window) 439 { 440 MONITORINFO mi = { sizeof(mi) }; 441 GetMonitorInfoW(window->monitor->win32.handle, &mi); 442 SetWindowPos(window->win32.handle, HWND_TOPMOST, 443 mi.rcMonitor.left, 444 mi.rcMonitor.top, 445 mi.rcMonitor.right - mi.rcMonitor.left, 446 mi.rcMonitor.bottom - mi.rcMonitor.top, 447 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); 448 } 449 450 // Make the specified window and its video mode active on its monitor 451 // 452 static void acquireMonitor(_GLFWwindow* window) 453 { 454 if (!_glfw.win32.acquiredMonitorCount) 455 { 456 SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); 457 458 // HACK: When mouse trails are enabled the cursor becomes invisible when 459 // the OpenGL ICD switches to page flipping 460 SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0); 461 SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0); 462 } 463 464 if (!window->monitor->window) 465 _glfw.win32.acquiredMonitorCount++; 466 467 _glfwSetVideoModeWin32(window->monitor, &window->videoMode); 468 _glfwInputMonitorWindow(window->monitor, window); 469 } 470 471 // Remove the window and restore the original video mode 472 // 473 static void releaseMonitor(_GLFWwindow* window) 474 { 475 if (window->monitor->window != window) 476 return; 477 478 _glfw.win32.acquiredMonitorCount--; 479 if (!_glfw.win32.acquiredMonitorCount) 480 { 481 SetThreadExecutionState(ES_CONTINUOUS); 482 483 // HACK: Restore mouse trail length saved in acquireMonitor 484 SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0); 485 } 486 487 _glfwInputMonitorWindow(window->monitor, NULL); 488 _glfwRestoreVideoModeWin32(window->monitor); 489 } 490 491 // Manually maximize the window, for when SW_MAXIMIZE cannot be used 492 // 493 static void maximizeWindowManually(_GLFWwindow* window) 494 { 495 RECT rect; 496 DWORD style; 497 MONITORINFO mi = { sizeof(mi) }; 498 499 GetMonitorInfoW(MonitorFromWindow(window->win32.handle, 500 MONITOR_DEFAULTTONEAREST), &mi); 501 502 rect = mi.rcWork; 503 504 if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) 505 { 506 rect.right = _glfw_min(rect.right, rect.left + window->maxwidth); 507 rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight); 508 } 509 510 style = GetWindowLongW(window->win32.handle, GWL_STYLE); 511 style |= WS_MAXIMIZE; 512 SetWindowLongW(window->win32.handle, GWL_STYLE, style); 513 514 if (window->decorated) 515 { 516 const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); 517 518 if (_glfwIsWindows10Version1607OrGreaterWin32()) 519 { 520 const UINT dpi = GetDpiForWindow(window->win32.handle); 521 AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi); 522 OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi)); 523 } 524 else 525 { 526 AdjustWindowRectEx(&rect, style, FALSE, exStyle); 527 OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION)); 528 } 529 530 rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom); 531 } 532 533 SetWindowPos(window->win32.handle, HWND_TOP, 534 rect.left, 535 rect.top, 536 rect.right - rect.left, 537 rect.bottom - rect.top, 538 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); 539 } 540 541 // Window procedure for user-created windows 542 // 543 static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 544 { 545 _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); 546 if (!window) 547 { 548 if (uMsg == WM_NCCREATE) 549 { 550 if (_glfwIsWindows10Version1607OrGreaterWin32()) 551 { 552 const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam; 553 const _GLFWwndconfig* wndconfig = cs->lpCreateParams; 554 555 // On per-monitor DPI aware V1 systems, only enable 556 // non-client scaling for windows that scale the client area 557 // We need WM_GETDPISCALEDSIZE from V2 to keep the client 558 // area static when the non-client area is scaled 559 if (wndconfig && wndconfig->scaleToMonitor) 560 EnableNonClientDpiScaling(hWnd); 561 } 562 } 563 564 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 565 } 566 567 switch (uMsg) 568 { 569 case WM_MOUSEACTIVATE: 570 { 571 // HACK: Postpone cursor disabling when the window was activated by 572 // clicking a caption button 573 if (HIWORD(lParam) == WM_LBUTTONDOWN) 574 { 575 if (LOWORD(lParam) != HTCLIENT) 576 window->win32.frameAction = GLFW_TRUE; 577 } 578 579 break; 580 } 581 582 case WM_CAPTURECHANGED: 583 { 584 // HACK: Disable the cursor once the caption button action has been 585 // completed or cancelled 586 if (lParam == 0 && window->win32.frameAction) 587 { 588 if (window->cursorMode == GLFW_CURSOR_DISABLED) 589 disableCursor(window); 590 else if (window->cursorMode == GLFW_CURSOR_CAPTURED) 591 captureCursor(window); 592 593 window->win32.frameAction = GLFW_FALSE; 594 } 595 596 break; 597 } 598 599 case WM_SETFOCUS: 600 { 601 _glfwInputWindowFocus(window, GLFW_TRUE); 602 603 // HACK: Do not disable cursor while the user is interacting with 604 // a caption button 605 if (window->win32.frameAction) 606 break; 607 608 if (window->cursorMode == GLFW_CURSOR_DISABLED) 609 disableCursor(window); 610 else if (window->cursorMode == GLFW_CURSOR_CAPTURED) 611 captureCursor(window); 612 613 return 0; 614 } 615 616 case WM_KILLFOCUS: 617 { 618 if (window->cursorMode == GLFW_CURSOR_DISABLED) 619 enableCursor(window); 620 else if (window->cursorMode == GLFW_CURSOR_CAPTURED) 621 releaseCursor(); 622 623 if (window->monitor && window->autoIconify) 624 _glfwIconifyWindowWin32(window); 625 626 _glfwInputWindowFocus(window, GLFW_FALSE); 627 return 0; 628 } 629 630 case WM_SYSCOMMAND: 631 { 632 switch (wParam & 0xfff0) 633 { 634 case SC_SCREENSAVE: 635 case SC_MONITORPOWER: 636 { 637 if (window->monitor) 638 { 639 // We are running in full screen mode, so disallow 640 // screen saver and screen blanking 641 return 0; 642 } 643 else 644 break; 645 } 646 647 // User trying to access application menu using ALT? 648 case SC_KEYMENU: 649 { 650 if (!window->win32.keymenu) 651 return 0; 652 653 break; 654 } 655 } 656 break; 657 } 658 659 case WM_CLOSE: 660 { 661 _glfwInputWindowCloseRequest(window); 662 return 0; 663 } 664 665 case WM_INPUTLANGCHANGE: 666 { 667 _glfwUpdateKeyNamesWin32(); 668 break; 669 } 670 671 case WM_CHAR: 672 case WM_SYSCHAR: 673 { 674 if (wParam >= 0xd800 && wParam <= 0xdbff) 675 window->win32.highSurrogate = (WCHAR) wParam; 676 else 677 { 678 uint32_t codepoint = 0; 679 680 if (wParam >= 0xdc00 && wParam <= 0xdfff) 681 { 682 if (window->win32.highSurrogate) 683 { 684 codepoint += (window->win32.highSurrogate - 0xd800) << 10; 685 codepoint += (WCHAR) wParam - 0xdc00; 686 codepoint += 0x10000; 687 } 688 } 689 else 690 codepoint = (WCHAR) wParam; 691 692 window->win32.highSurrogate = 0; 693 _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR); 694 } 695 696 if (uMsg == WM_SYSCHAR && window->win32.keymenu) 697 break; 698 699 return 0; 700 } 701 702 case WM_UNICHAR: 703 { 704 if (wParam == UNICODE_NOCHAR) 705 { 706 // WM_UNICHAR is not sent by Windows, but is sent by some 707 // third-party input method engine 708 // Returning TRUE here announces support for this message 709 return TRUE; 710 } 711 712 _glfwInputChar(window, (uint32_t) wParam, getKeyMods(), GLFW_TRUE); 713 return 0; 714 } 715 716 case WM_KEYDOWN: 717 case WM_SYSKEYDOWN: 718 case WM_KEYUP: 719 case WM_SYSKEYUP: 720 { 721 int key, scancode; 722 const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS; 723 const int mods = getKeyMods(); 724 725 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); 726 if (!scancode) 727 { 728 // NOTE: Some synthetic key messages have a scancode of zero 729 // HACK: Map the virtual key back to a usable scancode 730 scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC); 731 } 732 733 // HACK: Alt+PrtSc has a different scancode than just PrtSc 734 if (scancode == 0x54) 735 scancode = 0x137; 736 737 // HACK: Ctrl+Pause has a different scancode than just Pause 738 if (scancode == 0x146) 739 scancode = 0x45; 740 741 // HACK: CJK IME sets the extended bit for right Shift 742 if (scancode == 0x136) 743 scancode = 0x36; 744 745 key = _glfw.win32.keycodes[scancode]; 746 747 // The Ctrl keys require special handling 748 if (wParam == VK_CONTROL) 749 { 750 if (HIWORD(lParam) & KF_EXTENDED) 751 { 752 // Right side keys have the extended key bit set 753 key = GLFW_KEY_RIGHT_CONTROL; 754 } 755 else 756 { 757 // NOTE: Alt Gr sends Left Ctrl followed by Right Alt 758 // HACK: We only want one event for Alt Gr, so if we detect 759 // this sequence we discard this Left Ctrl message now 760 // and later report Right Alt normally 761 MSG next; 762 const DWORD time = GetMessageTime(); 763 764 if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) 765 { 766 if (next.message == WM_KEYDOWN || 767 next.message == WM_SYSKEYDOWN || 768 next.message == WM_KEYUP || 769 next.message == WM_SYSKEYUP) 770 { 771 if (next.wParam == VK_MENU && 772 (HIWORD(next.lParam) & KF_EXTENDED) && 773 next.time == time) 774 { 775 // Next message is Right Alt down so discard this 776 break; 777 } 778 } 779 } 780 781 // This is a regular Left Ctrl message 782 key = GLFW_KEY_LEFT_CONTROL; 783 } 784 } 785 else if (wParam == VK_PROCESSKEY) 786 { 787 // IME notifies that keys have been filtered by setting the 788 // virtual key-code to VK_PROCESSKEY 789 break; 790 } 791 792 if (action == GLFW_RELEASE && wParam == VK_SHIFT) 793 { 794 // HACK: Release both Shift keys on Shift up event, as when both 795 // are pressed the first release does not emit any event 796 // NOTE: The other half of this is in _glfwPollEventsWin32 797 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); 798 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); 799 } 800 else if (wParam == VK_SNAPSHOT) 801 { 802 // HACK: Key down is not reported for the Print Screen key 803 _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); 804 _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); 805 } 806 else 807 _glfwInputKey(window, key, scancode, action, mods); 808 809 break; 810 } 811 812 case WM_LBUTTONDOWN: 813 case WM_RBUTTONDOWN: 814 case WM_MBUTTONDOWN: 815 case WM_XBUTTONDOWN: 816 case WM_LBUTTONUP: 817 case WM_RBUTTONUP: 818 case WM_MBUTTONUP: 819 case WM_XBUTTONUP: 820 { 821 int i, button, action; 822 823 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) 824 button = GLFW_MOUSE_BUTTON_LEFT; 825 else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) 826 button = GLFW_MOUSE_BUTTON_RIGHT; 827 else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) 828 button = GLFW_MOUSE_BUTTON_MIDDLE; 829 else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) 830 button = GLFW_MOUSE_BUTTON_4; 831 else 832 button = GLFW_MOUSE_BUTTON_5; 833 834 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || 835 uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN) 836 { 837 action = GLFW_PRESS; 838 } 839 else 840 action = GLFW_RELEASE; 841 842 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) 843 { 844 if (window->mouseButtons[i] == GLFW_PRESS) 845 break; 846 } 847 848 if (i > GLFW_MOUSE_BUTTON_LAST) 849 SetCapture(hWnd); 850 851 _glfwInputMouseClick(window, button, action, getKeyMods()); 852 853 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) 854 { 855 if (window->mouseButtons[i] == GLFW_PRESS) 856 break; 857 } 858 859 if (i > GLFW_MOUSE_BUTTON_LAST) 860 ReleaseCapture(); 861 862 if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) 863 return TRUE; 864 865 return 0; 866 } 867 868 case WM_MOUSEMOVE: 869 { 870 const int x = GET_X_LPARAM(lParam); 871 const int y = GET_Y_LPARAM(lParam); 872 873 if (!window->win32.cursorTracked) 874 { 875 TRACKMOUSEEVENT tme; 876 ZeroMemory(&tme, sizeof(tme)); 877 tme.cbSize = sizeof(tme); 878 tme.dwFlags = TME_LEAVE; 879 tme.hwndTrack = window->win32.handle; 880 TrackMouseEvent(&tme); 881 882 window->win32.cursorTracked = GLFW_TRUE; 883 _glfwInputCursorEnter(window, GLFW_TRUE); 884 } 885 886 if (window->cursorMode == GLFW_CURSOR_DISABLED) 887 { 888 const int dx = x - window->win32.lastCursorPosX; 889 const int dy = y - window->win32.lastCursorPosY; 890 891 if (_glfw.win32.disabledCursorWindow != window) 892 break; 893 if (window->rawMouseMotion) 894 break; 895 896 _glfwInputCursorPos(window, 897 window->virtualCursorPosX + dx, 898 window->virtualCursorPosY + dy); 899 } 900 else 901 _glfwInputCursorPos(window, x, y); 902 903 window->win32.lastCursorPosX = x; 904 window->win32.lastCursorPosY = y; 905 906 return 0; 907 } 908 909 case WM_INPUT: 910 { 911 UINT size = 0; 912 HRAWINPUT ri = (HRAWINPUT) lParam; 913 RAWINPUT* data = NULL; 914 int dx, dy; 915 916 if (_glfw.win32.disabledCursorWindow != window) 917 break; 918 if (!window->rawMouseMotion) 919 break; 920 921 GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); 922 if (size > (UINT) _glfw.win32.rawInputSize) 923 { 924 _glfw_free(_glfw.win32.rawInput); 925 _glfw.win32.rawInput = _glfw_calloc(size, 1); 926 _glfw.win32.rawInputSize = size; 927 } 928 929 size = _glfw.win32.rawInputSize; 930 if (GetRawInputData(ri, RID_INPUT, 931 _glfw.win32.rawInput, &size, 932 sizeof(RAWINPUTHEADER)) == (UINT) -1) 933 { 934 _glfwInputError(GLFW_PLATFORM_ERROR, 935 "Win32: Failed to retrieve raw input data"); 936 break; 937 } 938 939 data = _glfw.win32.rawInput; 940 if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) 941 { 942 dx = data->data.mouse.lLastX - window->win32.lastCursorPosX; 943 dy = data->data.mouse.lLastY - window->win32.lastCursorPosY; 944 } 945 else 946 { 947 dx = data->data.mouse.lLastX; 948 dy = data->data.mouse.lLastY; 949 } 950 951 _glfwInputCursorPos(window, 952 window->virtualCursorPosX + dx, 953 window->virtualCursorPosY + dy); 954 955 window->win32.lastCursorPosX += dx; 956 window->win32.lastCursorPosY += dy; 957 break; 958 } 959 960 case WM_MOUSELEAVE: 961 { 962 window->win32.cursorTracked = GLFW_FALSE; 963 _glfwInputCursorEnter(window, GLFW_FALSE); 964 return 0; 965 } 966 967 case WM_MOUSEWHEEL: 968 { 969 _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); 970 return 0; 971 } 972 973 case WM_MOUSEHWHEEL: 974 { 975 // This message is only sent on Windows Vista and later 976 // NOTE: The X-axis is inverted for consistency with macOS and X11 977 _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); 978 return 0; 979 } 980 981 case WM_ENTERSIZEMOVE: 982 case WM_ENTERMENULOOP: 983 { 984 if (window->win32.frameAction) 985 break; 986 987 // HACK: Enable the cursor while the user is moving or 988 // resizing the window or using the window menu 989 if (window->cursorMode == GLFW_CURSOR_DISABLED) 990 enableCursor(window); 991 else if (window->cursorMode == GLFW_CURSOR_CAPTURED) 992 releaseCursor(); 993 994 break; 995 } 996 997 case WM_EXITSIZEMOVE: 998 case WM_EXITMENULOOP: 999 { 1000 if (window->win32.frameAction) 1001 break; 1002 1003 // HACK: Disable the cursor once the user is done moving or 1004 // resizing the window or using the menu 1005 if (window->cursorMode == GLFW_CURSOR_DISABLED) 1006 disableCursor(window); 1007 else if (window->cursorMode == GLFW_CURSOR_CAPTURED) 1008 captureCursor(window); 1009 1010 break; 1011 } 1012 1013 case WM_SIZE: 1014 { 1015 const int width = LOWORD(lParam); 1016 const int height = HIWORD(lParam); 1017 const GLFWbool iconified = wParam == SIZE_MINIMIZED; 1018 const GLFWbool maximized = wParam == SIZE_MAXIMIZED || 1019 (window->win32.maximized && 1020 wParam != SIZE_RESTORED); 1021 1022 if (_glfw.win32.capturedCursorWindow == window) 1023 captureCursor(window); 1024 1025 if (window->win32.iconified != iconified) 1026 _glfwInputWindowIconify(window, iconified); 1027 1028 if (window->win32.maximized != maximized) 1029 _glfwInputWindowMaximize(window, maximized); 1030 1031 if (width != window->win32.width || height != window->win32.height) 1032 { 1033 window->win32.width = width; 1034 window->win32.height = height; 1035 1036 _glfwInputFramebufferSize(window, width, height); 1037 _glfwInputWindowSize(window, width, height); 1038 } 1039 1040 if (window->monitor && window->win32.iconified != iconified) 1041 { 1042 if (iconified) 1043 releaseMonitor(window); 1044 else 1045 { 1046 acquireMonitor(window); 1047 fitToMonitor(window); 1048 } 1049 } 1050 1051 window->win32.iconified = iconified; 1052 window->win32.maximized = maximized; 1053 return 0; 1054 } 1055 1056 case WM_MOVE: 1057 { 1058 if (_glfw.win32.capturedCursorWindow == window) 1059 captureCursor(window); 1060 1061 // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as 1062 // those macros do not handle negative window positions correctly 1063 _glfwInputWindowPos(window, 1064 GET_X_LPARAM(lParam), 1065 GET_Y_LPARAM(lParam)); 1066 return 0; 1067 } 1068 1069 case WM_SIZING: 1070 { 1071 if (window->numer == GLFW_DONT_CARE || 1072 window->denom == GLFW_DONT_CARE) 1073 { 1074 break; 1075 } 1076 1077 applyAspectRatio(window, (int) wParam, (RECT*) lParam); 1078 return TRUE; 1079 } 1080 1081 case WM_GETMINMAXINFO: 1082 { 1083 int xoff, yoff; 1084 UINT dpi = USER_DEFAULT_SCREEN_DPI; 1085 MINMAXINFO* mmi = (MINMAXINFO*) lParam; 1086 1087 if (window->monitor) 1088 break; 1089 1090 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1091 dpi = GetDpiForWindow(window->win32.handle); 1092 1093 getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 1094 0, 0, &xoff, &yoff, dpi); 1095 1096 if (window->minwidth != GLFW_DONT_CARE && 1097 window->minheight != GLFW_DONT_CARE) 1098 { 1099 mmi->ptMinTrackSize.x = window->minwidth + xoff; 1100 mmi->ptMinTrackSize.y = window->minheight + yoff; 1101 } 1102 1103 if (window->maxwidth != GLFW_DONT_CARE && 1104 window->maxheight != GLFW_DONT_CARE) 1105 { 1106 mmi->ptMaxTrackSize.x = window->maxwidth + xoff; 1107 mmi->ptMaxTrackSize.y = window->maxheight + yoff; 1108 } 1109 1110 if (!window->decorated) 1111 { 1112 MONITORINFO mi; 1113 const HMONITOR mh = MonitorFromWindow(window->win32.handle, 1114 MONITOR_DEFAULTTONEAREST); 1115 1116 ZeroMemory(&mi, sizeof(mi)); 1117 mi.cbSize = sizeof(mi); 1118 GetMonitorInfoW(mh, &mi); 1119 1120 mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left; 1121 mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top; 1122 mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left; 1123 mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top; 1124 } 1125 1126 return 0; 1127 } 1128 1129 case WM_PAINT: 1130 { 1131 _glfwInputWindowDamage(window); 1132 break; 1133 } 1134 1135 case WM_ERASEBKGND: 1136 { 1137 return TRUE; 1138 } 1139 1140 case WM_NCACTIVATE: 1141 case WM_NCPAINT: 1142 { 1143 // Prevent title bar from being drawn after restoring a minimized 1144 // undecorated window 1145 if (!window->decorated) 1146 return TRUE; 1147 1148 break; 1149 } 1150 1151 case WM_DWMCOMPOSITIONCHANGED: 1152 case WM_DWMCOLORIZATIONCOLORCHANGED: 1153 { 1154 if (window->win32.transparent) 1155 updateFramebufferTransparency(window); 1156 return 0; 1157 } 1158 1159 case WM_GETDPISCALEDSIZE: 1160 { 1161 if (window->win32.scaleToMonitor) 1162 break; 1163 1164 // Adjust the window size to keep the content area size constant 1165 if (_glfwIsWindows10Version1703OrGreaterWin32()) 1166 { 1167 RECT source = {0}, target = {0}; 1168 SIZE* size = (SIZE*) lParam; 1169 1170 AdjustWindowRectExForDpi(&source, getWindowStyle(window), 1171 FALSE, getWindowExStyle(window), 1172 GetDpiForWindow(window->win32.handle)); 1173 AdjustWindowRectExForDpi(&target, getWindowStyle(window), 1174 FALSE, getWindowExStyle(window), 1175 LOWORD(wParam)); 1176 1177 size->cx += (target.right - target.left) - 1178 (source.right - source.left); 1179 size->cy += (target.bottom - target.top) - 1180 (source.bottom - source.top); 1181 return TRUE; 1182 } 1183 1184 break; 1185 } 1186 1187 case WM_DPICHANGED: 1188 { 1189 const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; 1190 const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI; 1191 1192 // Resize windowed mode windows that either permit rescaling or that 1193 // need it to compensate for non-client area scaling 1194 if (!window->monitor && 1195 (window->win32.scaleToMonitor || 1196 _glfwIsWindows10Version1703OrGreaterWin32())) 1197 { 1198 RECT* suggested = (RECT*) lParam; 1199 SetWindowPos(window->win32.handle, HWND_TOP, 1200 suggested->left, 1201 suggested->top, 1202 suggested->right - suggested->left, 1203 suggested->bottom - suggested->top, 1204 SWP_NOACTIVATE | SWP_NOZORDER); 1205 } 1206 1207 _glfwInputWindowContentScale(window, xscale, yscale); 1208 break; 1209 } 1210 1211 case WM_SETCURSOR: 1212 { 1213 if (LOWORD(lParam) == HTCLIENT) 1214 { 1215 updateCursorImage(window); 1216 return TRUE; 1217 } 1218 1219 break; 1220 } 1221 1222 case WM_DROPFILES: 1223 { 1224 HDROP drop = (HDROP) wParam; 1225 POINT pt; 1226 int i; 1227 1228 const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); 1229 char** paths = _glfw_calloc(count, sizeof(char*)); 1230 1231 // Move the mouse to the position of the drop 1232 DragQueryPoint(drop, &pt); 1233 _glfwInputCursorPos(window, pt.x, pt.y); 1234 1235 for (i = 0; i < count; i++) 1236 { 1237 const UINT length = DragQueryFileW(drop, i, NULL, 0); 1238 WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR)); 1239 1240 DragQueryFileW(drop, i, buffer, length + 1); 1241 paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); 1242 1243 _glfw_free(buffer); 1244 } 1245 1246 _glfwInputDrop(window, count, (const char**) paths); 1247 1248 for (i = 0; i < count; i++) 1249 _glfw_free(paths[i]); 1250 _glfw_free(paths); 1251 1252 DragFinish(drop); 1253 return 0; 1254 } 1255 } 1256 1257 return DefWindowProcW(hWnd, uMsg, wParam, lParam); 1258 } 1259 1260 // Creates the GLFW window 1261 // 1262 static int createNativeWindow(_GLFWwindow* window, 1263 const _GLFWwndconfig* wndconfig, 1264 const _GLFWfbconfig* fbconfig) 1265 { 1266 int xpos, ypos, fullWidth, fullHeight; 1267 WCHAR* wideTitle; 1268 DWORD style = getWindowStyle(window); 1269 DWORD exStyle = getWindowExStyle(window); 1270 1271 if (!_glfw.win32.mainWindowClass) 1272 { 1273 WNDCLASSEXW wc = { sizeof(wc) }; 1274 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 1275 wc.lpfnWndProc = windowProc; 1276 wc.hInstance = _glfw.win32.instance; 1277 wc.hCursor = LoadCursorW(NULL, IDC_ARROW); 1278 #if defined(_GLFW_WNDCLASSNAME) 1279 wc.lpszClassName = _GLFW_WNDCLASSNAME; 1280 #else 1281 wc.lpszClassName = L"GLFW30"; 1282 #endif 1283 // Load user-provided icon if available 1284 wc.hIcon = LoadImageW(GetModuleHandleW(NULL), 1285 L"GLFW_ICON", IMAGE_ICON, 1286 0, 0, LR_DEFAULTSIZE | LR_SHARED); 1287 if (!wc.hIcon) 1288 { 1289 // No user-provided icon found, load default icon 1290 wc.hIcon = LoadImageW(NULL, 1291 IDI_APPLICATION, IMAGE_ICON, 1292 0, 0, LR_DEFAULTSIZE | LR_SHARED); 1293 } 1294 1295 _glfw.win32.mainWindowClass = RegisterClassExW(&wc); 1296 if (!_glfw.win32.mainWindowClass) 1297 { 1298 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 1299 "Win32: Failed to register window class"); 1300 return GLFW_FALSE; 1301 } 1302 } 1303 1304 if (window->monitor) 1305 { 1306 MONITORINFO mi = { sizeof(mi) }; 1307 GetMonitorInfoW(window->monitor->win32.handle, &mi); 1308 1309 // NOTE: This window placement is temporary and approximate, as the 1310 // correct position and size cannot be known until the monitor 1311 // video mode has been picked in _glfwSetVideoModeWin32 1312 xpos = mi.rcMonitor.left; 1313 ypos = mi.rcMonitor.top; 1314 fullWidth = mi.rcMonitor.right - mi.rcMonitor.left; 1315 fullHeight = mi.rcMonitor.bottom - mi.rcMonitor.top; 1316 } 1317 else 1318 { 1319 RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; 1320 1321 window->win32.maximized = wndconfig->maximized; 1322 if (wndconfig->maximized) 1323 style |= WS_MAXIMIZE; 1324 1325 AdjustWindowRectEx(&rect, style, FALSE, exStyle); 1326 1327 if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION) 1328 { 1329 xpos = CW_USEDEFAULT; 1330 ypos = CW_USEDEFAULT; 1331 } 1332 else 1333 { 1334 xpos = wndconfig->xpos + rect.left; 1335 ypos = wndconfig->ypos + rect.top; 1336 } 1337 1338 fullWidth = rect.right - rect.left; 1339 fullHeight = rect.bottom - rect.top; 1340 } 1341 1342 wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); 1343 if (!wideTitle) 1344 return GLFW_FALSE; 1345 1346 window->win32.handle = CreateWindowExW(exStyle, 1347 MAKEINTATOM(_glfw.win32.mainWindowClass), 1348 wideTitle, 1349 style, 1350 xpos, ypos, 1351 fullWidth, fullHeight, 1352 NULL, // No parent window 1353 NULL, // No window menu 1354 _glfw.win32.instance, 1355 (LPVOID) wndconfig); 1356 1357 _glfw_free(wideTitle); 1358 1359 if (!window->win32.handle) 1360 { 1361 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 1362 "Win32: Failed to create window"); 1363 return GLFW_FALSE; 1364 } 1365 1366 SetPropW(window->win32.handle, L"GLFW", window); 1367 1368 if (IsWindows7OrGreater()) 1369 { 1370 ChangeWindowMessageFilterEx(window->win32.handle, 1371 WM_DROPFILES, MSGFLT_ALLOW, NULL); 1372 ChangeWindowMessageFilterEx(window->win32.handle, 1373 WM_COPYDATA, MSGFLT_ALLOW, NULL); 1374 ChangeWindowMessageFilterEx(window->win32.handle, 1375 WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); 1376 } 1377 1378 window->win32.scaleToMonitor = wndconfig->scaleToMonitor; 1379 window->win32.keymenu = wndconfig->win32.keymenu; 1380 1381 if (!window->monitor) 1382 { 1383 RECT rect = { 0, 0, wndconfig->width, wndconfig->height }; 1384 WINDOWPLACEMENT wp = { sizeof(wp) }; 1385 const HMONITOR mh = MonitorFromWindow(window->win32.handle, 1386 MONITOR_DEFAULTTONEAREST); 1387 1388 // Adjust window rect to account for DPI scaling of the window frame and 1389 // (if enabled) DPI scaling of the content area 1390 // This cannot be done until we know what monitor the window was placed on 1391 // Only update the restored window rect as the window may be maximized 1392 1393 if (wndconfig->scaleToMonitor) 1394 { 1395 float xscale, yscale; 1396 _glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale); 1397 1398 if (xscale > 0.f && yscale > 0.f) 1399 { 1400 rect.right = (int) (rect.right * xscale); 1401 rect.bottom = (int) (rect.bottom * yscale); 1402 } 1403 } 1404 1405 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1406 { 1407 AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, 1408 GetDpiForWindow(window->win32.handle)); 1409 } 1410 else 1411 AdjustWindowRectEx(&rect, style, FALSE, exStyle); 1412 1413 GetWindowPlacement(window->win32.handle, &wp); 1414 OffsetRect(&rect, 1415 wp.rcNormalPosition.left - rect.left, 1416 wp.rcNormalPosition.top - rect.top); 1417 1418 wp.rcNormalPosition = rect; 1419 wp.showCmd = SW_HIDE; 1420 SetWindowPlacement(window->win32.handle, &wp); 1421 1422 // Adjust rect of maximized undecorated window, because by default Windows will 1423 // make such a window cover the whole monitor instead of its workarea 1424 1425 if (wndconfig->maximized && !wndconfig->decorated) 1426 { 1427 MONITORINFO mi = { sizeof(mi) }; 1428 GetMonitorInfoW(mh, &mi); 1429 1430 SetWindowPos(window->win32.handle, HWND_TOP, 1431 mi.rcWork.left, 1432 mi.rcWork.top, 1433 mi.rcWork.right - mi.rcWork.left, 1434 mi.rcWork.bottom - mi.rcWork.top, 1435 SWP_NOACTIVATE | SWP_NOZORDER); 1436 } 1437 } 1438 1439 DragAcceptFiles(window->win32.handle, TRUE); 1440 1441 if (fbconfig->transparent) 1442 { 1443 updateFramebufferTransparency(window); 1444 window->win32.transparent = GLFW_TRUE; 1445 } 1446 1447 _glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height); 1448 1449 return GLFW_TRUE; 1450 } 1451 1452 GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, 1453 const _GLFWwndconfig* wndconfig, 1454 const _GLFWctxconfig* ctxconfig, 1455 const _GLFWfbconfig* fbconfig) 1456 { 1457 if (!createNativeWindow(window, wndconfig, fbconfig)) 1458 return GLFW_FALSE; 1459 1460 if (ctxconfig->client != GLFW_NO_API) 1461 { 1462 if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) 1463 { 1464 if (!_glfwInitWGL()) 1465 return GLFW_FALSE; 1466 if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) 1467 return GLFW_FALSE; 1468 } 1469 else if (ctxconfig->source == GLFW_EGL_CONTEXT_API) 1470 { 1471 if (!_glfwInitEGL()) 1472 return GLFW_FALSE; 1473 if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) 1474 return GLFW_FALSE; 1475 } 1476 else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API) 1477 { 1478 if (!_glfwInitOSMesa()) 1479 return GLFW_FALSE; 1480 if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig)) 1481 return GLFW_FALSE; 1482 } 1483 1484 if (!_glfwRefreshContextAttribs(window, ctxconfig)) 1485 return GLFW_FALSE; 1486 } 1487 1488 if (wndconfig->mousePassthrough) 1489 _glfwSetWindowMousePassthroughWin32(window, GLFW_TRUE); 1490 1491 if (window->monitor) 1492 { 1493 _glfwShowWindowWin32(window); 1494 _glfwFocusWindowWin32(window); 1495 acquireMonitor(window); 1496 fitToMonitor(window); 1497 1498 if (wndconfig->centerCursor) 1499 _glfwCenterCursorInContentArea(window); 1500 } 1501 else 1502 { 1503 if (wndconfig->visible) 1504 { 1505 _glfwShowWindowWin32(window); 1506 if (wndconfig->focused) 1507 _glfwFocusWindowWin32(window); 1508 } 1509 } 1510 1511 return GLFW_TRUE; 1512 } 1513 1514 void _glfwDestroyWindowWin32(_GLFWwindow* window) 1515 { 1516 if (window->monitor) 1517 releaseMonitor(window); 1518 1519 if (window->context.destroy) 1520 window->context.destroy(window); 1521 1522 if (_glfw.win32.disabledCursorWindow == window) 1523 enableCursor(window); 1524 1525 if (_glfw.win32.capturedCursorWindow == window) 1526 releaseCursor(); 1527 1528 if (window->win32.handle) 1529 { 1530 RemovePropW(window->win32.handle, L"GLFW"); 1531 DestroyWindow(window->win32.handle); 1532 window->win32.handle = NULL; 1533 } 1534 1535 if (window->win32.bigIcon) 1536 DestroyIcon(window->win32.bigIcon); 1537 1538 if (window->win32.smallIcon) 1539 DestroyIcon(window->win32.smallIcon); 1540 } 1541 1542 void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title) 1543 { 1544 WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title); 1545 if (!wideTitle) 1546 return; 1547 1548 SetWindowTextW(window->win32.handle, wideTitle); 1549 _glfw_free(wideTitle); 1550 } 1551 1552 void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images) 1553 { 1554 HICON bigIcon = NULL, smallIcon = NULL; 1555 1556 if (count) 1557 { 1558 const GLFWimage* bigImage = chooseImage(count, images, 1559 GetSystemMetrics(SM_CXICON), 1560 GetSystemMetrics(SM_CYICON)); 1561 const GLFWimage* smallImage = chooseImage(count, images, 1562 GetSystemMetrics(SM_CXSMICON), 1563 GetSystemMetrics(SM_CYSMICON)); 1564 1565 bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE); 1566 smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE); 1567 } 1568 else 1569 { 1570 bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON); 1571 smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM); 1572 } 1573 1574 SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon); 1575 SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon); 1576 1577 if (window->win32.bigIcon) 1578 DestroyIcon(window->win32.bigIcon); 1579 1580 if (window->win32.smallIcon) 1581 DestroyIcon(window->win32.smallIcon); 1582 1583 if (count) 1584 { 1585 window->win32.bigIcon = bigIcon; 1586 window->win32.smallIcon = smallIcon; 1587 } 1588 } 1589 1590 void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos) 1591 { 1592 POINT pos = { 0, 0 }; 1593 ClientToScreen(window->win32.handle, &pos); 1594 1595 if (xpos) 1596 *xpos = pos.x; 1597 if (ypos) 1598 *ypos = pos.y; 1599 } 1600 1601 void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos) 1602 { 1603 RECT rect = { xpos, ypos, xpos, ypos }; 1604 1605 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1606 { 1607 AdjustWindowRectExForDpi(&rect, getWindowStyle(window), 1608 FALSE, getWindowExStyle(window), 1609 GetDpiForWindow(window->win32.handle)); 1610 } 1611 else 1612 { 1613 AdjustWindowRectEx(&rect, getWindowStyle(window), 1614 FALSE, getWindowExStyle(window)); 1615 } 1616 1617 SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, 1618 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); 1619 } 1620 1621 void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height) 1622 { 1623 RECT area; 1624 GetClientRect(window->win32.handle, &area); 1625 1626 if (width) 1627 *width = area.right; 1628 if (height) 1629 *height = area.bottom; 1630 } 1631 1632 void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height) 1633 { 1634 if (window->monitor) 1635 { 1636 if (window->monitor->window == window) 1637 { 1638 acquireMonitor(window); 1639 fitToMonitor(window); 1640 } 1641 } 1642 else 1643 { 1644 RECT rect = { 0, 0, width, height }; 1645 1646 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1647 { 1648 AdjustWindowRectExForDpi(&rect, getWindowStyle(window), 1649 FALSE, getWindowExStyle(window), 1650 GetDpiForWindow(window->win32.handle)); 1651 } 1652 else 1653 { 1654 AdjustWindowRectEx(&rect, getWindowStyle(window), 1655 FALSE, getWindowExStyle(window)); 1656 } 1657 1658 SetWindowPos(window->win32.handle, HWND_TOP, 1659 0, 0, rect.right - rect.left, rect.bottom - rect.top, 1660 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); 1661 } 1662 } 1663 1664 void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, 1665 int minwidth, int minheight, 1666 int maxwidth, int maxheight) 1667 { 1668 RECT area; 1669 1670 if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && 1671 (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) 1672 { 1673 return; 1674 } 1675 1676 GetWindowRect(window->win32.handle, &area); 1677 MoveWindow(window->win32.handle, 1678 area.left, area.top, 1679 area.right - area.left, 1680 area.bottom - area.top, TRUE); 1681 } 1682 1683 void _glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom) 1684 { 1685 RECT area; 1686 1687 if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) 1688 return; 1689 1690 GetWindowRect(window->win32.handle, &area); 1691 applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area); 1692 MoveWindow(window->win32.handle, 1693 area.left, area.top, 1694 area.right - area.left, 1695 area.bottom - area.top, TRUE); 1696 } 1697 1698 void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height) 1699 { 1700 _glfwGetWindowSizeWin32(window, width, height); 1701 } 1702 1703 void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window, 1704 int* left, int* top, 1705 int* right, int* bottom) 1706 { 1707 RECT rect; 1708 int width, height; 1709 1710 _glfwGetWindowSizeWin32(window, &width, &height); 1711 SetRect(&rect, 0, 0, width, height); 1712 1713 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1714 { 1715 AdjustWindowRectExForDpi(&rect, getWindowStyle(window), 1716 FALSE, getWindowExStyle(window), 1717 GetDpiForWindow(window->win32.handle)); 1718 } 1719 else 1720 { 1721 AdjustWindowRectEx(&rect, getWindowStyle(window), 1722 FALSE, getWindowExStyle(window)); 1723 } 1724 1725 if (left) 1726 *left = -rect.left; 1727 if (top) 1728 *top = -rect.top; 1729 if (right) 1730 *right = rect.right - width; 1731 if (bottom) 1732 *bottom = rect.bottom - height; 1733 } 1734 1735 void _glfwGetWindowContentScaleWin32(_GLFWwindow* window, float* xscale, float* yscale) 1736 { 1737 const HANDLE handle = MonitorFromWindow(window->win32.handle, 1738 MONITOR_DEFAULTTONEAREST); 1739 _glfwGetHMONITORContentScaleWin32(handle, xscale, yscale); 1740 } 1741 1742 void _glfwIconifyWindowWin32(_GLFWwindow* window) 1743 { 1744 ShowWindow(window->win32.handle, SW_MINIMIZE); 1745 } 1746 1747 void _glfwRestoreWindowWin32(_GLFWwindow* window) 1748 { 1749 ShowWindow(window->win32.handle, SW_RESTORE); 1750 } 1751 1752 void _glfwMaximizeWindowWin32(_GLFWwindow* window) 1753 { 1754 if (IsWindowVisible(window->win32.handle)) 1755 ShowWindow(window->win32.handle, SW_MAXIMIZE); 1756 else 1757 maximizeWindowManually(window); 1758 } 1759 1760 void _glfwShowWindowWin32(_GLFWwindow* window) 1761 { 1762 ShowWindow(window->win32.handle, SW_SHOWNA); 1763 } 1764 1765 void _glfwHideWindowWin32(_GLFWwindow* window) 1766 { 1767 ShowWindow(window->win32.handle, SW_HIDE); 1768 } 1769 1770 void _glfwRequestWindowAttentionWin32(_GLFWwindow* window) 1771 { 1772 FlashWindow(window->win32.handle, TRUE); 1773 } 1774 1775 void _glfwFocusWindowWin32(_GLFWwindow* window) 1776 { 1777 BringWindowToTop(window->win32.handle); 1778 SetForegroundWindow(window->win32.handle); 1779 SetFocus(window->win32.handle); 1780 } 1781 1782 void _glfwSetWindowMonitorWin32(_GLFWwindow* window, 1783 _GLFWmonitor* monitor, 1784 int xpos, int ypos, 1785 int width, int height, 1786 int refreshRate) 1787 { 1788 if (window->monitor == monitor) 1789 { 1790 if (monitor) 1791 { 1792 if (monitor->window == window) 1793 { 1794 acquireMonitor(window); 1795 fitToMonitor(window); 1796 } 1797 } 1798 else 1799 { 1800 RECT rect = { xpos, ypos, xpos + width, ypos + height }; 1801 1802 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1803 { 1804 AdjustWindowRectExForDpi(&rect, getWindowStyle(window), 1805 FALSE, getWindowExStyle(window), 1806 GetDpiForWindow(window->win32.handle)); 1807 } 1808 else 1809 { 1810 AdjustWindowRectEx(&rect, getWindowStyle(window), 1811 FALSE, getWindowExStyle(window)); 1812 } 1813 1814 SetWindowPos(window->win32.handle, HWND_TOP, 1815 rect.left, rect.top, 1816 rect.right - rect.left, rect.bottom - rect.top, 1817 SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); 1818 } 1819 1820 return; 1821 } 1822 1823 if (window->monitor) 1824 releaseMonitor(window); 1825 1826 _glfwInputWindowMonitor(window, monitor); 1827 1828 if (window->monitor) 1829 { 1830 MONITORINFO mi = { sizeof(mi) }; 1831 UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; 1832 1833 if (window->decorated) 1834 { 1835 DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); 1836 style &= ~WS_OVERLAPPEDWINDOW; 1837 style |= getWindowStyle(window); 1838 SetWindowLongW(window->win32.handle, GWL_STYLE, style); 1839 flags |= SWP_FRAMECHANGED; 1840 } 1841 1842 acquireMonitor(window); 1843 1844 GetMonitorInfoW(window->monitor->win32.handle, &mi); 1845 SetWindowPos(window->win32.handle, HWND_TOPMOST, 1846 mi.rcMonitor.left, 1847 mi.rcMonitor.top, 1848 mi.rcMonitor.right - mi.rcMonitor.left, 1849 mi.rcMonitor.bottom - mi.rcMonitor.top, 1850 flags); 1851 } 1852 else 1853 { 1854 HWND after; 1855 RECT rect = { xpos, ypos, xpos + width, ypos + height }; 1856 DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); 1857 UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; 1858 1859 if (window->decorated) 1860 { 1861 style &= ~WS_POPUP; 1862 style |= getWindowStyle(window); 1863 SetWindowLongW(window->win32.handle, GWL_STYLE, style); 1864 1865 flags |= SWP_FRAMECHANGED; 1866 } 1867 1868 if (window->floating) 1869 after = HWND_TOPMOST; 1870 else 1871 after = HWND_NOTOPMOST; 1872 1873 if (_glfwIsWindows10Version1607OrGreaterWin32()) 1874 { 1875 AdjustWindowRectExForDpi(&rect, getWindowStyle(window), 1876 FALSE, getWindowExStyle(window), 1877 GetDpiForWindow(window->win32.handle)); 1878 } 1879 else 1880 { 1881 AdjustWindowRectEx(&rect, getWindowStyle(window), 1882 FALSE, getWindowExStyle(window)); 1883 } 1884 1885 SetWindowPos(window->win32.handle, after, 1886 rect.left, rect.top, 1887 rect.right - rect.left, rect.bottom - rect.top, 1888 flags); 1889 } 1890 } 1891 1892 GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window) 1893 { 1894 return window->win32.handle == GetActiveWindow(); 1895 } 1896 1897 GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window) 1898 { 1899 return IsIconic(window->win32.handle); 1900 } 1901 1902 GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window) 1903 { 1904 return IsWindowVisible(window->win32.handle); 1905 } 1906 1907 GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window) 1908 { 1909 return IsZoomed(window->win32.handle); 1910 } 1911 1912 GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window) 1913 { 1914 return cursorInContentArea(window); 1915 } 1916 1917 GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window) 1918 { 1919 BOOL composition, opaque; 1920 DWORD color; 1921 1922 if (!window->win32.transparent) 1923 return GLFW_FALSE; 1924 1925 if (!IsWindowsVistaOrGreater()) 1926 return GLFW_FALSE; 1927 1928 if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition) 1929 return GLFW_FALSE; 1930 1931 if (!IsWindows8OrGreater()) 1932 { 1933 // HACK: Disable framebuffer transparency on Windows 7 when the 1934 // colorization color is opaque, because otherwise the window 1935 // contents is blended additively with the previous frame instead 1936 // of replacing it 1937 if (FAILED(DwmGetColorizationColor(&color, &opaque)) || opaque) 1938 return GLFW_FALSE; 1939 } 1940 1941 return GLFW_TRUE; 1942 } 1943 1944 void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled) 1945 { 1946 updateWindowStyles(window); 1947 } 1948 1949 void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled) 1950 { 1951 updateWindowStyles(window); 1952 } 1953 1954 void _glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled) 1955 { 1956 const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST; 1957 SetWindowPos(window->win32.handle, after, 0, 0, 0, 0, 1958 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); 1959 } 1960 1961 void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled) 1962 { 1963 COLORREF key = 0; 1964 BYTE alpha = 0; 1965 DWORD flags = 0; 1966 DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); 1967 1968 if (exStyle & WS_EX_LAYERED) 1969 GetLayeredWindowAttributes(window->win32.handle, &key, &alpha, &flags); 1970 1971 if (enabled) 1972 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); 1973 else 1974 { 1975 exStyle &= ~WS_EX_TRANSPARENT; 1976 // NOTE: Window opacity also needs the layered window style so do not 1977 // remove it if the window is alpha blended 1978 if (exStyle & WS_EX_LAYERED) 1979 { 1980 if (!(flags & LWA_ALPHA)) 1981 exStyle &= ~WS_EX_LAYERED; 1982 } 1983 } 1984 1985 SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); 1986 1987 if (enabled) 1988 SetLayeredWindowAttributes(window->win32.handle, key, alpha, flags); 1989 } 1990 1991 float _glfwGetWindowOpacityWin32(_GLFWwindow* window) 1992 { 1993 BYTE alpha; 1994 DWORD flags; 1995 1996 if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) && 1997 GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags)) 1998 { 1999 if (flags & LWA_ALPHA) 2000 return alpha / 255.f; 2001 } 2002 2003 return 1.f; 2004 } 2005 2006 void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity) 2007 { 2008 LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); 2009 if (opacity < 1.f || (exStyle & WS_EX_TRANSPARENT)) 2010 { 2011 const BYTE alpha = (BYTE) (255 * opacity); 2012 exStyle |= WS_EX_LAYERED; 2013 SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); 2014 SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA); 2015 } 2016 else if (exStyle & WS_EX_TRANSPARENT) 2017 { 2018 SetLayeredWindowAttributes(window->win32.handle, 0, 0, 0); 2019 } 2020 else 2021 { 2022 exStyle &= ~WS_EX_LAYERED; 2023 SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle); 2024 } 2025 } 2026 2027 void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled) 2028 { 2029 if (_glfw.win32.disabledCursorWindow != window) 2030 return; 2031 2032 if (enabled) 2033 enableRawMouseMotion(window); 2034 else 2035 disableRawMouseMotion(window); 2036 } 2037 2038 GLFWbool _glfwRawMouseMotionSupportedWin32(void) 2039 { 2040 return GLFW_TRUE; 2041 } 2042 2043 void _glfwPollEventsWin32(void) 2044 { 2045 MSG msg; 2046 HWND handle; 2047 _GLFWwindow* window; 2048 2049 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) 2050 { 2051 if (msg.message == WM_QUIT) 2052 { 2053 // NOTE: While GLFW does not itself post WM_QUIT, other processes 2054 // may post it to this one, for example Task Manager 2055 // HACK: Treat WM_QUIT as a close on all windows 2056 2057 window = _glfw.windowListHead; 2058 while (window) 2059 { 2060 _glfwInputWindowCloseRequest(window); 2061 window = window->next; 2062 } 2063 } 2064 else 2065 { 2066 TranslateMessage(&msg); 2067 DispatchMessageW(&msg); 2068 } 2069 } 2070 2071 // HACK: Release modifier keys that the system did not emit KEYUP for 2072 // NOTE: Shift keys on Windows tend to "stick" when both are pressed as 2073 // no key up message is generated by the first key release 2074 // NOTE: Windows key is not reported as released by the Win+V hotkey 2075 // Other Win hotkeys are handled implicitly by _glfwInputWindowFocus 2076 // because they change the input focus 2077 // NOTE: The other half of this is in the WM_*KEY* handler in windowProc 2078 handle = GetActiveWindow(); 2079 if (handle) 2080 { 2081 window = GetPropW(handle, L"GLFW"); 2082 if (window) 2083 { 2084 int i; 2085 const int keys[4][2] = 2086 { 2087 { VK_LSHIFT, GLFW_KEY_LEFT_SHIFT }, 2088 { VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT }, 2089 { VK_LWIN, GLFW_KEY_LEFT_SUPER }, 2090 { VK_RWIN, GLFW_KEY_RIGHT_SUPER } 2091 }; 2092 2093 for (i = 0; i < 4; i++) 2094 { 2095 const int vk = keys[i][0]; 2096 const int key = keys[i][1]; 2097 const int scancode = _glfw.win32.scancodes[key]; 2098 2099 if ((GetKeyState(vk) & 0x8000)) 2100 continue; 2101 if (window->keys[key] != GLFW_PRESS) 2102 continue; 2103 2104 _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods()); 2105 } 2106 } 2107 } 2108 2109 window = _glfw.win32.disabledCursorWindow; 2110 if (window) 2111 { 2112 int width, height; 2113 _glfwGetWindowSizeWin32(window, &width, &height); 2114 2115 // NOTE: Re-center the cursor only if it has moved since the last call, 2116 // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE 2117 if (window->win32.lastCursorPosX != width / 2 || 2118 window->win32.lastCursorPosY != height / 2) 2119 { 2120 _glfwSetCursorPosWin32(window, width / 2, height / 2); 2121 } 2122 } 2123 } 2124 2125 void _glfwWaitEventsWin32(void) 2126 { 2127 WaitMessage(); 2128 2129 _glfwPollEventsWin32(); 2130 } 2131 2132 void _glfwWaitEventsTimeoutWin32(double timeout) 2133 { 2134 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS); 2135 2136 _glfwPollEventsWin32(); 2137 } 2138 2139 void _glfwPostEmptyEventWin32(void) 2140 { 2141 PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0); 2142 } 2143 2144 void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos) 2145 { 2146 POINT pos; 2147 2148 if (GetCursorPos(&pos)) 2149 { 2150 ScreenToClient(window->win32.handle, &pos); 2151 2152 if (xpos) 2153 *xpos = pos.x; 2154 if (ypos) 2155 *ypos = pos.y; 2156 } 2157 } 2158 2159 void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos) 2160 { 2161 POINT pos = { (int) xpos, (int) ypos }; 2162 2163 // Store the new position so it can be recognized later 2164 window->win32.lastCursorPosX = pos.x; 2165 window->win32.lastCursorPosY = pos.y; 2166 2167 ClientToScreen(window->win32.handle, &pos); 2168 SetCursorPos(pos.x, pos.y); 2169 } 2170 2171 void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode) 2172 { 2173 if (_glfwWindowFocusedWin32(window)) 2174 { 2175 if (mode == GLFW_CURSOR_DISABLED) 2176 { 2177 _glfwGetCursorPosWin32(window, 2178 &_glfw.win32.restoreCursorPosX, 2179 &_glfw.win32.restoreCursorPosY); 2180 _glfwCenterCursorInContentArea(window); 2181 if (window->rawMouseMotion) 2182 enableRawMouseMotion(window); 2183 } 2184 else if (_glfw.win32.disabledCursorWindow == window) 2185 { 2186 if (window->rawMouseMotion) 2187 disableRawMouseMotion(window); 2188 } 2189 2190 if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED) 2191 captureCursor(window); 2192 else 2193 releaseCursor(); 2194 2195 if (mode == GLFW_CURSOR_DISABLED) 2196 _glfw.win32.disabledCursorWindow = window; 2197 else if (_glfw.win32.disabledCursorWindow == window) 2198 { 2199 _glfw.win32.disabledCursorWindow = NULL; 2200 _glfwSetCursorPosWin32(window, 2201 _glfw.win32.restoreCursorPosX, 2202 _glfw.win32.restoreCursorPosY); 2203 } 2204 } 2205 2206 if (cursorInContentArea(window)) 2207 updateCursorImage(window); 2208 } 2209 2210 const char* _glfwGetScancodeNameWin32(int scancode) 2211 { 2212 if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) || 2213 _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN) 2214 { 2215 _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode); 2216 return NULL; 2217 } 2218 2219 return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]]; 2220 } 2221 2222 int _glfwGetKeyScancodeWin32(int key) 2223 { 2224 return _glfw.win32.scancodes[key]; 2225 } 2226 2227 GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor, 2228 const GLFWimage* image, 2229 int xhot, int yhot) 2230 { 2231 cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE); 2232 if (!cursor->win32.handle) 2233 return GLFW_FALSE; 2234 2235 return GLFW_TRUE; 2236 } 2237 2238 GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape) 2239 { 2240 int id = 0; 2241 2242 switch (shape) 2243 { 2244 case GLFW_ARROW_CURSOR: 2245 id = OCR_NORMAL; 2246 break; 2247 case GLFW_IBEAM_CURSOR: 2248 id = OCR_IBEAM; 2249 break; 2250 case GLFW_CROSSHAIR_CURSOR: 2251 id = OCR_CROSS; 2252 break; 2253 case GLFW_POINTING_HAND_CURSOR: 2254 id = OCR_HAND; 2255 break; 2256 case GLFW_RESIZE_EW_CURSOR: 2257 id = OCR_SIZEWE; 2258 break; 2259 case GLFW_RESIZE_NS_CURSOR: 2260 id = OCR_SIZENS; 2261 break; 2262 case GLFW_RESIZE_NWSE_CURSOR: 2263 id = OCR_SIZENWSE; 2264 break; 2265 case GLFW_RESIZE_NESW_CURSOR: 2266 id = OCR_SIZENESW; 2267 break; 2268 case GLFW_RESIZE_ALL_CURSOR: 2269 id = OCR_SIZEALL; 2270 break; 2271 case GLFW_NOT_ALLOWED_CURSOR: 2272 id = OCR_NO; 2273 break; 2274 default: 2275 _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor"); 2276 return GLFW_FALSE; 2277 } 2278 2279 cursor->win32.handle = LoadImageW(NULL, 2280 MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, 2281 LR_DEFAULTSIZE | LR_SHARED); 2282 if (!cursor->win32.handle) 2283 { 2284 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 2285 "Win32: Failed to create standard cursor"); 2286 return GLFW_FALSE; 2287 } 2288 2289 return GLFW_TRUE; 2290 } 2291 2292 void _glfwDestroyCursorWin32(_GLFWcursor* cursor) 2293 { 2294 if (cursor->win32.handle) 2295 DestroyIcon((HICON) cursor->win32.handle); 2296 } 2297 2298 void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor) 2299 { 2300 if (cursorInContentArea(window)) 2301 updateCursorImage(window); 2302 } 2303 2304 void _glfwSetClipboardStringWin32(const char* string) 2305 { 2306 int characterCount; 2307 HANDLE object; 2308 WCHAR* buffer; 2309 2310 characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); 2311 if (!characterCount) 2312 return; 2313 2314 object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR)); 2315 if (!object) 2316 { 2317 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 2318 "Win32: Failed to allocate global handle for clipboard"); 2319 return; 2320 } 2321 2322 buffer = GlobalLock(object); 2323 if (!buffer) 2324 { 2325 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 2326 "Win32: Failed to lock global handle"); 2327 GlobalFree(object); 2328 return; 2329 } 2330 2331 MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount); 2332 GlobalUnlock(object); 2333 2334 if (!OpenClipboard(_glfw.win32.helperWindowHandle)) 2335 { 2336 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 2337 "Win32: Failed to open clipboard"); 2338 GlobalFree(object); 2339 return; 2340 } 2341 2342 EmptyClipboard(); 2343 SetClipboardData(CF_UNICODETEXT, object); 2344 CloseClipboard(); 2345 } 2346 2347 const char* _glfwGetClipboardStringWin32(void) 2348 { 2349 HANDLE object; 2350 WCHAR* buffer; 2351 2352 if (!OpenClipboard(_glfw.win32.helperWindowHandle)) 2353 { 2354 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 2355 "Win32: Failed to open clipboard"); 2356 return NULL; 2357 } 2358 2359 object = GetClipboardData(CF_UNICODETEXT); 2360 if (!object) 2361 { 2362 _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE, 2363 "Win32: Failed to convert clipboard to string"); 2364 CloseClipboard(); 2365 return NULL; 2366 } 2367 2368 buffer = GlobalLock(object); 2369 if (!buffer) 2370 { 2371 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, 2372 "Win32: Failed to lock global handle"); 2373 CloseClipboard(); 2374 return NULL; 2375 } 2376 2377 _glfw_free(_glfw.win32.clipboardString); 2378 _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer); 2379 2380 GlobalUnlock(object); 2381 CloseClipboard(); 2382 2383 return _glfw.win32.clipboardString; 2384 } 2385 2386 EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs) 2387 { 2388 if (_glfw.egl.ANGLE_platform_angle) 2389 { 2390 int type = 0; 2391 2392 if (_glfw.egl.ANGLE_platform_angle_opengl) 2393 { 2394 if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL) 2395 type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE; 2396 else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES) 2397 type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE; 2398 } 2399 2400 if (_glfw.egl.ANGLE_platform_angle_d3d) 2401 { 2402 if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D9) 2403 type = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE; 2404 else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D11) 2405 type = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE; 2406 } 2407 2408 if (_glfw.egl.ANGLE_platform_angle_vulkan) 2409 { 2410 if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN) 2411 type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE; 2412 } 2413 2414 if (type) 2415 { 2416 *attribs = _glfw_calloc(3, sizeof(EGLint)); 2417 (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE; 2418 (*attribs)[1] = type; 2419 (*attribs)[2] = EGL_NONE; 2420 return EGL_PLATFORM_ANGLE_ANGLE; 2421 } 2422 } 2423 2424 return 0; 2425 } 2426 2427 EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void) 2428 { 2429 return GetDC(_glfw.win32.helperWindowHandle); 2430 } 2431 2432 EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window) 2433 { 2434 return window->win32.handle; 2435 } 2436 2437 void _glfwGetRequiredInstanceExtensionsWin32(char** extensions) 2438 { 2439 if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface) 2440 return; 2441 2442 extensions[0] = "VK_KHR_surface"; 2443 extensions[1] = "VK_KHR_win32_surface"; 2444 } 2445 2446 GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, 2447 VkPhysicalDevice device, 2448 uint32_t queuefamily) 2449 { 2450 PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR 2451 vkGetPhysicalDeviceWin32PresentationSupportKHR = 2452 (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) 2453 vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); 2454 if (!vkGetPhysicalDeviceWin32PresentationSupportKHR) 2455 { 2456 _glfwInputError(GLFW_API_UNAVAILABLE, 2457 "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); 2458 return GLFW_FALSE; 2459 } 2460 2461 return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily); 2462 } 2463 2464 VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, 2465 _GLFWwindow* window, 2466 const VkAllocationCallbacks* allocator, 2467 VkSurfaceKHR* surface) 2468 { 2469 VkResult err; 2470 VkWin32SurfaceCreateInfoKHR sci; 2471 PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; 2472 2473 vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) 2474 vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); 2475 if (!vkCreateWin32SurfaceKHR) 2476 { 2477 _glfwInputError(GLFW_API_UNAVAILABLE, 2478 "Win32: Vulkan instance missing VK_KHR_win32_surface extension"); 2479 return VK_ERROR_EXTENSION_NOT_PRESENT; 2480 } 2481 2482 memset(&sci, 0, sizeof(sci)); 2483 sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; 2484 sci.hinstance = _glfw.win32.instance; 2485 sci.hwnd = window->win32.handle; 2486 2487 err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface); 2488 if (err) 2489 { 2490 _glfwInputError(GLFW_PLATFORM_ERROR, 2491 "Win32: Failed to create Vulkan surface: %s", 2492 _glfwGetVulkanResultString(err)); 2493 } 2494 2495 return err; 2496 } 2497 2498 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) 2499 { 2500 _GLFWwindow* window = (_GLFWwindow*) handle; 2501 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 2502 2503 if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32) 2504 { 2505 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE, 2506 "Win32: Platform not initialized"); 2507 return NULL; 2508 } 2509 2510 return window->win32.handle; 2511 } 2512