mirror of
				https://gitee.com/jiuyilian/embedded-framework.git
				synced 2025-10-24 18:20:15 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			1367 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1367 lines
		
	
	
		
			40 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * @file win32drv.c
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*********************
 | |
|  *      INCLUDES
 | |
|  *********************/
 | |
| 
 | |
| #include "win32drv.h"
 | |
| 
 | |
| #if USE_WIN32DRV
 | |
| 
 | |
| #include <windowsx.h>
 | |
| #include <malloc.h>
 | |
| #include <process.h>
 | |
| #include <stdbool.h>
 | |
| #include <stdint.h>
 | |
| 
 | |
| /*********************
 | |
|  *      DEFINES
 | |
|  *********************/
 | |
| 
 | |
| #define WINDOW_EX_STYLE \
 | |
|     WS_EX_CLIENTEDGE
 | |
| 
 | |
| #define WINDOW_STYLE \
 | |
|     (WS_OVERLAPPEDWINDOW & ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME))
 | |
| 
 | |
| #ifndef WIN32DRV_MONITOR_ZOOM
 | |
| #define WIN32DRV_MONITOR_ZOOM 1
 | |
| #endif
 | |
| 
 | |
| #ifndef USER_DEFAULT_SCREEN_DPI
 | |
| #define USER_DEFAULT_SCREEN_DPI 96
 | |
| #endif
 | |
| 
 | |
| /**********************
 | |
|  *      TYPEDEFS
 | |
|  **********************/
 | |
| 
 | |
| typedef struct _WINDOW_THREAD_PARAMETER
 | |
| {
 | |
|     HANDLE window_mutex;
 | |
|     HINSTANCE instance_handle;
 | |
|     HICON icon_handle;
 | |
|     lv_coord_t hor_res;
 | |
|     lv_coord_t ver_res;
 | |
|     int show_window_mode;
 | |
| } WINDOW_THREAD_PARAMETER, * PWINDOW_THREAD_PARAMETER;
 | |
| 
 | |
| /**********************
 | |
|  *  STATIC PROTOTYPES
 | |
|  **********************/
 | |
| 
 | |
| /**
 | |
|  * @brief Creates a B8G8R8A8 frame buffer.
 | |
|  * @param WindowHandle A handle to the window for the creation of the frame
 | |
|  *                     buffer. If this value is NULL, the entire screen will be
 | |
|  *                     referenced.
 | |
|  * @param Width The width of the frame buffer.
 | |
|  * @param Height The height of the frame buffer.
 | |
|  * @param PixelBuffer The raw pixel buffer of the frame buffer you created.
 | |
|  * @param PixelBufferSize The size of the frame buffer you created.
 | |
|  * @return If the function succeeds, the return value is a handle to the device
 | |
|  *         context (DC) for the frame buffer. If the function fails, the return
 | |
|  *         value is NULL, and PixelBuffer parameter is NULL.
 | |
| */
 | |
| static HDC lv_win32_create_frame_buffer(
 | |
|     _In_opt_ HWND WindowHandle,
 | |
|     _In_ LONG Width,
 | |
|     _In_ LONG Height,
 | |
|     _Out_ UINT32** PixelBuffer,
 | |
|     _Out_ SIZE_T* PixelBufferSize);
 | |
| 
 | |
| /**
 | |
|  * @brief Enables WM_DPICHANGED message for child window for the associated
 | |
|  *        window.
 | |
|  * @param WindowHandle The window you want to enable WM_DPICHANGED message for
 | |
|  *                     child window.
 | |
|  * @return If the function succeeds, the return value is non-zero. If the
 | |
|  *         function fails, the return value is zero.
 | |
|  * @remarks You need to use this function in Windows 10 Threshold 1 or Windows
 | |
|  *          10 Threshold 2.
 | |
| */
 | |
| static BOOL lv_win32_enable_child_window_dpi_message(
 | |
|     _In_ HWND WindowHandle);
 | |
| 
 | |
| /**
 | |
|  * @brief Registers a window as being touch-capable.
 | |
|  * @param hWnd The handle of the window being registered.
 | |
|  * @param ulFlags A set of bit flags that specify optional modifications.
 | |
|  * @return If the function succeeds, the return value is nonzero. If the
 | |
|  *         function fails, the return value is zero.
 | |
|  * @remark For more information, see RegisterTouchWindow.
 | |
| */
 | |
| static BOOL lv_win32_register_touch_window(
 | |
|     HWND hWnd,
 | |
|     ULONG ulFlags);
 | |
| 
 | |
| /**
 | |
|  * @brief Retrieves detailed information about touch inputs associated with a
 | |
|  *        particular touch input handle.
 | |
|  * @param hTouchInput The touch input handle received in the LPARAM of a touch
 | |
|  *                    message.
 | |
|  * @param cInputs The number of structures in the pInputs array.
 | |
|  * @param pInputs A pointer to an array of TOUCHINPUT structures to receive
 | |
|  *                information about the touch points associated with the
 | |
|  *                specified touch input handle.
 | |
|  * @param cbSize The size, in bytes, of a single TOUCHINPUT structure.
 | |
|  * @return If the function succeeds, the return value is nonzero. If the
 | |
|  *         function fails, the return value is zero.
 | |
|  * @remark For more information, see GetTouchInputInfo.
 | |
| */
 | |
| static BOOL lv_win32_get_touch_input_info(
 | |
|     HTOUCHINPUT hTouchInput,
 | |
|     UINT cInputs,
 | |
|     PTOUCHINPUT pInputs,
 | |
|     int cbSize);
 | |
| 
 | |
| /**
 | |
|  * @brief Closes a touch input handle, frees process memory associated with it,
 | |
|           and invalidates the handle.
 | |
|  * @param hTouchInput The touch input handle received in the LPARAM of a touch
 | |
|  *                    message.
 | |
|  * @return If the function succeeds, the return value is nonzero. If the
 | |
|  *         function fails, the return value is zero.
 | |
|  * @remark For more information, see CloseTouchInputHandle.
 | |
| */
 | |
| static BOOL lv_win32_close_touch_input_handle(
 | |
|     HTOUCHINPUT hTouchInput);
 | |
| 
 | |
| /**
 | |
|  * @brief Returns the dots per inch (dpi) value for the associated window.
 | |
|  * @param WindowHandle The window you want to get information about.
 | |
|  * @return The DPI for the window.
 | |
| */
 | |
| static UINT lv_win32_get_dpi_for_window(
 | |
|     _In_ HWND WindowHandle);
 | |
| 
 | |
| static void lv_win32_display_driver_flush_callback(
 | |
|     lv_disp_drv_t* disp_drv,
 | |
|     const lv_area_t* area,
 | |
|     lv_color_t* color_p);
 | |
| 
 | |
| static void lv_win32_pointer_driver_read_callback(
 | |
|     lv_indev_drv_t* indev_drv,
 | |
|     lv_indev_data_t* data);
 | |
