Path: blob/main_old/util/windows/win32/Win32Window.cpp
1693 views
//1// Copyright 2014 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56// Win32Window.cpp: Implementation of OSWindow for Win32 (Windows)78#include "util/windows/win32/Win32Window.h"910#include <crtdbg.h>11#include <sstream>1213#include "common/debug.h"1415Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags)16{17switch (key)18{19// Check the scancode to distinguish between left and right shift20case VK_SHIFT:21{22static unsigned int lShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);23unsigned int scancode = static_cast<unsigned int>((flags & (0xFF << 16)) >> 16);24return scancode == lShift ? KEY_LSHIFT : KEY_RSHIFT;25}2627// Check the "extended" flag to distinguish between left and right alt28case VK_MENU:29return (HIWORD(flags) & KF_EXTENDED) ? KEY_RALT : KEY_LALT;3031// Check the "extended" flag to distinguish between left and right control32case VK_CONTROL:33return (HIWORD(flags) & KF_EXTENDED) ? KEY_RCONTROL : KEY_LCONTROL;3435// Other keys are reported properly36case VK_LWIN:37return KEY_LSYSTEM;38case VK_RWIN:39return KEY_RSYSTEM;40case VK_APPS:41return KEY_MENU;42case VK_OEM_1:43return KEY_SEMICOLON;44case VK_OEM_2:45return KEY_SLASH;46case VK_OEM_PLUS:47return KEY_EQUAL;48case VK_OEM_MINUS:49return KEY_DASH;50case VK_OEM_4:51return KEY_LBRACKET;52case VK_OEM_6:53return KEY_RBRACKET;54case VK_OEM_COMMA:55return KEY_COMMA;56case VK_OEM_PERIOD:57return KEY_PERIOD;58case VK_OEM_7:59return KEY_QUOTE;60case VK_OEM_5:61return KEY_BACKSLASH;62case VK_OEM_3:63return KEY_TILDE;64case VK_ESCAPE:65return KEY_ESCAPE;66case VK_SPACE:67return KEY_SPACE;68case VK_RETURN:69return KEY_RETURN;70case VK_BACK:71return KEY_BACK;72case VK_TAB:73return KEY_TAB;74case VK_PRIOR:75return KEY_PAGEUP;76case VK_NEXT:77return KEY_PAGEDOWN;78case VK_END:79return KEY_END;80case VK_HOME:81return KEY_HOME;82case VK_INSERT:83return KEY_INSERT;84case VK_DELETE:85return KEY_DELETE;86case VK_ADD:87return KEY_ADD;88case VK_SUBTRACT:89return KEY_SUBTRACT;90case VK_MULTIPLY:91return KEY_MULTIPLY;92case VK_DIVIDE:93return KEY_DIVIDE;94case VK_PAUSE:95return KEY_PAUSE;96case VK_F1:97return KEY_F1;98case VK_F2:99return KEY_F2;100case VK_F3:101return KEY_F3;102case VK_F4:103return KEY_F4;104case VK_F5:105return KEY_F5;106case VK_F6:107return KEY_F6;108case VK_F7:109return KEY_F7;110case VK_F8:111return KEY_F8;112case VK_F9:113return KEY_F9;114case VK_F10:115return KEY_F10;116case VK_F11:117return KEY_F11;118case VK_F12:119return KEY_F12;120case VK_F13:121return KEY_F13;122case VK_F14:123return KEY_F14;124case VK_F15:125return KEY_F15;126case VK_LEFT:127return KEY_LEFT;128case VK_RIGHT:129return KEY_RIGHT;130case VK_UP:131return KEY_UP;132case VK_DOWN:133return KEY_DOWN;134case VK_NUMPAD0:135return KEY_NUMPAD0;136case VK_NUMPAD1:137return KEY_NUMPAD1;138case VK_NUMPAD2:139return KEY_NUMPAD2;140case VK_NUMPAD3:141return KEY_NUMPAD3;142case VK_NUMPAD4:143return KEY_NUMPAD4;144case VK_NUMPAD5:145return KEY_NUMPAD5;146case VK_NUMPAD6:147return KEY_NUMPAD6;148case VK_NUMPAD7:149return KEY_NUMPAD7;150case VK_NUMPAD8:151return KEY_NUMPAD8;152case VK_NUMPAD9:153return KEY_NUMPAD9;154case 'A':155return KEY_A;156case 'Z':157return KEY_Z;158case 'E':159return KEY_E;160case 'R':161return KEY_R;162case 'T':163return KEY_T;164case 'Y':165return KEY_Y;166case 'U':167return KEY_U;168case 'I':169return KEY_I;170case 'O':171return KEY_O;172case 'P':173return KEY_P;174case 'Q':175return KEY_Q;176case 'S':177return KEY_S;178case 'D':179return KEY_D;180case 'F':181return KEY_F;182case 'G':183return KEY_G;184case 'H':185return KEY_H;186case 'J':187return KEY_J;188case 'K':189return KEY_K;190case 'L':191return KEY_L;192case 'M':193return KEY_M;194case 'W':195return KEY_W;196case 'X':197return KEY_X;198case 'C':199return KEY_C;200case 'V':201return KEY_V;202case 'B':203return KEY_B;204case 'N':205return KEY_N;206case '0':207return KEY_NUM0;208case '1':209return KEY_NUM1;210case '2':211return KEY_NUM2;212case '3':213return KEY_NUM3;214case '4':215return KEY_NUM4;216case '5':217return KEY_NUM5;218case '6':219return KEY_NUM6;220case '7':221return KEY_NUM7;222case '8':223return KEY_NUM8;224case '9':225return KEY_NUM9;226}227228return Key(0);229}230231LRESULT CALLBACK Win32Window::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)232{233switch (message)234{235case WM_NCCREATE:236{237LPCREATESTRUCT pCreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);238SetWindowLongPtr(hWnd, GWLP_USERDATA,239reinterpret_cast<LONG_PTR>(pCreateStruct->lpCreateParams));240return DefWindowProcA(hWnd, message, wParam, lParam);241}242}243244Win32Window *window = reinterpret_cast<Win32Window *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));245if (window)246{247switch (message)248{249case WM_DESTROY:250case WM_CLOSE:251{252Event event;253event.Type = Event::EVENT_CLOSED;254window->pushEvent(event);255break;256}257258case WM_MOVE:259{260RECT winRect;261GetClientRect(hWnd, &winRect);262263POINT topLeft;264topLeft.x = winRect.left;265topLeft.y = winRect.top;266ClientToScreen(hWnd, &topLeft);267268Event event;269event.Type = Event::EVENT_MOVED;270event.Move.X = topLeft.x;271event.Move.Y = topLeft.y;272window->pushEvent(event);273274break;275}276277case WM_SIZE:278{279if (window->mIgnoreSizeEvents)280break;281282RECT winRect;283GetClientRect(hWnd, &winRect);284285POINT topLeft;286topLeft.x = winRect.left;287topLeft.y = winRect.top;288ClientToScreen(hWnd, &topLeft);289290POINT botRight;291botRight.x = winRect.right;292botRight.y = winRect.bottom;293ClientToScreen(hWnd, &botRight);294295Event event;296event.Type = Event::EVENT_RESIZED;297event.Size.Width = botRight.x - topLeft.x;298event.Size.Height = botRight.y - topLeft.y;299window->pushEvent(event);300301break;302}303304case WM_SETFOCUS:305{306Event event;307event.Type = Event::EVENT_GAINED_FOCUS;308window->pushEvent(event);309break;310}311312case WM_KILLFOCUS:313{314Event event;315event.Type = Event::EVENT_LOST_FOCUS;316window->pushEvent(event);317break;318}319320case WM_KEYDOWN:321case WM_SYSKEYDOWN:322case WM_KEYUP:323case WM_SYSKEYUP:324{325bool down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);326327Event event;328event.Type = down ? Event::EVENT_KEY_PRESSED : Event::EVENT_KEY_RELEASED;329event.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0;330event.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;331event.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0;332event.Key.System =333HIWORD(GetAsyncKeyState(VK_LWIN)) || HIWORD(GetAsyncKeyState(VK_RWIN));334event.Key.Code = VirtualKeyCodeToKey(wParam, lParam);335window->pushEvent(event);336337break;338}339340case WM_MOUSEWHEEL:341{342Event event;343event.Type = Event::EVENT_MOUSE_WHEEL_MOVED;344event.MouseWheel.Delta = static_cast<short>(HIWORD(wParam)) / 120;345window->pushEvent(event);346break;347}348349case WM_LBUTTONDOWN:350case WM_LBUTTONDBLCLK:351{352Event event;353event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;354event.MouseButton.Button = MOUSEBUTTON_LEFT;355event.MouseButton.X = static_cast<short>(LOWORD(lParam));356event.MouseButton.Y = static_cast<short>(HIWORD(lParam));357window->pushEvent(event);358break;359}360361case WM_LBUTTONUP:362{363Event event;364event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;365event.MouseButton.Button = MOUSEBUTTON_LEFT;366event.MouseButton.X = static_cast<short>(LOWORD(lParam));367event.MouseButton.Y = static_cast<short>(HIWORD(lParam));368window->pushEvent(event);369break;370}371372case WM_RBUTTONDOWN:373case WM_RBUTTONDBLCLK:374{375Event event;376event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;377event.MouseButton.Button = MOUSEBUTTON_RIGHT;378event.MouseButton.X = static_cast<short>(LOWORD(lParam));379event.MouseButton.Y = static_cast<short>(HIWORD(lParam));380window->pushEvent(event);381break;382}383384// Mouse right button up event385case WM_RBUTTONUP:386{387Event event;388event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;389event.MouseButton.Button = MOUSEBUTTON_RIGHT;390event.MouseButton.X = static_cast<short>(LOWORD(lParam));391event.MouseButton.Y = static_cast<short>(HIWORD(lParam));392window->pushEvent(event);393break;394}395396// Mouse wheel button down event397case WM_MBUTTONDOWN:398case WM_MBUTTONDBLCLK:399{400Event event;401event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;402event.MouseButton.Button = MOUSEBUTTON_MIDDLE;403event.MouseButton.X = static_cast<short>(LOWORD(lParam));404event.MouseButton.Y = static_cast<short>(HIWORD(lParam));405window->pushEvent(event);406break;407}408409// Mouse wheel button up event410case WM_MBUTTONUP:411{412Event event;413event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;414event.MouseButton.Button = MOUSEBUTTON_MIDDLE;415event.MouseButton.X = static_cast<short>(LOWORD(lParam));416event.MouseButton.Y = static_cast<short>(HIWORD(lParam));417window->pushEvent(event);418break;419}420421// Mouse X button down event422case WM_XBUTTONDOWN:423case WM_XBUTTONDBLCLK:424{425Event event;426event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;427event.MouseButton.Button =428(HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;429event.MouseButton.X = static_cast<short>(LOWORD(lParam));430event.MouseButton.Y = static_cast<short>(HIWORD(lParam));431window->pushEvent(event);432break;433}434435// Mouse X button up event436case WM_XBUTTONUP:437{438Event event;439event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;440event.MouseButton.Button =441(HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;442event.MouseButton.X = static_cast<short>(LOWORD(lParam));443event.MouseButton.Y = static_cast<short>(HIWORD(lParam));444window->pushEvent(event);445break;446}447448case WM_MOUSEMOVE:449{450if (!window->mIsMouseInWindow)451{452window->mIsMouseInWindow = true;453Event event;454event.Type = Event::EVENT_MOUSE_ENTERED;455window->pushEvent(event);456}457458int mouseX = static_cast<short>(LOWORD(lParam));459int mouseY = static_cast<short>(HIWORD(lParam));460461Event event;462event.Type = Event::EVENT_MOUSE_MOVED;463event.MouseMove.X = mouseX;464event.MouseMove.Y = mouseY;465window->pushEvent(event);466break;467}468469case WM_MOUSELEAVE:470{471Event event;472event.Type = Event::EVENT_MOUSE_LEFT;473window->pushEvent(event);474window->mIsMouseInWindow = false;475break;476}477478case WM_USER:479{480Event testEvent;481testEvent.Type = Event::EVENT_TEST;482window->pushEvent(testEvent);483break;484}485}486}487return DefWindowProcA(hWnd, message, wParam, lParam);488}489490Win32Window::Win32Window()491: mIsVisible(false),492mIsMouseInWindow(false),493mNativeWindow(0),494mParentWindow(0),495mNativeDisplay(0)496{}497498Win32Window::~Win32Window()499{500destroy();501}502503bool Win32Window::initializeImpl(const std::string &name, int width, int height)504{505destroy();506507// Use a new window class name for ever window to ensure that a new window can be created508// even if the last one was not properly destroyed509static size_t windowIdx = 0;510std::ostringstream nameStream;511nameStream << name << "_" << windowIdx++;512513mParentClassName = nameStream.str();514mChildClassName = mParentClassName + "_Child";515516// Work around compile error from not defining "UNICODE" while Chromium does517const LPSTR idcArrow = MAKEINTRESOURCEA(32512);518519WNDCLASSEXA parentWindowClass = {};520parentWindowClass.cbSize = sizeof(WNDCLASSEXA);521parentWindowClass.style = 0;522parentWindowClass.lpfnWndProc = WndProc;523parentWindowClass.cbClsExtra = 0;524parentWindowClass.cbWndExtra = 0;525parentWindowClass.hInstance = GetModuleHandle(nullptr);526parentWindowClass.hIcon = nullptr;527parentWindowClass.hCursor = LoadCursorA(nullptr, idcArrow);528parentWindowClass.hbrBackground = 0;529parentWindowClass.lpszMenuName = nullptr;530parentWindowClass.lpszClassName = mParentClassName.c_str();531if (!RegisterClassExA(&parentWindowClass))532{533return false;534}535536WNDCLASSEXA childWindowClass = {};537childWindowClass.cbSize = sizeof(WNDCLASSEXA);538childWindowClass.style = CS_OWNDC;539childWindowClass.lpfnWndProc = WndProc;540childWindowClass.cbClsExtra = 0;541childWindowClass.cbWndExtra = 0;542childWindowClass.hInstance = GetModuleHandle(nullptr);543childWindowClass.hIcon = nullptr;544childWindowClass.hCursor = LoadCursorA(nullptr, idcArrow);545childWindowClass.hbrBackground = 0;546childWindowClass.lpszMenuName = nullptr;547childWindowClass.lpszClassName = mChildClassName.c_str();548if (!RegisterClassExA(&childWindowClass))549{550return false;551}552553DWORD parentStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;554DWORD parentExtendedStyle = WS_EX_APPWINDOW | WS_EX_TOOLWINDOW;555556RECT sizeRect = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};557AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle);558559mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(),560parentStyle, CW_USEDEFAULT, CW_USEDEFAULT,561sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top,562nullptr, nullptr, GetModuleHandle(nullptr), this);563564mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_CHILD, 0, 0,565static_cast<int>(width), static_cast<int>(height),566mParentWindow, nullptr, GetModuleHandle(nullptr), this);567568mNativeDisplay = GetDC(mNativeWindow);569if (!mNativeDisplay)570{571destroy();572return false;573}574575return true;576}577578void Win32Window::disableErrorMessageDialog()579{580_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);581_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);582}583584void Win32Window::destroy()585{586if (mNativeDisplay)587{588ReleaseDC(mNativeWindow, mNativeDisplay);589mNativeDisplay = 0;590}591592if (mNativeWindow)593{594DestroyWindow(mNativeWindow);595mNativeWindow = 0;596}597598if (mParentWindow)599{600DestroyWindow(mParentWindow);601mParentWindow = 0;602}603604UnregisterClassA(mParentClassName.c_str(), nullptr);605UnregisterClassA(mChildClassName.c_str(), nullptr);606}607608bool Win32Window::takeScreenshot(uint8_t *pixelData)609{610if (mIsVisible)611{612return false;613}614615bool error = false;616617// Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait618// for a while before issuing screenshot if window was just made visible.619{620static const double WAIT_WINDOW_VISIBLE_MS = 0.5; // Half a second for the animation621double timeSinceVisible = mSetVisibleTimer.getElapsedTime();622623if (timeSinceVisible < WAIT_WINDOW_VISIBLE_MS)624{625Sleep(static_cast<DWORD>((WAIT_WINDOW_VISIBLE_MS - timeSinceVisible) * 1000));626}627}628629HDC screenDC = nullptr;630HDC windowDC = nullptr;631HDC tmpDC = nullptr;632HBITMAP tmpBitmap = nullptr;633634if (!error)635{636screenDC = GetDC(HWND_DESKTOP);637error = screenDC == nullptr;638}639640if (!error)641{642windowDC = GetDC(mNativeWindow);643error = windowDC == nullptr;644}645646if (!error)647{648tmpDC = CreateCompatibleDC(screenDC);649error = tmpDC == nullptr;650}651652if (!error)653{654tmpBitmap = CreateCompatibleBitmap(screenDC, mWidth, mHeight);655error = tmpBitmap == nullptr;656}657658POINT topLeft = {0, 0};659if (!error)660{661error = (MapWindowPoints(mNativeWindow, HWND_DESKTOP, &topLeft, 1) == 0);662}663664if (!error)665{666error = SelectObject(tmpDC, tmpBitmap) == nullptr;667}668669if (!error)670{671error = BitBlt(tmpDC, 0, 0, mWidth, mHeight, screenDC, topLeft.x, topLeft.y, SRCCOPY) == 0;672}673674if (!error)675{676BITMAPINFOHEADER bitmapInfo;677bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);678bitmapInfo.biWidth = mWidth;679bitmapInfo.biHeight = -mHeight;680bitmapInfo.biPlanes = 1;681bitmapInfo.biBitCount = 32;682bitmapInfo.biCompression = BI_RGB;683bitmapInfo.biSizeImage = 0;684bitmapInfo.biXPelsPerMeter = 0;685bitmapInfo.biYPelsPerMeter = 0;686bitmapInfo.biClrUsed = 0;687bitmapInfo.biClrImportant = 0;688int getBitsResult = GetDIBits(screenDC, tmpBitmap, 0, mHeight, pixelData,689reinterpret_cast<BITMAPINFO *>(&bitmapInfo), DIB_RGB_COLORS);690error = (getBitsResult == 0);691}692693if (tmpBitmap != nullptr)694{695DeleteObject(tmpBitmap);696}697if (tmpDC != nullptr)698{699DeleteDC(tmpDC);700}701if (screenDC != nullptr)702{703ReleaseDC(nullptr, screenDC);704}705if (windowDC != nullptr)706{707ReleaseDC(mNativeWindow, windowDC);708}709710return !error;711}712713void Win32Window::resetNativeWindow() {}714715EGLNativeWindowType Win32Window::getNativeWindow() const716{717return mNativeWindow;718}719720EGLNativeDisplayType Win32Window::getNativeDisplay() const721{722return mNativeDisplay;723}724725void Win32Window::messageLoop()726{727MSG msg;728while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))729{730TranslateMessage(&msg);731DispatchMessage(&msg);732}733}734735void Win32Window::setMousePosition(int x, int y)736{737RECT winRect;738GetClientRect(mNativeWindow, &winRect);739740POINT topLeft;741topLeft.x = winRect.left;742topLeft.y = winRect.top;743ClientToScreen(mNativeWindow, &topLeft);744745SetCursorPos(topLeft.x + x, topLeft.y + y);746}747748bool Win32Window::setOrientation(int width, int height)749{750UNIMPLEMENTED();751return false;752}753754bool Win32Window::setPosition(int x, int y)755{756if (mX == x && mY == y)757{758return true;759}760761RECT windowRect;762if (!GetWindowRect(mParentWindow, &windowRect))763{764return false;765}766767if (!MoveWindow(mParentWindow, x, y, windowRect.right - windowRect.left,768windowRect.bottom - windowRect.top, TRUE))769{770return false;771}772773return true;774}775776bool Win32Window::resize(int width, int height)777{778if (width == mWidth && height == mHeight)779{780return true;781}782783RECT windowRect;784if (!GetWindowRect(mParentWindow, &windowRect))785{786return false;787}788789RECT clientRect;790if (!GetClientRect(mParentWindow, &clientRect))791{792return false;793}794795LONG diffX = (windowRect.right - windowRect.left) - clientRect.right;796LONG diffY = (windowRect.bottom - windowRect.top) - clientRect.bottom;797if (!MoveWindow(mParentWindow, windowRect.left, windowRect.top, width + diffX, height + diffY,798TRUE))799{800return false;801}802803if (!MoveWindow(mNativeWindow, 0, 0, width, height, FALSE))804{805return false;806}807808return true;809}810811void Win32Window::setVisible(bool isVisible)812{813int flag = (isVisible ? SW_SHOW : SW_HIDE);814815ShowWindow(mParentWindow, flag);816ShowWindow(mNativeWindow, flag);817818if (isVisible)819{820mSetVisibleTimer.stop();821mSetVisibleTimer.start();822}823}824825void Win32Window::pushEvent(Event event)826{827OSWindow::pushEvent(event);828829switch (event.Type)830{831case Event::EVENT_RESIZED:832MoveWindow(mNativeWindow, 0, 0, mWidth, mHeight, FALSE);833break;834default:835break;836}837}838839void Win32Window::signalTestEvent()840{841PostMessage(mNativeWindow, WM_USER, 0, 0);842}843844// static845OSWindow *OSWindow::New()846{847return new Win32Window();848}849850851