• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 
8 #include "tools/sk_app/win/Window_win.h"
9 
10 #include <tchar.h>
11 #include <windows.h>
12 #include <windowsx.h>
13 
14 #include "src/base/SkUTF.h"
15 #include "tools/sk_app/WindowContext.h"
16 #include "tools/sk_app/win/WindowContextFactory_win.h"
17 #include "tools/skui/ModifierKey.h"
18 
19 #ifdef SK_VULKAN
20 #include "tools/sk_app/VulkanWindowContext.h"
21 #endif
22 
23 namespace sk_app {
24 
25 static int gWindowX = CW_USEDEFAULT;
26 static int gWindowY = 0;
27 static int gWindowWidth = CW_USEDEFAULT;
28 static int gWindowHeight = 0;
29 
CreateNativeWindow(void * platformData)30 Window* Window::CreateNativeWindow(void* platformData) {
31     HINSTANCE hInstance = (HINSTANCE)platformData;
32 
33     Window_win* window = new Window_win();
34     if (!window->init(hInstance)) {
35         delete window;
36         return nullptr;
37     }
38 
39     return window;
40 }
41 
closeWindow()42 void Window_win::closeWindow() {
43     RECT r;
44     if (GetWindowRect(fHWnd, &r)) {
45         gWindowX = r.left;
46         gWindowY = r.top;
47         gWindowWidth = r.right - r.left;
48         gWindowHeight = r.bottom - r.top;
49     }
50     DestroyWindow(fHWnd);
51 }
52 
~Window_win()53 Window_win::~Window_win() {
54     this->closeWindow();
55 }
56 
57 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
58 
59 
init(HINSTANCE hInstance)60 bool Window_win::init(HINSTANCE hInstance) {
61     fHInstance = hInstance ? hInstance : GetModuleHandle(nullptr);
62 
63     // The main window class name
64     static const TCHAR gSZWindowClass[] = _T("SkiaApp");
65 
66     static WNDCLASSEX wcex;
67     static bool wcexInit = false;
68     if (!wcexInit) {
69         wcex.cbSize = sizeof(WNDCLASSEX);
70 
71         wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
72         wcex.lpfnWndProc = WndProc;
73         wcex.cbClsExtra = 0;
74         wcex.cbWndExtra = 0;
75         wcex.hInstance = fHInstance;
76         wcex.hIcon = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);
77         wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
78         wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
79         wcex.lpszMenuName = nullptr;
80         wcex.lpszClassName = gSZWindowClass;
81         wcex.hIconSm = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);
82 
83         if (!RegisterClassEx(&wcex)) {
84             return false;
85         }
86         wcexInit = true;
87     }
88 
89    /*
90     if (fullscreen)
91     {
92         DEVMODE dmScreenSettings;
93         // If full screen set the screen to maximum size of the users desktop and 32bit.
94         memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
95         dmScreenSettings.dmSize = sizeof(dmScreenSettings);
96         dmScreenSettings.dmPelsWidth = (unsigned long)width;
97         dmScreenSettings.dmPelsHeight = (unsigned long)height;
98         dmScreenSettings.dmBitsPerPel = 32;
99         dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
100 
101         // Change the display settings to full screen.
102         ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
103 
104         // Set the position of the window to the top left corner.
105         posX = posY = 0;
106     }
107     */
108  //   gIsFullscreen = fullscreen;
109 
110     fHWnd = CreateWindow(gSZWindowClass, nullptr, WS_OVERLAPPEDWINDOW,
111                          gWindowX, gWindowY, gWindowWidth, gWindowHeight,
112                          nullptr, nullptr, fHInstance, nullptr);
113     if (!fHWnd)
114     {
115         return false;
116     }
117 
118     SetWindowLongPtr(fHWnd, GWLP_USERDATA, (LONG_PTR)this);
119     RegisterTouchWindow(fHWnd, 0);
120 
121     return true;
122 }
123 
get_key(WPARAM vk)124 static skui::Key get_key(WPARAM vk) {
125     static const struct {
126         WPARAM      fVK;
127         skui::Key fKey;
128     } gPair[] = {
129         { VK_BACK,    skui::Key::kBack     },
130         { VK_CLEAR,   skui::Key::kBack     },
131         { VK_RETURN,  skui::Key::kOK       },
132         { VK_UP,      skui::Key::kUp       },
133         { VK_DOWN,    skui::Key::kDown     },
134         { VK_LEFT,    skui::Key::kLeft     },
135         { VK_RIGHT,   skui::Key::kRight    },
136         { VK_TAB,     skui::Key::kTab      },
137         { VK_PRIOR,   skui::Key::kPageUp   },
138         { VK_NEXT,    skui::Key::kPageDown },
139         { VK_HOME,    skui::Key::kHome     },
140         { VK_END,     skui::Key::kEnd      },
141         { VK_DELETE,  skui::Key::kDelete   },
142         { VK_ESCAPE,  skui::Key::kEscape   },
143         { VK_SHIFT,   skui::Key::kShift    },
144         { VK_CONTROL, skui::Key::kCtrl     },
145         { VK_MENU,    skui::Key::kOption   },
146         { 'A',        skui::Key::kA        },
147         { 'C',        skui::Key::kC        },
148         { 'V',        skui::Key::kV        },
149         { 'X',        skui::Key::kX        },
150         { 'Y',        skui::Key::kY        },
151         { 'Z',        skui::Key::kZ        },
152     };
153     for (size_t i = 0; i < std::size(gPair); i++) {
154         if (gPair[i].fVK == vk) {
155             return gPair[i].fKey;
156         }
157     }
158     return skui::Key::kNONE;
159 }
160 
get_modifiers(UINT message,WPARAM wParam,LPARAM lParam)161 static skui::ModifierKey get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) {
162     skui::ModifierKey modifiers = skui::ModifierKey::kNone;
163 
164     switch (message) {
165         case WM_UNICHAR:
166         case WM_CHAR:
167             if (0 == (lParam & (1 << 30))) {
168                 modifiers |= skui::ModifierKey::kFirstPress;
169             }
170             if (lParam & (1 << 29)) {
171                 modifiers |= skui::ModifierKey::kOption;
172             }
173             break;
174 
175         case WM_KEYDOWN:
176         case WM_SYSKEYDOWN:
177             if (0 == (lParam & (1 << 30))) {
178                 modifiers |= skui::ModifierKey::kFirstPress;
179             }
180             if (lParam & (1 << 29)) {
181                 modifiers |= skui::ModifierKey::kOption;
182             }
183             break;
184 
185         case WM_KEYUP:
186         case WM_SYSKEYUP:
187             if (lParam & (1 << 29)) {
188                 modifiers |= skui::ModifierKey::kOption;
189             }
190             break;
191 
192         case WM_LBUTTONDOWN:
193         case WM_LBUTTONUP:
194         case WM_MOUSEMOVE:
195         case WM_MOUSEWHEEL:
196             if (wParam & MK_CONTROL) {
197                 modifiers |= skui::ModifierKey::kControl;
198             }
199             if (wParam & MK_SHIFT) {
200                 modifiers |= skui::ModifierKey::kShift;
201             }
202             break;
203     }
204 
205     return modifiers;
206 }
207 
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)208 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
209 {
210     PAINTSTRUCT ps;
211 
212     Window_win* window = (Window_win*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
213 
214     bool eventHandled = false;
215 
216     switch (message) {
217         case WM_PAINT:
218             BeginPaint(hWnd, &ps);
219             window->onPaint();
220             EndPaint(hWnd, &ps);
221             eventHandled = true;
222             break;
223 
224         case WM_CLOSE:
225             PostQuitMessage(0);
226             eventHandled = true;
227             break;
228 
229         case WM_ACTIVATE:
230             // disable/enable rendering here, depending on wParam != WA_INACTIVE
231             break;
232 
233         case WM_SIZE:
234             window->onResize(LOWORD(lParam), HIWORD(lParam));
235             eventHandled = true;
236             break;
237 
238         case WM_UNICHAR:
239             eventHandled = window->onChar((SkUnichar)wParam,
240                                           get_modifiers(message, wParam, lParam));
241             break;
242 
243         case WM_CHAR: {
244             const uint16_t* cPtr = reinterpret_cast<uint16_t*>(&wParam);
245             SkUnichar c = SkUTF::NextUTF16(&cPtr, cPtr + 2);
246             eventHandled = window->onChar(c, get_modifiers(message, wParam, lParam));
247         } break;
248 
249         case WM_KEYDOWN:
250         case WM_SYSKEYDOWN:
251             eventHandled = window->onKey(get_key(wParam), skui::InputState::kDown,
252                                          get_modifiers(message, wParam, lParam));
253             break;
254 
255         case WM_KEYUP:
256         case WM_SYSKEYUP:
257             eventHandled = window->onKey(get_key(wParam), skui::InputState::kUp,
258                                          get_modifiers(message, wParam, lParam));
259             break;
260 
261         case WM_LBUTTONDOWN:
262         case WM_LBUTTONUP: {
263             int xPos = GET_X_LPARAM(lParam);
264             int yPos = GET_Y_LPARAM(lParam);
265 
266             //if (!gIsFullscreen)
267             //{
268             //    RECT rc = { 0, 0, 640, 480 };
269             //    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
270             //    xPos -= rc.left;
271             //    yPos -= rc.top;
272             //}
273 
274             skui::InputState istate = ((wParam & MK_LBUTTON) != 0) ? skui::InputState::kDown
275                                                                      : skui::InputState::kUp;
276 
277             eventHandled = window->onMouse(xPos, yPos, istate,
278                                             get_modifiers(message, wParam, lParam));
279         } break;
280 
281         case WM_MOUSEMOVE: {
282             int xPos = GET_X_LPARAM(lParam);
283             int yPos = GET_Y_LPARAM(lParam);
284 
285             //if (!gIsFullscreen)
286             //{
287             //    RECT rc = { 0, 0, 640, 480 };
288             //    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
289             //    xPos -= rc.left;
290             //    yPos -= rc.top;
291             //}
292 
293             eventHandled = window->onMouse(xPos, yPos, skui::InputState::kMove,
294                                            get_modifiers(message, wParam, lParam));
295         } break;
296 
297         case WM_MOUSEWHEEL:
298             eventHandled = window->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f,
299                                                 get_modifiers(message, wParam, lParam));
300             break;
301 
302         case WM_TOUCH: {
303             uint16_t numInputs = LOWORD(wParam);
304             std::unique_ptr<TOUCHINPUT[]> inputs(new TOUCHINPUT[numInputs]);
305             if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, inputs.get(),
306                                   sizeof(TOUCHINPUT))) {
307                 POINT topLeft = {0, 0};
308                 ClientToScreen(hWnd, &topLeft);
309                 for (uint16_t i = 0; i < numInputs; ++i) {
310                     TOUCHINPUT ti = inputs[i];
311                     skui::InputState state;
312                     if (ti.dwFlags & TOUCHEVENTF_DOWN) {
313                         state = skui::InputState::kDown;
314                     } else if (ti.dwFlags & TOUCHEVENTF_MOVE) {
315                         state = skui::InputState::kMove;
316                     } else if (ti.dwFlags & TOUCHEVENTF_UP) {
317                         state = skui::InputState::kUp;
318                     } else {
319                         continue;
320                     }
321                     // TOUCHINPUT coordinates are in 100ths of pixels
322                     // Adjust for that, and make them window relative
323                     LONG tx = (ti.x / 100) - topLeft.x;
324                     LONG ty = (ti.y / 100) - topLeft.y;
325                     eventHandled = window->onTouch(ti.dwID, state, tx, ty) || eventHandled;
326                 }
327             }
328         } break;
329 
330         default:
331             return DefWindowProc(hWnd, message, wParam, lParam);
332     }
333 
334     return eventHandled ? 0 : 1;
335 }
336 
setTitle(const char * title)337 void Window_win::setTitle(const char* title) {
338     SetWindowTextA(fHWnd, title);
339 }
340 
show()341 void Window_win::show() {
342     ShowWindow(fHWnd, SW_SHOW);
343 }
344 
345 
attach(BackendType attachType)346 bool Window_win::attach(BackendType attachType) {
347     fBackend = attachType;
348     fInitializedBackend = true;
349 
350     switch (attachType) {
351 #ifdef SK_GL
352         case kNativeGL_BackendType:
353             fWindowContext = window_context_factory::MakeGLForWin(fHWnd, fRequestedDisplayParams);
354             break;
355 #endif
356 #if SK_ANGLE
357         case kANGLE_BackendType:
358             fWindowContext =
359                     window_context_factory::MakeANGLEForWin(fHWnd, fRequestedDisplayParams);
360             break;
361 #endif
362 #ifdef SK_DAWN
363         case kDawn_BackendType:
364             fWindowContext =
365                     window_context_factory::MakeDawnD3D12ForWin(fHWnd, fRequestedDisplayParams);
366             break;
367 #if defined(SK_GRAPHITE)
368         case kGraphiteDawn_BackendType:
369             fWindowContext = window_context_factory::MakeGraphiteDawnD3D12ForWin(
370                     fHWnd, fRequestedDisplayParams);
371             break;
372 #endif
373 #endif
374         case kRaster_BackendType:
375             fWindowContext =
376                     window_context_factory::MakeRasterForWin(fHWnd, fRequestedDisplayParams);
377             break;
378 #ifdef SK_VULKAN
379         case kVulkan_BackendType:
380             fWindowContext =
381                     window_context_factory::MakeVulkanForWin(fHWnd, fRequestedDisplayParams);
382             break;
383 #endif
384 #ifdef SK_DIRECT3D
385         case kDirect3D_BackendType:
386             fWindowContext =
387                 window_context_factory::MakeD3D12ForWin(fHWnd, fRequestedDisplayParams);
388             break;
389 #endif
390     }
391     this->onBackendCreated();
392 
393     return (SkToBool(fWindowContext));
394 }
395 
onInval()396 void Window_win::onInval() {
397     InvalidateRect(fHWnd, nullptr, false);
398 }
399 
setRequestedDisplayParams(const DisplayParams & params,bool allowReattach)400 void Window_win::setRequestedDisplayParams(const DisplayParams& params, bool allowReattach) {
401     // GL on Windows doesn't let us change MSAA after the window is created
402     if (params.fMSAASampleCount != this->getRequestedDisplayParams().fMSAASampleCount
403             && allowReattach) {
404         // Need to change these early, so attach() creates the window context correctly
405         fRequestedDisplayParams = params;
406 
407         fWindowContext = nullptr;
408         this->closeWindow();
409         this->init(fHInstance);
410         if (fInitializedBackend) {
411             this->attach(fBackend);
412         }
413     }
414 
415     INHERITED::setRequestedDisplayParams(params, allowReattach);
416 }
417 
418 }   // namespace sk_app
419