| 
 | |
| static void lv_win32_keypad_driver_read_callback(
 | |
|     lv_indev_drv_t* indev_drv,
 | |
|     lv_indev_data_t* data);
 | |
| 
 | |
| static void lv_win32_encoder_driver_read_callback(
 | |
|     lv_indev_drv_t* indev_drv,
 | |
|     lv_indev_data_t* data);
 | |
| 
 | |
| static lv_win32_window_context_t* lv_win32_get_display_context(
 | |
|     lv_disp_t* display);
 | |
| 
 | |
| static LRESULT CALLBACK lv_win32_window_message_callback(
 | |
|     HWND   hWnd,
 | |
|     UINT   uMsg,
 | |
|     WPARAM wParam,
 | |
|     LPARAM lParam);
 | |
| 
 | |
| static unsigned int __stdcall lv_win32_window_thread_entrypoint(
 | |
|     void* raw_parameter);
 | |
| 
 | |
| static void lv_win32_push_key_to_keyboard_queue(
 | |
|     lv_win32_window_context_t* context,
 | |
|     uint32_t key,
 | |
|     lv_indev_state_t state)
 | |
| {
 | |
|     lv_win32_keyboard_queue_item_t* current =
 | |
|         (lv_win32_keyboard_queue_item_t*)(_aligned_malloc(
 | |
|             sizeof(lv_win32_keyboard_queue_item_t),
 | |
|             MEMORY_ALLOCATION_ALIGNMENT));
 | |
|     if (current)
 | |
|     {
 | |
|         current->key = key;
 | |
|         current->state = state;
 | |
|         InterlockedPushEntrySList(
 | |
|             context->keyboard_queue,
 | |
|             ¤t->ItemEntry);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /**********************
 | |
|  *  GLOBAL VARIABLES
 | |
|  **********************/
 | |
| 
 | |
| EXTERN_C bool lv_win32_quit_signal = false;
 | |
| 
 | |
| EXTERN_C lv_indev_t* lv_win32_pointer_device_object = NULL;
 | |
| EXTERN_C lv_indev_t* lv_win32_keypad_device_object = NULL;
 | |
| EXTERN_C lv_indev_t* lv_win32_encoder_device_object = NULL;
 | |
| 
 | |
| /**********************
 | |
|  *  STATIC VARIABLES
 | |
|  **********************/
 | |
| 
 | |
| static HWND g_window_handle = NULL;
 | |
| 
 | |
| /**********************
 | |
|  *      MACROS
 | |
|  **********************/
 | |
| 
 | |
| /**********************
 | |
|  *   GLOBAL FUNCTIONS
 | |
|  **********************/
 | |
| 
 | |
| EXTERN_C void lv_win32_add_all_input_devices_to_group(
 | |
|     lv_group_t* group)
 | |
| {
 | |
|     if (!group)
 | |
|     {
 | |
|         LV_LOG_WARN(
 | |
|             "The group object is NULL. Get the default group object instead.");
 | |
| 
 | |
|         group = lv_group_get_default();
 | |
|         if (!group)
 | |
|         {
 | |
|             LV_LOG_WARN(
 | |
|                 "The default group object is NULL. Create a new group object "
 | |
|                 "and set it to default instead.");
 | |
| 
 | |
|             group = lv_group_create();
 | |
|             if (group)
 | |
|             {
 | |
|                 lv_group_set_default(group);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     LV_ASSERT_MSG(group, "Cannot obtain an available group object.");
 | |
| 
 | |
|     lv_indev_set_group(lv_win32_pointer_device_object, group);
 | |
|     lv_indev_set_group(lv_win32_keypad_device_object, group);
 | |
|     lv_indev_set_group(lv_win32_encoder_device_object, group);
 | |
| }
 | |
| 
 | |
| EXTERN_C lv_win32_window_context_t* lv_win32_get_window_context(
 | |
|     HWND window_handle)
 | |
| {
 | |
|     return (lv_win32_window_context_t*)(
 | |
|         GetPropW(window_handle, L"LVGL.SimulatorWindow.WindowContext"));
 | |
| }
 | |
| 
 | |
| EXTERN_C bool lv_win32_init_window_class()
 | |
| {
 | |
|     WNDCLASSEXW window_class;
 | |
|     window_class.cbSize = sizeof(WNDCLASSEXW);
 | |
|     window_class.style = 0;
 | |
|     window_class.lpfnWndProc = lv_win32_window_message_callback;
 | |
|     window_class.cbClsExtra = 0;
 | |
|     window_class.cbWndExtra = 0;
 | |
|     window_class.hInstance = NULL;
 | |
|     window_class.hIcon = NULL;
 | |
|     window_class.hCursor = LoadCursorW(NULL, IDC_ARROW);
 | |
|     window_class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
 | |
|     window_class.lpszMenuName = NULL;
 | |
|     window_class.lpszClassName = LVGL_SIMULATOR_WINDOW_CLASS;
 | |
|     window_class.hIconSm = NULL;
 | |
|     return RegisterClassExW(&window_class);
 | |
| }
 | |
| 
 | |
| EXTERN_C HWND 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)
 | |
| {
 | |
|     HWND display_window_handle = CreateWindowExW(
 | |
|         WINDOW_EX_STYLE,
 | |
|         LVGL_SIMULATOR_WINDOW_CLASS,
 | |
|         window_title,
 | |
|         WINDOW_STYLE,
 | |
|         CW_USEDEFAULT,
 | |
|         0,
 | |
|         hor_res,
 | |
|         ver_res,
 | |
|         NULL,
 | |
|         NULL,
 | |
|         instance_handle,
 | |
|         NULL);
 | |
|     if (display_window_handle)
 | |
|     {
 | |
|         SendMessageW(
 | |
|             display_window_handle,
 | |
|             WM_SETICON,
 | |
|             TRUE,
 | |
|             (LPARAM)icon_handle);
 | |
|         SendMessageW(
 | |
|             display_window_handle,
 | |
|             WM_SETICON,
 | |
|             FALSE,
 | |
|             (LPARAM)icon_handle);
 | |
| 
 | |
|         ShowWindow(display_window_handle, show_window_mode);
 | |
|         UpdateWindow(display_window_handle);
 | |
|     }
 | |
| 
 | |
|     return display_window_handle;
 | |
| }
 | |
| 
 | |
| EXTERN_C bool lv_win32_init(
 | |
|     HINSTANCE instance_handle,
 | |
|     int show_window_mode,
 | |
|     lv_coord_t hor_res,
 | |
|     lv_coord_t ver_res,
 | |
|     HICON icon_handle)
 | |
| {
 | |
|     if (!lv_win32_init_window_class())
 | |
|     {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     PWINDOW_THREAD_PARAMETER parameter =
 | |
|         (PWINDOW_THREAD_PARAMETER)malloc(sizeof(WINDOW_THREAD_PARAMETER));
 | |
|     parameter->window_mutex = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
 | |
|     parameter->instance_handle = instance_handle;
 | |
|     parameter->icon_handle = icon_handle;
 | |
|     parameter->hor_res = hor_res;
 | |
|     parameter->ver_res = ver_res;
 | |
|     parameter->show_window_mode = show_window_mode;
 | |
| 
 | |
|     _beginthreadex(
 | |
|         NULL,
 | |
|         0,
 | |
|         lv_win32_window_thread_entrypoint,
 | |
|         parameter,
 | |
|         0,
 | |
|         NULL);
 | |
| 
 | |
|     WaitForSingleObjectEx(parameter->window_mutex, INFINITE, FALSE);
 | |
| 
 | |
|     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|         lv_win32_get_window_context(g_window_handle));
 | |
|     if (!context)
 | |
|     {
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     lv_win32_pointer_device_object = context->mouse_device_object;
 | |
|     lv_win32_keypad_device_object = context->keyboard_device_object;
 | |
|     lv_win32_encoder_device_object = context->mousewheel_device_object;
 | |
| 
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| /**********************
 | |
|  *   STATIC FUNCTIONS
 | |
|  **********************/
 | |
| 
 | |
| static HDC lv_win32_create_frame_buffer(
 | |
|     HWND WindowHandle,
 | |
|     LONG Width,
 | |
|     LONG Height,
 | |
|     UINT32** PixelBuffer,
 | |
|     SIZE_T* PixelBufferSize)
 | |
| {
 | |
|     HDC hFrameBufferDC = NULL;
 | |
| 
 | |
|     if (PixelBuffer && PixelBufferSize)
 | |
|     {
 | |
|         HDC hWindowDC = GetDC(WindowHandle);
 | |
|         if (hWindowDC)
 | |
|         {
 | |
|             hFrameBufferDC = CreateCompatibleDC(hWindowDC);
 | |
|             ReleaseDC(WindowHandle, hWindowDC);
 | |
|         }
 | |
| 
 | |
|         if (hFrameBufferDC)
 | |
|         {
 | |
| #if LV_COLOR_DEPTH == 32
 | |
|             BITMAPINFO BitmapInfo = { 0 };
 | |
| #elif LV_COLOR_DEPTH == 16
 | |
|             typedef struct _BITMAPINFO_16BPP {
 | |
|                 BITMAPINFOHEADER bmiHeader;
 | |
|                 DWORD bmiColorMask[3];
 | |
|             } BITMAPINFO_16BPP, *PBITMAPINFO_16BPP;
 | |
| 
 | |
|             BITMAPINFO_16BPP BitmapInfo = { 0 };
 | |
| #elif LV_COLOR_DEPTH == 8
 | |
|             typedef struct _BITMAPINFO_8BPP {
 | |
|                 BITMAPINFOHEADER bmiHeader;
 | |
|                 RGBQUAD bmiColors[256];
 | |
|             } BITMAPINFO_8BPP, *PBITMAPINFO_8BPP;
 | |
| 
 | |
|             BITMAPINFO_8BPP BitmapInfo = { 0 };
 | |
| #elif LV_COLOR_DEPTH == 1
 | |
|             typedef struct _BITMAPINFO_1BPP {
 | |
|                 BITMAPINFOHEADER bmiHeader;
 | |
|                 RGBQUAD bmiColors[2];
 | |
|             } BITMAPINFO_1BPP, *PBITMAPINFO_1BPP;
 | |
| 
 | |
|             BITMAPINFO_1BPP BitmapInfo = { 0 };
 | |
| #else
 | |
|             BITMAPINFO BitmapInfo = { 0 };
 | |
| #endif
 | |
| 
 | |
|             BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 | |
|             BitmapInfo.bmiHeader.biWidth = Width;
 | |
|             BitmapInfo.bmiHeader.biHeight = -Height;
 | |
|             BitmapInfo.bmiHeader.biPlanes = 1;
 | |
| #if LV_COLOR_DEPTH == 32
 | |
|             BitmapInfo.bmiHeader.biBitCount = 32;
 | |
|             BitmapInfo.bmiHeader.biCompression = BI_RGB;
 | |
| #elif LV_COLOR_DEPTH == 16
 | |
|             BitmapInfo.bmiHeader.biBitCount = 16;
 | |
|             BitmapInfo.bmiHeader.biCompression = BI_BITFIELDS;
 | |
|             BitmapInfo.bmiColorMask[0] = 0xF800;
 | |
|             BitmapInfo.bmiColorMask[1] = 0x07E0;
 | |
|             BitmapInfo.bmiColorMask[2] = 0x001F;
 | |
| #elif LV_COLOR_DEPTH == 8
 | |
|             BitmapInfo.bmiHeader.biBitCount = 8;
 | |
|             BitmapInfo.bmiHeader.biCompression = BI_RGB;
 | |
|             for (size_t i = 0; i < 256; ++i)
 | |
|             {
 | |
|                 lv_color8_t color;
 | |
|                 color.full = i;
 | |
| 
 | |
|                 BitmapInfo.bmiColors[i].rgbRed = LV_COLOR_GET_R(color) * 36;
 | |
|                 BitmapInfo.bmiColors[i].rgbGreen = LV_COLOR_GET_G(color) * 36;
 | |
|                 BitmapInfo.bmiColors[i].rgbBlue = LV_COLOR_GET_B(color) * 85;
 | |
|                 BitmapInfo.bmiColors[i].rgbReserved = 0xFF;
 | |
|             }
 | |
| #elif LV_COLOR_DEPTH == 1
 | |
|             BitmapInfo.bmiHeader.biBitCount = 8;
 | |
|             BitmapInfo.bmiHeader.biCompression = BI_RGB;
 | |
|             BitmapInfo.bmiHeader.biClrUsed = 2;
 | |
|             BitmapInfo.bmiHeader.biClrImportant = 2;
 | |
|             BitmapInfo.bmiColors[0].rgbRed = 0x00;
 | |
|             BitmapInfo.bmiColors[0].rgbGreen = 0x00;
 | |
|             BitmapInfo.bmiColors[0].rgbBlue = 0x00;
 | |
|             BitmapInfo.bmiColors[0].rgbReserved = 0xFF;
 | |
|             BitmapInfo.bmiColors[1].rgbRed = 0xFF;
 | |
|             BitmapInfo.bmiColors[1].rgbGreen = 0xFF;
 | |
|             BitmapInfo.bmiColors[1].rgbBlue = 0xFF;
 | |
|             BitmapInfo.bmiColors[1].rgbReserved = 0xFF;
 | |
| #else
 | |
|             BitmapInfo.bmiHeader.biBitCount = 32;
 | |
|             BitmapInfo.bmiHeader.biCompression = BI_RGB;
 | |
| #endif
 | |
| 
 | |
|             HBITMAP hBitmap = CreateDIBSection(
 | |
|                 hFrameBufferDC,
 | |
|                 (PBITMAPINFO)(&BitmapInfo),
 | |
|                 DIB_RGB_COLORS,
 | |
|                 (void**)PixelBuffer,
 | |
|                 NULL,
 | |
|                 0);
 | |
|             if (hBitmap)
 | |
|             {
 | |
| #if LV_COLOR_DEPTH == 32
 | |
|                 *PixelBufferSize = Width * Height * sizeof(UINT32);
 | |
| #elif LV_COLOR_DEPTH == 16
 | |
|                 *PixelBufferSize = Width * Height * sizeof(UINT16);
 | |
| #elif LV_COLOR_DEPTH == 8
 | |
|                 *PixelBufferSize = Width * Height * sizeof(UINT8);
 | |
| #elif LV_COLOR_DEPTH == 1
 | |
|                 *PixelBufferSize = Width * Height * sizeof(UINT8);
 | |
| #else
 | |
|                 *PixelBufferSize = Width * Height * sizeof(UINT32);
 | |
| #endif
 | |
| 
 | |
|                 DeleteObject(SelectObject(hFrameBufferDC, hBitmap));
 | |
|                 DeleteObject(hBitmap);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 DeleteDC(hFrameBufferDC);
 | |
|                 hFrameBufferDC = NULL;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return hFrameBufferDC;
 | |
| }
 | |
| 
 | |
| static BOOL lv_win32_enable_child_window_dpi_message(
 | |
|     HWND WindowHandle)
 | |
| {
 | |
|     // This hack is only for Windows 10 TH1/TH2 only.
 | |
|     // We don't need this hack if the Per Monitor Aware V2 is existed.
 | |
|     OSVERSIONINFOEXW OSVersionInfoEx = { 0 };
 | |
|     OSVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
 | |
|     OSVersionInfoEx.dwMajorVersion = 10;
 | |
|     OSVersionInfoEx.dwMinorVersion = 0;
 | |
|     OSVersionInfoEx.dwBuildNumber = 14393;
 | |
|     if (!VerifyVersionInfoW(
 | |
|         &OSVersionInfoEx,
 | |
|         VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER,
 | |
|         VerSetConditionMask(
 | |
|             VerSetConditionMask(
 | |
|                 VerSetConditionMask(
 | |
|                     0,
 | |
|                     VER_MAJORVERSION,
 | |
|                     VER_GREATER_EQUAL),
 | |
|                 VER_MINORVERSION,
 | |
|                 VER_GREATER_EQUAL),
 | |
|             VER_BUILDNUMBER,
 | |
|             VER_LESS)))
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
 | |
|     if (!ModuleHandle)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     typedef BOOL(WINAPI* FunctionType)(HWND, BOOL);
 | |
| 
 | |
|     FunctionType pFunction = (FunctionType)(
 | |
|         GetProcAddress(ModuleHandle, "EnableChildWindowDpiMessage"));
 | |
|     if (!pFunction)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return pFunction(WindowHandle, TRUE);
 | |
| }
 | |
| 
 | |
| static BOOL lv_win32_register_touch_window(
 | |
|     HWND hWnd,
 | |
|     ULONG ulFlags)
 | |
| {
 | |
|     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
 | |
|     if (!ModuleHandle)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     typedef BOOL(WINAPI* FunctionType)(HWND, ULONG);
 | |
| 
 | |
|     FunctionType pFunction = (FunctionType)(
 | |
|         GetProcAddress(ModuleHandle, "RegisterTouchWindow"));
 | |
|     if (!pFunction)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return pFunction(hWnd, ulFlags);
 | |
| }
 | |
| 
 | |
| static BOOL lv_win32_get_touch_input_info(
 | |
|     HTOUCHINPUT hTouchInput,
 | |
|     UINT cInputs,
 | |
|     PTOUCHINPUT pInputs,
 | |
|     int cbSize)
 | |
| {
 | |
|     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
 | |
|     if (!ModuleHandle)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     typedef BOOL(WINAPI* FunctionType)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
 | |
| 
 | |
|     FunctionType pFunction = (FunctionType)(
 | |
|         GetProcAddress(ModuleHandle, "GetTouchInputInfo"));
 | |
|     if (!pFunction)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return pFunction(hTouchInput, cInputs, pInputs, cbSize);
 | |
| }
 | |
| 
 | |
| static BOOL lv_win32_close_touch_input_handle(
 | |
|     HTOUCHINPUT hTouchInput)
 | |
| {
 | |
|     HMODULE ModuleHandle = GetModuleHandleW(L"user32.dll");
 | |
|     if (!ModuleHandle)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     typedef BOOL(WINAPI* FunctionType)(HTOUCHINPUT);
 | |
| 
 | |
|     FunctionType pFunction = (FunctionType)(
 | |
|         GetProcAddress(ModuleHandle, "CloseTouchInputHandle"));
 | |
|     if (!pFunction)
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return pFunction(hTouchInput);
 | |
| }
 | |
| 
 | |
| static UINT lv_win32_get_dpi_for_window(
 | |
|     _In_ HWND WindowHandle)
 | |
| {
 | |
|     UINT Result = (UINT)(-1);
 | |
| 
 | |
|     HMODULE ModuleHandle = LoadLibraryW(L"SHCore.dll");
 | |
|     if (ModuleHandle)
 | |
|     {
 | |
|         typedef enum MONITOR_DPI_TYPE_PRIVATE {
 | |
|             MDT_EFFECTIVE_DPI = 0,
 | |
|             MDT_ANGULAR_DPI = 1,
 | |
|             MDT_RAW_DPI = 2,
 | |
|             MDT_DEFAULT = MDT_EFFECTIVE_DPI
 | |
|         } MONITOR_DPI_TYPE_PRIVATE;
 | |
| 
 | |
|         typedef HRESULT(WINAPI* FunctionType)(
 | |
|             HMONITOR, MONITOR_DPI_TYPE_PRIVATE, UINT*, UINT*);
 | |
| 
 | |
|         FunctionType pFunction = (FunctionType)(
 | |
|             GetProcAddress(ModuleHandle, "GetDpiForMonitor"));
 | |
|         if (pFunction)
 | |
|         {
 | |
|             HMONITOR MonitorHandle = MonitorFromWindow(
 | |
|                 WindowHandle,
 | |
|                 MONITOR_DEFAULTTONEAREST);
 | |
| 
 | |
|             UINT dpiX = 0;
 | |
|             UINT dpiY = 0;
 | |
|             if (SUCCEEDED(pFunction(
 | |
|                 MonitorHandle,
 | |
|                 MDT_EFFECTIVE_DPI,
 | |
|                 &dpiX,
 | |
|                 &dpiY)))
 | |
|             {
 | |
|                 Result = dpiX;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         FreeLibrary(ModuleHandle);
 | |
|     }
 | |
| 
 | |
|     if (Result == (UINT)(-1))
 | |
|     {
 | |
|         HDC hWindowDC = GetDC(WindowHandle);
 | |
|         if (hWindowDC)
 | |
|         {
 | |
|             Result = GetDeviceCaps(hWindowDC, LOGPIXELSX);
 | |
|             ReleaseDC(WindowHandle, hWindowDC);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (Result == (UINT)(-1))
 | |
|     {
 | |
|         Result = USER_DEFAULT_SCREEN_DPI;
 | |
|     }
 | |
| 
 | |
|     return Result;
 | |
| }
 | |
| 
 | |
| static void lv_win32_display_driver_flush_callback(
 | |
|     lv_disp_drv_t* disp_drv,
 | |
|     const lv_area_t* area,
 | |
|     lv_color_t* color_p)
 | |
| {
 | |
|     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|         lv_win32_get_window_context((HWND)disp_drv->user_data));
 | |
|     if (context)
 | |
|     {
 | |
|         if (lv_disp_flush_is_last(disp_drv))
 | |
|         {
 | |
| #if (LV_COLOR_DEPTH == 32) || \
 | |
|     (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
 | |
|     (LV_COLOR_DEPTH == 8) || \
 | |
|     (LV_COLOR_DEPTH == 1)
 | |
|             UNREFERENCED_PARAMETER(color_p);
 | |
| #elif (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0)
 | |
|             SIZE_T count = context->display_framebuffer_size / sizeof(UINT16);
 | |
|             PUINT16 source = (PUINT16)color_p;
 | |
|             PUINT16 destination = (PUINT16)context->display_framebuffer_base;
 | |
|             for (SIZE_T i = 0; i < count; ++i)
 | |
|             {
 | |
|                 UINT16 current = *source;
 | |
|                 *destination = (LOBYTE(current) << 8) | HIBYTE(current);
 | |
| 
 | |
|                 ++source;
 | |
|                 ++destination;
 | |
|             }
 | |
| #else
 | |
|             uint32_t* destination = context->display_framebuffer_base;
 | |
| 
 | |
|             for (int y = area->y1; y <= area->y2; ++y)
 | |
|             {
 | |
|                 for (int x = area->x1; x <= area->x2; ++x)
 | |
|                 {
 | |
|                     destination[y * disp_drv->hor_res + x] =
 | |
|                         lv_color_to32(*color_p);
 | |
|                     color_p++;
 | |
|                 }
 | |
|             }
 | |
| #endif
 | |
| 
 | |
|             InvalidateRect(disp_drv->user_data, NULL, FALSE);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     lv_disp_flush_ready(disp_drv);
 | |
| }
 | |
| 
 | |
| static void lv_win32_pointer_driver_read_callback(
 | |
|     lv_indev_drv_t* indev_drv,
 | |
|     lv_indev_data_t* data)
 | |
| {
 | |
|     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|         lv_win32_get_display_context(indev_drv->disp));
 | |
|     if (!context)
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     data->state = context->mouse_state;
 | |
|     data->point = context->mouse_point;
 | |
| }
 | |
| 
 | |
| static void lv_win32_keypad_driver_read_callback(
 | |
|     lv_indev_drv_t* indev_drv,
 | |
|     lv_indev_data_t* data)
 | |
| {
 | |
|     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|         lv_win32_get_display_context(indev_drv->disp));
 | |
|     if (!context)
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     EnterCriticalSection(&context->keyboard_mutex);
 | |
| 
 | |
|     lv_win32_keyboard_queue_item_t* current =
 | |
|         (lv_win32_keyboard_queue_item_t*)(InterlockedPopEntrySList(
 | |
|             context->keyboard_queue));
 | |
|     if (current)
 | |
|     {
 | |
|         data->key = current->key;
 | |
|         data->state = current->state;
 | |
| 
 | |
|         _aligned_free(current);
 | |
| 
 | |
|         data->continue_reading = true;
 | |
|     }
 | |
| 
 | |
|     LeaveCriticalSection(&context->keyboard_mutex);
 | |
| }
 | |
| 
 | |
| static void lv_win32_encoder_driver_read_callback(
 | |
|     lv_indev_drv_t* indev_drv,
 | |
|     lv_indev_data_t* data)
 | |
| {
 | |
|     lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|         lv_win32_get_display_context(indev_drv->disp));
 | |
|     if (!context)
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     data->state = context->mousewheel_state;
 | |
|     data->enc_diff = context->mousewheel_enc_diff;
 | |
|     context->mousewheel_enc_diff = 0;
 | |
| }
 | |
| 
 | |
| static lv_win32_window_context_t* lv_win32_get_display_context(
 | |
|     lv_disp_t* display)
 | |
| {
 | |
|     if (display)
 | |
|     {
 | |
|         return lv_win32_get_window_context((HWND)display->driver->user_data);
 | |
|     }
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static LRESULT CALLBACK lv_win32_window_message_callback(
 | |
|     HWND   hWnd,
 | |
|     UINT   uMsg,
 | |
|     WPARAM wParam,
 | |
|     LPARAM lParam)
 | |
| {
 | |
|     switch (uMsg)
 | |
|     {
 | |
|     case WM_CREATE:
 | |
|     {
 | |
|         // Note: Return -1 directly because WM_DESTROY message will be sent
 | |
|         // when destroy the window automatically. We free the resource when
 | |
|         // processing the WM_DESTROY message of this window.
 | |
| 
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             malloc(sizeof(lv_win32_window_context_t)));
 | |
|         if (!context)
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         RECT request_content_size;
 | |
|         GetWindowRect(hWnd, &request_content_size);
 | |
| 
 | |
|         context->display_hor_res =
 | |
|             request_content_size.right - request_content_size.left;
 | |
|         context->display_ver_res =
 | |
|             request_content_size.bottom - request_content_size.top;
 | |
|         context->display_dpi = lv_win32_get_dpi_for_window(hWnd);
 | |
|         context->display_framebuffer_context_handle =
 | |
|             lv_win32_create_frame_buffer(
 | |
|                 hWnd,
 | |
|                 context->display_hor_res,
 | |
|                 context->display_ver_res,
 | |
|                 &context->display_framebuffer_base,
 | |
|                 &context->display_framebuffer_size);
 | |
| #if (LV_COLOR_DEPTH == 32) || \
 | |
|     (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
 | |
|     (LV_COLOR_DEPTH == 8) || \
 | |
|     (LV_COLOR_DEPTH == 1)
 | |
|         lv_disp_draw_buf_init(
 | |
|             &context->display_buffer,
 | |
|             (lv_color_t*)context->display_framebuffer_base,
 | |
|             NULL,
 | |
|             context->display_hor_res * context->display_ver_res);
 | |
| #else
 | |
|         size_t draw_buffer_size = sizeof(lv_color_t);
 | |
|         draw_buffer_size *= context->display_hor_res;
 | |
|         draw_buffer_size *= context->display_ver_res;
 | |
|         lv_disp_draw_buf_init(
 | |
|             &context->display_buffer,
 | |
|             (lv_color_t*)malloc(draw_buffer_size),
 | |
|             NULL,
 | |
|             context->display_hor_res * context->display_ver_res);
 | |
| #endif
 | |
|         lv_disp_drv_init(&context->display_driver);
 | |
|         context->display_driver.hor_res = context->display_hor_res;
 | |
|         context->display_driver.ver_res = context->display_ver_res;
 | |
|         context->display_driver.flush_cb =
 | |
|             lv_win32_display_driver_flush_callback;
 | |
|         context->display_driver.draw_buf = &context->display_buffer;
 | |
|         context->display_driver.direct_mode = 1;
 | |
|         context->display_driver.user_data = hWnd;
 | |
|         context->display_device_object =
 | |
|             lv_disp_drv_register(&context->display_driver);
 | |
|         if (!context->display_device_object)
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         context->mouse_state = LV_INDEV_STATE_REL;
 | |
|         context->mouse_point.x = 0;
 | |
|         context->mouse_point.y = 0;
 | |
|         lv_indev_drv_init(&context->mouse_driver);
 | |
|         context->mouse_driver.type = LV_INDEV_TYPE_POINTER;
 | |
|         context->mouse_driver.disp = context->display_device_object;
 | |
|         context->mouse_driver.read_cb =
 | |
|             lv_win32_pointer_driver_read_callback;
 | |
|         context->mouse_device_object =
 | |
|             lv_indev_drv_register(&context->mouse_driver);
 | |
|         if (!context->mouse_device_object)
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         context->mousewheel_state = LV_INDEV_STATE_REL;
 | |
|         context->mousewheel_enc_diff = 0;
 | |
|         lv_indev_drv_init(&context->mousewheel_driver);
 | |
|         context->mousewheel_driver.type = LV_INDEV_TYPE_ENCODER;
 | |
|         context->mousewheel_driver.disp = context->display_device_object;
 | |
|         context->mousewheel_driver.read_cb =
 | |
|             lv_win32_encoder_driver_read_callback;
 | |
|         context->mousewheel_device_object =
 | |
|             lv_indev_drv_register(&context->mousewheel_driver);
 | |
|         if (!context->mousewheel_device_object)
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         InitializeCriticalSection(&context->keyboard_mutex);
 | |
|         context->keyboard_queue = _aligned_malloc(
 | |
|             sizeof(SLIST_HEADER),
 | |
|             MEMORY_ALLOCATION_ALIGNMENT);
 | |
|         if (!context->keyboard_queue)
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
|         InitializeSListHead(context->keyboard_queue);
 | |
|         context->keyboard_utf16_high_surrogate = 0;
 | |
|         context->keyboard_utf16_low_surrogate = 0;
 | |
|         lv_indev_drv_init(&context->keyboard_driver);
 | |
|         context->keyboard_driver.type = LV_INDEV_TYPE_KEYPAD;
 | |
|         context->keyboard_driver.disp = context->display_device_object;
 | |
|         context->keyboard_driver.read_cb =
 | |
|             lv_win32_keypad_driver_read_callback;
 | |
|         context->keyboard_device_object =
 | |
|             lv_indev_drv_register(&context->keyboard_driver);
 | |
|         if (!context->keyboard_device_object)
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         if (!SetPropW(
 | |
|             hWnd,
 | |
|             L"LVGL.SimulatorWindow.WindowContext",
 | |
|             (HANDLE)(context)))
 | |
|         {
 | |
|             return -1;
 | |
|         }
 | |
| 
 | |
|         RECT calculated_window_size;
 | |
| 
 | |
|         calculated_window_size.left = 0;
 | |
|         calculated_window_size.right = MulDiv(
 | |
|             context->display_hor_res * WIN32DRV_MONITOR_ZOOM,
 | |
|             context->display_dpi,
 | |
|             USER_DEFAULT_SCREEN_DPI);
 | |
|         calculated_window_size.top = 0;
 | |
|         calculated_window_size.bottom = MulDiv(
 | |
|             context->display_ver_res * WIN32DRV_MONITOR_ZOOM,
 | |
|             context->display_dpi,
 | |
|             USER_DEFAULT_SCREEN_DPI);
 | |
| 
 | |
|         AdjustWindowRectEx(
 | |
|             &calculated_window_size,
 | |
|             WINDOW_STYLE,
 | |
|             FALSE,
 | |
|             WINDOW_EX_STYLE);
 | |
|         OffsetRect(
 | |
|             &calculated_window_size,
 | |
|             -calculated_window_size.left,
 | |
|             -calculated_window_size.top);
 | |
| 
 | |
|         SetWindowPos(
 | |
|             hWnd,
 | |
|             NULL,
 | |
|             0,
 | |
|             0,
 | |
|             calculated_window_size.right,
 | |
|             calculated_window_size.bottom,
 | |
|             SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
 | |
| 
 | |
|         lv_win32_register_touch_window(hWnd, 0);
 | |
| 
 | |
|         lv_win32_enable_child_window_dpi_message(hWnd);
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_MOUSEMOVE:
 | |
|     case WM_LBUTTONDOWN:
 | |
|     case WM_LBUTTONUP:
 | |
|     case WM_MBUTTONDOWN:
 | |
|     case WM_MBUTTONUP:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (!context)
 | |
|         {
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         context->mouse_point.x = MulDiv(
 | |
|             GET_X_LPARAM(lParam),
 | |
|             USER_DEFAULT_SCREEN_DPI,
 | |
|             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
 | |
|         context->mouse_point.y = MulDiv(
 | |
|             GET_Y_LPARAM(lParam),
 | |
|             USER_DEFAULT_SCREEN_DPI,
 | |
|             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
 | |
|         if (context->mouse_point.x < 0)
 | |
|         {
 | |
|             context->mouse_point.x = 0;
 | |
|         }
 | |
|         if (context->mouse_point.x > context->display_hor_res - 1)
 | |
|         {
 | |
|             context->mouse_point.x = context->display_hor_res - 1;
 | |
|         }
 | |
|         if (context->mouse_point.y < 0)
 | |
|         {
 | |
|             context->mouse_point.y = 0;
 | |
|         }
 | |
|         if (context->mouse_point.y > context->display_ver_res - 1)
 | |
|         {
 | |
|             context->mouse_point.y = context->display_ver_res - 1;
 | |
|         }
 | |
| 
 | |
|         if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
 | |
|         {
 | |
|             context->mouse_state = (
 | |
|                 uMsg == WM_LBUTTONDOWN
 | |
|                 ? LV_INDEV_STATE_PR
 | |
|                 : LV_INDEV_STATE_REL);
 | |
|         }
 | |
|         else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
 | |
|         {
 | |
|             context->mousewheel_state = (
 | |
|                 uMsg == WM_MBUTTONDOWN
 | |
|                 ? LV_INDEV_STATE_PR
 | |
|                 : LV_INDEV_STATE_REL);
 | |
|         }
 | |
|         return 0;
 | |
|     }
 | |
|     case WM_KEYDOWN:
 | |
|     case WM_KEYUP:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (context)
 | |
|         {
 | |
|             EnterCriticalSection(&context->keyboard_mutex);
 | |
| 
 | |
|             bool skip_translation = false;
 | |
|             uint32_t translated_key = 0;
 | |
| 
 | |
|             switch (wParam)
 | |
|             {
 | |
|             case VK_UP:
 | |
|                 translated_key = LV_KEY_UP;
 | |
|                 break;
 | |
|             case VK_DOWN:
 | |
|                 translated_key = LV_KEY_DOWN;
 | |
|                 break;
 | |
|             case VK_LEFT:
 | |
|                 translated_key = LV_KEY_LEFT;
 | |
|                 break;
 | |
|             case VK_RIGHT:
 | |
|                 translated_key = LV_KEY_RIGHT;
 | |
|                 break;
 | |
|             case VK_ESCAPE:
 | |
|                 translated_key = LV_KEY_ESC;
 | |
|                 break;
 | |
|             case VK_DELETE:
 | |
|                 translated_key = LV_KEY_DEL;
 | |
|                 break;
 | |
|             case VK_BACK:
 | |
|                 translated_key = LV_KEY_BACKSPACE;
 | |
|                 break;
 | |
|             case VK_RETURN:
 | |
|                 translated_key = LV_KEY_ENTER;
 | |
|                 break;
 | |
|             case VK_TAB:
 | |
|             case VK_NEXT:
 | |
|                 translated_key = LV_KEY_NEXT;
 | |
|                 break;
 | |
|             case VK_PRIOR:
 | |
|                 translated_key = LV_KEY_PREV;
 | |
|                 break;
 | |
|             case VK_HOME:
 | |
|                 translated_key = LV_KEY_HOME;
 | |
|                 break;
 | |
|             case VK_END:
 | |
|                 translated_key = LV_KEY_END;
 | |
|                 break;
 | |
|             default:
 | |
|                 skip_translation = true;
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             if (!skip_translation)
 | |
|             {
 | |
|                 lv_win32_push_key_to_keyboard_queue(
 | |
|                     context,
 | |
|                     translated_key,
 | |
|                     ((uMsg == WM_KEYUP)
 | |
|                         ? LV_INDEV_STATE_REL
 | |
|                         : LV_INDEV_STATE_PR)); 
 | |
|             }
 | |
| 
 | |
|             LeaveCriticalSection(&context->keyboard_mutex);
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_CHAR:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (context)
 | |
|         {
 | |
|             EnterCriticalSection(&context->keyboard_mutex);
 | |
| 
 | |
|             uint16_t raw_code_point = (uint16_t)(wParam);
 | |
| 
 | |
|             if (raw_code_point >= 0x20 && raw_code_point != 0x7F)
 | |
|             {
 | |
|                 if (IS_HIGH_SURROGATE(raw_code_point))
 | |
|                 {
 | |
|                     context->keyboard_utf16_high_surrogate = raw_code_point;
 | |
|                 }
 | |
|                 else if (IS_LOW_SURROGATE(raw_code_point))
 | |
|                 {
 | |
|                     context->keyboard_utf16_low_surrogate = raw_code_point;
 | |
|                 }
 | |
| 
 | |
|                 uint32_t code_point = raw_code_point;
 | |
| 
 | |
|                 if (context->keyboard_utf16_high_surrogate &&
 | |
|                     context->keyboard_utf16_low_surrogate)
 | |
|                 {
 | |
|                     uint16_t high_surrogate =
 | |
|                         context->keyboard_utf16_high_surrogate;
 | |
|                     uint16_t low_surrogate =
 | |
|                         context->keyboard_utf16_low_surrogate;
 | |
| 
 | |
|                     code_point = (low_surrogate & 0x03FF);
 | |
|                     code_point += (((high_surrogate & 0x03FF) + 0x40) << 10);
 | |
| 
 | |
|                     context->keyboard_utf16_high_surrogate = 0;
 | |
|                     context->keyboard_utf16_low_surrogate = 0;
 | |
|                 }
 | |
| 
 | |
|                 uint32_t lvgl_code_point =
 | |
|                     _lv_txt_unicode_to_encoded(code_point);
 | |
| 
 | |
|                 lv_win32_push_key_to_keyboard_queue(
 | |
|                     context,
 | |
|                     lvgl_code_point,
 | |
|                     LV_INDEV_STATE_PR);
 | |
|                 lv_win32_push_key_to_keyboard_queue(
 | |
|                     context,
 | |
|                     lvgl_code_point,
 | |
|                     LV_INDEV_STATE_REL);
 | |
|             }
 | |
| 
 | |
|             LeaveCriticalSection(&context->keyboard_mutex);
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_MOUSEWHEEL:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (context)
 | |
|         {
 | |
|             context->mousewheel_enc_diff =
 | |
|                 -(GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_TOUCH:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (context)
 | |
|         {
 | |
|             UINT cInputs = LOWORD(wParam);
 | |
|             HTOUCHINPUT hTouchInput = (HTOUCHINPUT)(lParam);
 | |
| 
 | |
|             PTOUCHINPUT pInputs = malloc(cInputs * sizeof(TOUCHINPUT));
 | |
|             if (pInputs)
 | |
|             {
 | |
|                 if (lv_win32_get_touch_input_info(
 | |
|                     hTouchInput,
 | |
|                     cInputs,
 | |
|                     pInputs,
 | |
|                     sizeof(TOUCHINPUT)))
 | |
|                 {
 | |
|                     for (UINT i = 0; i < cInputs; ++i)
 | |
|                     {
 | |
|                         POINT Point;
 | |
|                         Point.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x);
 | |
|                         Point.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y);
 | |
|                         if (!ScreenToClient(hWnd, &Point))
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
| 
 | |
|                         context->mouse_point.x = MulDiv(
 | |
|                             Point.x,
 | |
|                             USER_DEFAULT_SCREEN_DPI,
 | |
|                             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
 | |
|                         context->mouse_point.y = MulDiv(
 | |
|                             Point.y,
 | |
|                             USER_DEFAULT_SCREEN_DPI,
 | |
|                             WIN32DRV_MONITOR_ZOOM * context->display_dpi);
 | |
| 
 | |
|                         DWORD MousePressedMask =
 | |
|                             TOUCHEVENTF_MOVE | TOUCHEVENTF_DOWN;
 | |
| 
 | |
|                         context->mouse_state = (
 | |
|                             pInputs[i].dwFlags & MousePressedMask
 | |
|                             ? LV_INDEV_STATE_PR
 | |
|                             : LV_INDEV_STATE_REL);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 free(pInputs);
 | |
|             }
 | |
| 
 | |
|             lv_win32_close_touch_input_handle(hTouchInput);
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_DPICHANGED:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (context)
 | |
|         {
 | |
|             context->display_dpi = HIWORD(wParam);
 | |
| 
 | |
|             LPRECT SuggestedRect = (LPRECT)lParam;
 | |
| 
 | |
|             SetWindowPos(
 | |
|                 hWnd,
 | |
|                 NULL,
 | |
|                 SuggestedRect->left,
 | |
|                 SuggestedRect->top,
 | |
|                 SuggestedRect->right,
 | |
|                 SuggestedRect->bottom,
 | |
|                 SWP_NOZORDER | SWP_NOACTIVATE);
 | |
| 
 | |
|             RECT ClientRect;
 | |
|             GetClientRect(hWnd, &ClientRect);
 | |
| 
 | |
|             int WindowWidth = MulDiv(
 | |
|                 context->display_hor_res * WIN32DRV_MONITOR_ZOOM,
 | |
|                 context->display_dpi,
 | |
|                 USER_DEFAULT_SCREEN_DPI);
 | |
|             int WindowHeight = MulDiv(
 | |
|                 context->display_ver_res * WIN32DRV_MONITOR_ZOOM,
 | |
|                 context->display_dpi,
 | |
|                 USER_DEFAULT_SCREEN_DPI);
 | |
| 
 | |
|             SetWindowPos(
 | |
|                 hWnd,
 | |
|                 NULL,
 | |
|                 SuggestedRect->left,
 | |
|                 SuggestedRect->top,
 | |
|                 SuggestedRect->right + (WindowWidth - ClientRect.right),
 | |
|                 SuggestedRect->bottom + (WindowHeight - ClientRect.bottom),
 | |
|                 SWP_NOZORDER | SWP_NOACTIVATE);
 | |
|         }
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_PAINT:
 | |
|     {
 | |
|         PAINTSTRUCT ps;
 | |
|         HDC hdc = BeginPaint(hWnd, &ps);
 | |
| 
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             lv_win32_get_window_context(hWnd));
 | |
|         if (context)
 | |
|         {
 | |
|             if (context->display_framebuffer_context_handle)
 | |
|             {
 | |
|                 SetStretchBltMode(hdc, HALFTONE);
 | |
| 
 | |
|                 StretchBlt(
 | |
|                     hdc,
 | |
|                     ps.rcPaint.left,
 | |
|                     ps.rcPaint.top,
 | |
|                     ps.rcPaint.right - ps.rcPaint.left,
 | |
|                     ps.rcPaint.bottom - ps.rcPaint.top,
 | |
|                     context->display_framebuffer_context_handle,
 | |
|                     0,
 | |
|                     0,
 | |
|                     MulDiv(
 | |
|                         ps.rcPaint.right - ps.rcPaint.left,
 | |
|                         USER_DEFAULT_SCREEN_DPI,
 | |
|                         WIN32DRV_MONITOR_ZOOM * context->display_dpi),
 | |
|                     MulDiv(
 | |
|                         ps.rcPaint.bottom - ps.rcPaint.top,
 | |
|                         USER_DEFAULT_SCREEN_DPI,
 | |
|                         WIN32DRV_MONITOR_ZOOM * context->display_dpi),
 | |
|                     SRCCOPY);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         EndPaint(hWnd, &ps);
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     case WM_DESTROY:
 | |
|     {
 | |
|         lv_win32_window_context_t* context = (lv_win32_window_context_t*)(
 | |
|             RemovePropW(hWnd, L"LVGL.SimulatorWindow.WindowContext"));
 | |
|         if (context)
 | |
|         {
 | |
|             lv_disp_t* display_device_object = context->display_device_object;
 | |
|             context->display_device_object = NULL;
 | |
|             lv_disp_remove(display_device_object);
 | |
| #if (LV_COLOR_DEPTH == 32) || \
 | |
|     (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
 | |
|     (LV_COLOR_DEPTH == 8) || \
 | |
|     (LV_COLOR_DEPTH == 1)
 | |
| #else
 | |
|             free(context->display_buffer.buf1);
 | |
| #endif
 | |
|             DeleteDC(context->display_framebuffer_context_handle);
 | |
| 
 | |
|             lv_indev_t* mouse_device_object =
 | |
|                 context->mouse_device_object;
 | |
|             context->mouse_device_object = NULL;
 | |
|             lv_indev_delete(mouse_device_object);
 | |
| 
 | |
|             lv_indev_t* mousewheel_device_object =
 | |
|                 context->mousewheel_device_object;
 | |
|             context->mousewheel_device_object = NULL;
 | |
|             lv_indev_delete(mousewheel_device_object);
 | |
| 
 | |
|             lv_indev_t* keyboard_device_object =
 | |
|                 context->keyboard_device_object;
 | |
|             context->keyboard_device_object = NULL;
 | |
|             lv_indev_delete(keyboard_device_object);
 | |
|             do
 | |
|             {
 | |
|                 PSLIST_ENTRY current = InterlockedPopEntrySList(
 | |
|                     context->keyboard_queue);
 | |
|                 if (!current)
 | |
|                 {
 | |
|                     _aligned_free(context->keyboard_queue);
 | |
|                     context->keyboard_queue = NULL;
 | |
|                     break;
 | |
|                 }
 | |
| 
 | |
|                 _aligned_free(current);
 | |
| 
 | |
|             } while (true);
 | |
|             DeleteCriticalSection(&context->keyboard_mutex);
 | |
| 
 | |
|             free(context);
 | |
|         }
 | |
| 
 | |
|         PostQuitMessage(0);
 | |
| 
 | |
|         break;
 | |
|     }
 | |
|     default:
 | |
|         return DefWindowProcW(hWnd, uMsg, wParam, lParam);
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static unsigned int __stdcall lv_win32_window_thread_entrypoint(
 | |
|     void* raw_parameter)
 | |
| {
 | |
|     PWINDOW_THREAD_PARAMETER parameter =
 | |
|         (PWINDOW_THREAD_PARAMETER)raw_parameter;
 | |
| 
 | |
|     g_window_handle = lv_win32_create_display_window(
 | |
|         L"LVGL Simulator for Windows Desktop (Display 1)",
 | |
|         parameter->hor_res,
 | |
|         parameter->ver_res,
 | |
|         parameter->instance_handle,
 | |
|         parameter->icon_handle,
 | |
|         parameter->show_window_mode);
 | |
|     if (!g_window_handle)
 | |
|     {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     SetEvent(parameter->window_mutex);
 | |
| 
 | |
|     MSG message;
 | |
|     while (GetMessageW(&message, NULL, 0, 0))
 | |
|     {
 | |
|         TranslateMessage(&message);
 | |
|         DispatchMessageW(&message);
 | |
|     }
 | |
| 
 | |
|     lv_win32_quit_signal = true;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #endif /*USE_WIN32DRV*/
 | 
