2 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
7 #include "win32/Win32Window.h"
11 Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags)
15 // Check the scancode to distinguish between left and right shift
18 static unsigned int lShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
19 unsigned int scancode = static_cast<unsigned int>((flags & (0xFF << 16)) >> 16);
20 return scancode == lShift ? KEY_LSHIFT : KEY_RSHIFT;
23 // Check the "extended" flag to distinguish between left and right alt
24 case VK_MENU: return (HIWORD(flags) & KF_EXTENDED) ? KEY_RALT : KEY_LALT;
26 // Check the "extended" flag to distinguish between left and right control
27 case VK_CONTROL: return (HIWORD(flags) & KF_EXTENDED) ? KEY_RCONTROL : KEY_LCONTROL;
29 // Other keys are reported properly
30 case VK_LWIN: return KEY_LSYSTEM;
31 case VK_RWIN: return KEY_RSYSTEM;
32 case VK_APPS: return KEY_MENU;
33 case VK_OEM_1: return KEY_SEMICOLON;
34 case VK_OEM_2: return KEY_SLASH;
35 case VK_OEM_PLUS: return KEY_EQUAL;
36 case VK_OEM_MINUS: return KEY_DASH;
37 case VK_OEM_4: return KEY_LBRACKET;
38 case VK_OEM_6: return KEY_RBRACKET;
39 case VK_OEM_COMMA: return KEY_COMMA;
40 case VK_OEM_PERIOD: return KEY_PERIOD;
41 case VK_OEM_7: return KEY_QUOTE;
42 case VK_OEM_5: return KEY_BACKSLASH;
43 case VK_OEM_3: return KEY_TILDE;
44 case VK_ESCAPE: return KEY_ESCAPE;
45 case VK_SPACE: return KEY_SPACE;
46 case VK_RETURN: return KEY_RETURN;
47 case VK_BACK: return KEY_BACK;
48 case VK_TAB: return KEY_TAB;
49 case VK_PRIOR: return KEY_PAGEUP;
50 case VK_NEXT: return KEY_PAGEDOWN;
51 case VK_END: return KEY_END;
52 case VK_HOME: return KEY_HOME;
53 case VK_INSERT: return KEY_INSERT;
54 case VK_DELETE: return KEY_DELETE;
55 case VK_ADD: return KEY_ADD;
56 case VK_SUBTRACT: return KEY_SUBTRACT;
57 case VK_MULTIPLY: return KEY_MULTIPLY;
58 case VK_DIVIDE: return KEY_DIVIDE;
59 case VK_PAUSE: return KEY_PAUSE;
60 case VK_F1: return KEY_F1;
61 case VK_F2: return KEY_F2;
62 case VK_F3: return KEY_F3;
63 case VK_F4: return KEY_F4;
64 case VK_F5: return KEY_F5;
65 case VK_F6: return KEY_F6;
66 case VK_F7: return KEY_F7;
67 case VK_F8: return KEY_F8;
68 case VK_F9: return KEY_F9;
69 case VK_F10: return KEY_F10;
70 case VK_F11: return KEY_F11;
71 case VK_F12: return KEY_F12;
72 case VK_F13: return KEY_F13;
73 case VK_F14: return KEY_F14;
74 case VK_F15: return KEY_F15;
75 case VK_LEFT: return KEY_LEFT;
76 case VK_RIGHT: return KEY_RIGHT;
77 case VK_UP: return KEY_UP;
78 case VK_DOWN: return KEY_DOWN;
79 case VK_NUMPAD0: return KEY_NUMPAD0;
80 case VK_NUMPAD1: return KEY_NUMPAD1;
81 case VK_NUMPAD2: return KEY_NUMPAD2;
82 case VK_NUMPAD3: return KEY_NUMPAD3;
83 case VK_NUMPAD4: return KEY_NUMPAD4;
84 case VK_NUMPAD5: return KEY_NUMPAD5;
85 case VK_NUMPAD6: return KEY_NUMPAD6;
86 case VK_NUMPAD7: return KEY_NUMPAD7;
87 case VK_NUMPAD8: return KEY_NUMPAD8;
88 case VK_NUMPAD9: return KEY_NUMPAD9;
89 case 'A': return KEY_A;
90 case 'Z': return KEY_Z;
91 case 'E': return KEY_E;
92 case 'R': return KEY_R;
93 case 'T': return KEY_T;
94 case 'Y': return KEY_Y;
95 case 'U': return KEY_U;
96 case 'I': return KEY_I;
97 case 'O': return KEY_O;
98 case 'P': return KEY_P;
99 case 'Q': return KEY_Q;
100 case 'S': return KEY_S;
101 case 'D': return KEY_D;
102 case 'F': return KEY_F;
103 case 'G': return KEY_G;
104 case 'H': return KEY_H;
105 case 'J': return KEY_J;
106 case 'K': return KEY_K;
107 case 'L': return KEY_L;
108 case 'M': return KEY_M;
109 case 'W': return KEY_W;
110 case 'X': return KEY_X;
111 case 'C': return KEY_C;
112 case 'V': return KEY_V;
113 case 'B': return KEY_B;
114 case 'N': return KEY_N;
115 case '0': return KEY_NUM0;
116 case '1': return KEY_NUM1;
117 case '2': return KEY_NUM2;
118 case '3': return KEY_NUM3;
119 case '4': return KEY_NUM4;
120 case '5': return KEY_NUM5;
121 case '6': return KEY_NUM6;
122 case '7': return KEY_NUM7;
123 case '8': return KEY_NUM8;
124 case '9': return KEY_NUM9;
130 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
136 LPCREATESTRUCT pCreateStruct = (LPCREATESTRUCT)lParam;
137 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCreateStruct->lpCreateParams);
138 return DefWindowProcA(hWnd, message, wParam, lParam);
142 OSWindow *window = (OSWindow*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
151 event.Type = Event::EVENT_CLOSED;
152 window->pushEvent(event);
159 GetClientRect(hWnd, &winRect);
162 topLeft.x = winRect.left;
163 topLeft.y = winRect.top;
164 ClientToScreen(hWnd, &topLeft);
167 event.Type = Event::EVENT_MOVED;
168 event.Move.X = topLeft.x;
169 event.Move.Y = topLeft.y;
170 window->pushEvent(event);
178 GetClientRect(hWnd, &winRect);
181 topLeft.x = winRect.left;
182 topLeft.y = winRect.top;
183 ClientToScreen(hWnd, &topLeft);
186 botRight.x = winRect.right;
187 botRight.y = winRect.bottom;
188 ClientToScreen(hWnd, &botRight);
191 event.Type = Event::EVENT_RESIZED;
192 event.Size.Width = botRight.x - topLeft.x;
193 event.Size.Height = botRight.y - topLeft.y;
194 window->pushEvent(event);
202 event.Type = Event::EVENT_GAINED_FOCUS;
203 window->pushEvent(event);
210 event.Type = Event::EVENT_LOST_FOCUS;
211 window->pushEvent(event);
220 bool down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);
223 event.Type = down ? Event::EVENT_KEY_PRESSED : Event::EVENT_KEY_RELEASED;
224 event.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0;
225 event.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
226 event.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0;
227 event.Key.System = HIWORD(GetAsyncKeyState(VK_LWIN)) || HIWORD(GetAsyncKeyState(VK_RWIN));
228 event.Key.Code = VirtualKeyCodeToKey(wParam, lParam);
229 window->pushEvent(event);
237 event.Type = Event::EVENT_MOUSE_WHEEL_MOVED;
238 event.MouseWheel.Delta = static_cast<short>(HIWORD(wParam)) / 120;
239 window->pushEvent(event);
244 case WM_LBUTTONDBLCLK:
247 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
248 event.MouseButton.Button = MOUSEBUTTON_LEFT;
249 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
250 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
251 window->pushEvent(event);
258 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
259 event.MouseButton.Button = MOUSEBUTTON_LEFT;
260 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
261 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
262 window->pushEvent(event);
267 case WM_RBUTTONDBLCLK:
270 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
271 event.MouseButton.Button = MOUSEBUTTON_RIGHT;
272 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
273 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
274 window->pushEvent(event);
278 // Mouse right button up event
282 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
283 event.MouseButton.Button = MOUSEBUTTON_RIGHT;
284 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
285 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
286 window->pushEvent(event);
290 // Mouse wheel button down event
292 case WM_MBUTTONDBLCLK:
295 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
296 event.MouseButton.Button = MOUSEBUTTON_MIDDLE;
297 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
298 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
299 window->pushEvent(event);
303 // Mouse wheel button up event
307 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
308 event.MouseButton.Button = MOUSEBUTTON_MIDDLE;
309 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
310 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
311 window->pushEvent(event);
315 // Mouse X button down event
317 case WM_XBUTTONDBLCLK:
320 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
321 event.MouseButton.Button = (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;
322 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
323 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
324 window->pushEvent(event);
328 // Mouse X button up event
332 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
333 event.MouseButton.Button = (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;
334 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
335 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
336 window->pushEvent(event);
342 int mouseX = static_cast<short>(LOWORD(lParam));
343 int mouseY = static_cast<short>(HIWORD(lParam));
346 event.Type = Event::EVENT_MOUSE_MOVED;
347 event.MouseMove.X = mouseX;
348 event.MouseMove.Y = mouseY;
349 window->pushEvent(event);
356 event.Type = Event::EVENT_MOUSE_LEFT;
357 window->pushEvent(event);
363 return DefWindowProcA(hWnd, message, wParam, lParam);
366 Win32Window::Win32Window()
373 Win32Window::~Win32Window()
378 bool Win32Window::initialize(const std::string &name, size_t width, size_t height)
382 // Use a new window class name for ever window to ensure that a new window can be created
383 // even if the last one was not properly destroyed
384 static size_t windowIdx = 0;
385 std::ostringstream nameStream;
386 nameStream << name << "_" << windowIdx++;
388 mParentClassName = nameStream.str();
389 mChildClassName = mParentClassName + "_Child";
391 // Work around compile error from not defining "UNICODE" while Chromium does
392 const LPSTR idcArrow = MAKEINTRESOURCEA(32512);
394 WNDCLASSEXA parentWindowClass = { 0 };
395 parentWindowClass.cbSize = sizeof(WNDCLASSEXA);
396 parentWindowClass.style = 0;
397 parentWindowClass.lpfnWndProc = WndProc;
398 parentWindowClass.cbClsExtra = 0;
399 parentWindowClass.cbWndExtra = 0;
400 parentWindowClass.hInstance = GetModuleHandle(NULL);
401 parentWindowClass.hIcon = NULL;
402 parentWindowClass.hCursor = LoadCursorA(NULL, idcArrow);
403 parentWindowClass.hbrBackground = 0;
404 parentWindowClass.lpszMenuName = NULL;
405 parentWindowClass.lpszClassName = mParentClassName.c_str();
406 if (!RegisterClassExA(&parentWindowClass))
411 WNDCLASSEXA childWindowClass = { 0 };
412 childWindowClass.cbSize = sizeof(WNDCLASSEXA);
413 childWindowClass.style = CS_OWNDC;
414 childWindowClass.lpfnWndProc = WndProc;
415 childWindowClass.cbClsExtra = 0;
416 childWindowClass.cbWndExtra = 0;
417 childWindowClass.hInstance = GetModuleHandle(NULL);
418 childWindowClass.hIcon = NULL;
419 childWindowClass.hCursor = LoadCursorA(NULL, idcArrow);
420 childWindowClass.hbrBackground = 0;
421 childWindowClass.lpszMenuName = NULL;
422 childWindowClass.lpszClassName = mChildClassName.c_str();
423 if (!RegisterClassExA(&childWindowClass))
428 DWORD parentStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
429 DWORD parentExtendedStyle = WS_EX_APPWINDOW;
431 RECT sizeRect = { 0, 0, width, height };
432 AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle);
434 mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(), parentStyle, CW_USEDEFAULT, CW_USEDEFAULT,
435 sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, NULL, NULL,
436 GetModuleHandle(NULL), this);
438 mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_CHILD, 0, 0, width, height,
439 mParentWindow, NULL, GetModuleHandle(NULL), this);
441 mNativeDisplay = GetDC(mNativeWindow);
451 void Win32Window::destroy()
455 ReleaseDC(mNativeWindow, mNativeDisplay);
461 DestroyWindow(mNativeWindow);
467 DestroyWindow(mParentWindow);
471 UnregisterClassA(mParentClassName.c_str(), NULL);
472 UnregisterClassA(mChildClassName.c_str(), NULL);
475 EGLNativeWindowType Win32Window::getNativeWindow() const
477 return mNativeWindow;
480 EGLNativeDisplayType Win32Window::getNativeDisplay() const
482 return mNativeDisplay;
485 void Win32Window::messageLoop()
488 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
490 TranslateMessage(&msg);
491 DispatchMessage(&msg);
495 void Win32Window::setMousePosition(int x, int y)
498 GetClientRect(mNativeWindow, &winRect);
501 topLeft.x = winRect.left;
502 topLeft.y = winRect.top;
503 ClientToScreen(mNativeWindow, &topLeft);
505 SetCursorPos(topLeft.x + x, topLeft.y + y);
508 OSWindow *CreateOSWindow()
510 return new Win32Window();
513 bool Win32Window::resize(int width, int height)
515 if (width == mWidth && height == mHeight)
521 if (!GetWindowRect(mParentWindow, &windowRect))
527 if (!GetClientRect(mParentWindow, &clientRect))
532 LONG diffX = (windowRect.right - windowRect.left) - clientRect.right;
533 LONG diffY = (windowRect.bottom - windowRect.top) - clientRect.bottom;
534 if (!MoveWindow(mParentWindow, windowRect.left, windowRect.top, width + diffX, height + diffY, FALSE))
539 if (!MoveWindow(mNativeWindow, 0, 0, width, height, FALSE))
547 void Win32Window::setVisible(bool isVisible)
549 int flag = (isVisible ? SW_SHOW : SW_HIDE);
551 ShowWindow(mParentWindow, flag);
552 ShowWindow(mNativeWindow, flag);
555 void Win32Window::pushEvent(Event event)
557 OSWindow::pushEvent(event);
561 case Event::EVENT_RESIZED:
562 MoveWindow(mNativeWindow, 0, 0, mWidth, mHeight, FALSE);