Kaynağa Gözat

[simulator][win32] add lvgl driver

Meco Man 3 yıl önce
ebeveyn
işleme
e72eb1ae95

+ 0 - 1
bsp/qemu-vexpress-a9/drivers/lvgl/lv_demo.c

@@ -9,7 +9,6 @@
  */
 #include <rtthread.h>
 #include <lvgl.h>
-#include <lv_port_indev.h>
 #define DBG_TAG    "LVGL.demo"
 #define DBG_LVL    DBG_INFO
 #include <rtdbg.h>

+ 17 - 2
bsp/simulator/Kconfig

@@ -26,8 +26,23 @@ config SOC_SIMULATOR
 
 if RT_USING_DFS
     config RT_USING_DFS_WINSHAREDIR
-    bool "Enable shared file system between windows"
-    default n
+        bool "Enable shared file system between windows"
+        default n
 endif
 
+config BSP_USING_LVGL
+    bool "Enable LVGL for LCD"
+    select PKG_USING_LVGL
+    select PKG_USING_LV_MUSIC_DEMO
+    default n
+
+if BSP_USING_LVGL
+    config BSP_LCD_WIDTH
+        int "LCD width"
+        default 800
 
+    config BSP_LCD_HEIGHT
+        int "LCD height"
+        default 480
+
+endif

+ 6 - 0
bsp/simulator/drivers/SConscript

@@ -1,4 +1,5 @@
 import sys
+import os
 from building import *
 
 cwd = GetCurrentDir()
@@ -34,4 +35,9 @@ if sys.platform[0:5]=="linux": #check whether under linux
 group = DefineGroup('Drivers', src, depend = [''],
                     CPPPATH = CPPPATH, LIBS=LIBS, LIBPATH=LIBPATH, CPPDEFINES = CPPDEFINES)
 
+list = os.listdir(cwd)
+for item in list:
+    if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
+        group = group + SConscript(os.path.join(item, 'SConscript'))
+
 Return('group')

+ 17 - 0
bsp/simulator/drivers/lvgl/SConscript

@@ -0,0 +1,17 @@
+from building import *
+import os
+
+cwd = GetCurrentDir()
+group = []
+src = Glob('*.c')
+CPPPATH = [cwd]
+
+list = os.listdir(cwd)
+for d in list:
+    path = os.path.join(cwd, d)
+    if os.path.isfile(os.path.join(path, 'SConscript')):
+        group = group + SConscript(os.path.join(d, 'SConscript'))
+
+group += DefineGroup('LVGL-port', src, depend = ['BSP_USING_LVGL'], CPPPATH = CPPPATH)
+
+Return('group')

+ 30 - 0
bsp/simulator/drivers/lvgl/lv_conf.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author        Notes
+ * 2021-10-18     Meco Man      First version
+ */
+
+#ifndef LV_CONF_H
+#define LV_CONF_H
+
+#define LV_USE_PERF_MONITOR         1
+#define LV_COLOR_DEPTH              32
+
+# define USE_WIN32DRV               1
+# define WIN32DRV_MONITOR_ZOOM      1
+
+/* music player demo */
+#include <rtconfig.h>
+#define LV_DISP_DEF_REFR_PERIOD     10
+#define LV_HOR_RES_MAX          BSP_LCD_WIDTH
+#define LV_VER_RES_MAX          BSP_LCD_HEIGHT
+#define LV_USE_DEMO_RTT_MUSIC       1
+#define LV_DEMO_RTT_MUSIC_AUTO_PLAY 1
+#define LV_FONT_MONTSERRAT_12       1
+#define LV_FONT_MONTSERRAT_16       1
+
+#endif

+ 68 - 0
bsp/simulator/drivers/lvgl/lv_demo.c

