diff options
Diffstat (limited to 'Source/ThirdParty/ANGLE/util/windows/win32/Win32Window.cpp')
-rw-r--r-- | Source/ThirdParty/ANGLE/util/windows/win32/Win32Window.cpp | 831 |
1 files changed, 831 insertions, 0 deletions
diff --git a/Source/ThirdParty/ANGLE/util/windows/win32/Win32Window.cpp b/Source/ThirdParty/ANGLE/util/windows/win32/Win32Window.cpp new file mode 100644 index 000000000..abd1132b2 --- /dev/null +++ b/Source/ThirdParty/ANGLE/util/windows/win32/Win32Window.cpp @@ -0,0 +1,831 @@ +// +// Copyright (c) 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 "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), + mSetVisibleTimer(CreateTimer()), + mIsMouseInWindow(false), + mNativeWindow(0), + mParentWindow(0), + mNativeDisplay(0) +{ +} + +Win32Window::~Win32Window() +{ + destroy(); + delete mSetVisibleTimer; +} + +bool Win32Window::initialize(const std::string &name, size_t width, size_t 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 = {0}; + parentWindowClass.cbSize = sizeof(WNDCLASSEXA); + parentWindowClass.style = 0; + parentWindowClass.lpfnWndProc = WndProc; + parentWindowClass.cbClsExtra = 0; + parentWindowClass.cbWndExtra = 0; + parentWindowClass.hInstance = GetModuleHandle(NULL); + parentWindowClass.hIcon = NULL; + parentWindowClass.hCursor = LoadCursorA(NULL, idcArrow); + parentWindowClass.hbrBackground = 0; + parentWindowClass.lpszMenuName = NULL; + parentWindowClass.lpszClassName = mParentClassName.c_str(); + if (!RegisterClassExA(&parentWindowClass)) + { + return false; + } + + WNDCLASSEXA childWindowClass = {0}; + childWindowClass.cbSize = sizeof(WNDCLASSEXA); + childWindowClass.style = CS_OWNDC; + childWindowClass.lpfnWndProc = WndProc; + childWindowClass.cbClsExtra = 0; + childWindowClass.cbWndExtra = 0; + childWindowClass.hInstance = GetModuleHandle(NULL); + childWindowClass.hIcon = NULL; + childWindowClass.hCursor = LoadCursorA(NULL, idcArrow); + childWindowClass.hbrBackground = 0; + childWindowClass.lpszMenuName = NULL; + 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; + + 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, NULL, NULL, GetModuleHandle(NULL), this); + + mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_CHILD, 0, 0, + static_cast<int>(width), static_cast<int>(height), + mParentWindow, NULL, GetModuleHandle(NULL), 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(), NULL); + UnregisterClassA(mChildClassName.c_str(), NULL); +} + +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(nullptr); + 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; + } + + RECT rect = {0, 0, 0, 0}; + if (!error) + { + MapWindowPoints(mNativeWindow, nullptr, reinterpret_cast<LPPOINT>(&rect), 0); + + error = SelectObject(tmpDC, tmpBitmap) == nullptr; + } + + if (!error) + { + error = + BitBlt(tmpDC, 0, 0, mWidth, mHeight, screenDC, rect.left, rect.top, SRCCOPY) == TRUE; + } + + 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; +} + +EGLNativeWindowType Win32Window::getNativeWindow() const +{ + return mNativeWindow; +} + +EGLNativeDisplayType Win32Window::getNativeDisplay() const +{ + return mNativeDisplay; +} + +void Win32Window::messageLoop() +{ + MSG msg; + while (PeekMessage(&msg, NULL, 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); +} + +OSWindow *CreateOSWindow() +{ + return new Win32Window(); +} + +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); +} |