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     Window *window = (Window*)(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     : mClassName(),
    366       mDisplay(0),
    367       mNativeWindow(0),
    368       mNativeDisplay(0)
    369 {
    370 }
    371 
    372 Win32Window::~Win32Window()
    373 {
    374     destroy();
    375 }
    376 
    377 bool Win32Window::initialize(const std::string &name, size_t width, size_t height, RendererType requestedRenderer)
    378 {
    379     destroy();
    380 
    381     mClassName = name;
    382 
    383     WNDCLASSEXA windowClass = { 0 };
    384     windowClass.cbSize = sizeof(WNDCLASSEXA);
    385     windowClass.style = CS_OWNDC;
    386     windowClass.lpfnWndProc = WndProc;
    387     windowClass.cbClsExtra = 0;
    388     windowClass.cbWndExtra = 0;
    389     windowClass.hInstance = GetModuleHandle(NULL);
    390     windowClass.hIcon = NULL;
    391     windowClass.hCursor = LoadCursorA(NULL, IDC_ARROW);
    392     windowClass.hbrBackground = 0;
    393     windowClass.lpszMenuName = NULL;
    394     windowClass.lpszClassName = mClassName.c_str();
    395     if (!RegisterClassExA(&windowClass))
    396     {
    397         return false;
    398     }
    399 
    400     DWORD style = WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_SYSMENU;
    401     DWORD extendedStyle = WS_EX_APPWINDOW;
    402 
    403     RECT sizeRect = { 0, 0, width, height };
    404     AdjustWindowRectEx(&sizeRect, style, false, extendedStyle);
    405 
    406     mNativeWindow = CreateWindowExA(extendedStyle, mClassName.c_str(), name.c_str(), style, CW_USEDEFAULT, CW_USEDEFAULT,
    407                                     sizeRect.right - sizeRect.left, sizeRect.bottom - sizeRect.top, NULL, NULL,
    408                                     GetModuleHandle(NULL), this);
    409 
    410     SetWindowLongPtrA(mNativeWindow, GWLP_USERDATA, reinterpret_cast<LONG>(this));
    411 
    412     ShowWindow(mNativeWindow, SW_SHOW);
    413 
    414     mNativeDisplay = GetDC(mNativeWindow);
    415     if (!mNativeDisplay)
    416     {
    417         destroy();
    418         return false;
    419     }
    420 
    421     EGLNativeDisplayType requestedDisplay = mNativeDisplay;
    422     if (requestedRenderer == RENDERER_D3D11)
    423     {
    424         requestedDisplay = EGL_D3D11_ONLY_DISPLAY_ANGLE;
    425     }
    426 
    427     mDisplay = eglGetDisplay(requestedDisplay);
    428     if (mDisplay == EGL_NO_DISPLAY)
    429     {
    430         mDisplay = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
    431     }
    432 
    433     EGLint majorVersion, minorVersion;
    434     if (!eglInitialize(mDisplay, &majorVersion, &minorVersion))
    435     {
    436         destroy();
    437         return false;
    438     }
    439 
    440     eglBindAPI(EGL_OPENGL_ES_API);
    441     if (eglGetError() != EGL_SUCCESS)
    442     {
    443         destroy();
    444         return false;
    445     }
    446 
    447     return true;
    448 }
    449 
    450 void Win32Window::destroy()
    451 {
    452     if (mDisplay != EGL_NO_DISPLAY)
    453     {
    454         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    455         eglTerminate(mDisplay);
    456         mDisplay = EGL_NO_DISPLAY;
    457     }
    458 
    459     if (mNativeDisplay)
    460     {
    461         ReleaseDC(mNativeWindow, mNativeDisplay);
    462         mNativeDisplay = 0;
    463     }
    464 
    465     if (mNativeWindow)
    466     {
    467         DestroyWindow(mNativeWindow);
    468         mNativeWindow = 0;
    469     }
    470 
    471     UnregisterClassA(mClassName.c_str(), NULL);
    472 }
    473 
    474 EGLDisplay Win32Window::getDisplay() const
    475 {
    476     return mDisplay;
    477 }
    478 
    479 EGLNativeWindowType Win32Window::getNativeWindow() const
    480 {
    481     return mNativeWindow;
    482 }
    483 
    484 EGLNativeDisplayType Win32Window::getNativeDisplay() const
    485 {
    486     return mNativeDisplay;
    487 }
    488 
    489 void Win32Window::messageLoop()
    490 {
    491     MSG msg;
    492     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    493     {
    494         TranslateMessage(&msg);
    495         DispatchMessage(&msg);
    496     }
    497 }
    498 
    499 void Win32Window::setMousePosition(int x, int y)
    500 {
    501     RECT winRect;
    502     GetClientRect(mNativeWindow, &winRect);
    503 
    504     POINT topLeft;
    505     topLeft.x = winRect.left;
    506     topLeft.y = winRect.top;
    507     ClientToScreen(mNativeWindow, &topLeft);
    508 
    509     SetCursorPos(topLeft.x + x, topLeft.y + y);
    510 }
    511