// Enforce the client rect aspect ratio based on which edge is being dragged // static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) { int xoff, yoff; const float ratio = (float) window->win32.numer / (float) window->win32.denom; getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT || edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT) { area->bottom = area->top + yoff + (int) ((area->right - area->left - xoff) / ratio); } else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT) { area->top = area->bottom - yoff - (int) ((area->right - area->left - xoff) / ratio); } else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM) { area->right = area->left + xoff + (int) ((area->bottom - area->top - yoff) * ratio); } }
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) enterFullscreenMode(window); else { int fullWidth, fullHeight; getFullWindowSize(window, width, height, &fullWidth, &fullHeight); SetWindowPos(window->win32.handle, HWND_TOP, 0, 0, fullWidth, fullHeight, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } }
// Creates the GLFW window and rendering context // static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; window->win32.dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; window->win32.dwExStyle = WS_EX_APPWINDOW; if (window->monitor) { window->win32.dwStyle |= WS_POPUP; // NOTE: This window placement is temporary and approximate, as the // correct position and size cannot be known until the monitor // video mode has been set _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos); fullWidth = wndconfig->width; fullHeight = wndconfig->height; } else { if (wndconfig->decorated) { window->win32.dwStyle |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; if (wndconfig->resizable) { window->win32.dwStyle |= WS_MAXIMIZEBOX | WS_SIZEBOX; window->win32.dwExStyle |= WS_EX_WINDOWEDGE; } } else window->win32.dwStyle |= WS_POPUP; xpos = CW_USEDEFAULT; ypos = CW_USEDEFAULT; getFullWindowSize(window, wndconfig->width, wndconfig->height, &fullWidth, &fullHeight); } wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title); if (!wideTitle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to convert window title to UTF-16"); return GL_FALSE; } window->win32.handle = CreateWindowExW(window->win32.dwExStyle, _GLFW_WNDCLASSNAME, wideTitle, window->win32.dwStyle, xpos, ypos, fullWidth, fullHeight, NULL, // No parent window NULL, // No window menu GetModuleHandleW(NULL), window); // Pass object to WM_CREATE free(wideTitle); if (!window->win32.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); return GL_FALSE; } if (_glfw_ChangeWindowMessageFilterEx) { _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL); _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL); _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } if (wndconfig->floating && !wndconfig->monitor) { SetWindowPos(window->win32.handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } DragAcceptFiles(window->win32.handle, TRUE); if (!_glfwCreateContext(window, ctxconfig, fbconfig)) return GL_FALSE; return GL_TRUE; }
// Creates the GLFW window and rendering context // static GLFWbool createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; if (wndconfig->monitor) { GLFWvidmode mode; // NOTE: This window placement is temporary and approximate, as the // correct position and size cannot be known until the monitor // video mode has been set _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(wndconfig->monitor, &mode); fullWidth = mode.width; fullHeight = mode.height; } else { xpos = CW_USEDEFAULT; ypos = CW_USEDEFAULT; getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), wndconfig->width, wndconfig->height, &fullWidth, &fullHeight); } wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title); if (!wideTitle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to convert window title to UTF-16"); return GLFW_FALSE; } window->win32.handle = CreateWindowExW(getWindowExStyle(window), _GLFW_WNDCLASSNAME, wideTitle, getWindowStyle(window), xpos, ypos, fullWidth, fullHeight, NULL, // No parent window NULL, // No window menu GetModuleHandleW(NULL), window); // Pass object to WM_CREATE free(wideTitle); if (!window->win32.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); return GLFW_FALSE; } if (_glfw_ChangeWindowMessageFilterEx) { _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL); _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL); _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } if (wndconfig->floating && !wndconfig->monitor) { SetWindowPos(window->win32.handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } DragAcceptFiles(window->win32.handle, TRUE); if (!_glfwCreateContext(window, ctxconfig, fbconfig)) return GLFW_FALSE; window->win32.minwidth = GLFW_DONT_CARE; window->win32.minheight = GLFW_DONT_CARE; window->win32.maxwidth = GLFW_DONT_CARE; window->win32.maxheight = GLFW_DONT_CARE; window->win32.numer = GLFW_DONT_CARE; window->win32.denom = GLFW_DONT_CARE; return GLFW_TRUE; }
// Window callback function (handles window events) // static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtrW(hWnd, 0); switch (uMsg) { case WM_NCCREATE: { CREATESTRUCTW* cs = (CREATESTRUCTW*) lParam; SetWindowLongPtrW(hWnd, 0, (LONG_PTR) cs->lpCreateParams); break; } case WM_SETFOCUS: { if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); _glfwInputWindowFocus(window, GLFW_TRUE); return 0; } case WM_KILLFOCUS: { if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); return 0; } case WM_SYSCOMMAND: { switch (wParam & 0xfff0) { case SC_SCREENSAVE: case SC_MONITORPOWER: { if (window->monitor) { // We are running in full screen mode, so disallow // screen saver and screen blanking return 0; } else break; } // User trying to access application menu using ALT? case SC_KEYMENU: return 0; } break; } case WM_CLOSE: { _glfwInputWindowCloseRequest(window); return 0; } case WM_KEYDOWN: case WM_SYSKEYDOWN: { const int scancode = (lParam >> 16) & 0x1ff; const int key = translateKey(wParam, lParam); if (key == _GLFW_KEY_INVALID) break; _glfwInputKey(window, key, scancode, GLFW_PRESS, getKeyMods()); break; } case WM_CHAR: { _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_TRUE); return 0; } case WM_SYSCHAR: { _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_FALSE); return 0; } case WM_UNICHAR: { // This message is not sent by Windows, but is sent by some // third-party input method engines if (wParam == UNICODE_NOCHAR) { // Returning TRUE here announces support for this message return TRUE; } _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_TRUE); return FALSE; } case WM_KEYUP: case WM_SYSKEYUP: { const int mods = getKeyMods(); const int scancode = (lParam >> 16) & 0x1ff; const int key = translateKey(wParam, lParam); if (key == _GLFW_KEY_INVALID) break; if (wParam == VK_SHIFT) { // Release both Shift keys on Shift up event, as only one event // is sent even if both keys are released _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods); } else if (wParam == VK_SNAPSHOT) { // Key down is not reported for the print screen key _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); } else _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); break; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: { const int mods = getKeyMods(); SetCapture(hWnd); if (uMsg == WM_LBUTTONDOWN) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); else if (uMsg == WM_RBUTTONDOWN) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); else if (uMsg == WM_MBUTTONDOWN) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); else { if (HIWORD(wParam) == XBUTTON1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_PRESS, mods); else if (HIWORD(wParam) == XBUTTON2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_PRESS, mods); return TRUE; } return 0; } case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: { const int mods = getKeyMods(); ReleaseCapture(); if (uMsg == WM_LBUTTONUP) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); else if (uMsg == WM_RBUTTONUP) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); else if (uMsg == WM_MBUTTONUP) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, mods); else { if (HIWORD(wParam) == XBUTTON1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_RELEASE, mods); else if (HIWORD(wParam) == XBUTTON2) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_RELEASE, mods); return TRUE; } return 0; } case WM_MOUSEMOVE: { const int x = GET_X_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam); if (window->cursorMode == GLFW_CURSOR_DISABLED) { if (_glfw.cursorWindow != window) break; _glfwInputCursorMotion(window, x - window->win32.cursorPosX, y - window->win32.cursorPosY); } else _glfwInputCursorMotion(window, x, y); window->win32.cursorPosX = x; window->win32.cursorPosY = y; if (!window->win32.cursorTracked) { TRACKMOUSEEVENT tme; ZeroMemory(&tme, sizeof(tme)); tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = window->win32.handle; TrackMouseEvent(&tme); window->win32.cursorTracked = GLFW_TRUE; _glfwInputCursorEnter(window, GLFW_TRUE); } return 0; } case WM_MOUSELEAVE: { window->win32.cursorTracked = GLFW_FALSE; _glfwInputCursorEnter(window, GLFW_FALSE); return 0; } case WM_MOUSEWHEEL: { _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); return 0; } case WM_MOUSEHWHEEL: { // This message is only sent on Windows Vista and later // NOTE: The X-axis is inverted for consistency with OS X and X11. _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); return 0; } case WM_SIZE: { if (_glfw.cursorWindow == window) { if (window->cursorMode == GLFW_CURSOR_DISABLED) updateClipRect(window); } if (!window->win32.iconified && wParam == SIZE_MINIMIZED) { window->win32.iconified = GLFW_TRUE; if (window->monitor) leaveFullscreenMode(window); _glfwInputWindowIconify(window, GLFW_TRUE); } else if (window->win32.iconified && (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)) { window->win32.iconified = GLFW_FALSE; if (window->monitor) enterFullscreenMode(window); _glfwInputWindowIconify(window, GLFW_FALSE); } _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); return 0; } case WM_MOVE: { if (_glfw.cursorWindow == window) { if (window->cursorMode == GLFW_CURSOR_DISABLED) updateClipRect(window); } // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly _glfwInputWindowPos(window, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } case WM_SIZING: { if (window->win32.numer == GLFW_DONT_CARE || window->win32.denom == GLFW_DONT_CARE) { break; } applyAspectRatio(window, (int) wParam, (RECT*) lParam); return TRUE; } case WM_GETMINMAXINFO: { int xoff, yoff; MINMAXINFO* mmi = (MINMAXINFO*) lParam; if (!window) break; getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); if (window->win32.minwidth != GLFW_DONT_CARE && window->win32.minheight != GLFW_DONT_CARE) { mmi->ptMinTrackSize.x = window->win32.minwidth + xoff; mmi->ptMinTrackSize.y = window->win32.minheight + yoff; } if (window->win32.maxwidth != GLFW_DONT_CARE && window->win32.maxheight != GLFW_DONT_CARE) { mmi->ptMaxTrackSize.x = window->win32.maxwidth + xoff; mmi->ptMaxTrackSize.y = window->win32.maxheight + yoff; } return 0; } case WM_PAINT: { _glfwInputWindowDamage(window); break; } case WM_ERASEBKGND: { return TRUE; } case WM_SETCURSOR: { if (_glfw.cursorWindow == window && LOWORD(lParam) == HTCLIENT) { if (window->cursorMode == GLFW_CURSOR_HIDDEN || window->cursorMode == GLFW_CURSOR_DISABLED) { SetCursor(NULL); return TRUE; } else if (window->cursor) { SetCursor(window->cursor->win32.handle); return TRUE; } } break; } case WM_DEVICECHANGE: { if (DBT_DEVNODES_CHANGED == wParam) { _glfwInputMonitorChange(); return TRUE; } break; } case WM_DROPFILES: { HDROP drop = (HDROP) wParam; POINT pt; int i; const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); char** paths = calloc(count, sizeof(char*)); // Move the mouse to the position of the drop DragQueryPoint(drop, &pt); _glfwInputCursorMotion(window, pt.x, pt.y); for (i = 0; i < count; i++) { const UINT length = DragQueryFileW(drop, i, NULL, 0); WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); DragQueryFileW(drop, i, buffer, length + 1); paths[i] = _glfwCreateUTF8FromWideString(buffer); free(buffer); } _glfwInputDrop(window, count, (const char**) paths); for (i = 0; i < count; i++) free(paths[i]); free(paths); DragFinish(drop); return 0; } } return DefWindowProc(hWnd, uMsg, wParam, lParam); }
// Creates the GLFW window // static int createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; DWORD style = getWindowStyle(window); DWORD exStyle = getWindowExStyle(window); if (window->monitor) { GLFWvidmode mode; // NOTE: This window placement is temporary and approximate, as the // correct position and size cannot be known until the monitor // video mode has been set _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(window->monitor, &mode); fullWidth = mode.width; fullHeight = mode.height; } else { xpos = CW_USEDEFAULT; ypos = CW_USEDEFAULT; if (wndconfig->maximized) style |= WS_MAXIMIZE; getFullWindowSize(style, exStyle, wndconfig->width, wndconfig->height, &fullWidth, &fullHeight); } wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); if (!wideTitle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to convert window title to UTF-16"); return GLFW_FALSE; } window->win32.handle = CreateWindowExW(exStyle, _GLFW_WNDCLASSNAME, wideTitle, style, xpos, ypos, fullWidth, fullHeight, NULL, // No parent window NULL, // No window menu GetModuleHandleW(NULL), NULL); free(wideTitle); if (!window->win32.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); return GLFW_FALSE; } SetPropW(window->win32.handle, L"GLFW", window); if (_glfw_ChangeWindowMessageFilterEx) { _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_DROPFILES, MSGFLT_ALLOW, NULL); _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYDATA, MSGFLT_ALLOW, NULL); _glfw_ChangeWindowMessageFilterEx(window->win32.handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } DragAcceptFiles(window->win32.handle, TRUE); return GLFW_TRUE; }
// Window callback function (handles window messages) // static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { _GLFWwindow* window = GetPropW(hWnd, L"GLFW"); if (!window) { // This is the message handling for the hidden helper window switch (uMsg) { case WM_DEVICECHANGE: { if (wParam == DBT_DEVNODES_CHANGED) { _glfwInputMonitorChange(); return TRUE; } else if (wParam == DBT_DEVICEARRIVAL) { DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; if (dbh) { if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) _glfwDetectJoystickConnectionWin32(); } } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam; if (dbh) { if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) _glfwDetectJoystickDisconnectionWin32(); } } break; } } return DefWindowProcW(hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_SETFOCUS: { _glfwInputWindowFocus(window, GLFW_TRUE); if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); return 0; } case WM_KILLFOCUS: { if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); if (window->monitor && window->autoIconify) _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); return 0; } case WM_SYSCOMMAND: { switch (wParam & 0xfff0) { case SC_SCREENSAVE: case SC_MONITORPOWER: { if (window->monitor) { // We are running in full screen mode, so disallow // screen saver and screen blanking return 0; } else break; } // User trying to access application menu using ALT? case SC_KEYMENU: return 0; } break; } case WM_CLOSE: { _glfwInputWindowCloseRequest(window); return 0; } case WM_CHAR: case WM_SYSCHAR: case WM_UNICHAR: { const GLFWbool plain = (uMsg != WM_SYSCHAR); if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR) { // WM_UNICHAR is not sent by Windows, but is sent by some // third-party input method engine // Returning TRUE here announces support for this message return TRUE; } _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain); return 0; } case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: { const int key = translateKey(wParam, lParam); const int scancode = (lParam >> 16) & 0x1ff; const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS; const int mods = getKeyMods(); if (key == _GLFW_KEY_INVALID) break; if (action == GLFW_RELEASE && wParam == VK_SHIFT) { // Release both Shift keys on Shift up event, as only one event // is sent even if both keys are released _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods); _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods); } else if (wParam == VK_SNAPSHOT) { // Key down is not reported for the Print Screen key _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); } else _glfwInputKey(window, key, scancode, action, mods); break; } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP: { int button, action; if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) button = GLFW_MOUSE_BUTTON_LEFT; else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) button = GLFW_MOUSE_BUTTON_RIGHT; else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) button = GLFW_MOUSE_BUTTON_MIDDLE; else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) button = GLFW_MOUSE_BUTTON_4; else button = GLFW_MOUSE_BUTTON_5; if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN || uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN) { action = GLFW_PRESS; SetCapture(hWnd); } else { action = GLFW_RELEASE; ReleaseCapture(); } _glfwInputMouseClick(window, button, action, getKeyMods()); if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) return TRUE; return 0; } case WM_MOUSEMOVE: { const int x = GET_X_LPARAM(lParam); const int y = GET_Y_LPARAM(lParam); if (window->cursorMode == GLFW_CURSOR_DISABLED) { const int dx = x - window->win32.lastCursorPosX; const int dy = y - window->win32.lastCursorPosY; if (_glfw.win32.disabledCursorWindow != window) break; _glfwInputCursorPos(window, window->virtualCursorPosX + dx, window->virtualCursorPosY + dy); } else _glfwInputCursorPos(window, x, y); window->win32.lastCursorPosX = x; window->win32.lastCursorPosY = y; if (!window->win32.cursorTracked) { TRACKMOUSEEVENT tme; ZeroMemory(&tme, sizeof(tme)); tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = window->win32.handle; TrackMouseEvent(&tme); window->win32.cursorTracked = GLFW_TRUE; _glfwInputCursorEnter(window, GLFW_TRUE); } return 0; } case WM_MOUSELEAVE: { window->win32.cursorTracked = GLFW_FALSE; _glfwInputCursorEnter(window, GLFW_FALSE); return 0; } case WM_MOUSEWHEEL: { _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); return 0; } case WM_MOUSEHWHEEL: { // This message is only sent on Windows Vista and later // NOTE: The X-axis is inverted for consistency with OS X and X11. _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); return 0; } case WM_ENTERSIZEMOVE: case WM_ENTERMENULOOP: { if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); break; } case WM_EXITSIZEMOVE: case WM_EXITMENULOOP: { if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED); break; } case WM_SIZE: { const GLFWbool iconified = wParam == SIZE_MINIMIZED; const GLFWbool maximized = wParam == SIZE_MAXIMIZED || (window->win32.maximized && wParam != SIZE_RESTORED); if (_glfw.win32.disabledCursorWindow == window) updateClipRect(window); if (window->win32.iconified != iconified) _glfwInputWindowIconify(window, iconified); if (window->win32.maximized != maximized) _glfwInputWindowMaximize(window, maximized); _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); if (window->monitor && window->win32.iconified != iconified) { if (iconified) releaseMonitor(window); else acquireMonitor(window); } window->win32.iconified = iconified; window->win32.maximized = maximized; return 0; } case WM_MOVE: { if (_glfw.win32.disabledCursorWindow == window) updateClipRect(window); // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // those macros do not handle negative window positions correctly _glfwInputWindowPos(window, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); return 0; } case WM_SIZING: { if (window->numer == GLFW_DONT_CARE || window->denom == GLFW_DONT_CARE) { break; } applyAspectRatio(window, (int) wParam, (RECT*) lParam); return TRUE; } case WM_GETMINMAXINFO: { int xoff, yoff; MINMAXINFO* mmi = (MINMAXINFO*) lParam; if (window->monitor) break; getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); if (window->minwidth != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE) { mmi->ptMinTrackSize.x = window->minwidth + xoff; mmi->ptMinTrackSize.y = window->minheight + yoff; } if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE) { mmi->ptMaxTrackSize.x = window->maxwidth + xoff; mmi->ptMaxTrackSize.y = window->maxheight + yoff; } return 0; } case WM_PAINT: { _glfwInputWindowDamage(window); break; } case WM_ERASEBKGND: { return TRUE; } case WM_SETCURSOR: { if (LOWORD(lParam) == HTCLIENT) { updateCursorImage(window); return TRUE; } break; } case WM_DPICHANGED: { RECT* rect = (RECT*) lParam; SetWindowPos(window->win32.handle, HWND_TOP, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOACTIVATE | SWP_NOZORDER); break; } case WM_DROPFILES: { HDROP drop = (HDROP) wParam; POINT pt; int i; const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0); wchar_t** paths = calloc(count, sizeof(wchar_t*)); // Move the mouse to the position of the drop DragQueryPoint(drop, &pt); _glfwInputCursorPos(window, pt.x, pt.y); for (i = 0; i < count; i++) { const UINT length = DragQueryFileW(drop, i, NULL, 0); WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); DragQueryFileW(drop, i, buffer, length + 1); //paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); paths[i] = buffer; //free(buffer); } _glfwInputDrop(window, count, (const wchar_t**) paths); for (i = 0; i < count; i++) free(paths[i]); free(paths); DragFinish(drop); return 0; } } return DefWindowProcW(hWnd, uMsg, wParam, lParam); }