@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author        Notes
+ * 2021-10-17     Meco Man      First version
+ */
+#include <rtthread.h>
+#define DBG_TAG    "LVGL.demo"
+#define DBG_LVL    DBG_INFO
+#include <rtdbg.h>
+#include <lvgl.h>
+#include <lv_port_disp.h>
+#include <win32drv.h>
+
+#define IDI_LVGL                       101
+
+#ifndef LV_THREAD_STACK_SIZE
+#define LV_THREAD_STACK_SIZE 4096
+#endif
+
+#ifndef LV_THREAD_PRIO
+#define LV_THREAD_PRIO (RT_THREAD_PRIORITY_MAX*2/3)
+#endif
+
+static void lvgl_thread(void *parameter)
+{
+    /* initialize win32 driver; don't put this in lv_port_disp() */
+    if (!lv_win32_init(
+        GetModuleHandleW(NULL),
+        SW_SHOW,
+        BSP_LCD_WIDTH,
+        BSP_LCD_HEIGHT,
+        LoadIconW(GetModuleHandleW(NULL), MAKEINTRESOURCE(IDI_LVGL))))
+    {
+        LOG_E("lv_win32_init failure!");
+        return;
+    }
+
+    lv_win32_add_all_input_devices_to_group(NULL);
+
+    /* display demo */
+    extern void lv_demo_music(void);
+    lv_demo_music();
+
+    while (!lv_win32_quit_signal)
+    {
+        lv_task_handler();
+        Sleep(1);
+    }
+}
+
+static int lvgl_demo_init(void)
+{
+    rt_thread_t tid;
+
+    tid = rt_thread_create("LVGL", lvgl_thread, RT_NULL, LV_THREAD_STACK_SIZE, LV_THREAD_PRIO, 10);
+    if(tid == RT_NULL)
+    {
+        LOG_E("Fail to create 'LVGL' thread");
+    }
+    rt_thread_startup(tid);
+
+    return 0;
+}
+INIT_APP_EXPORT(lvgl_demo_init);

+ 14 - 0
bsp/simulator/drivers/lvgl/lv_port_disp.c

@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-10-18     Meco Man     The first version
+ */
+
+void lv_port_disp_init(void)
+{
+    /* do nothing*/
+}

+ 25 - 0
bsp/simulator/drivers/lvgl/lv_port_disp.h

@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-10-18     Meco Man     The first version
+ */
+#ifndef LV_PORT_DISP_H
+#define LV_PORT_DISP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <win32drv.h>
+
+void lv_port_disp_init(void);
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif

+ 14 - 0
bsp/simulator/drivers/lvgl/lv_port_indev.c

@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-10-18     Meco Man     The first version
+ */
+
+void lv_port_indev_init(void)
+{
+    /* do nothing */
+}

+ 23 - 0
bsp/simulator/drivers/lvgl/lv_port_indev.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-10-18     Meco Man     The first version
+ */
+#ifndef LV_PORT_INDEV_H
+#define LV_PORT_INDEV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void lv_port_indev_init(void);
+
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
+
+#endif

+ 1007 - 0
bsp/simulator/drivers/lvgl/win32drv.c

@@ -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*/

+ 67 - 0
bsp/simulator/drivers/lvgl/win32drv.h

@@ -0,0 +1,67 @@
+/**
+ * @file win32drv.h
+ *
+ */
+
+#ifndef LV_WIN32DRV_H
+#define LV_WIN32DRV_H
+
+/*********************
+ *      INCLUDES
+ *********************/
+
+#include <lvgl.h>
+
+#if USE_WIN32DRV
+
+#include <Windows.h>
+
+#if _MSC_VER >= 1200
+ // Disable compilation warnings.
+#pragma warning(push)
+// nonstandard extension used : bit field types other than int
+#pragma warning(disable:4214)
+// 'conversion' conversion from 'type1' to 'type2', possible loss of data
+#pragma warning(disable:4244)
+#endif
+
+#if _MSC_VER >= 1200
+// Restore compilation warnings.
+#pragma warning(pop)
+#endif
+
+/*********************
+ *      DEFINES
+ *********************/
+
+/**********************
+ *      TYPEDEFS
+ **********************/
+
+/**********************
+ * GLOBAL PROTOTYPES
+ **********************/
+
+EXTERN_C bool lv_win32_quit_signal;
+
+EXTERN_C lv_indev_t* lv_win32_pointer_device_object;
+EXTERN_C lv_indev_t* lv_win32_keypad_device_object;
+EXTERN_C lv_indev_t* lv_win32_encoder_device_object;
+
+EXTERN_C void lv_win32_add_all_input_devices_to_group(
+    lv_group_t* 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);
+
+/**********************
+ *      MACROS
+ **********************/
+
+#endif /*USE_WIN32DRV*/
+
+#endif /*LV_WIN32DRV_H*/