|
@@ -0,0 +1,1007 @@
|
|
|
+/**
|
|
|
+ * @file win32drv.c
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+/*********************
|
|
|
+ * INCLUDES
|
|
|
+ *********************/
|
|
|
+
|
|
|
+#include "win32drv.h"
|
|
|
+
|
|
|
+#if USE_WIN32DRV
|
|
|
+
|
|
|
+#include <windowsx.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
|
|
|
+ **********************/
|
|
|
+
|
|
|
+/**********************
|
|
|
+ * 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_display_driver_rounder_callback(
|
|
|
+ lv_disp_drv_t* disp_drv,
|
|
|
+ lv_area_t* area);
|
|
|
+
|
|
|
+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 LRESULT CALLBACK lv_win32_window_message_callback(
|
|
|
+ HWND hWnd,
|
|
|
+ UINT uMsg,
|
|
|
+ WPARAM wParam,
|
|
|
+ LPARAM lParam);
|
|
|
+
|
|
|
+static void lv_win32_message_handler(
|
|
|
+ lv_timer_t* param);
|
|
|
+
|
|
|
+/**********************
|
|
|
+ * 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 HINSTANCE g_instance_handle = NULL;
|
|
|
+static HWND g_window_handle = NULL;
|
|
|
+
|
|
|
+static HDC g_buffer_dc_handle = NULL;
|
|
|
+static UINT32* g_pixel_buffer = NULL;
|
|
|
+static SIZE_T g_pixel_buffer_size = 0;
|
|
|
+
|
|
|
+static lv_disp_t* g_display = NULL;
|
|
|
+
|
|
|
+static bool volatile g_mouse_pressed = false;
|
|
|
+static LPARAM volatile g_mouse_value = 0;
|
|
|
+
|
|
|
+static bool volatile g_mousewheel_pressed = false;
|
|
|
+static int16_t volatile g_mousewheel_value = 0;
|
|
|
+
|
|
|
+static bool volatile g_keyboard_pressed = false;
|
|
|
+static WPARAM volatile g_keyboard_value = 0;
|
|
|
+
|
|
|
+static int volatile g_dpi_value = USER_DEFAULT_SCREEN_DPI;
|
|
|
+
|
|
|
+/**********************
|
|
|
+ * 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 bool lv_win32_init(
|
|
|
+ HINSTANCE instance_handle,
|
|
|
+ int show_window_mode,
|
|
|
+ lv_coord_t hor_res,
|
|
|
+ lv_coord_t ver_res,
|
|
|
+ HICON icon_handle)
|
|
|
+{
|
|
|
+ WNDCLASSEXW WindowClass;
|
|
|
+
|
|
|
+ WindowClass.cbSize = sizeof(WNDCLASSEX);
|
|
|
+
|
|
|
+ WindowClass.style = 0;
|
|
|
+ WindowClass.lpfnWndProc = lv_win32_window_message_callback;
|
|
|
+ WindowClass.cbClsExtra = 0;
|
|
|
+ WindowClass.cbWndExtra = 0;
|
|
|
+ WindowClass.hInstance = instance_handle;
|
|
|
+ WindowClass.hIcon = icon_handle;
|
|
|
+ WindowClass.hCursor = LoadCursorW(NULL, IDC_ARROW);
|
|
|
+ WindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
|
+ WindowClass.lpszMenuName = NULL;
|
|
|
+ WindowClass.lpszClassName = L"lv_sim_visual_studio";
|
|
|
+ WindowClass.hIconSm = icon_handle;
|
|
|
+
|
|
|
+ if (!RegisterClassExW(&WindowClass))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ g_instance_handle = instance_handle;
|
|
|
+
|
|
|
+ g_window_handle = CreateWindowExW(
|
|
|
+ WINDOW_EX_STYLE,
|
|
|
+ WindowClass.lpszClassName,
|
|
|
+ L"LVGL Simulator for Windows Desktop",
|
|
|
+ WINDOW_STYLE,
|
|
|
+ CW_USEDEFAULT,
|
|
|
+ 0,
|
|
|
+ CW_USEDEFAULT,
|
|
|
+ 0,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ instance_handle,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ if (!g_window_handle)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ g_dpi_value = lv_win32_get_dpi_for_window(g_window_handle);
|
|
|
+
|
|
|
+ RECT WindowSize;
|
|
|
+
|
|
|
+ WindowSize.left = 0;
|
|
|
+ WindowSize.right = MulDiv(
|
|
|
+ hor_res * WIN32DRV_MONITOR_ZOOM,
|
|
|
+ g_dpi_value,
|
|
|
+ USER_DEFAULT_SCREEN_DPI);
|
|
|
+ WindowSize.top = 0;
|
|
|
+ WindowSize.bottom = MulDiv(
|
|
|
+ ver_res * WIN32DRV_MONITOR_ZOOM,
|
|
|
+ g_dpi_value,
|
|
|
+ USER_DEFAULT_SCREEN_DPI);
|
|
|
+
|
|
|
+ AdjustWindowRectEx(
|
|
|
+ &WindowSize,
|
|
|
+ WINDOW_STYLE,
|
|
|
+ FALSE,
|
|
|
+ WINDOW_EX_STYLE);
|
|
|
+ OffsetRect(
|
|
|
+ &WindowSize,
|
|
|
+ -WindowSize.left,
|
|
|
+ -WindowSize.top);
|
|
|
+
|
|
|
+ SetWindowPos(
|
|
|
+ g_window_handle,
|
|
|
+ NULL,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ WindowSize.right,
|
|
|
+ WindowSize.bottom,
|
|
|
+ SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
|
|
|
+
|
|
|
+ lv_win32_register_touch_window(g_window_handle, 0);
|
|
|
+
|
|
|
+ lv_timer_create(lv_win32_message_handler, 0, NULL);
|
|
|
+
|
|
|
+ lv_win32_enable_child_window_dpi_message(g_window_handle);
|
|
|
+
|
|
|
+ HDC hNewBufferDC = lv_win32_create_frame_buffer(
|
|
|
+ g_window_handle,
|
|
|
+ hor_res,
|
|
|
+ ver_res,
|
|
|
+ &g_pixel_buffer,
|
|
|
+ &g_pixel_buffer_size);
|
|
|
+
|
|
|
+ DeleteDC(g_buffer_dc_handle);
|
|
|
+ g_buffer_dc_handle = hNewBufferDC;
|
|
|
+
|
|
|
+ static lv_disp_draw_buf_t display_buffer;
|
|
|
+ lv_disp_draw_buf_init(
|
|
|
+ &display_buffer,
|
|
|
+ (lv_color_t*)malloc(hor_res * ver_res * sizeof(lv_color_t)),
|
|
|
+ NULL,
|
|
|
+ hor_res * ver_res);
|
|
|
+
|
|
|
+ static lv_disp_drv_t display_driver;
|
|
|
+ lv_disp_drv_init(&display_driver);
|
|
|
+ display_driver.hor_res = hor_res;
|
|
|
+ display_driver.ver_res = ver_res;
|
|
|
+ display_driver.flush_cb = lv_win32_display_driver_flush_callback;
|
|
|
+ display_driver.draw_buf = &display_buffer;
|
|
|
+ display_driver.rounder_cb = lv_win32_display_driver_rounder_callback;
|
|
|
+ g_display = lv_disp_drv_register(&display_driver);
|
|
|
+
|
|
|
+ static lv_indev_drv_t pointer_driver;
|
|
|
+ lv_indev_drv_init(&pointer_driver);
|
|
|
+ pointer_driver.type = LV_INDEV_TYPE_POINTER;
|
|
|
+ pointer_driver.read_cb = lv_win32_pointer_driver_read_callback;
|
|
|
+ lv_win32_pointer_device_object = lv_indev_drv_register(&pointer_driver);
|
|
|
+
|
|
|
+ static lv_indev_drv_t keypad_driver;
|
|
|
+ lv_indev_drv_init(&keypad_driver);
|
|
|
+ keypad_driver.type = LV_INDEV_TYPE_KEYPAD;
|
|
|
+ keypad_driver.read_cb = lv_win32_keypad_driver_read_callback;
|
|
|
+ lv_win32_keypad_device_object = lv_indev_drv_register(&keypad_driver);
|
|
|
+
|
|
|
+ static lv_indev_drv_t encoder_driver;
|
|
|
+ lv_indev_drv_init(&encoder_driver);
|
|
|
+ encoder_driver.type = LV_INDEV_TYPE_ENCODER;
|
|
|
+ encoder_driver.read_cb = lv_win32_encoder_driver_read_callback;
|
|
|
+ lv_win32_encoder_device_object = lv_indev_drv_register(&encoder_driver);
|
|
|
+
|
|
|
+ ShowWindow(g_window_handle, show_window_mode);
|
|
|
+ UpdateWindow(g_window_handle);
|
|
|
+
|
|
|
+ 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)
|
|
|
+{
|
|
|
+#if (LV_COLOR_DEPTH == 32) || \
|
|
|
+ (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0) || \
|
|
|
+ (LV_COLOR_DEPTH == 8) || \
|
|
|
+ (LV_COLOR_DEPTH == 1)
|
|
|
+ UNREFERENCED_PARAMETER(area);
|
|
|
+ memcpy(g_pixel_buffer, color_p, g_pixel_buffer_size);
|
|
|
+#elif (LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0)
|
|
|
+ SIZE_T count = g_pixel_buffer_size / sizeof(UINT16);
|
|
|
+ PUINT16 source = (PUINT16)color_p;
|
|
|
+ PUINT16 destination = (PUINT16)g_pixel_buffer;
|
|
|
+ for (SIZE_T i = 0; i < count; ++i)
|
|
|
+ {
|
|
|
+ UINT16 current = *source;
|
|
|
+ *destination = (LOBYTE(current) << 8) | HIBYTE(current);
|
|
|
+
|
|
|
+ ++source;
|
|
|
+ ++destination;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ for (int y = area->y1; y <= area->y2; ++y)
|
|
|
+ {
|
|
|
+ for (int x = area->x1; x <= area->x2; ++x)
|
|
|
+ {
|
|
|
+ g_pixel_buffer[y * disp_drv->hor_res + x] = lv_color_to32(*color_p);
|
|
|
+ color_p++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ HDC hWindowDC = GetDC(g_window_handle);
|
|
|
+ if (hWindowDC)
|
|
|
+ {
|
|
|
+ int PreviousMode = SetStretchBltMode(
|
|
|
+ hWindowDC,
|
|
|
+ HALFTONE);
|
|
|
+
|
|
|
+ StretchBlt(
|
|
|
+ hWindowDC,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ MulDiv(
|
|
|
+ disp_drv->hor_res * WIN32DRV_MONITOR_ZOOM,
|
|
|
+ g_dpi_value,
|
|
|
+ USER_DEFAULT_SCREEN_DPI),
|
|
|
+ MulDiv(
|
|
|
+ disp_drv->ver_res * WIN32DRV_MONITOR_ZOOM,
|
|
|
+ g_dpi_value,
|
|
|
+ USER_DEFAULT_SCREEN_DPI),
|
|
|
+ g_buffer_dc_handle,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ disp_drv->hor_res,
|
|
|
+ disp_drv->ver_res,
|
|
|
+ SRCCOPY);
|
|
|
+
|
|
|
+ SetStretchBltMode(
|
|
|
+ hWindowDC,
|
|
|
+ PreviousMode);
|
|
|
+
|
|
|
+ ReleaseDC(g_window_handle, hWindowDC);
|
|
|
+ }
|
|
|
+
|
|
|
+ lv_disp_flush_ready(disp_drv);
|
|
|
+}
|
|
|
+
|
|
|
+static void lv_win32_display_driver_rounder_callback(
|
|
|
+ lv_disp_drv_t* disp_drv,
|
|
|
+ lv_area_t* area)
|
|
|
+{
|
|
|
+ area->x1 = 0;
|
|
|
+ area->x2 = disp_drv->hor_res - 1;
|
|
|
+ area->y1 = 0;
|
|
|
+ area->y2 = disp_drv->ver_res - 1;
|
|
|
+}
|
|
|
+
|
|
|
+static void lv_win32_pointer_driver_read_callback(
|
|
|
+ lv_indev_drv_t* indev_drv,
|
|
|
+ lv_indev_data_t* data)
|
|
|
+{
|
|
|
+ UNREFERENCED_PARAMETER(indev_drv);
|
|
|
+
|
|
|
+ data->state = (lv_indev_state_t)(
|
|
|
+ g_mouse_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL);
|
|
|
+
|
|
|
+ data->point.x = MulDiv(
|
|
|
+ GET_X_LPARAM(g_mouse_value),
|
|
|
+ USER_DEFAULT_SCREEN_DPI,
|
|
|
+ WIN32DRV_MONITOR_ZOOM * g_dpi_value);
|
|
|
+ data->point.y = MulDiv(
|
|
|
+ GET_Y_LPARAM(g_mouse_value),
|
|
|
+ USER_DEFAULT_SCREEN_DPI,
|
|
|
+ WIN32DRV_MONITOR_ZOOM * g_dpi_value);
|
|
|
+
|
|
|
+ if (data->point.x < 0)
|
|
|
+ {
|
|
|
+ data->point.x = 0;
|
|
|
+ }
|
|
|
+ if (data->point.x > g_display->driver->hor_res - 1)
|
|
|
+ {
|
|
|
+ data->point.x = g_display->driver->hor_res - 1;
|
|
|
+ }
|
|
|
+ if (data->point.y < 0)
|
|
|
+ {
|
|
|
+ data->point.y = 0;
|
|
|
+ }
|
|
|
+ if (data->point.y > g_display->driver->ver_res - 1)
|
|
|
+ {
|
|
|
+ data->point.y = g_display->driver->ver_res - 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void lv_win32_keypad_driver_read_callback(
|
|
|
+ lv_indev_drv_t* indev_drv,
|
|
|
+ lv_indev_data_t* data)
|
|
|
+{
|
|
|
+ UNREFERENCED_PARAMETER(indev_drv);
|
|
|
+
|
|
|
+ data->state = (lv_indev_state_t)(
|
|
|
+ g_keyboard_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL);
|
|
|
+
|
|
|
+ WPARAM KeyboardValue = g_keyboard_value;
|
|
|
+
|
|
|
+ switch (KeyboardValue)
|
|
|
+ {
|
|
|
+ case VK_UP:
|
|
|
+ data->key = LV_KEY_UP;
|
|
|
+ break;
|
|
|
+ case VK_DOWN:
|
|
|
+ data->key = LV_KEY_DOWN;
|
|
|
+ break;
|
|
|
+ case VK_LEFT:
|
|
|
+ data->key = LV_KEY_LEFT;
|
|
|
+ break;
|
|
|
+ case VK_RIGHT:
|
|
|
+ data->key = LV_KEY_RIGHT;
|
|
|
+ break;
|
|
|
+ case VK_ESCAPE:
|
|
|
+ data->key = LV_KEY_ESC;
|
|
|
+ break;
|
|
|
+ case VK_DELETE:
|
|
|
+ data->key = LV_KEY_DEL;
|
|
|
+ break;
|
|
|
+ case VK_BACK:
|
|
|
+ data->key = LV_KEY_BACKSPACE;
|
|
|
+ break;
|
|
|
+ case VK_RETURN:
|
|
|
+ data->key = LV_KEY_ENTER;
|
|
|
+ break;
|
|
|
+ case VK_NEXT:
|
|
|
+ data->key = LV_KEY_NEXT;
|
|
|
+ break;
|
|
|
+ case VK_PRIOR:
|
|
|
+ data->key = LV_KEY_PREV;
|
|
|
+ break;
|
|
|
+ case VK_HOME:
|
|
|
+ data->key = LV_KEY_HOME;
|
|
|
+ break;
|
|
|
+ case VK_END:
|
|
|
+ data->key = LV_KEY_END;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (KeyboardValue >= 'A' && KeyboardValue <= 'Z')
|
|
|
+ {
|
|
|
+ KeyboardValue += 0x20;
|
|
|
+ }
|
|
|
+
|
|
|
+ data->key = (uint32_t)KeyboardValue;
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void lv_win32_encoder_driver_read_callback(
|
|
|
+ lv_indev_drv_t* indev_drv,
|
|
|
+ lv_indev_data_t* data)
|
|
|
+{
|
|
|
+ UNREFERENCED_PARAMETER(indev_drv);
|
|
|
+
|
|
|
+ data->state = (lv_indev_state_t)(
|
|
|
+ g_mousewheel_pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL);
|
|
|
+ data->enc_diff = g_mousewheel_value;
|
|
|
+ g_mousewheel_value = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static LRESULT CALLBACK lv_win32_window_message_callback(
|
|
|
+ HWND hWnd,
|
|
|
+ UINT uMsg,
|
|
|
+ WPARAM wParam,
|
|
|
+ LPARAM lParam)
|
|
|
+{
|
|
|
+ switch (uMsg)
|
|
|
+ {
|
|
|
+ case WM_MOUSEMOVE:
|
|
|
+ case WM_LBUTTONDOWN:
|
|
|
+ case WM_LBUTTONUP:
|
|
|
+ case WM_MBUTTONDOWN:
|
|
|
+ case WM_MBUTTONUP:
|
|
|
+ {
|
|
|
+ g_mouse_value = lParam;
|
|
|
+ if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
|
|
|
+ {
|
|
|
+ g_mouse_pressed = (uMsg == WM_LBUTTONDOWN);
|
|
|
+ }
|
|
|
+ else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
|
|
|
+ {
|
|
|
+ g_mousewheel_pressed = (uMsg == WM_MBUTTONDOWN);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ case WM_KEYDOWN:
|
|
|
+ case WM_KEYUP:
|
|
|
+ {
|
|
|
+ g_keyboard_pressed = (uMsg == WM_KEYDOWN);
|
|
|
+ g_keyboard_value = wParam;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case WM_MOUSEWHEEL:
|
|
|
+ {
|
|
|
+ g_mousewheel_value = -(GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case WM_TOUCH:
|
|
|
+ {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ uint16_t x = (uint16_t)(Point.x & 0xffff);
|
|
|
+ uint16_t y = (uint16_t)(Point.y & 0xffff);
|
|
|
+
|
|
|
+ DWORD MousePressedMask =
|
|
|
+ TOUCHEVENTF_MOVE | TOUCHEVENTF_DOWN;
|
|
|
+
|
|
|
+ g_mouse_value = (y << 16) | x;
|
|
|
+ g_mouse_pressed = (pInputs[i].dwFlags & MousePressedMask);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ free(pInputs);
|
|
|
+ }
|
|
|
+
|
|
|
+ lv_win32_close_touch_input_handle(hTouchInput);
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case WM_DPICHANGED:
|
|
|
+ {
|
|
|
+ g_dpi_value = 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(
|
|
|
+ g_display->driver->hor_res * WIN32DRV_MONITOR_ZOOM,
|
|
|
+ g_dpi_value,
|
|
|
+ USER_DEFAULT_SCREEN_DPI);
|
|
|
+ int WindowHeight = MulDiv(
|
|
|
+ g_display->driver->ver_res * WIN32DRV_MONITOR_ZOOM,
|
|
|
+ g_dpi_value,
|
|
|
+ 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_DESTROY:
|
|
|
+ PostQuitMessage(0);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void lv_win32_message_handler(
|
|
|
+ lv_timer_t* param)
|
|
|
+{
|
|
|
+ UNREFERENCED_PARAMETER(param);
|
|
|
+
|
|
|
+ MSG Message;
|
|
|
+ BOOL Result = PeekMessageW(&Message, NULL, 0, 0, TRUE);
|
|
|
+ if (Result != 0 && Result != -1)
|
|
|
+ {
|
|
|
+ TranslateMessage(&Message);
|
|
|
+ DispatchMessageW(&Message);
|
|
|
+
|
|
|
+ if (Message.message == WM_QUIT)
|
|
|
+ {
|
|
|
+ lv_win32_quit_signal = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#endif /*USE_WIN32DRV*/
|