1 // 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 9 Key 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 128 LRESULT 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 140 OSWindow *window = (OSWindow*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA); 141 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 364 Win32Window::Win32Window() 365 : mNativeWindow(0), 366 mParentWindow(0), 367 mNativeDisplay(0) 368 { 369 } 370 371 Win32Window::~Win32Window() 372 { 373 destroy(); 374 } 375 376 bool Win32Window::initialize(const std::string &name, size_t width, size_t height) 377 { 378 destroy(); 379 380 mParentClassName = name; 381 mChildClassName = name + "Child"; 382 383 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)) 396 { 397 return false; 398 } 399 400 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; 419 420 RECT sizeRect = { 0, 0, width, height }; 421 AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle); 422 423 mParentWindow = CreateWindowExA(parentExtendedStyle, mParentClassName.c_str(), name.c_str(), parentStyle, CW_USEDEFAULT, CW_USEDEFAULT, 424 sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, NULL, NULL, 425 GetModuleHandle(NULL), this); 426 427 mNativeWindow = CreateWindowExA(0, mChildClassName.c_str(), name.c_str(), WS_VISIBLE | WS_CHILD, 0, 0, width, height, 428 mParentWindow, NULL, GetModuleHandle(NULL), this); 429 430 mNativeDisplay = GetDC(mNativeWindow); 431 if (!mNativeDisplay) 432 { 433 destroy(); 434 return false; 435 } 436 437 return true; 438 } 439 440 void Win32Window::destroy() 441 { 442 if (mNativeDisplay) 443 { 444 ReleaseDC(mNativeWindow, mNativeDisplay); 445 mNativeDisplay = 0; 446 } 447 448 if (mNativeWindow) 449 { 450 DestroyWindow(mNativeWindow); 451 mNativeWindow = 0; 452 } 453 454 if (mParentWindow) 455 { 456 DestroyWindow(mParentWindow); 457 mParentWindow = 0; 458 } 459 460 UnregisterClassA(mParentClassName.c_str(), NULL); 461 UnregisterClassA(mChildClassName.c_str(), NULL); 462 } 463 464 EGLNativeWindowType Win32Window::getNativeWindow() const 465 { 466 return mNativeWindow; 467 } 468 469 EGLNativeDisplayType Win32Window::getNativeDisplay() const 470 { 471 return mNativeDisplay; 472 } 473 474 void 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 484 void 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 } 496 497 OSWindow *CreateOSWindow() 498 { 499 return new Win32Window(); 500 } 501 502 bool Win32Window::resize(int width, int height) 503 { 504 if (width == mWidth && height == mHeight) 505 { 506 return true; 507 } 508 509 RECT windowRect; 510 if (!GetWindowRect(mParentWindow, &windowRect)) 511 { 512 return false; 513 } 514 515 RECT clientRect; 516 if (!GetClientRect(mParentWindow, &clientRect)) 517 { 518 return false; 519 } 520 521 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 } 532 533 return true; 534 } 535 536 bool Win32Window::setVisible(bool isVisible) 537 { 538 int flag = (isVisible ? SW_SHOW : SW_HIDE); 539 540 return (ShowWindow(mNativeWindow, flag) == TRUE) && 541 (ShowWindow(mParentWindow, flag) == TRUE); 542 } 543 544 void 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 } 554 } 555