1 /**
2  * @file win32drv.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "win32drv.h"
11 
12 #if USE_WIN32DRV
13 
14 #include <windowsx.h>
15 #include <malloc.h>
16 #include <process.h>
17 #include <stdbool.h>
18 #include <stdint.h>
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 
24 #define WINDOW_EX_STYLE \
25     WS_EX_CLIENTEDGE
26 
27 #define WINDOW_STYLE \
28     (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME))
29 
30 #ifndef WIN32DRV_MONITOR_ZOOM
31 #define WIN32DRV_MONITOR_ZOOM 1
32 #endif
33 
34 #ifndef USER_DEFAULT_SCREEN_DPI
35 #define USER_DEFAULT_SCREEN_DPI 96
36 #endif
37 
38 /**********************
39  *      TYPEDEFS
40  **********************/
41 
42 typedef struct _WINDOW_THREAD_PARAMETER
43 {
44     HANDLE window_mutex;
45     HINSTANCE instance_handle;
46     HICON icon_handle;
47     lv_coord_t hor_res;
48     lv_coord_t ver_res;
49     int show_window_mode;
50 } WINDOW_THREAD_PARAMETER, * PWINDOW_THREAD_PARAMETER;
51 
52 /**********************
53  *  STATIC PROTOTYPES
54  **********************/
55 
56 /**
57  * @brief Creates a B8G8R8A8 frame buffer.
58  * @param WindowHandle A handle to the window for the creation of the frame
59  *                     buffer. If this value is NULL, the entire screen will be
60  *                     referenced.
61  * @param Width The width of the frame buffer.
62  * @param Height The height of the frame buffer.
63  * @param PixelBuffer The raw pixel buffer of the frame buffer you created.
64  * @param PixelBufferSize The size of the frame buffer you created.
65  * @return If the function succeeds, the return value is a handle to the device
66  *         context (DC) for the frame buffer. If the function fails, the return
67  *         value is NULL, and PixelBuffer parameter is NULL.
68 */
69 static HDC lv_win32_create_frame_buffer(
70     _In_opt_ HWND WindowHandle,
71     _In_ LONG Width,
72     _In_ LONG Height,
73     _Out_ UINT32** PixelBuffer,
74     _Out_ SIZE_T* PixelBufferSize);
75 
76 /**
77  * @brief Enables WM_DPICHANGED message for child window for the associated
78  *        window.
79  * @param WindowHandle The window you want to enable WM_DPICHANGED message for
80  *                     child window.
81  * @return If the function succeeds, the return value is non-zero. If the
82  *         function fails, the return value is zero.
83  * @remarks You need to use this function in Windows 10 Threshold 1 or Windows
84  *          10 Threshold 2.
85 */
86 static BOOL lv_win32_enable_child_window_dpi_message(
87     _In_ HWND WindowHandle);
88 
89 /**
90  * @brief Registers a window as being touch-capable.
91  * @param hWnd The handle of the window being registered.
92  * @param ulFlags A set of bit flags that specify optional modifications.
93  * @return If the function succeeds, the return value is nonzero. If the
94  *         function fails, the return value is zero.
95  * @remark For more information, see RegisterTouchWindow.
96 */
97 static BOOL lv_win32_register_touch_window(
98     HWND hWnd,
99     ULONG ulFlags);
100 
101 /**
102  * @brief Retrieves detailed information about touch inputs associated with a
103  *        particular touch input handle.
104  * @param hTouchInput The touch input handle received in the LPARAM of a touch
105  *                    message.
106  * @param cInputs The number of structures in the pInputs array.
107  * @param pInputs A pointer to an array of TOUCHINPUT structures to receive
108  *                information about the touch points associated with the
109  *                specified touch input handle.
110  * @param cbSize The size, in bytes, of a single TOUCHINPUT structure.
111  * @return If the function succeeds, the return value is nonzero. If the
112  *         function fails, the return value is zero.
113  * @remark For more information, see GetTouchInputInfo.
114 */
115 static BOOL lv_win32_get_touch_input_info(
116     HTOUCHINPUT hTouchInput,
117     UINT cInputs,
118     PTOUCHINPUT pInputs,
119     int cbSize);
120 
121 /**
122  * @brief Closes a touch input handle, frees process memory associated with it,
123           and invalidates the handle.
124  * @param hTouchInput The touch input handle received in the LPARAM of a touch
125  *                    message.
126  * @return If the function succeeds, the return value is nonzero. If the
127  *         function fails, the return value is zero.
128  * @remark For more information, see CloseTouchInputHandle.
129 */
130 static BOOL lv_win32_close_touch_input_handle(
131     HTOUCHINPUT hTouchInput);
132 
133 /**
134  * @brief Returns the dots per inch (dpi) value for the associated window.
135  * @param WindowHandle The window you want to get information about.
136  * @return The DPI for the window.
137 */
138 static UINT lv_win32_get_dpi_for_window(
139     _In_ HWND WindowHandle);
140 
141 static void lv_win32_display_driver_flush_callback(
142     lv_disp_drv_t* disp_drv,
143     const lv_area_t* area,
144     lv_color_t* color_p);
145 
146 static void lv_win32_pointer_driver_read_callback(
147     lv_indev_drv_t* indev_drv,
148     lv_indev_data_t* data);
149 
150 static void lv_win32_keypad_driver_read_callback(
151     lv_indev_drv_t* indev_drv,
152     lv_indev_data_t* data);
153 
154 static void lv_win32_encoder_driver_read_callback(
155     lv_indev_drv_t* indev_drv,
156     lv_indev_data_t* data);
157 
158 static lv_win32_window_context_t* lv_win32_get_display_context(
159     lv_disp_t* display);
160 
161 static LRESULT CALLBACK lv_win32_window_message_callback(
162     HWND   hWnd,
163     UINT   uMsg,
164     WPARAM wParam,
165     LPARAM lParam);
166 
167 static unsigned int __stdcall lv_win32_window_thread_entrypoint(
168     void* raw_parameter);
169 
lv_win32_push_key_to_keyboard_queue(lv_win32_window_context_t * context,uint32_t key,lv_indev_state_t state)170 static void lv_win32_push_key_to_keyboard_queue(
171     lv_win32_window_context_t* context,
172     uint32_t key,
173     lv_indev_state_t state)
174 {
175     lv_win32_keyboard_queue_item_t* current =
176         (lv_win32_keyboard_queue_item_t*)(_aligned_malloc(
177             sizeof(lv_win32_keyboard_queue_item_t),
178             MEMORY_ALLOCATION_ALIGNMENT));
179     if (current)
180     {
181         current->key = key;
182         current->state = state;
183         InterlockedPushEntrySList(
184             context->keyboard_queue,
185             &current->ItemEntry);
186     }
187 }
188 
189 /**********************
190  *  GLOBAL VARIABLES
191  **********************/
192 
193 EXTERN_C bool lv_win32_quit_signal = false;
194 
195 EXTERN_C lv_indev_t* lv_win32_pointer_device_object = NULL;
196 EXTERN_C lv_indev_t* lv_win32_keypad_device_object = NULL;
197 EXTERN_C lv_indev_t* lv_win32_encoder_device_object = NULL;
198 
199 /**********************
200  *  STATIC VARIABLES
201  **********************/
202 
203 static HWND g_window_handle = NULL;
204 
205 /**********************
206  *      MACROS
207  **********************/
208 
209 /**********************
210  *   GLOBAL FUNCTIONS
211  **********************/
212 
lv_win32_add_all_input_devices_to_group(lv_group_t * group)213 EXTERN_C void lv_win32_add_all_input_devices_to_group(
214     lv_group_t* group)
215 {
216     if (!group)
217     {
218         LV_LOG_WARN(
219             "The group object is NULL. Get the default group object instead.");
220 
221         group = lv_group_get_default();
222         if (!group)
223         {
224             LV_LOG_WARN(
225                 "The default group object is NULL. Create a new group object "
226                 "and set it to default instead.");
227 
228             group = lv_group_create();
229             if (group)
230             {
231                 lv_group_set_default(group);
232             }
233         }
234     }
235 
236     LV_ASSERT_MSG(group, "Cannot obtain an available group object.");
237 
238     lv_indev_set_group(lv_win32_pointer_device_object, group);
239     lv_indev_set_group(lv_win32_keypad_device_object, group);
240     lv_indev_set_group(lv_win32_encoder_device_object, group);
241 }
242 
lv_win32_get_window_context(HWND window_handle)243 EXTERN_C lv_win32_window_context_t* lv_win32_get_window_context(
244     HWND window_handle)
245 {
246     return (lv_win32_window_context_t*)(
247         GetPropW(window_handle, L"LVGL.SimulatorWindow.WindowContext"));
248 }
249 
lv_win32_init_window_class()250 EXTERN_C bool lv_win32_init_window_class()
251 {
252     WNDCLASSEXW window_class;
253     window_class.cbSize = sizeof(WNDCLASSEXW);
254     window_class.style = 0;
255     window_class.lpfnWndProc = lv_win32_window_message_callback;
256     window_class.cbClsExtra = 0;
257     window_class.cbWndExtra = 0;
258     window_class.hInstance = NULL;
259     window_class.hIcon = NULL;
260     window_class.hCursor = LoadCursorW(NULL, IDC_ARROW);
261     window_class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
262     window_class.lpszMenuName = NULL;
263     window_class.lpszClassName = LVGL_SIMULATOR_WINDOW_CLASS;
264     window_class.hIconSm = NULL;
265     return RegisterClassExW(&window_class);
266 }
267 
lv_win32_create_display_window(const wchar_t * window_title,lv_coord_t hor_res,lv_coord_t ver_res,HINSTANCE instance_handle,HICON icon_handle,int show_window_mode)268 EXTERN_C HWND lv_win32_create_display_window(
269     const wchar_t* window_title,
270     lv_coord_t hor_res,
271     lv_coord_t ver_res,
272     HINSTANCE instance_handle,
273     HICON icon_handle,
274     int show_window_mode)
275 {
276     HWND display_window_handle = CreateWindowExW(
277         WINDOW_EX_STYLE,
278         LVGL_SIMULATOR_WINDOW_CLASS,
279         window_title,
280         WINDOW_STYLE,
281         CW_USEDEFAULT,
282         0,
283         hor_res,
284         ver_res,
285         NULL,
286         NULL,
287         instance_handle,
288         NULL);
289     if (display_window_handle)
290     {
291         SendMessageW(
292             display_window_handle,
293             WM_SETICON,
294             TRUE,
295             (LPARAM)icon_handle);
296         SendMessageW(
297             display_window_handle,
298             WM_SETICON,
299             FALSE,
300             (LPARAM)icon_handle);
301 
302         ShowWindow(display_window_handle, show_window_mode);
303         UpdateWindow(display_window_handle);
304     }
305 
306     return display_window_handle;
307 }
308 
lv_win32_init(HINSTANCE instance_handle,int show_window_mode,lv_coord_t hor_res,lv_coord_t ver_res,HICON icon_handle)309 EXTERN_C bool lv_win32_init(
310     HINSTANCE instance_handle,
311     int show_window_mode,
312     lv_coord_t hor_res,
313     lv_coord_t ver_res,
314     HICON icon_handle)
315 {
316     if (!lv_win32_init_window_class())
317     {
318         return false;
319     }
320 
321     PWINDOW_THREAD_PARAMETER parameter =
322         (PWINDOW_THREAD_PARAMETER)malloc(sizeof(WINDOW_THREAD_PARAMETER));
323     parameter->window_mutex = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
324     parameter->instance_handle = instance_handle;
325     parameter->icon_handle = icon_handle;
326     parameter->hor_res = hor_res;
327     parameter->ver_res = ver_res;
328     parameter->show_window_mode = show_window_mode;
329 
330     _beginthreadex(
331         NULL,
332         0,
333         lv_win32_window_thread_entrypoint,
334         parameter,
335         0,
336         NULL);
337 
338     WaitForSingleObjectEx(parameter->window_mutex, INFINITE, FALSE);
339 
340     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
341         lv_win32_get_window_context(g_window_handle));
342     if (!context)
343     {
344         return false;
345     }
346 
347     lv_win32_pointer_device_object = context->mouse_device_object;
348     lv_win32_keypad_device_object = context->keyboard_device_object;
349     lv_win32_encoder_device_object = context->mousewheel_device_object;
350 
351     return true;
352 }
353 
354 /**********************
355  *   STATIC FUNCTIONS
356  **********************/
357 
lv_win32_create_frame_buffer(HWND WindowHandle,LONG Width,LONG Height,UINT32 ** PixelBuffer,SIZE_T * PixelBufferSize)358 static HDC lv_win32_create_frame_buffer(
359     HWND WindowHandle,
360     LONG Width,
361     LONG Height,
362     UINT32** PixelBuffer,
363     SIZE_T* PixelBufferSize)
364 {
365     HDC hFrameBufferDC = NULL;
366 
367     if (PixelBuffer && PixelBufferSize)
368     {
369         HDC hWindowDC = GetDC(WindowHandle);
370         if (hWindowDC)
371         {
372             hFrameBufferDC = CreateCompatibleDC(hWindowDC);
373             ReleaseDC(WindowHandle, hWindowDC);
374         }
375 
376         if (hFrameBufferDC)
377         {
378 #if LV_COLOR_DEPTH == 32
379             BITMAPINFO BitmapInfo = { 0 };
380 #elif LV_COLOR_DEPTH == 16
381             typedef struct _BITMAPINFO_16BPP {
382                 BITMAPINFOHEADER bmiHeader;
383                 DWORD bmiColorMask[3];
384             } BITMAPINFO_16BPP, *PBITMAPINFO_16BPP;
385 
386             BITMAPINFO_16BPP BitmapInfo = { 0 };
387 #elif LV_COLOR_DEPTH == 8
388             typedef struct _BITMAPINFO_8BPP {
389                 BITMAPINFOHEADER bmiHeader;
390                 RGBQUAD bmiColors[256];
391             } BITMAPINFO_8BPP, *PBITMAPINFO_8BPP;
392 
393             BITMAPINFO_8BPP BitmapInfo = { 0 };
394 #elif LV_COLOR_DEPTH == 1
395             typedef struct _BITMAPINFO_1BPP {
396                 BITMAPINFOHEADER bmiHeader;
397                 RGBQUAD bmiColors[2];
398             } BITMAPINFO_1BPP, *PBITMAPINFO_1BPP;
399 
400             BITMAPINFO_1BPP BitmapInfo = { 0 };
401 #else
402             BITMAPINFO BitmapInfo = { 0 };
403 #endif
404 
405             BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
406             BitmapInfo.bmiHeader.biWidth = Width;
407             BitmapInfo.bmiHeader.biHeight = -Height;
408             BitmapInfo.bmiHeader.biPlanes = 1;
409 #if LV_COLOR_DEPTH == 32
410             BitmapInfo.bmiHeader.biBitCount = 32;
411             BitmapInfo.bmiHeader.biCompression = BI_RGB;
412 #elif LV_COLOR_DEPTH == 16
413             BitmapInfo.bmiHeader.biBitCount = 16;
414             BitmapInfo.bmiHeader.biCompression = BI_BITFIELDS;
415             BitmapInfo.bmiColorMask[0] = 0xF800;
416             BitmapInfo.bmiColorMask[1] = 0x07E0;
417             BitmapInfo.bmiColorMask[2] = 0x001F;
418 #elif LV_COLOR_DEPTH == 8
419             BitmapInfo.bmiHeader.biBitCount = 8;
420             BitmapInfo.bmiHeader.biCompression = BI_RGB;
421             for (size_t i = 0; i < 256; ++i)
422             {
423                 lv_color8_t color;
424                 color.full = i;
425 
426                 BitmapInfo.bmiColors[i].rgbRed = LV_COLOR_GET_R(color) * 36;
427                 BitmapInfo.bmiColors[i].rgbGreen = LV_COLOR_GET_G(color) * 36;
428                 BitmapInfo.bmiColors[i].rgbBlue = LV_COLOR_GET_B(color) * 85;
429                 BitmapInfo.bmiColors[i].rgbReserved = 0xFF;
430             }
431 #elif LV_COLOR_DEPTH == 1
432             BitmapInfo.bmiHeader.biBitCount = 8;
433             BitmapInfo.bmiHeader.biCompression = BI_RGB;
434             BitmapInfo.bmiHeader.biClrUsed = 2;
435             BitmapInfo.bmiHeader.biClrImportant = 2;
436             BitmapInfo.bmiColors[0].rgbRed = 0x00;
437             BitmapInfo.bmiColors[0].rgbGreen = 0x00;
438             BitmapInfo.bmiColors[0].rgbBlue = 0x00;
439             BitmapInfo.bmiColors[0].rgbReserved = 0xFF;
440             BitmapInfo.bmiColors[1].rgbRed = 0xFF;
441             BitmapInfo.bmiColors[1].rgbGreen = 0xFF;
442             BitmapInfo.bmiColors[1].rgbBlue = 0xFF;
443             BitmapInfo.bmiColors[1].rgbReserved = 0xFF;
444 #else
445             BitmapInfo.bmiHeader.biBitCount = 32;
446             BitmapInfo.bmiHeader.biCompression = BI_RGB;
447 #endif
448 
449             HBITMAP hBitmap = CreateDIBSection(
450                 hFrameBufferDC,
451                 (PBITMAPINFO)(&BitmapInfo),
452                 DIB_RGB_COLORS,
453                 (void**)PixelBuffer,
454                 NULL,
455                 0);
456             if (hBitmap)
457             {
458 #if LV_COLOR_DEPTH == 32
459                 *PixelBufferSize = Width * Height * sizeof(UINT32);
460 #elif LV_COLOR_DEPTH == 16
461                 *PixelBufferSize = Width * Height * sizeof(UINT16);
462 #elif LV_COLOR_DEPTH == 8
463                 *PixelBufferSize = Width * Height * sizeof(UINT8);
464 #elif LV_COLOR_DEPTH == 1
465                 *PixelBufferSize = Width * Height * sizeof(UINT8);
466 #else
467                 *PixelBufferSize = Width * Height * sizeof(UINT32);
468 #endif
469 
470                 DeleteObject(SelectObject(hFrameBufferDC, hBitmap));
471                 DeleteObject(hBitmap);
472             }
473             else
474             {
475                 DeleteDC(hFrameBufferDC);
476                 hFrameBufferDC = NULL;
477             }
478         }
479     }
480 
481     return hFrameBufferDC;
482 }
483 
lv_win32_enable_child_window_dpi_message(HWND WindowHandle)484 static BOOL lv_win32_enable_child_window_dpi_message(
485     HWND WindowHandle)
486 {
487     // This hack is only for Windows 10 TH1/TH2 only.
488     // We don't need this hack if the Per Monitor Aware V2 is existed.
489     OSVERSIONINFOEXW OSVersionInfoEx = { 0 };
490     OSVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
491     OSVersionInfoEx.dwMajorVersion = 10;
492     OSVersionInfoEx.dwMinorVersion = 0;
493     OSVersionInfoEx.dwBuildNumber = 14393;
494     if (!VerifyVersionInfoW(
495         &OSVersionInfoEx,
496         VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER,
497         VerSetConditionMask(
498             VerSetConditionMask(
499                 VerSetConditionMask(
500                     0,
501                     VER_MAJORVERSION,
502                     VER_GREATER_EQUAL),
503                 VER_MINORVERSION,
504                 VER_GREATER_EQUAL),
505             VER_BUILDNUMBER,
506             VER_LESS)))
507     {
508         return FALSE;
509     }
510 
511     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
512     if (!ModuleHandle)
513     {
514         return FALSE;
515     }
516 
517     typedef BOOL(WINAPI* FunctionType)(HWND, BOOL);
518 
519     FunctionType pFunction = (FunctionType)(
520         GetProcAddress(ModuleHandle, "EnableChildWindowDpiMessage"));
521     if (!pFunction)
522     {
523         return FALSE;
524     }
525 
526     return pFunction(WindowHandle, TRUE);
527 }
528 
lv_win32_register_touch_window(HWND hWnd,ULONG ulFlags)529 static BOOL lv_win32_register_touch_window(
530     HWND hWnd,
531     ULONG ulFlags)
532 {
533     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
534     if (!ModuleHandle)
535     {
536         return FALSE;
537     }
538 
539     typedef BOOL(WINAPI* FunctionType)(HWND, ULONG);
540 
541     FunctionType pFunction = (FunctionType)(
542         GetProcAddress(ModuleHandle, "RegisterTouchWindow"));
543     if (!pFunction)
544     {
545         return FALSE;
546     }
547 
548     return pFunction(hWnd, ulFlags);
549 }
550 
lv_win32_get_touch_input_info(HTOUCHINPUT hTouchInput,UINT cInputs,PTOUCHINPUT pInputs,int cbSize)551 static BOOL lv_win32_get_touch_input_info(
552     HTOUCHINPUT hTouchInput,
553     UINT cInputs,
554     PTOUCHINPUT pInputs,
555     int cbSize)
556 {
557     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
558     if (!ModuleHandle)
559     {
560         return FALSE;
561     }
562 
563     typedef BOOL(WINAPI* FunctionType)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
564 
565     FunctionType pFunction = (FunctionType)(
566         GetProcAddress(ModuleHandle, "GetTouchInputInfo"));
567     if (!pFunction)
568     {
569         return FALSE;
570     }
571 
572     return pFunction(hTouchInput, cInputs, pInputs, cbSize);
573 }
574 
lv_win32_close_touch_input_handle(HTOUCHINPUT hTouchInput)575 static BOOL lv_win32_close_touch_input_handle(
576     HTOUCHINPUT hTouchInput)
577 {
578     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
579     if (!ModuleHandle)
580     {
581         return FALSE;
582     }
583 
584     typedef BOOL(WINAPI* FunctionType)(HTOUCHINPUT);
585 
586     FunctionType pFunction = (FunctionType)(
587         GetProcAddress(ModuleHandle, "CloseTouchInputHandle"));
588     if (!pFunction)
589     {
590         return FALSE;
591     }
592 
593     return pFunction(hTouchInput);
594 }
595 
lv_win32_get_dpi_for_window(_In_ HWND WindowHandle)596 static UINT lv_win32_get_dpi_for_window(
597     _In_ HWND WindowHandle)
598 {
599     UINT Result = (UINT)(-1);
600 
601     HMODULE ModuleHandle = LoadLibraryW(L"SHCore.dll");
602     if (ModuleHandle)
603     {
604         typedef enum MONITOR_DPI_TYPE_PRIVATE {
605             MDT_EFFECTIVE_DPI = 0,
606             MDT_ANGULAR_DPI = 1,
607             MDT_RAW_DPI = 2,
608             MDT_DEFAULT = MDT_EFFECTIVE_DPI
609         } MONITOR_DPI_TYPE_PRIVATE;
610 
611         typedef HRESULT(WINAPI* FunctionType)(
612             HMONITOR, MONITOR_DPI_TYPE_PRIVATE, UINT*, UINT*);
613 
614         FunctionType pFunction = (FunctionType)(
615             GetProcAddress(ModuleHandle, "GetDpiForMonitor"));
616         if (pFunction)
617         {
618             HMONITOR MonitorHandle = MonitorFromWindow(
619                 WindowHandle,
620                 MONITOR_DEFAULTTONEAREST);
621 
622             UINT dpiX = 0;
623             UINT dpiY = 0;
624             if (SUCCEEDED(pFunction(
625                 MonitorHandle,
626                 MDT_EFFECTIVE_DPI,
627                 &dpiX,
628                 &dpiY)))
629             {
630                 Result = dpiX;
631             }
632         }
633 
634         FreeLibrary(ModuleHandle);
635     }
636 
637     if (Result == (UINT)(-1))
638     {
639         HDC hWindowDC = GetDC(WindowHandle);
640         if (hWindowDC)
641         {
642             Result = GetDeviceCaps(hWindowDC, LOGPIXELSX);
643             ReleaseDC(WindowHandle, hWindowDC);
644         }
645     }
646 
647     if (Result == (UINT)(-1))
648     {
649         Result = USER_DEFAULT_SCREEN_DPI;
650     }
651 
652     return Result;
653 }
654 
lv_win32_display_driver_flush_callback(lv_disp_drv_t * disp_drv,const lv_area_t * area,lv_color_t * color_p)655 static void lv_win32_display_driver_flush_callback(
656     lv_disp_drv_t* disp_drv,
657     const lv_area_t* area,
658     lv_color_t* color_p)
659 {
660     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
661         lv_win32_get_window_context((HWND)disp_drv->user_data));
662     if (context)
663     {
664         if (lv_disp_flush_is_last(disp_drv))
665         {
666 #if (LV_COLOR_DEPTH == 32) || \
667     (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
668     (LV_COLOR_DEPTH == 8) || \
669     (LV_COLOR_DEPTH == 1)
670             UNREFERENCED_PARAMETER(color_p);
671 #elif (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0)
672             SIZE_T count = context->display_framebuffer_size / sizeof(UINT16);
673             PUINT16 source = (PUINT16)color_p;
674             PUINT16 destination = (PUINT16)context->display_framebuffer_base;
675             for (SIZE_T i = 0; i < count; ++i)
676             {
677                 UINT16 current = *source;
678                 *destination = (LOBYTE(current) << 8) | HIBYTE(current);
679 
680                 ++source;
681                 ++destination;
682             }
683 #else
684             uint32_t* destination = context->display_framebuffer_base;
685 
686             for (int y = area->y1; y <= area->y2; ++y)
687             {
688                 for (int x = area->x1; x <= area->x2; ++x)
689                 {
690                     destination[y * disp_drv->hor_res + x] =
691                         lv_color_to32(*color_p);
692                     color_p++;
693                 }
694             }
695 #endif
696 
697             InvalidateRect(disp_drv->user_data, NULL, FALSE);
698         }
699     }
700 
701     lv_disp_flush_ready(disp_drv);
702 }
703 
lv_win32_pointer_driver_read_callback(lv_indev_drv_t * indev_drv,lv_indev_data_t * data)704 static void lv_win32_pointer_driver_read_callback(
705     lv_indev_drv_t* indev_drv,
706     lv_indev_data_t* data)
707 {
708     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
709         lv_win32_get_display_context(indev_drv->disp));
710     if (!context)
711     {
712         return;
713     }
714 
715     data->state = context->mouse_state;
716     data->point = context->mouse_point;
717 }
718 
lv_win32_keypad_driver_read_callback(lv_indev_drv_t * indev_drv,lv_indev_data_t * data)719 static void lv_win32_keypad_driver_read_callback(
720     lv_indev_drv_t* indev_drv,
721     lv_indev_data_t* data)
722 {
723     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
724         lv_win32_get_display_context(indev_drv->disp));
725     if (!context)
726     {
727         return;
728     }
729 
730     EnterCriticalSection(&context->keyboard_mutex);
731 
732     lv_win32_keyboard_queue_item_t* current =
733         (lv_win32_keyboard_queue_item_t*)(InterlockedPopEntrySList(
734             context->keyboard_queue));
735     if (current)
736     {
737         data->key = current->key;
738         data->state = current->state;
739 
740         _aligned_free(current);
741 
742         data->continue_reading = true;
743     }
744 
745     LeaveCriticalSection(&context->keyboard_mutex);
746 }
747 
lv_win32_encoder_driver_read_callback(lv_indev_drv_t * indev_drv,lv_indev_data_t * data)748 static void lv_win32_encoder_driver_read_callback(
749     lv_indev_drv_t* indev_drv,
750     lv_indev_data_t* data)
751 {
752     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
753         lv_win32_get_display_context(indev_drv->disp));
754     if (!context)
755     {
756         return;
757     }
758 
759     data->state = context->mousewheel_state;
760     data->enc_diff = context->mousewheel_enc_diff;
761     context->mousewheel_enc_diff = 0;
762 }
763 
lv_win32_get_display_context(lv_disp_t * display)764 static lv_win32_window_context_t* lv_win32_get_display_context(
765     lv_disp_t* display)
766 {
767     if (display)
768     {
769         return lv_win32_get_window_context((HWND)display->driver->user_data);
770     }
771 
772     return NULL;
773 }
774 
lv_win32_window_message_callback(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)775 static LRESULT CALLBACK lv_win32_window_message_callback(
776     HWND   hWnd,
777     UINT   uMsg,
778     WPARAM wParam,
779     LPARAM lParam)
780 {
781     switch (uMsg)
782     {
783     case WM_CREATE:
784     {
785         // Note: Return -1 directly because WM_DESTROY message will be sent
786         // when destroy the window automatically. We free the resource when
787         // processing the WM_DESTROY message of this window.
788 
789         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
790             malloc(sizeof(lv_win32_window_context_t)));
791         if (!context)
792         {
793             return -1;
794         }
795 
796         RECT request_content_size;
797         GetWindowRect(hWnd, &request_content_size);
798 
799         context->display_hor_res =
800             request_content_size.right - request_content_size.left;
801         context->display_ver_res =
802             request_content_size.bottom - request_content_size.top;
803         context->display_dpi = lv_win32_get_dpi_for_window(hWnd);
804         context->display_framebuffer_context_handle =
805             lv_win32_create_frame_buffer(
806                 hWnd,
807                 context->display_hor_res,
808                 context->display_ver_res,
809                 &context->display_framebuffer_base,
810                 &context->display_framebuffer_size);
811 #if (LV_COLOR_DEPTH == 32) || \
812     (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
813     (LV_COLOR_DEPTH == 8) || \
814     (LV_COLOR_DEPTH == 1)
815         lv_disp_draw_buf_init(
816             &context->display_buffer,
817             (lv_color_t*)context->display_framebuffer_base,
818             NULL,
819             context->display_hor_res * context->display_ver_res);
820 #else
821         size_t draw_buffer_size = sizeof(lv_color_t);
822         draw_buffer_size *= context->display_hor_res;
823         draw_buffer_size *= context->display_ver_res;
824         lv_disp_draw_buf_init(
825             &context->display_buffer,
826             (lv_color_t*)malloc(draw_buffer_size),
827             NULL,
828             context->display_hor_res * context->display_ver_res);
829 #endif
830         lv_disp_drv_init(&context->display_driver);
831         context->display_driver.hor_res = context->display_hor_res;
832         context->display_driver.ver_res = context->display_ver_res;
833         context->display_driver.flush_cb =
834             lv_win32_display_driver_flush_callback;
835         context->display_driver.draw_buf = &context->display_buffer;
836         context->display_driver.direct_mode = 1;
837         context->display_driver.user_data = hWnd;
838         context->display_device_object =
839             lv_disp_drv_register(&context->display_driver);
840         if (!context->display_device_object)
841         {
842             return -1;
843         }
844 
845         context->mouse_state = LV_INDEV_STATE_REL;
846         context->mouse_point.x = 0;
847         context->mouse_point.y = 0;
848         lv_indev_drv_init(&context->mouse_driver);
849         context->mouse_driver.type = LV_INDEV_TYPE_POINTER;
850         context->mouse_driver.disp = context->display_device_object;
851         context->mouse_driver.read_cb =
852             lv_win32_pointer_driver_read_callback;
853         context->mouse_device_object =
854             lv_indev_drv_register(&context->mouse_driver);
855         if (!context->mouse_device_object)
856         {
857             return -1;
858         }
859 
860         context->mousewheel_state = LV_INDEV_STATE_REL;
861         context->mousewheel_enc_diff = 0;
862         lv_indev_drv_init(&context->mousewheel_driver);
863         context->mousewheel_driver.type = LV_INDEV_TYPE_ENCODER;
864         context->mousewheel_driver.disp = context->display_device_object;
865         context->mousewheel_driver.read_cb =
866             lv_win32_encoder_driver_read_callback;
867         context->mousewheel_device_object =
868             lv_indev_drv_register(&context->mousewheel_driver);
869         if (!context->mousewheel_device_object)
870         {
871             return -1;
872         }
873 
874         InitializeCriticalSection(&context->keyboard_mutex);
875         context->keyboard_queue = _aligned_malloc(
876             sizeof(SLIST_HEADER),
877             MEMORY_ALLOCATION_ALIGNMENT);
878         if (!context->keyboard_queue)
879         {
880             return -1;
881         }
882         InitializeSListHead(context->keyboard_queue);
883         context->keyboard_utf16_high_surrogate = 0;
884         context->keyboard_utf16_low_surrogate = 0;
885         lv_indev_drv_init(&context->keyboard_driver);
886         context->keyboard_driver.type = LV_INDEV_TYPE_KEYPAD;
887         context->keyboard_driver.disp = context->display_device_object;
888         context->keyboard_driver.read_cb =
889             lv_win32_keypad_driver_read_callback;
890         context->keyboard_device_object =
891             lv_indev_drv_register(&context->keyboard_driver);
892         if (!context->keyboard_device_object)
893         {
894             return -1;
895         }
896 
897         if (!SetPropW(
898             hWnd,
899             L"LVGL.SimulatorWindow.WindowContext",
900             (HANDLE)(context)))
901         {
902             return -1;
903         }
904 
905         RECT calculated_window_size;
906 
907         calculated_window_size.left = 0;
908         calculated_window_size.right = MulDiv(
909             context->display_hor_res * WIN32DRV_MONITOR_ZOOM,
910             context->display_dpi,
911             USER_DEFAULT_SCREEN_DPI);
912         calculated_window_size.top = 0;
913         calculated_window_size.bottom = MulDiv(
914             context->display_ver_res * WIN32DRV_MONITOR_ZOOM,
915             context->display_dpi,
916             USER_DEFAULT_SCREEN_DPI);
917 
918         AdjustWindowRectEx(
919             &calculated_window_size,
920             WINDOW_STYLE,
921             FALSE,
922             WINDOW_EX_STYLE);
923         OffsetRect(
924             &calculated_window_size,
925             -calculated_window_size.left,
926             -calculated_window_size.top);
927 
928         SetWindowPos(
929             hWnd,
930             NULL,
931             0,
932             0,
933             calculated_window_size.right,
934             calculated_window_size.bottom,
935             SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
936 
937         lv_win32_register_touch_window(hWnd, 0);
938 
939         lv_win32_enable_child_window_dpi_message(hWnd);
940 
941         break;
942     }
943     case WM_MOUSEMOVE:
944     case WM_LBUTTONDOWN:
945     case WM_LBUTTONUP:
946     case WM_MBUTTONDOWN:
947     case WM_MBUTTONUP:
948     {
949         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
950             lv_win32_get_window_context(hWnd));
951         if (!context)
952         {
953             return 0;
954         }
955 
956         context->mouse_point.x = MulDiv(
957             GET_X_LPARAM(lParam),
958             USER_DEFAULT_SCREEN_DPI,
959             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
960         context->mouse_point.y = MulDiv(
961             GET_Y_LPARAM(lParam),
962             USER_DEFAULT_SCREEN_DPI,
963             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
964         if (context->mouse_point.x < 0)
965         {
966             context->mouse_point.x = 0;
967         }
968         if (context->mouse_point.x > context->display_hor_res - 1)
969         {
970             context->mouse_point.x = context->display_hor_res - 1;
971         }
972         if (context->mouse_point.y < 0)
973         {
974             context->mouse_point.y = 0;
975         }
976         if (context->mouse_point.y > context->display_ver_res - 1)
977         {
978             context->mouse_point.y = context->display_ver_res - 1;
979         }
980 
981         if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
982         {
983             context->mouse_state = (
984                 uMsg == WM_LBUTTONDOWN
985                 ? LV_INDEV_STATE_PR
986                 : LV_INDEV_STATE_REL);
987         }
988         else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
989         {
990             context->mousewheel_state = (
991                 uMsg == WM_MBUTTONDOWN
992                 ? LV_INDEV_STATE_PR
993                 : LV_INDEV_STATE_REL);
994         }
995         return 0;
996     }
997     case WM_KEYDOWN:
998     case WM_KEYUP:
999     {
1000         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1001             lv_win32_get_window_context(hWnd));
1002         if (context)
1003         {
1004             EnterCriticalSection(&context->keyboard_mutex);
1005 
1006             bool skip_translation = false;
1007             uint32_t translated_key = 0;
1008 
1009             switch (wParam)
1010             {
1011             case VK_UP:
1012                 translated_key = LV_KEY_UP;
1013                 break;
1014             case VK_DOWN:
1015                 translated_key = LV_KEY_DOWN;
1016                 break;
1017             case VK_LEFT:
1018                 translated_key = LV_KEY_LEFT;
1019                 break;
1020             case VK_RIGHT:
1021                 translated_key = LV_KEY_RIGHT;
1022                 break;
1023             case VK_ESCAPE:
1024                 translated_key = LV_KEY_ESC;
1025                 break;
1026             case VK_DELETE:
1027                 translated_key = LV_KEY_DEL;
1028                 break;
1029             case VK_BACK:
1030                 translated_key = LV_KEY_BACKSPACE;
1031                 break;
1032             case VK_RETURN:
1033                 translated_key = LV_KEY_ENTER;
1034                 break;
1035             case VK_TAB:
1036             case VK_NEXT:
1037                 translated_key = LV_KEY_NEXT;
1038                 break;
1039             case VK_PRIOR:
1040                 translated_key = LV_KEY_PREV;
1041                 break;
1042             case VK_HOME:
1043                 translated_key = LV_KEY_HOME;
1044                 break;
1045             case VK_END:
1046                 translated_key = LV_KEY_END;
1047                 break;
1048             default:
1049                 skip_translation = true;
1050                 break;
1051             }
1052 
1053             if (!skip_translation)
1054             {
1055                 lv_win32_push_key_to_keyboard_queue(
1056                     context,
1057                     translated_key,
1058                     ((uMsg == WM_KEYUP)
1059                         ? LV_INDEV_STATE_REL
1060                         : LV_INDEV_STATE_PR));
1061             }
1062 
1063             LeaveCriticalSection(&context->keyboard_mutex);
1064         }
1065 
1066         break;
1067     }
1068     case WM_CHAR:
1069     {
1070         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1071             lv_win32_get_window_context(hWnd));
1072         if (context)
1073         {
1074             EnterCriticalSection(&context->keyboard_mutex);
1075 
1076             uint16_t raw_code_point = (uint16_t)(wParam);
1077 
1078             if (raw_code_point >= 0x20 && raw_code_point != 0x7F)
1079             {
1080                 if (IS_HIGH_SURROGATE(raw_code_point))
1081                 {
1082                     context->keyboard_utf16_high_surrogate = raw_code_point;
1083                 }
1084                 else if (IS_LOW_SURROGATE(raw_code_point))
1085                 {
1086                     context->keyboard_utf16_low_surrogate = raw_code_point;
1087                 }
1088 
1089                 uint32_t code_point = raw_code_point;
1090 
1091                 if (context->keyboard_utf16_high_surrogate &&
1092                     context->keyboard_utf16_low_surrogate)
1093                 {
1094                     uint16_t high_surrogate =
1095                         context->keyboard_utf16_high_surrogate;
1096                     uint16_t low_surrogate =
1097                         context->keyboard_utf16_low_surrogate;
1098 
1099                     code_point = (low_surrogate & 0x03FF);
1100                     code_point += (((high_surrogate & 0x03FF) + 0x40) << 10);
1101 
1102                     context->keyboard_utf16_high_surrogate = 0;
1103                     context->keyboard_utf16_low_surrogate = 0;
1104                 }
1105 
1106                 uint32_t lvgl_code_point =
1107                     _lv_txt_unicode_to_encoded(code_point);
1108 
1109                 lv_win32_push_key_to_keyboard_queue(
1110                     context,
1111                     lvgl_code_point,
1112                     LV_INDEV_STATE_PR);
1113                 lv_win32_push_key_to_keyboard_queue(
1114                     context,
1115                     lvgl_code_point,
1116                     LV_INDEV_STATE_REL);
1117             }
1118 
1119             LeaveCriticalSection(&context->keyboard_mutex);
1120         }
1121 
1122         break;
1123     }
1124     case WM_MOUSEWHEEL:
1125     {
1126         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1127             lv_win32_get_window_context(hWnd));
1128         if (context)
1129         {
1130             context->mousewheel_enc_diff =
1131                 -(GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);
1132         }
1133 
1134         break;
1135     }
1136     case WM_TOUCH:
1137     {
1138         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1139             lv_win32_get_window_context(hWnd));
1140         if (context)
1141         {
1142             UINT cInputs = LOWORD(wParam);
1143             HTOUCHINPUT hTouchInput = (HTOUCHINPUT)(lParam);
1144 
1145             PTOUCHINPUT pInputs = malloc(cInputs * sizeof(TOUCHINPUT));
1146             if (pInputs)
1147             {
1148                 if (lv_win32_get_touch_input_info(
1149                     hTouchInput,
1150                     cInputs,
1151                     pInputs,
1152                     sizeof(TOUCHINPUT)))
1153                 {
1154                     for (UINT i = 0; i < cInputs; ++i)
1155                     {
1156                         POINT Point;
1157                         Point.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
1158                         Point.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
1159                         if (!ScreenToClient(hWnd, &Point))
1160                         {
1161                             continue;
1162                         }
1163 
1164                         context->mouse_point.x = MulDiv(
1165                             Point.x,
1166                             USER_DEFAULT_SCREEN_DPI,
1167                             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
1168                         context->mouse_point.y = MulDiv(
1169                             Point.y,
1170                             USER_DEFAULT_SCREEN_DPI,
1171                             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
1172 
1173                         DWORD MousePressedMask =
1174                             TOUCHEVENTF_MOVE | TOUCHEVENTF_DOWN;
1175 
1176                         context->mouse_state = (
1177                             pInputs[i].dwFlags & MousePressedMask
1178                             ? LV_INDEV_STATE_PR
1179                             : LV_INDEV_STATE_REL);
1180                     }
1181                 }
1182 
1183                 free(pInputs);
1184             }
1185 
1186             lv_win32_close_touch_input_handle(hTouchInput);
1187         }
1188 
1189         break;
1190     }
1191     case WM_DPICHANGED:
1192     {
1193         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1194             lv_win32_get_window_context(hWnd));
1195         if (context)
1196         {
1197             context->display_dpi = HIWORD(wParam);
1198 
1199             LPRECT SuggestedRect = (LPRECT)lParam;
1200 
1201             SetWindowPos(
1202                 hWnd,
1203                 NULL,
1204                 SuggestedRect->left,
1205                 SuggestedRect->top,
1206                 SuggestedRect->right,
1207                 SuggestedRect->bottom,
1208                 SWP_NOZORDER | SWP_NOACTIVATE);
1209 
1210             RECT ClientRect;
1211             GetClientRect(hWnd, &ClientRect);
1212 
1213             int WindowWidth = MulDiv(
1214                 context->display_hor_res * WIN32DRV_MONITOR_ZOOM,
1215                 context->display_dpi,
1216                 USER_DEFAULT_SCREEN_DPI);
1217             int WindowHeight = MulDiv(
1218                 context->display_ver_res * WIN32DRV_MONITOR_ZOOM,
1219                 context->display_dpi,
1220                 USER_DEFAULT_SCREEN_DPI);
1221 
1222             SetWindowPos(
1223                 hWnd,
1224                 NULL,
1225                 SuggestedRect->left,
1226                 SuggestedRect->top,
1227                 SuggestedRect->right + (WindowWidth - ClientRect.right),
1228                 SuggestedRect->bottom + (WindowHeight - ClientRect.bottom),
1229                 SWP_NOZORDER | SWP_NOACTIVATE);
1230         }
1231 
1232         break;
1233     }
1234     case WM_PAINT:
1235     {
1236         PAINTSTRUCT ps;
1237         HDC hdc = BeginPaint(hWnd, &ps);
1238 
1239         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1240             lv_win32_get_window_context(hWnd));
1241         if (context)
1242         {
1243             if (context->display_framebuffer_context_handle)
1244             {
1245                 SetStretchBltMode(hdc, HALFTONE);
1246 
1247                 StretchBlt(
1248                     hdc,
1249                     ps.rcPaint.left,
1250                     ps.rcPaint.top,
1251                     ps.rcPaint.right - ps.rcPaint.left,
1252                     ps.rcPaint.bottom - ps.rcPaint.top,
1253                     context->display_framebuffer_context_handle,
1254                     0,
1255                     0,
1256                     MulDiv(
1257                         ps.rcPaint.right - ps.rcPaint.left,
1258                         USER_DEFAULT_SCREEN_DPI,
1259                         WIN32DRV_MONITOR_ZOOM * context->display_dpi),
1260                     MulDiv(
1261                         ps.rcPaint.bottom - ps.rcPaint.top,
1262                         USER_DEFAULT_SCREEN_DPI,
1263                         WIN32DRV_MONITOR_ZOOM * context->display_dpi),
1264                     SRCCOPY);
1265             }
1266         }
1267 
1268         EndPaint(hWnd, &ps);
1269 
1270         break;
1271     }
1272     case WM_DESTROY:
1273     {
1274         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
1275             RemovePropW(hWnd, L"LVGL.SimulatorWindow.WindowContext"));
1276         if (context)
1277         {
1278             lv_disp_t* display_device_object = context->display_device_object;
1279             context->display_device_object = NULL;
1280             lv_disp_remove(display_device_object);
1281 #if (LV_COLOR_DEPTH == 32) || \
1282     (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
1283     (LV_COLOR_DEPTH == 8) || \
1284     (LV_COLOR_DEPTH == 1)
1285 #else
1286             free(context->display_buffer.buf1);
1287 #endif
1288             DeleteDC(context->display_framebuffer_context_handle);
1289 
1290             lv_indev_t* mouse_device_object =
1291                 context->mouse_device_object;
1292             context->mouse_device_object = NULL;
1293             lv_indev_delete(mouse_device_object);
1294 
1295             lv_indev_t* mousewheel_device_object =
1296                 context->mousewheel_device_object;
1297             context->mousewheel_device_object = NULL;
1298             lv_indev_delete(mousewheel_device_object);
1299 
1300             lv_indev_t* keyboard_device_object =
1301                 context->keyboard_device_object;
1302             context->keyboard_device_object = NULL;
1303             lv_indev_delete(keyboard_device_object);
1304             do
1305             {
1306                 PSLIST_ENTRY current = InterlockedPopEntrySList(
1307                     context->keyboard_queue);
1308                 if (!current)
1309                 {
1310                     _aligned_free(context->keyboard_queue);
1311                     context->keyboard_queue = NULL;
1312                     break;
1313                 }
1314 
1315                 _aligned_free(current);
1316 
1317             } while (true);
1318             DeleteCriticalSection(&context->keyboard_mutex);
1319 
1320             free(context);
1321         }
1322 
1323         PostQuitMessage(0);
1324 
1325         break;
1326     }
1327     default:
1328         return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1329     }
1330 
1331     return 0;
1332 }
1333 
lv_win32_window_thread_entrypoint(void * raw_parameter)1334 static unsigned int __stdcall lv_win32_window_thread_entrypoint(
1335     void* raw_parameter)
1336 {
1337     PWINDOW_THREAD_PARAMETER parameter =
1338         (PWINDOW_THREAD_PARAMETER)raw_parameter;
1339 
1340     g_window_handle = lv_win32_create_display_window(
1341         L"LVGL Simulator for Windows Desktop (Display 1)",
1342         parameter->hor_res,
1343         parameter->ver_res,
1344         parameter->instance_handle,
1345         parameter->icon_handle,
1346         parameter->show_window_mode);
1347     if (!g_window_handle)
1348     {
1349         return 0;
1350     }
1351 
1352     SetEvent(parameter->window_mutex);
1353 
1354     MSG message;
1355     while (GetMessageW(&message, NULL, 0, 0))
1356     {
1357         TranslateMessage(&message);
1358         DispatchMessageW(&message);
1359     }
1360 
1361     lv_win32_quit_signal = true;
1362 
1363     return 0;
1364 }
1365 
1366 #endif /*USE_WIN32DRV*/
1367