Home | History | Annotate | Download | only in win32
      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