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