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 "vk/GrVkVulkan.h"
9
10 #include "Window_win.h"
11
12 #include <tchar.h>
13 #include <windows.h>
14 #include <windowsx.h>
15
16 #include "SkUtils.h"
17 #include "../WindowContext.h"
18 #include "WindowContextFactory_win.h"
19 #ifdef SK_VULKAN
20 #include "../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 Window::Key get_key(WPARAM vk) {
125 static const struct {
126 WPARAM fVK;
127 Window::Key fKey;
128 } gPair[] = {
129 { VK_BACK, Window::Key::kBack },
130 { VK_CLEAR, Window::Key::kBack },
131 { VK_RETURN, Window::Key::kOK },
132 { VK_UP, Window::Key::kUp },
133 { VK_DOWN, Window::Key::kDown },
134 { VK_LEFT, Window::Key::kLeft },
135 { VK_RIGHT, Window::Key::kRight },
136 { VK_TAB, Window::Key::kTab },
137 { VK_PRIOR, Window::Key::kPageUp },
138 { VK_NEXT, Window::Key::kPageDown },
139 { VK_HOME, Window::Key::kHome },
140 { VK_END, Window::Key::kEnd },
141 { VK_DELETE, Window::Key::kDelete },
142 { VK_ESCAPE, Window::Key::kEscape },
143 { VK_SHIFT, Window::Key::kShift },
144 { VK_CONTROL, Window::Key::kCtrl },
145 { VK_MENU, Window::Key::kOption },
146 { 'A', Window::Key::kA },
147 { 'C', Window::Key::kC },
148 { 'V', Window::Key::kV },
149 { 'X', Window::Key::kX },
150 { 'Y', Window::Key::kY },
151 { 'Z', Window::Key::kZ },
152 };
153 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
154 if (gPair[i].fVK == vk) {
155 return gPair[i].fKey;
156 }
157 }
158 return Window::Key::kNONE;
159 }
160
get_modifiers(UINT message,WPARAM wParam,LPARAM lParam)161 static uint32_t get_modifiers(UINT message, WPARAM wParam, LPARAM lParam) {
162 uint32_t modifiers = 0;
163
164 switch (message) {
165 case WM_UNICHAR:
166 case WM_CHAR:
167 if (0 == (lParam & (1 << 30))) {
168 modifiers |= Window::kFirstPress_ModifierKey;
169 }
170 if (lParam & (1 << 29)) {
171 modifiers |= Window::kOption_ModifierKey;
172 }
173 break;
174
175 case WM_KEYDOWN:
176 case WM_SYSKEYDOWN:
177 if (0 == (lParam & (1 << 30))) {
178 modifiers |= Window::kFirstPress_ModifierKey;
179 }
180 if (lParam & (1 << 29)) {
181 modifiers |= Window::kOption_ModifierKey;
182 }
183 break;
184
185 case WM_KEYUP:
186 case WM_SYSKEYUP:
187 if (lParam & (1 << 29)) {
188 modifiers |= Window::kOption_ModifierKey;
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 |= Window::kControl_ModifierKey;
198 }
199 if (wParam & MK_SHIFT) {
200 modifiers |= Window::kShift_ModifierKey;
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 HDC hdc;
212
213 Window_win* window = (Window_win*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
214
215 bool eventHandled = false;
216
217 switch (message) {
218 case WM_PAINT:
219 hdc = BeginPaint(hWnd, &ps);
220 window->onPaint();
221 EndPaint(hWnd, &ps);
222 eventHandled = true;
223 break;
224
225 case WM_CLOSE:
226 PostQuitMessage(0);
227 eventHandled = true;
228 break;
229
230 case WM_ACTIVATE:
231 // disable/enable rendering here, depending on wParam != WA_INACTIVE
232 break;
233
234 case WM_SIZE:
235 window->onResize(LOWORD(lParam), HIWORD(lParam));
236 eventHandled = true;
237 break;
238
239 case WM_UNICHAR:
240 eventHandled = window->onChar((SkUnichar)wParam,
241 get_modifiers(message, wParam, lParam));
242 break;
243
244 case WM_CHAR: {
245 const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam);
246 eventHandled = window->onChar(SkUTF16_NextUnichar(&c),
247 get_modifiers(message, wParam, lParam));
248 } break;
249
250 case WM_KEYDOWN:
251 case WM_SYSKEYDOWN:
252 eventHandled = window->onKey(get_key(wParam), Window::kDown_InputState,
253 get_modifiers(message, wParam, lParam));
254 break;
255
256 case WM_KEYUP:
257 case WM_SYSKEYUP:
258 eventHandled = window->onKey(get_key(wParam), Window::kUp_InputState,
259 get_modifiers(message, wParam, lParam));
260 break;
261
262 case WM_LBUTTONDOWN:
263 case WM_LBUTTONUP: {
264 int xPos = GET_X_LPARAM(lParam);
265 int yPos = GET_Y_LPARAM(lParam);
266
267 //if (!gIsFullscreen)
268 //{
269 // RECT rc = { 0, 0, 640, 480 };
270 // AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
271 // xPos -= rc.left;
272 // yPos -= rc.top;
273 //}
274
275 Window::InputState istate = ((wParam & MK_LBUTTON) != 0) ? Window::kDown_InputState
276 : Window::kUp_InputState;
277
278 eventHandled = window->onMouse(xPos, yPos, istate,
279 get_modifiers(message, wParam, lParam));
280 } break;
281
282 case WM_MOUSEMOVE: {
283 int xPos = GET_X_LPARAM(lParam);
284 int yPos = GET_Y_LPARAM(lParam);
285
286 //if (!gIsFullscreen)
287 //{
288 // RECT rc = { 0, 0, 640, 480 };
289 // AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
290 // xPos -= rc.left;
291 // yPos -= rc.top;
292 //}
293
294 eventHandled = window->onMouse(xPos, yPos, Window::kMove_InputState,
295 get_modifiers(message, wParam, lParam));
296 } break;
297
298 case WM_MOUSEWHEEL:
299 eventHandled = window->onMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f,
300 get_modifiers(message, wParam, lParam));
301 break;
302
303 case WM_TOUCH: {
304 uint16_t numInputs = LOWORD(wParam);
305 std::unique_ptr<TOUCHINPUT[]> inputs(new TOUCHINPUT[numInputs]);
306 if (GetTouchInputInfo((HTOUCHINPUT)lParam, numInputs, inputs.get(),
307 sizeof(TOUCHINPUT))) {
308 POINT topLeft = {0, 0};
309 ClientToScreen(hWnd, &topLeft);
310 for (uint16_t i = 0; i < numInputs; ++i) {
311 TOUCHINPUT ti = inputs[i];
312 Window::InputState state;
313 if (ti.dwFlags & TOUCHEVENTF_DOWN) {
314 state = Window::kDown_InputState;
315 } else if (ti.dwFlags & TOUCHEVENTF_MOVE) {
316 state = Window::kMove_InputState;
317 } else if (ti.dwFlags & TOUCHEVENTF_UP) {
318 state = Window::kUp_InputState;
319 } else {
320 continue;
321 }
322 // TOUCHINPUT coordinates are in 100ths of pixels
323 // Adjust for that, and make them window relative
324 LONG tx = (ti.x / 100) - topLeft.x;
325 LONG ty = (ti.y / 100) - topLeft.y;
326 eventHandled = window->onTouch(ti.dwID, state, tx, ty) || eventHandled;
327 }
328 }
329 } break;
330
331 default:
332 return DefWindowProc(hWnd, message, wParam, lParam);
333 }
334
335 return eventHandled ? 0 : 1;
336 }
337
setTitle(const char * title)338 void Window_win::setTitle(const char* title) {
339 SetWindowTextA(fHWnd, title);
340 }
341
show()342 void Window_win::show() {
343 ShowWindow(fHWnd, SW_SHOW);
344 }
345
346
attach(BackendType attachType)347 bool Window_win::attach(BackendType attachType) {
348 fBackend = attachType;
349
350 switch (attachType) {
351 case kNativeGL_BackendType:
352 fWindowContext = window_context_factory::NewGLForWin(fHWnd, fRequestedDisplayParams);
353 break;
354 #if SK_ANGLE
355 case kANGLE_BackendType:
356 fWindowContext = window_context_factory::NewANGLEForWin(fHWnd, fRequestedDisplayParams);
357 break;
358 #endif
359 case kRaster_BackendType:
360 fWindowContext = window_context_factory::NewRasterForWin(fHWnd,
361 fRequestedDisplayParams);
362 break;
363 #ifdef SK_VULKAN
364 case kVulkan_BackendType:
365 fWindowContext = window_context_factory::NewVulkanForWin(fHWnd,
366 fRequestedDisplayParams);
367 break;
368 #endif
369 }
370 this->onBackendCreated();
371
372 return (SkToBool(fWindowContext));
373 }
374
onInval()375 void Window_win::onInval() {
376 InvalidateRect(fHWnd, nullptr, false);
377 }
378
setRequestedDisplayParams(const DisplayParams & params,bool allowReattach)379 void Window_win::setRequestedDisplayParams(const DisplayParams& params, bool allowReattach) {
380 // GL on Windows doesn't let us change MSAA after the window is created
381 if (params.fMSAASampleCount != this->getRequestedDisplayParams().fMSAASampleCount
382 && allowReattach) {
383 // Need to change these early, so attach() creates the window context correctly
384 fRequestedDisplayParams = params;
385
386 delete fWindowContext;
387 this->closeWindow();
388 this->init(fHInstance);
389 this->attach(fBackend);
390 }
391
392 INHERITED::setRequestedDisplayParams(params, allowReattach);
393 }
394
395 } // namespace sk_app
396