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