| // | |
| // Copyright 2014 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // Win32Window.cpp: Implementation of OSWindow for Win32 (Windows) | |
| #include "util/windows/win32/Win32Window.h" | |
| #include <sstream> | |
| #include "common/debug.h" | |
| Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags) | |
| { | |
| switch (key) | |
| { | |
| // Check the scancode to distinguish between left and right shift | |
| case VK_SHIFT: | |
| { | |
| static unsigned int lShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC); | |
| unsigned int scancode = static_cast<unsigned int>((flags & (0xFF << 16)) >> 16); | |
| return scancode == lShift ? KEY_LSHIFT : KEY_RSHIFT; | |
| } | |
| // Check the "extended" flag to distinguish between left and right alt | |
| case VK_MENU: | |
| return (HIWORD(flags) & KF_EXTENDED) ? KEY_RALT : KEY_LALT; | |
| // Check the "extended" flag to distinguish between left and right control | |
| case VK_CONTROL: | |
| return (HIWORD(flags) & KF_EXTENDED) ? KEY_RCONTROL : KEY_LCONTROL; | |
| // Other keys are reported properly | |
| case VK_LWIN: | |
| return KEY_LSYSTEM; | |
| case VK_RWIN: | |
| return KEY_RSYSTEM; | |
| case VK_APPS: | |
| return KEY_MENU; | |
| case VK_OEM_1: | |
| return KEY_SEMICOLON; | |
| case VK_OEM_2: | |
| return KEY_SLASH; | |
| case VK_OEM_PLUS: | |
| return KEY_EQUAL; | |
| case VK_OEM_MINUS: | |
| return KEY_DASH; | |
| case VK_OEM_4: | |
| return KEY_LBRACKET; | |
| case VK_OEM_6: | |
| return KEY_RBRACKET; | |
| case VK_OEM_COMMA: | |
| return KEY_COMMA; | |
| case VK_OEM_PERIOD: | |
| return KEY_PERIOD; | |
| case VK_OEM_7: | |
| return KEY_QUOTE; | |
| case VK_OEM_5: | |
| return KEY_BACKSLASH; | |
| case VK_OEM_3: | |
| return KEY_TILDE; | |
| case VK_ESCAPE: | |
| return KEY_ESCAPE; | |
| case VK_SPACE: | |
| return KEY_SPACE; | |
| case VK_RETURN: | |
| return KEY_RETURN; | |
| case VK_BACK: | |
| return KEY_BACK; | |
| case VK_TAB: | |
| return KEY_TAB; | |
| case VK_PRIOR: | |
| return KEY_PAGEUP; | |
| case VK_NEXT: | |
| return KEY_PAGEDOWN; | |
| case VK_END: | |
| return KEY_END; | |
| case VK_HOME: | |
| return KEY_HOME; | |
| case VK_INSERT: | |
| return KEY_INSERT; | |
| case VK_DELETE: | |
| return KEY_DELETE; | |
| case VK_ADD: | |
| return KEY_ADD; | |
| case VK_SUBTRACT: | |
| return KEY_SUBTRACT; | |
| case VK_MULTIPLY: | |
| return KEY_MULTIPLY; | |
| case VK_DIVIDE: | |
| return KEY_DIVIDE; | |
| case VK_PAUSE: | |
| return KEY_PAUSE; | |
| case VK_F1: | |
| return KEY_F1; | |
| case VK_F2: | |
| return KEY_F2; | |
| case VK_F3: | |
| return KEY_F3; | |
| case VK_F4: | |
| return KEY_F4; | |
| case VK_F5: | |
| return KEY_F5; | |
| case VK_F6: | |
| return KEY_F6; | |
| case VK_F7: | |
| return KEY_F7; | |
| case VK_F8: | |
| return KEY_F8; | |
| case VK_F9: | |
| return KEY_F9; | |
| case VK_F10: | |
| return KEY_F10; | |
| case VK_F11: | |
| return KEY_F11; | |
| case VK_F12: | |
| return KEY_F12; | |
| case VK_F13: | |
| return KEY_F13; | |
| case VK_F14: | |
| return KEY_F14; | |
| case VK_F15: | |
| return KEY_F15; | |
| case VK_LEFT: | |
| return KEY_LEFT; | |
| case VK_RIGHT: | |
| return KEY_RIGHT; | |
| case VK_UP: | |
| return KEY_UP; | |
| case VK_DOWN: | |
| return KEY_DOWN; | |
| case VK_NUMPAD0: | |
| return KEY_NUMPAD0; | |
| case VK_NUMPAD1: | |
| return KEY_NUMPAD1; | |
| case VK_NUMPAD2: | |
| return KEY_NUMPAD2; | |
| case VK_NUMPAD3: | |
| return KEY_NUMPAD3; | |
| case VK_NUMPAD4: | |
| return KEY_NUMPAD4; | |
| case VK_NUMPAD5: | |
| return KEY_NUMPAD5; | |
| case VK_NUMPAD6: | |
| return KEY_NUMPAD6; | |
| case VK_NUMPAD7: | |
| return KEY_NUMPAD7; | |
| case VK_NUMPAD8: | |
| return KEY_NUMPAD8; | |
| case VK_NUMPAD9: | |
| return KEY_NUMPAD9; | |
| case 'A': | |
| return KEY_A; | |
| case 'Z': | |
| return KEY_Z; | |
| case 'E': | |
| return KEY_E; | |
| case 'R': | |
| return KEY_R; | |
| case 'T': | |
| return KEY_T; | |
| case 'Y': | |
| return KEY_Y; | |
| case 'U': | |
| return KEY_U; | |
| case 'I': | |
| return KEY_I; | |
| case 'O': | |
| return KEY_O; | |
| case 'P': | |
| return KEY_P; | |
| case 'Q': | |
| return KEY_Q; | |
| case 'S': | |
| return KEY_S; | |
| case 'D': | |
| return KEY_D; | |
| case 'F': | |
| return KEY_F; | |
| case 'G': | |
| return KEY_G; | |
| case 'H': | |
| return KEY_H; | |
| case 'J': | |
| return KEY_J; | |
| case 'K': | |
| return KEY_K; | |
| case 'L': | |
| return KEY_L; | |
| case 'M': | |
| return KEY_M; | |
| case 'W': | |
| return KEY_W; | |
| case 'X': | |
| return KEY_X; | |
| case 'C': | |
| return KEY_C; | |
| case 'V': | |
| return KEY_V; | |
| case 'B': | |
| return KEY_B; | |
| case 'N': | |
| return KEY_N; | |
| case '0': | |
| return KEY_NUM0; | |
| case '1': | |
| return KEY_NUM1; | |
| case '2': | |
| return KEY_NUM2; | |
| case '3': | |
| return KEY_NUM3; | |
| case '4': | |
| return KEY_NUM4; | |
| case '5': | |
| return KEY_NUM5; | |
| case '6': | |
| return KEY_NUM6; | |
| case '7': | |
| return KEY_NUM7; | |
| case '8': | |
| return KEY_NUM8; | |
| case '9': | |
| return KEY_NUM9; | |
| } | |
| return Key(0); | |
| } | |
| LRESULT CALLBACK Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | |
| { | |
| switch (message) | |
| { | |
| case WM_NCCREATE: | |
| { | |
| LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); | |
| SetWindowLongPtr(hWnd, GWLP_USERDATA, | |
| reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams)); | |
| return DefWindowProcA(hWnd, message, wParam, lParam); | |
| } | |
| } | |
| Win32Window *window = reinterpret_cast<Win32Window *>(GetWindowLongPtr(hWnd, GWLP_USERDATA)); | |
| if (window) | |
| { | |
| switch (message) | |
| { | |
| case WM_DESTROY: | |
| case WM_CLOSE: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_CLOSED; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_MOVE: | |
| { | |
| RECT winRect; | |
| GetClientRect(hWnd, &winRect); | |
| POINT topLeft; | |
| topLeft.x = winRect.left; | |
| topLeft.y = winRect.top; | |
| ClientToScreen(hWnd, &topLeft); | |
| Event event; | |
| event.Type = Event::EVENT_MOVED; | |
| event.Move.X = topLeft.x; | |
| event.Move.Y = topLeft.y; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_SIZE: | |
| { | |
| RECT winRect; | |
| GetClientRect(hWnd, &winRect); | |
| POINT topLeft; | |
| topLeft.x = winRect.left; | |
| topLeft.y = winRect.top; | |
| ClientToScreen(hWnd, &topLeft); | |
| POINT botRight; | |
| botRight.x = winRect.right; | |
| botRight.y = winRect.bottom; | |
| ClientToScreen(hWnd, &botRight); | |
| Event event; | |
| event.Type = Event::EVENT_RESIZED; | |
| event.Size.Width = botRight.x - topLeft.x; | |
| event.Size.Height = botRight.y - topLeft.y; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_SETFOCUS: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_GAINED_FOCUS; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_KILLFOCUS: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_LOST_FOCUS; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_KEYDOWN: | |
| case WM_SYSKEYDOWN: | |
| case WM_KEYUP: | |
| case WM_SYSKEYUP: | |
| { | |
| bool down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN); | |
| Event event; | |
| event.Type = down ? Event::EVENT_KEY_PRESSED : Event::EVENT_KEY_RELEASED; | |
| event.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0; | |
| event.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0; | |
| event.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0; | |
| event.Key.System = | |
| HIWORD(GetAsyncKeyState(VK_LWIN)) || HIWORD(GetAsyncKeyState(VK_RWIN)); | |
| event.Key.Code = VirtualKeyCodeToKey(wParam, lParam); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_MOUSEWHEEL: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_WHEEL_MOVED; | |
| event.MouseWheel.Delta = static_cast<short>(HIWORD(wParam)) / 120; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_LBUTTONDOWN: | |
| case WM_LBUTTONDBLCLK: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; | |
| event.MouseButton.Button = MOUSEBUTTON_LEFT; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_LBUTTONUP: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; | |
| event.MouseButton.Button = MOUSEBUTTON_LEFT; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_RBUTTONDOWN: | |
| case WM_RBUTTONDBLCLK: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; | |
| event.MouseButton.Button = MOUSEBUTTON_RIGHT; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| // Mouse right button up event | |
| case WM_RBUTTONUP: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; | |
| event.MouseButton.Button = MOUSEBUTTON_RIGHT; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| // Mouse wheel button down event | |
| case WM_MBUTTONDOWN: | |
| case WM_MBUTTONDBLCLK: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; | |
| event.MouseButton.Button = MOUSEBUTTON_MIDDLE; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| // Mouse wheel button up event | |
| case WM_MBUTTONUP: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; | |
| event.MouseButton.Button = MOUSEBUTTON_MIDDLE; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| // Mouse X button down event | |
| case WM_XBUTTONDOWN: | |
| case WM_XBUTTONDBLCLK: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED; | |
| event.MouseButton.Button = | |
| (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| // Mouse X button up event | |
| case WM_XBUTTONUP: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED; | |
| event.MouseButton.Button = | |
| (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5; | |
| event.MouseButton.X = static_cast<short>(LOWORD(lParam)); | |
| event.MouseButton.Y = static_cast<short>(HIWORD(lParam)); | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_MOUSEMOVE: | |
| { | |
| if (!window->mIsMouseInWindow) | |
| { | |
| window->mIsMouseInWindow = true; | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_ENTERED; | |
| window->pushEvent(event); | |
| } | |
| int mouseX = static_cast<short>(LOWORD(lParam)); | |
| int mouseY = static_cast<short>(HIWORD(lParam)); | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_MOVED; | |
| event.MouseMove.X = mouseX; | |
| event.MouseMove.Y = mouseY; | |
| window->pushEvent(event); | |
| break; | |
| } | |
| case WM_MOUSELEAVE: | |
| { | |
| Event event; | |
| event.Type = Event::EVENT_MOUSE_LEFT; | |
| window->pushEvent(event); | |
| window->mIsMouseInWindow = false; | |
| break; | |
| } | |
| case WM_USER: | |
| { | |
| Event testEvent; | |
| testEvent.Type = Event::EVENT_TEST; | |
| window->pushEvent(testEvent); | |
| break; | |
| } | |
| } | |
| } | |
| return DefWindowProcA(hWnd, message, wParam, lParam); | |
| } | |
| Win32Window::Win32Window() | |
| : mIsVisible(false), | |
| mIsMouseInWindow(false), | |
| mNativeWindow(0), | |
| mParentWindow(0), | |
| mNativeDisplay(0) | |
| {} | |
| Win32Window::~Win32Window() | |
| { | |
| destroy(); | |
| } | |
| bool Win32Window::initialize(const std::string &name, int width, int height) | |
| { | |
| destroy(); | |
| // Use a new window class name for ever window to ensure that a new window can be created | |
| // even if the last one was not properly destroyed | |
| static size_t windowIdx = 0; | |
| std::ostringstream nameStream; | |
| nameStream << name << "_" << windowIdx++; | |
| mParentClassName = nameStream.str(); | |
| mChildClassName = mParentClassName + "_Child"; | |
| // Work around compile error from not defining "UNICODE" while Chromium does | |
| const LPSTR idcArrow = MAKEINTRESOURCEA(32512); | |
| WNDCLASSEXA parentWindowClass = {}; | |
| parentWindowClass.cbSize = sizeof(WNDCLASSEXA); | |
| parentWindowClass.style = 0; | |
| parentWindowClass.lpfnWndProc = WndProc; | |
| parentWindowClass.cbClsExtra = 0; | |
| parentWindowClass.cbWndExtra = 0; | |
| parentWindowClass.hInstance = GetModuleHandle(nullptr); | |
| parentWindowClass.hIcon = nullptr; | |
| parentWindowClass.hCursor = LoadCursorA(nullptr, idcArrow); | |
| parentWindowClass.hbrBackground = 0; | |
| parentWindowClass.lpszMenuName = nullptr; | |
| parentWindowClass.lpszClassName = mParentClassName.c_str(); | |
| if (!RegisterClassExA(&parentWindowClass)) | |
| { | |
| return false; | |
| } | |
| WNDCLASSEXA childWindowClass = {}; | |
| childWindowClass.cbSize = sizeof(WNDCLASSEXA); | |
| childWindowClass.style = CS_OWNDC; | |
| childWindowClass.lpfnWndProc = WndProc; | |
| childWindowClass.cbClsExtra = 0; | |
| childWindowClass.cbWndExtra = 0; | |
| childWindowClass.hInstance = GetModuleHandle(nullptr); | |
| childWindowClass.hIcon = nullptr; | |
| childWindowClass.hCursor = LoadCursorA(nullptr, idcArrow); | |
| childWindowClass.hbrBackground = 0; | |
| childWindowClass.lpszMenuName = nullptr; | |
| childWindowClass.lpszClassName = mChildClassName.c_str(); | |
| if (!RegisterClassExA(&childWindowClass)) | |
| { | |
| return false; | |
| } | |
| DWORD parentStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU; | |
| DWORD parentExtendedStyle = WS_EX_APPWINDOW | WS_EX_TOOLWINDOW; | |
| RECT sizeRect = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)}; | |
| AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle); | |
| mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(), | |
| parentStyle, CW_USEDEFAULT, CW_USEDEFAULT, | |
| sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, | |
| nullptr, nullptr, GetModuleHandle(nullptr), this); | |
| mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_CHILD, 0, 0, | |
| static_cast<int>(width), static_cast<int>(height), | |
| mParentWindow, nullptr, GetModuleHandle(nullptr), this); | |
| mNativeDisplay = GetDC(mNativeWindow); | |
| if (!mNativeDisplay) | |
| { | |
| destroy(); | |
| return false; | |
| } | |
| return true; | |
| } | |
| void Win32Window::destroy() | |
| { | |
| if (mNativeDisplay) | |
| { | |
| ReleaseDC(mNativeWindow, mNativeDisplay); | |
| mNativeDisplay = 0; | |
| } | |
| if (mNativeWindow) | |
| { | |
| DestroyWindow(mNativeWindow); | |
| mNativeWindow = 0; | |
| } | |
| if (mParentWindow) | |
| { | |
| DestroyWindow(mParentWindow); | |
| mParentWindow = 0; | |
| } | |
| UnregisterClassA(mParentClassName.c_str(), nullptr); | |
| UnregisterClassA(mChildClassName.c_str(), nullptr); | |
| } | |
| bool Win32Window::takeScreenshot(uint8_t *pixelData) | |
| { | |
| if (mIsVisible) | |
| { | |
| return false; | |
| } | |
| bool error = false; | |
| // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait | |
| // for a while before issuing screenshot if window was just made visible. | |
| { | |
| static const double WAIT_WINDOW_VISIBLE_MS = 0.5; // Half a second for the animation | |
| double timeSinceVisible = mSetVisibleTimer.getElapsedTime(); | |
| if (timeSinceVisible < WAIT_WINDOW_VISIBLE_MS) | |
| { | |
| Sleep(static_cast<DWORD>((WAIT_WINDOW_VISIBLE_MS - timeSinceVisible) * 1000)); | |
| } | |
| } | |
| HDC screenDC = nullptr; | |
| HDC windowDC = nullptr; | |
| HDC tmpDC = nullptr; | |
| HBITMAP tmpBitmap = nullptr; | |
| if (!error) | |
| { | |
| screenDC = GetDC(HWND_DESKTOP); | |
| error = screenDC == nullptr; | |
| } | |
| if (!error) | |
| { | |
| windowDC = GetDC(mNativeWindow); | |
| error = windowDC == nullptr; | |
| } | |
| if (!error) | |
| { | |
| tmpDC = CreateCompatibleDC(screenDC); | |
| error = tmpDC == nullptr; | |
| } | |
| if (!error) | |
| { | |
| tmpBitmap = CreateCompatibleBitmap(screenDC, mWidth, mHeight); | |
| error = tmpBitmap == nullptr; | |
| } | |
| POINT topLeft = {0, 0}; | |
| if (!error) | |
| { | |
| error = (MapWindowPoints(mNativeWindow, HWND_DESKTOP, &topLeft, 1) == 0); | |
| } | |
| if (!error) | |
| { | |
| error = SelectObject(tmpDC, tmpBitmap) == nullptr; | |
| } | |
| if (!error) | |
| { | |
| error = BitBlt(tmpDC, 0, 0, mWidth, mHeight, screenDC, topLeft.x, topLeft.y, SRCCOPY) == 0; | |
| } | |
| if (!error) | |
| { | |
| BITMAPINFOHEADER bitmapInfo; | |
| bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); | |
| bitmapInfo.biWidth = mWidth; | |
| bitmapInfo.biHeight = -mHeight; | |
| bitmapInfo.biPlanes = 1; | |
| bitmapInfo.biBitCount = 32; | |
| bitmapInfo.biCompression = BI_RGB; | |
| bitmapInfo.biSizeImage = 0; | |
| bitmapInfo.biXPelsPerMeter = 0; | |
| bitmapInfo.biYPelsPerMeter = 0; | |
| bitmapInfo.biClrUsed = 0; | |
| bitmapInfo.biClrImportant = 0; | |
| int getBitsResult = GetDIBits(screenDC, tmpBitmap, 0, mHeight, pixelData, | |
| reinterpret_cast<BITMAPINFO *>(&bitmapInfo), DIB_RGB_COLORS); | |
| error = (getBitsResult == 0); | |
| } | |
| if (tmpBitmap != nullptr) | |
| { | |
| DeleteObject(tmpBitmap); | |
| } | |
| if (tmpDC != nullptr) | |
| { | |
| DeleteDC(tmpDC); | |
| } | |
| if (screenDC != nullptr) | |
| { | |
| ReleaseDC(nullptr, screenDC); | |
| } | |
| if (windowDC != nullptr) | |
| { | |
| ReleaseDC(mNativeWindow, windowDC); | |
| } | |
| return !error; | |
| } | |
| void Win32Window::resetNativeWindow() {} | |
| EGLNativeWindowType Win32Window::getNativeWindow() const | |
| { | |
| return mNativeWindow; | |
| } | |
| EGLNativeDisplayType Win32Window::getNativeDisplay() const | |
| { | |
| return mNativeDisplay; | |
| } | |
| void Win32Window::messageLoop() | |
| { | |
| MSG msg; | |
| while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) | |
| { | |
| TranslateMessage(&msg); | |
| DispatchMessage(&msg); | |
| } | |
| } | |
| void Win32Window::setMousePosition(int x, int y) | |
| { | |
| RECT winRect; | |
| GetClientRect(mNativeWindow, &winRect); | |
| POINT topLeft; | |
| topLeft.x = winRect.left; | |
| topLeft.y = winRect.top; | |
| ClientToScreen(mNativeWindow, &topLeft); | |
| SetCursorPos(topLeft.x + x, topLeft.y + y); | |
| } | |
| bool Win32Window::setPosition(int x, int y) | |
| { | |
| if (mX == x && mY == y) | |
| { | |
| return true; | |
| } | |
| RECT windowRect; | |
| if (!GetWindowRect(mParentWindow, &windowRect)) | |
| { | |
| return false; | |
| } | |
| if (!MoveWindow(mParentWindow, x, y, windowRect.right - windowRect.left, | |
| windowRect.bottom - windowRect.top, TRUE)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool Win32Window::resize(int width, int height) | |
| { | |
| if (width == mWidth && height == mHeight) | |
| { | |
| return true; | |
| } | |
| RECT windowRect; | |
| if (!GetWindowRect(mParentWindow, &windowRect)) | |
| { | |
| return false; | |
| } | |
| RECT clientRect; | |
| if (!GetClientRect(mParentWindow, &clientRect)) | |
| { | |
| return false; | |
| } | |
| LONG diffX = (windowRect.right - windowRect.left) - clientRect.right; | |
| LONG diffY = (windowRect.bottom - windowRect.top) - clientRect.bottom; | |
| if (!MoveWindow(mParentWindow, windowRect.left, windowRect.top, width + diffX, height + diffY, | |
| TRUE)) | |
| { | |
| return false; | |
| } | |
| if (!MoveWindow(mNativeWindow, 0, 0, width, height, FALSE)) | |
| { | |
| return false; | |
| } | |
| return true; | |
| } | |
| void Win32Window::setVisible(bool isVisible) | |
| { | |
| int flag = (isVisible ? SW_SHOW : SW_HIDE); | |
| ShowWindow(mParentWindow, flag); | |
| ShowWindow(mNativeWindow, flag); | |
| if (isVisible) | |
| { | |
| mSetVisibleTimer.stop(); | |
| mSetVisibleTimer.start(); | |
| } | |
| } | |
| void Win32Window::pushEvent(Event event) | |
| { | |
| OSWindow::pushEvent(event); | |
| switch (event.Type) | |
| { | |
| case Event::EVENT_RESIZED: | |
| MoveWindow(mNativeWindow, 0, 0, mWidth, mHeight, FALSE); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void Win32Window::signalTestEvent() | |
| { | |
| PostMessage(mNativeWindow, WM_USER, 0, 0); | |
| } | |
| // static | |
| OSWindow *OSWindow::New() | |
| { | |
| return new Win32Window(); | |
| } |