blob: ec5a0c0cac68125b99f7a54bb88441e7d034ce12 [file] [log] [blame]
Geoff Lang49be2ad2014-02-28 13:05:51 -05001//
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.
5//
6
7#include "win32/Win32Window.h"
8
9Key VirtualKeyCodeToKey(WPARAM key, LPARAM flags)
10{
11 switch (key)
12 {
13 // Check the scancode to distinguish between left and right shift
14 case VK_SHIFT:
15 {
16 static unsigned int lShift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC);
17 unsigned int scancode = static_cast<unsigned int>((flags & (0xFF << 16)) >> 16);
18 return scancode == lShift ? KEY_LSHIFT : KEY_RSHIFT;
19 }
20
21 // Check the "extended" flag to distinguish between left and right alt
22 case VK_MENU: return (HIWORD(flags) & KF_EXTENDED) ? KEY_RALT : KEY_LALT;
23
24 // Check the "extended" flag to distinguish between left and right control
25 case VK_CONTROL: return (HIWORD(flags) & KF_EXTENDED) ? KEY_RCONTROL : KEY_LCONTROL;
26
27 // Other keys are reported properly
28 case VK_LWIN: return KEY_LSYSTEM;
29 case VK_RWIN: return KEY_RSYSTEM;
30 case VK_APPS: return KEY_MENU;
31 case VK_OEM_1: return KEY_SEMICOLON;
32 case VK_OEM_2: return KEY_SLASH;
33 case VK_OEM_PLUS: return KEY_EQUAL;
34 case VK_OEM_MINUS: return KEY_DASH;
35 case VK_OEM_4: return KEY_LBRACKET;
36 case VK_OEM_6: return KEY_RBRACKET;
37 case VK_OEM_COMMA: return KEY_COMMA;
38 case VK_OEM_PERIOD: return KEY_PERIOD;
39 case VK_OEM_7: return KEY_QUOTE;
40 case VK_OEM_5: return KEY_BACKSLASH;
41 case VK_OEM_3: return KEY_TILDE;
42 case VK_ESCAPE: return KEY_ESCAPE;
43 case VK_SPACE: return KEY_SPACE;
44 case VK_RETURN: return KEY_RETURN;
45 case VK_BACK: return KEY_BACK;
46 case VK_TAB: return KEY_TAB;
47 case VK_PRIOR: return KEY_PAGEUP;
48 case VK_NEXT: return KEY_PAGEDOWN;
49 case VK_END: return KEY_END;
50 case VK_HOME: return KEY_HOME;
51 case VK_INSERT: return KEY_INSERT;
52 case VK_DELETE: return KEY_DELETE;
53 case VK_ADD: return KEY_ADD;
54 case VK_SUBTRACT: return KEY_SUBTRACT;
55 case VK_MULTIPLY: return KEY_MULTIPLY;
56 case VK_DIVIDE: return KEY_DIVIDE;
57 case VK_PAUSE: return KEY_PAUSE;
58 case VK_F1: return KEY_F1;
59 case VK_F2: return KEY_F2;
60 case VK_F3: return KEY_F3;
61 case VK_F4: return KEY_F4;
62 case VK_F5: return KEY_F5;
63 case VK_F6: return KEY_F6;
64 case VK_F7: return KEY_F7;
65 case VK_F8: return KEY_F8;
66 case VK_F9: return KEY_F9;
67 case VK_F10: return KEY_F10;
68 case VK_F11: return KEY_F11;
69 case VK_F12: return KEY_F12;
70 case VK_F13: return KEY_F13;
71 case VK_F14: return KEY_F14;
72 case VK_F15: return KEY_F15;
73 case VK_LEFT: return KEY_LEFT;
74 case VK_RIGHT: return KEY_RIGHT;
75 case VK_UP: return KEY_UP;
76 case VK_DOWN: return KEY_DOWN;
77 case VK_NUMPAD0: return KEY_NUMPAD0;
78 case VK_NUMPAD1: return KEY_NUMPAD1;
79 case VK_NUMPAD2: return KEY_NUMPAD2;
80 case VK_NUMPAD3: return KEY_NUMPAD3;
81 case VK_NUMPAD4: return KEY_NUMPAD4;
82 case VK_NUMPAD5: return KEY_NUMPAD5;
83 case VK_NUMPAD6: return KEY_NUMPAD6;
84 case VK_NUMPAD7: return KEY_NUMPAD7;
85 case VK_NUMPAD8: return KEY_NUMPAD8;
86 case VK_NUMPAD9: return KEY_NUMPAD9;
87 case 'A': return KEY_A;
88 case 'Z': return KEY_Z;
89 case 'E': return KEY_E;
90 case 'R': return KEY_R;
91 case 'T': return KEY_T;
92 case 'Y': return KEY_Y;
93 case 'U': return KEY_U;
94 case 'I': return KEY_I;
95 case 'O': return KEY_O;
96 case 'P': return KEY_P;
97 case 'Q': return KEY_Q;
98 case 'S': return KEY_S;
99 case 'D': return KEY_D;
100 case 'F': return KEY_F;
101 case 'G': return KEY_G;
102 case 'H': return KEY_H;
103 case 'J': return KEY_J;
104 case 'K': return KEY_K;
105 case 'L': return KEY_L;
106 case 'M': return KEY_M;
107 case 'W': return KEY_W;
108 case 'X': return KEY_X;
109 case 'C': return KEY_C;
110 case 'V': return KEY_V;
111 case 'B': return KEY_B;
112 case 'N': return KEY_N;
113 case '0': return KEY_NUM0;
114 case '1': return KEY_NUM1;
115 case '2': return KEY_NUM2;
116 case '3': return KEY_NUM3;
117 case '4': return KEY_NUM4;
118 case '5': return KEY_NUM5;
119 case '6': return KEY_NUM6;
120 case '7': return KEY_NUM7;
121 case '8': return KEY_NUM8;
122 case '9': return KEY_NUM9;
123 }
124
125 return Key(0);
126}
127
128LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
129{
130 switch(message)
131 {
132 case WM_NCCREATE:
133 {
134 LPCREATESTRUCT pCreateStruct = (LPCREATESTRUCT)lParam;
135 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCreateStruct->lpCreateParams);
136 return DefWindowProcA(hWnd, message, wParam, lParam);
137 }
138 }
139
Jamie Madill1cfaaf82014-08-21 10:04:04 -0400140 OSWindow *window = (OSWindow*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500141 if (window)
142 {
143 switch (message)
144 {
145 case WM_DESTROY:
146 case WM_CLOSE:
147 {
148 Event event;
149 event.Type = Event::EVENT_CLOSED;
150 window->pushEvent(event);
151 break;
152 }
153
154 case WM_MOVE:
155 {
156 RECT winRect;
157 GetClientRect(hWnd, &winRect);
158
159 POINT topLeft;
160 topLeft.x = winRect.left;
161 topLeft.y = winRect.top;
162 ClientToScreen(hWnd, &topLeft);
163
164 Event event;
165 event.Type = Event::EVENT_MOVED;
166 event.Move.X = topLeft.x;
167 event.Move.Y = topLeft.y;
168 window->pushEvent(event);
169
170 break;
171 }
172
173 case WM_SIZE:
174 {
175 RECT winRect;
176 GetClientRect(hWnd, &winRect);
177
178 POINT topLeft;
179 topLeft.x = winRect.left;
180 topLeft.y = winRect.top;
181 ClientToScreen(hWnd, &topLeft);
182
183 POINT botRight;
184 botRight.x = winRect.right;
185 botRight.y = winRect.bottom;
186 ClientToScreen(hWnd, &botRight);
187
188 Event event;
189 event.Type = Event::EVENT_RESIZED;
190 event.Size.Width = botRight.x - topLeft.x;
191 event.Size.Height = botRight.y - topLeft.y;
192 window->pushEvent(event);
193
194 break;
195 }
196
197 case WM_SETFOCUS:
198 {
199 Event event;
200 event.Type = Event::EVENT_GAINED_FOCUS;
201 window->pushEvent(event);
202 break;
203 }
204
205 case WM_KILLFOCUS:
206 {
207 Event event;
208 event.Type = Event::EVENT_LOST_FOCUS;
209 window->pushEvent(event);
210 break;
211 }
212
213 case WM_KEYDOWN:
214 case WM_SYSKEYDOWN:
215 case WM_KEYUP:
216 case WM_SYSKEYUP:
217 {
218 bool down = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN);
219
220 Event event;
221 event.Type = down ? Event::EVENT_KEY_PRESSED : Event::EVENT_KEY_RELEASED;
222 event.Key.Alt = HIWORD(GetAsyncKeyState(VK_MENU)) != 0;
223 event.Key.Control = HIWORD(GetAsyncKeyState(VK_CONTROL)) != 0;
224 event.Key.Shift = HIWORD(GetAsyncKeyState(VK_SHIFT)) != 0;
225 event.Key.System = HIWORD(GetAsyncKeyState(VK_LWIN)) || HIWORD(GetAsyncKeyState(VK_RWIN));
226 event.Key.Code = VirtualKeyCodeToKey(wParam, lParam);
227 window->pushEvent(event);
228
229 break;
230 }
231
232 case WM_MOUSEWHEEL:
233 {
234 Event event;
235 event.Type = Event::EVENT_MOUSE_WHEEL_MOVED;
236 event.MouseWheel.Delta = static_cast<short>(HIWORD(wParam)) / 120;
237 window->pushEvent(event);
238 break;
239 }
240
241 case WM_LBUTTONDOWN:
242 case WM_LBUTTONDBLCLK:
243 {
244 Event event;
245 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
246 event.MouseButton.Button = MOUSEBUTTON_LEFT;
247 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
248 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
249 window->pushEvent(event);
250 break;
251 }
252
253 case WM_LBUTTONUP:
254 {
255 Event event;
256 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
257 event.MouseButton.Button = MOUSEBUTTON_LEFT;
258 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
259 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
260 window->pushEvent(event);
261 break;
262 }
263
264 case WM_RBUTTONDOWN:
265 case WM_RBUTTONDBLCLK:
266 {
267 Event event;
268 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
269 event.MouseButton.Button = MOUSEBUTTON_RIGHT;
270 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
271 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
272 window->pushEvent(event);
273 break;
274 }
275
276 // Mouse right button up event
277 case WM_RBUTTONUP:
278 {
279 Event event;
280 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
281 event.MouseButton.Button = MOUSEBUTTON_RIGHT;
282 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
283 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
284 window->pushEvent(event);
285 break;
286 }
287
288 // Mouse wheel button down event
289 case WM_MBUTTONDOWN:
290 case WM_MBUTTONDBLCLK:
291 {
292 Event event;
293 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
294 event.MouseButton.Button = MOUSEBUTTON_MIDDLE;
295 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
296 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
297 window->pushEvent(event);
298 break;
299 }
300
301 // Mouse wheel button up event
302 case WM_MBUTTONUP:
303 {
304 Event event;
305 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
306 event.MouseButton.Button = MOUSEBUTTON_MIDDLE;
307 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
308 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
309 window->pushEvent(event);
310 break;
311 }
312
313 // Mouse X button down event
314 case WM_XBUTTONDOWN:
315 case WM_XBUTTONDBLCLK:
316 {
317 Event event;
318 event.Type = Event::EVENT_MOUSE_BUTTON_PRESSED;
319 event.MouseButton.Button = (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;
320 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
321 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
322 window->pushEvent(event);
323 break;
324 }
325
326 // Mouse X button up event
327 case WM_XBUTTONUP:
328 {
329 Event event;
330 event.Type = Event::EVENT_MOUSE_BUTTON_RELEASED;
331 event.MouseButton.Button = (HIWORD(wParam) == XBUTTON1) ? MOUSEBUTTON_BUTTON4 : MOUSEBUTTON_BUTTON5;
332 event.MouseButton.X = static_cast<short>(LOWORD(lParam));
333 event.MouseButton.Y = static_cast<short>(HIWORD(lParam));
334 window->pushEvent(event);
335 break;
336 }
337
338 case WM_MOUSEMOVE:
339 {
340 int mouseX = static_cast<short>(LOWORD(lParam));
341 int mouseY = static_cast<short>(HIWORD(lParam));
342
343 Event event;
344 event.Type = Event::EVENT_MOUSE_MOVED;
345 event.MouseMove.X = mouseX;
346 event.MouseMove.Y = mouseY;
347 window->pushEvent(event);
348 break;
349 }
350
351 case WM_MOUSELEAVE:
352 {
353 Event event;
354 event.Type = Event::EVENT_MOUSE_LEFT;
355 window->pushEvent(event);
356 break;
357 }
358 }
359
360 }
361 return DefWindowProcA(hWnd, message, wParam, lParam);
362}
363
364Win32Window::Win32Window()
Jamie Madill9e16d402014-09-08 17:36:33 -0400365 : mNativeWindow(0),
366 mParentWindow(0),
Geoff Lang49be2ad2014-02-28 13:05:51 -0500367 mNativeDisplay(0)
368{
369}
370
371Win32Window::~Win32Window()
372{
373 destroy();
374}
375
Geoff Langf0955f12014-06-20 16:07:07 -0400376bool Win32Window::initialize(const std::string &name, size_t width, size_t height)
Geoff Lang49be2ad2014-02-28 13:05:51 -0500377{
378 destroy();
379
Jamie Madill9e16d402014-09-08 17:36:33 -0400380 mParentClassName = name;
381 mChildClassName = name + "Child";
Geoff Lang49be2ad2014-02-28 13:05:51 -0500382
Jamie Madill9e16d402014-09-08 17:36:33 -0400383 WNDCLASSEXA parentWindowClass = { 0 };
384 parentWindowClass.cbSize = sizeof(WNDCLASSEXA);
385 parentWindowClass.style = 0;
386 parentWindowClass.lpfnWndProc = WndProc;
387 parentWindowClass.cbClsExtra = 0;
388 parentWindowClass.cbWndExtra = 0;
389 parentWindowClass.hInstance = GetModuleHandle(NULL);
390 parentWindowClass.hIcon = NULL;
391 parentWindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
392 parentWindowClass.hbrBackground = 0;
393 parentWindowClass.lpszMenuName = NULL;
394 parentWindowClass.lpszClassName = mParentClassName.c_str();
395 if (!RegisterClassExA(&parentWindowClass))
Geoff Lang49be2ad2014-02-28 13:05:51 -0500396 {
397 return false;
398 }
399
Jamie Madill9e16d402014-09-08 17:36:33 -0400400 WNDCLASSEXA childWindowClass = { 0 };
401 childWindowClass.cbSize = sizeof(WNDCLASSEXA);
402 childWindowClass.style = CS_OWNDC;
403 childWindowClass.lpfnWndProc = WndProc;
404 childWindowClass.cbClsExtra = 0;
405 childWindowClass.cbWndExtra = 0;
406 childWindowClass.hInstance = GetModuleHandle(NULL);
407 childWindowClass.hIcon = NULL;
408 childWindowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
409 childWindowClass.hbrBackground = 0;
410 childWindowClass.lpszMenuName = NULL;
411 childWindowClass.lpszClassName = mChildClassName.c_str();
412 if (!RegisterClassExA(&childWindowClass))
413 {
414 return false;
415 }
416
417 DWORD parentStyle = WS_VISIBLE | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
418 DWORD parentExtendedStyle = WS_EX_APPWINDOW;
Geoff Lang49be2ad2014-02-28 13:05:51 -0500419
420 RECT sizeRect = { 0, 0, width, height };
Jamie Madill9e16d402014-09-08 17:36:33 -0400421 AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500422
Jamie Madill9e16d402014-09-08 17:36:33 -0400423 mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(), parentStyle, CW_USEDEFAULT, CW_USEDEFAULT,
Geoff Lang49be2ad2014-02-28 13:05:51 -0500424 sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, NULL, NULL,
425 GetModuleHandle(NULL), this);
426
Jamie Madill9e16d402014-09-08 17:36:33 -0400427 mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_VISIBLE | WS_CHILD, 0, 0, width, height,
428 mParentWindow, NULL, GetModuleHandle(NULL), this);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500429
430 mNativeDisplay = GetDC(mNativeWindow);
431 if (!mNativeDisplay)
432 {
433 destroy();
434 return false;
435 }
436
Geoff Lang49be2ad2014-02-28 13:05:51 -0500437 return true;
438}
439
440void Win32Window::destroy()
441{
Geoff Lang49be2ad2014-02-28 13:05:51 -0500442 if (mNativeDisplay)
443 {
444 ReleaseDC(mNativeWindow, mNativeDisplay);
445 mNativeDisplay = 0;
446 }
447
448 if (mNativeWindow)
449 {
450 DestroyWindow(mNativeWindow);
451 mNativeWindow = 0;
452 }
453
Jamie Madill9e16d402014-09-08 17:36:33 -0400454 if (mParentWindow)
455 {
456 DestroyWindow(mParentWindow);
457 mParentWindow = 0;
458 }
459
460 UnregisterClassA(mParentClassName.c_str(), NULL);
461 UnregisterClassA(mChildClassName.c_str(), NULL);
Geoff Lang49be2ad2014-02-28 13:05:51 -0500462}
463
Geoff Lang49be2ad2014-02-28 13:05:51 -0500464EGLNativeWindowType Win32Window::getNativeWindow() const
465{
466 return mNativeWindow;
467}
468
469EGLNativeDisplayType Win32Window::getNativeDisplay() const
470{
471 return mNativeDisplay;
472}
473
474void Win32Window::messageLoop()
475{
476 MSG msg;
477 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
478 {
479 TranslateMessage(&msg);
480 DispatchMessage(&msg);
481 }
482}
483
484void Win32Window::setMousePosition(int x, int y)
485{
486 RECT winRect;
487 GetClientRect(mNativeWindow, &winRect);
488
489 POINT topLeft;
490 topLeft.x = winRect.left;
491 topLeft.y = winRect.top;
492 ClientToScreen(mNativeWindow, &topLeft);
493
494 SetCursorPos(topLeft.x + x, topLeft.y + y);
495}
Geoff Lang8def9aa2014-08-05 11:39:15 -0400496
Jamie Madill1cfaaf82014-08-21 10:04:04 -0400497OSWindow *CreateOSWindow()
Geoff Lang8def9aa2014-08-05 11:39:15 -0400498{
499 return new Win32Window();
500}
Jamie Madill25f0e5e2014-08-22 14:50:41 -0400501
502bool Win32Window::resize(int width, int height)
503{
Jamie Madill9e16d402014-09-08 17:36:33 -0400504 if (width == mWidth && height == mHeight)
505 {
506 return true;
507 }
508
Jamie Madill25f0e5e2014-08-22 14:50:41 -0400509 RECT windowRect;
Jamie Madill9e16d402014-09-08 17:36:33 -0400510 if (!GetWindowRect(mParentWindow, &windowRect))
Jamie Madill25f0e5e2014-08-22 14:50:41 -0400511 {
512 return false;
513 }
514
Jamie Madill9e16d402014-09-08 17:36:33 -0400515 RECT clientRect;
516 if (!GetClientRect(mParentWindow, &clientRect))
Jamie Madill25f0e5e2014-08-22 14:50:41 -0400517 {
518 return false;
519 }
520
Jamie Madill9e16d402014-09-08 17:36:33 -0400521 LONG diffX = (windowRect.right - windowRect.left) - clientRect.right;
522 LONG diffY = (windowRect.bottom - windowRect.top) - clientRect.bottom;
523 if (!MoveWindow(mParentWindow, windowRect.left, windowRect.top, width + diffX, height + diffY, FALSE))
524 {
525 return false;
526 }
527
528 if (!MoveWindow(mNativeWindow, 0, 0, width, height, FALSE))
529 {
530 return false;
531 }
Jamie Madill25f0e5e2014-08-22 14:50:41 -0400532
533 return true;
534}
Jamie Madill83da0ec2014-08-22 14:50:42 -0400535
536bool Win32Window::setVisible(bool isVisible)
537{
Jamie Madill9e16d402014-09-08 17:36:33 -0400538 int flag = (isVisible ? SW_SHOW : SW_HIDE);
539
540 return (ShowWindow(mNativeWindow, flag) == TRUE) &&
541 (ShowWindow(mParentWindow, flag) == TRUE);
542}
543
544void Win32Window::pushEvent(Event event)
545{
546 OSWindow::pushEvent(event);
547
548 switch (event.Type)
549 {
550 case Event::EVENT_RESIZED:
551 MoveWindow(mNativeWindow, 0, 0, mWidth, mHeight, FALSE);
552 break;
553 }
Jamie Madill83da0ec2014-08-22 14:50:42 -0400554}