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