mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
feat(drivers): add Windows backend for LVGL v9 (#5313)
This commit is contained in:
parent
b4cf95e7fa
commit
cab1336d8e
4
Kconfig
4
Kconfig
@ -1489,6 +1489,10 @@ menu "LVGL configuration"
|
||||
config LV_USE_ILI9341
|
||||
bool "Use ILI9341 LCD driver"
|
||||
default n
|
||||
|
||||
config LV_USE_WINDOWS
|
||||
bool "Use LVGL Windows backend"
|
||||
default n
|
||||
endmenu
|
||||
|
||||
menu "Examples"
|
||||
|
@ -8,3 +8,4 @@ Drivers
|
||||
display/index
|
||||
touchpad/index
|
||||
X11
|
||||
windows
|
||||
|
105
docs/integration/driver/windows.rst
Normal file
105
docs/integration/driver/windows.rst
Normal file
@ -0,0 +1,105 @@
|
||||
=============================
|
||||
Windows Display/Inputs driver
|
||||
=============================
|
||||
|
||||
Overview
|
||||
-------------
|
||||
|
||||
The **Windows** display/input `driver <https://github.com/lvgl/lvgl/src/dev/windows>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in a Windows Win32 window.
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application in a **Windows** simulation window via **simulator mode**, or developing a standard **Windows** desktop application with LVGL via **application mode**.
|
||||
|
||||
Here are the **similarity** for simulator mode and application mode.
|
||||
|
||||
- Support LVGL pointer, keypad and encoder devices integration.
|
||||
- Support Windows touch input.
|
||||
- Support Windows input method integration input.
|
||||
- Support Per-monitor DPI Aware (both V1 and V2).
|
||||
|
||||
Here are the **differences** for simulator mode and application mode.
|
||||
|
||||
Simulator Mode
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- Designed for LVGL simulation scenario.
|
||||
- Keep the LVGL display resolution all time for trying best to simulate UI layout which will see in their production devices.
|
||||
- When Windows DPI scaling setting is changed, Windows backend will stretch the display content.
|
||||
|
||||
Application Mode
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
- Designed for Windows desktop application development scenario.
|
||||
- Have the Window resizing support and LVGL display resolution will be changed.
|
||||
- When Windows DPI scaling setting is changed, the LVGL display DPI value will also be changed.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The minimum Windows OS version this driver supported is Windows Server 2003, or Windows XP with East Asian language support installed because the input method integration support need that.
|
||||
|
||||
Configure Windows driver
|
||||
--------------------
|
||||
|
||||
Enable the Windows driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
|
||||
.. code:: c
|
||||
|
||||
#define LV_USE_WINDOWS 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include <Windows.h>
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lvgl/examples/lv_examples.h"
|
||||
#include "lvgl/demos/lv_demos.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
lv_init();
|
||||
|
||||
int32_t zoom_level = 100;
|
||||
bool allow_dpi_override = false;
|
||||
bool simulator_mode = false;
|
||||
lv_display_t* display = lv_windows_create_display(
|
||||
L"LVGL Display Window",
|
||||
800,
|
||||
480,
|
||||
zoom_level,
|
||||
allow_dpi_override,
|
||||
simulator_mode);
|
||||
if (!display)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_indev_t* pointer_device = lv_windows_acquire_pointer_indev(display);
|
||||
if (!pointer_device)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_indev_t* keypad_device = lv_windows_acquire_keypad_indev(display);
|
||||
if (!keypad_device)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_indev_t* encoder_device = lv_windows_acquire_encoder_indev(display);
|
||||
if (!encoder_device)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_demo_widgets();
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t time_till_next = lv_timer_handler();
|
||||
Sleep(time_till_next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -893,6 +893,8 @@
|
||||
|
||||
#define LV_USE_GENERIC_MIPI (LV_USE_ST7735 | LV_USE_ST7789 | LV_USE_ST7796 | LV_USE_ILI9341)
|
||||
|
||||
/* LVGL Windows backend */
|
||||
#define LV_USE_WINDOWS 0
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
|
3
lvgl.h
3
lvgl.h
@ -133,6 +133,9 @@ extern "C" {
|
||||
|
||||
#include "src/dev/evdev/lv_evdev.h"
|
||||
|
||||
#include "src/dev/windows/lv_windows_input.h"
|
||||
#include "src/dev/windows/lv_windows_display.h"
|
||||
|
||||
#include "src/core/lv_global.h"
|
||||
/*********************
|
||||
* DEFINES
|
||||
|
669
src/dev/windows/lv_windows_context.c
Normal file
669
src/dev/windows/lv_windows_context.c
Normal file
@ -0,0 +1,669 @@
|
||||
/**
|
||||
* @file lv_windows_context.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_windows_context.h"
|
||||
#if LV_USE_WINDOWS
|
||||
|
||||
#include "lv_windows_display.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static uint32_t lv_windows_tick_count_callback(void);
|
||||
|
||||
static void lv_windows_check_display_existence_timer_callback(
|
||||
lv_timer_t * timer);
|
||||
|
||||
static LRESULT CALLBACK lv_windows_window_message_callback(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
bool lv_windows_pointer_device_window_message_handler(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT * plResult);
|
||||
|
||||
bool lv_windows_keypad_device_window_message_handler(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT * plResult);
|
||||
|
||||
bool lv_windows_encoder_device_window_message_handler(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT * plResult);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_windows_platform_init(void)
|
||||
{
|
||||
lv_tick_set_cb(lv_windows_tick_count_callback);
|
||||
|
||||
lv_timer_create(
|
||||
lv_windows_check_display_existence_timer_callback,
|
||||
200,
|
||||
NULL);
|
||||
|
||||
// Try to ensure the default group exists.
|
||||
{
|
||||
lv_group_t * default_group = lv_group_get_default();
|
||||
if(!default_group) {
|
||||
default_group = lv_group_create();
|
||||
if(default_group) {
|
||||
lv_group_set_default(default_group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WNDCLASSEXW window_class;
|
||||
lv_memzero(&window_class, sizeof(WNDCLASSEXW));
|
||||
window_class.cbSize = sizeof(WNDCLASSEXW);
|
||||
window_class.style = 0;
|
||||
window_class.lpfnWndProc = lv_windows_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 = L"LVGL.Window";
|
||||
window_class.hIconSm = NULL;
|
||||
LV_ASSERT_NULL(RegisterClassExW(&window_class));
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * lv_windows_get_window_context(
|
||||
HWND window_handle)
|
||||
{
|
||||
return (lv_windows_window_context_t *)(
|
||||
GetPropW(window_handle, L"LVGL.Window.Context"));
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static uint32_t lv_windows_tick_count_callback(void)
|
||||
{
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
static void lv_windows_check_display_existence_timer_callback(
|
||||
lv_timer_t * timer)
|
||||
{
|
||||
if(!lv_display_get_next(NULL)) {
|
||||
// Don't use lv_deinit() due to it will cause exception when parallel
|
||||
// rendering is enabled.
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static HDC lv_windows_create_frame_buffer(
|
||||
HWND window_handle,
|
||||
LONG width,
|
||||
LONG height,
|
||||
UINT32 ** pixel_buffer,
|
||||
SIZE_T * pixel_buffer_size)
|
||||
{
|
||||
HDC frame_buffer_dc_handle = NULL;
|
||||
|
||||
LV_ASSERT_NULL(pixel_buffer);
|
||||
LV_ASSERT_NULL(pixel_buffer_size);
|
||||
|
||||
HDC window_dc_handle = GetDC(window_handle);
|
||||
if(window_dc_handle) {
|
||||
frame_buffer_dc_handle = CreateCompatibleDC(window_dc_handle);
|
||||
ReleaseDC(window_handle, window_dc_handle);
|
||||
}
|
||||
|
||||
if(frame_buffer_dc_handle) {
|
||||
#if (LV_COLOR_DEPTH == 32) || (LV_COLOR_DEPTH == 24)
|
||||
BITMAPINFO bitmap_info = { 0 };
|
||||
#elif (LV_COLOR_DEPTH == 16)
|
||||
typedef struct _BITMAPINFO_16BPP {
|
||||
BITMAPINFOHEADER bmiHeader;
|
||||
DWORD bmiColorMask[3];
|
||||
} BITMAPINFO_16BPP, * PBITMAPINFO_16BPP;
|
||||
|
||||
BITMAPINFO_16BPP bitmap_info = { 0 };
|
||||
#else
|
||||
#error [lv_windows] Unsupported LV_COLOR_DEPTH.
|
||||
#endif
|
||||
|
||||
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bitmap_info.bmiHeader.biWidth = width;
|
||||
bitmap_info.bmiHeader.biHeight = -height;
|
||||
bitmap_info.bmiHeader.biPlanes = 1;
|
||||
bitmap_info.bmiHeader.biBitCount = lv_color_format_get_bpp(
|
||||
LV_COLOR_FORMAT_NATIVE);
|
||||
#if (LV_COLOR_DEPTH == 32) || (LV_COLOR_DEPTH == 24)
|
||||
bitmap_info.bmiHeader.biCompression = BI_RGB;
|
||||
#elif (LV_COLOR_DEPTH == 16)
|
||||
bitmap_info.bmiHeader.biCompression = BI_BITFIELDS;
|
||||
bitmap_info.bmiColorMask[0] = 0xF800;
|
||||
bitmap_info.bmiColorMask[1] = 0x07E0;
|
||||
bitmap_info.bmiColorMask[2] = 0x001F;
|
||||
#else
|
||||
#error [lv_windows] Unsupported LV_COLOR_DEPTH.
|
||||
#endif
|
||||
|
||||
HBITMAP hBitmap = CreateDIBSection(
|
||||
frame_buffer_dc_handle,
|
||||
(PBITMAPINFO)(&bitmap_info),
|
||||
DIB_RGB_COLORS,
|
||||
(void **)pixel_buffer,
|
||||
NULL,
|
||||
0);
|
||||
if(hBitmap) {
|
||||
*pixel_buffer_size = width * height;
|
||||
*pixel_buffer_size *= lv_color_format_get_size(
|
||||
LV_COLOR_FORMAT_NATIVE);
|
||||
|
||||
DeleteObject(SelectObject(frame_buffer_dc_handle, hBitmap));
|
||||
DeleteObject(hBitmap);
|
||||
}
|
||||
else {
|
||||
DeleteDC(frame_buffer_dc_handle);
|
||||
frame_buffer_dc_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return frame_buffer_dc_handle;
|
||||
}
|
||||
|
||||
static void lv_windows_display_timer_callback(lv_timer_t * timer)
|
||||
{
|
||||
lv_windows_window_context_t * context = lv_timer_get_user_data(timer);
|
||||
LV_ASSERT_NULL(context);
|
||||
|
||||
if(!context->display_resolution_changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_display_set_resolution(
|
||||
context->display_device_object,
|
||||
context->requested_display_resolution.x,
|
||||
context->requested_display_resolution.y);
|
||||
|
||||
int32_t hor_res = lv_display_get_horizontal_resolution(
|
||||
context->display_device_object);
|
||||
int32_t ver_res = lv_display_get_vertical_resolution(
|
||||
context->display_device_object);
|
||||
|
||||
HWND window_handle = lv_windows_get_display_window_handle(
|
||||
context->display_device_object);
|
||||
if(window_handle) {
|
||||
if(context->display_framebuffer_context_handle) {
|
||||
context->display_framebuffer_base = NULL;
|
||||
context->display_framebuffer_size = 0;
|
||||
DeleteDC(context->display_framebuffer_context_handle);
|
||||
context->display_framebuffer_context_handle = NULL;
|
||||
}
|
||||
|
||||
context->display_framebuffer_context_handle =
|
||||
lv_windows_create_frame_buffer(
|
||||
window_handle,
|
||||
hor_res,
|
||||
ver_res,
|
||||
&context->display_framebuffer_base,
|
||||
&context->display_framebuffer_size);
|
||||
if(context->display_framebuffer_context_handle) {
|
||||
lv_display_set_buffers(
|
||||
context->display_device_object,
|
||||
context->display_framebuffer_base,
|
||||
NULL,
|
||||
context->display_framebuffer_size,
|
||||
LV_DISPLAY_RENDER_MODE_DIRECT);
|
||||
}
|
||||
}
|
||||
|
||||
context->display_resolution_changed = false;
|
||||
context->requested_display_resolution.x = 0;
|
||||
context->requested_display_resolution.y = 0;
|
||||
}
|
||||
|
||||
static void lv_windows_display_driver_flush_callback(
|
||||
lv_display_t * display,
|
||||
const lv_area_t * area,
|
||||
uint8_t * px_map)
|
||||
{
|
||||
HWND window_handle = lv_windows_get_display_window_handle(display);
|
||||
if(!window_handle) {
|
||||
lv_display_flush_ready(display);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
lv_display_flush_ready(display);
|
||||
return;
|
||||
}
|
||||
|
||||
if(lv_display_flush_is_last(display)) {
|
||||
#if (LV_COLOR_DEPTH == 32) || \
|
||||
(LV_COLOR_DEPTH == 24) || \
|
||||
(LV_COLOR_DEPTH == 16)
|
||||
UNREFERENCED_PARAMETER(px_map);
|
||||
#else
|
||||
#error [lv_windows] Unsupported LV_COLOR_DEPTH.
|
||||
#endif
|
||||
|
||||
HDC hdc = GetDC(window_handle);
|
||||
if(hdc) {
|
||||
SetStretchBltMode(hdc, HALFTONE);
|
||||
|
||||
RECT client_rect;
|
||||
GetClientRect(window_handle, &client_rect);
|
||||
|
||||
int32_t width = lv_windows_zoom_to_logical(
|
||||
client_rect.right - client_rect.left,
|
||||
context->zoom_level);
|
||||
int32_t height = lv_windows_zoom_to_logical(
|
||||
client_rect.bottom - client_rect.top,
|
||||
context->zoom_level);
|
||||
if(context->simulator_mode) {
|
||||
width = lv_windows_dpi_to_logical(width, context->window_dpi);
|
||||
height = lv_windows_dpi_to_logical(height, context->window_dpi);
|
||||
}
|
||||
|
||||
StretchBlt(
|
||||
hdc,
|
||||
client_rect.left,
|
||||
client_rect.top,
|
||||
client_rect.right - client_rect.left,
|
||||
client_rect.bottom - client_rect.top,
|
||||
context->display_framebuffer_context_handle,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
SRCCOPY);
|
||||
|
||||
ReleaseDC(window_handle, hdc);
|
||||
}
|
||||
}
|
||||
|
||||
lv_display_flush_ready(display);
|
||||
}
|
||||
|
||||
static UINT lv_windows_get_dpi_for_window(HWND window_handle)
|
||||
{
|
||||
UINT result = (UINT)(-1);
|
||||
|
||||
HMODULE module_handle = LoadLibraryW(L"SHCore.dll");
|
||||
if(module_handle) {
|
||||
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 * function_type)(
|
||||
HMONITOR, MONITOR_DPI_TYPE_PRIVATE, UINT *, UINT *);
|
||||
|
||||
function_type function = (function_type)(
|
||||
GetProcAddress(module_handle, "GetDpiForMonitor"));
|
||||
if(function) {
|
||||
HMONITOR MonitorHandle = MonitorFromWindow(
|
||||
window_handle,
|
||||
MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
UINT dpiX = 0;
|
||||
UINT dpiY = 0;
|
||||
if(SUCCEEDED(function(
|
||||
MonitorHandle,
|
||||
MDT_EFFECTIVE_DPI,
|
||||
&dpiX,
|
||||
&dpiY))) {
|
||||
result = dpiX;
|
||||
}
|
||||
}
|
||||
|
||||
FreeLibrary(module_handle);
|
||||
}
|
||||
|
||||
if(result == (UINT)(-1)) {
|
||||
HDC hWindowDC = GetDC(window_handle);
|
||||
if(hWindowDC) {
|
||||
result = GetDeviceCaps(hWindowDC, LOGPIXELSX);
|
||||
ReleaseDC(window_handle, hWindowDC);
|
||||
}
|
||||
}
|
||||
|
||||
if(result == (UINT)(-1)) {
|
||||
result = USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL lv_windows_register_touch_window(
|
||||
HWND window_handle,
|
||||
ULONG flags)
|
||||
{
|
||||
HMODULE module_handle = GetModuleHandleW(L"user32.dll");
|
||||
if(!module_handle) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI * function_type)(HWND, ULONG);
|
||||
|
||||
function_type function = (function_type)(
|
||||
GetProcAddress(module_handle, "RegisterTouchWindow"));
|
||||
if(!function) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return function(window_handle, flags);
|
||||
}
|
||||
|
||||
static BOOL lv_windows_enable_child_window_dpi_message(
|
||||
HWND WindowHandle)
|
||||
{
|
||||
// The private Per-Monitor DPI Awareness support extension is Windows 10
|
||||
// only. We don't need the private Per-Monitor DPI Awareness support
|
||||
// extension if the Per-Monitor (V2) DPI Awareness exists.
|
||||
OSVERSIONINFOEXW os_version_info_ex = { 0 };
|
||||
os_version_info_ex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
|
||||
os_version_info_ex.dwMajorVersion = 10;
|
||||
os_version_info_ex.dwMinorVersion = 0;
|
||||
os_version_info_ex.dwBuildNumber = 14986;
|
||||
if(!VerifyVersionInfoW(
|
||||
&os_version_info_ex,
|
||||
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 module_handle = GetModuleHandleW(L"user32.dll");
|
||||
if(!module_handle) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI * function_type)(HWND, BOOL);
|
||||
|
||||
function_type function = (function_type)(
|
||||
GetProcAddress(module_handle, "EnableChildWindowDpiMessage"));
|
||||
if(!function) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return function(WindowHandle, TRUE);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK lv_windows_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_windows_create_display_data_t * data =
|
||||
(lv_windows_create_display_data_t *)(
|
||||
((LPCREATESTRUCTW)(lParam))->lpCreateParams);
|
||||
if(!data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context =
|
||||
(lv_windows_window_context_t *)(HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(lv_windows_window_context_t)));
|
||||
if(!context) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!SetPropW(hWnd, L"LVGL.Window.Context", (HANDLE)(context))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
context->window_dpi = lv_windows_get_dpi_for_window(hWnd);
|
||||
context->zoom_level = data->zoom_level;
|
||||
context->allow_dpi_override = data->allow_dpi_override;
|
||||
context->simulator_mode = data->simulator_mode;
|
||||
|
||||
context->display_timer_object = lv_timer_create(
|
||||
lv_windows_display_timer_callback,
|
||||
LV_DEF_REFR_PERIOD,
|
||||
context);
|
||||
|
||||
context->display_resolution_changed = false;
|
||||
context->requested_display_resolution.x = 0;
|
||||
context->requested_display_resolution.y = 0;
|
||||
|
||||
context->display_device_object = lv_display_create(0, 0);
|
||||
if(!context->display_device_object) {
|
||||
return -1;
|
||||
}
|
||||
RECT request_content_size;
|
||||
GetWindowRect(hWnd, &request_content_size);
|
||||
lv_display_set_resolution(
|
||||
context->display_device_object,
|
||||
request_content_size.right - request_content_size.left,
|
||||
request_content_size.bottom - request_content_size.top);
|
||||
lv_display_set_flush_cb(
|
||||
context->display_device_object,
|
||||
lv_windows_display_driver_flush_callback);
|
||||
lv_display_set_driver_data(
|
||||
context->display_device_object,
|
||||
hWnd);
|
||||
if(!context->allow_dpi_override) {
|
||||
lv_display_set_dpi(
|
||||
context->display_device_object,
|
||||
context->window_dpi);
|
||||
}
|
||||
|
||||
if(context->simulator_mode) {
|
||||
context->display_resolution_changed = true;
|
||||
context->requested_display_resolution.x =
|
||||
lv_display_get_horizontal_resolution(
|
||||
context->display_device_object);
|
||||
context->requested_display_resolution.y =
|
||||
lv_display_get_vertical_resolution(
|
||||
context->display_device_object);
|
||||
}
|
||||
|
||||
lv_windows_register_touch_window(hWnd, 0);
|
||||
|
||||
lv_windows_enable_child_window_dpi_message(hWnd);
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_SIZE: {
|
||||
if(wParam != SIZE_MINIMIZED) {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
if(!context->simulator_mode) {
|
||||
context->display_resolution_changed = true;
|
||||
context->requested_display_resolution.x = LOWORD(lParam);
|
||||
context->requested_display_resolution.y = HIWORD(lParam);
|
||||
}
|
||||
else {
|
||||
int32_t window_width = lv_windows_dpi_to_physical(
|
||||
lv_windows_zoom_to_physical(
|
||||
lv_display_get_horizontal_resolution(
|
||||
context->display_device_object),
|
||||
context->zoom_level),
|
||||
context->window_dpi);
|
||||
int32_t window_height = lv_windows_dpi_to_physical(
|
||||
lv_windows_zoom_to_physical(
|
||||
lv_display_get_vertical_resolution(
|
||||
context->display_device_object),
|
||||
context->zoom_level),
|
||||
context->window_dpi);
|
||||
|
||||
RECT window_rect;
|
||||
GetWindowRect(hWnd, &window_rect);
|
||||
|
||||
RECT client_rect;
|
||||
GetClientRect(hWnd, &client_rect);
|
||||
|
||||
int32_t original_window_width =
|
||||
window_rect.right - window_rect.left;
|
||||
int32_t original_window_height =
|
||||
window_rect.bottom - window_rect.top;
|
||||
|
||||
int32_t original_client_width =
|
||||
client_rect.right - client_rect.left;
|
||||
int32_t original_client_height =
|
||||
client_rect.bottom - client_rect.top;
|
||||
|
||||
int32_t reserved_width =
|
||||
original_window_width - original_client_width;
|
||||
int32_t reserved_height =
|
||||
original_window_height - original_client_height;
|
||||
|
||||
SetWindowPos(
|
||||
hWnd,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
reserved_width + window_width,
|
||||
reserved_height + window_height,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_DPICHANGED: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
context->window_dpi = HIWORD(wParam);
|
||||
|
||||
if(!context->allow_dpi_override) {
|
||||
lv_display_set_dpi(
|
||||
context->display_device_object,
|
||||
context->window_dpi);
|
||||
}
|
||||
|
||||
LPRECT suggested_rect = (LPRECT)lParam;
|
||||
|
||||
SetWindowPos(
|
||||
hWnd,
|
||||
NULL,
|
||||
suggested_rect->left,
|
||||
suggested_rect->top,
|
||||
suggested_rect->right,
|
||||
suggested_rect->bottom,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_ERASEBKGND: {
|
||||
return TRUE;
|
||||
}
|
||||
case WM_DESTROY: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
RemovePropW(hWnd, L"LVGL.Window.Context"));
|
||||
if(context) {
|
||||
lv_display_t * display_device_object =
|
||||
context->display_device_object;
|
||||
context->display_device_object = NULL;
|
||||
lv_display_delete(display_device_object);
|
||||
DeleteDC(context->display_framebuffer_context_handle);
|
||||
|
||||
lv_timer_delete(context->display_timer_object);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, context);
|
||||
}
|
||||
|
||||
PostQuitMessage(0);
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
LRESULT lResult = 0;
|
||||
if(context->pointer.indev &&
|
||||
lv_windows_pointer_device_window_message_handler(
|
||||
hWnd,
|
||||
uMsg,
|
||||
wParam,
|
||||
lParam,
|
||||
&lResult)) {
|
||||
return lResult;
|
||||
}
|
||||
else if(context->keypad.indev &&
|
||||
lv_windows_keypad_device_window_message_handler(
|
||||
hWnd,
|
||||
uMsg,
|
||||
wParam,
|
||||
lParam,
|
||||
&lResult)) {
|
||||
return lResult;
|
||||
}
|
||||
else if(context->encoder.indev &&
|
||||
lv_windows_encoder_device_window_message_handler(
|
||||
hWnd,
|
||||
uMsg,
|
||||
wParam,
|
||||
lParam,
|
||||
&lResult)) {
|
||||
return lResult;
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // LV_USE_WINDOWS
|
123
src/dev/windows/lv_windows_context.h
Normal file
123
src/dev/windows/lv_windows_context.h
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @file lv_windows_context.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_WINDOWS_CONTEXT_H
|
||||
#define LV_WINDOWS_CONTEXT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../display/lv_display.h"
|
||||
#include "../../indev/lv_indev.h"
|
||||
|
||||
#if LV_USE_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct _lv_windows_pointer_context_t {
|
||||
lv_indev_state_t state;
|
||||
lv_point_t point;
|
||||
lv_indev_t * indev;
|
||||
} lv_windows_pointer_context_t;
|
||||
|
||||
typedef struct _lv_windows_keypad_queue_item_t {
|
||||
uint32_t key;
|
||||
lv_indev_state_t state;
|
||||
} lv_windows_keypad_queue_item_t;
|
||||
|
||||
typedef struct _lv_windows_keypad_context_t {
|
||||
CRITICAL_SECTION mutex;
|
||||
lv_ll_t queue;
|
||||
uint16_t utf16_high_surrogate;
|
||||
uint16_t utf16_low_surrogate;
|
||||
lv_indev_t * indev;
|
||||
} lv_windows_keypad_context_t;
|
||||
|
||||
typedef struct _lv_windows_encoder_context_t {
|
||||
lv_indev_state_t state;
|
||||
int16_t enc_diff;
|
||||
lv_indev_t * indev;
|
||||
} lv_windows_encoder_context_t;
|
||||
|
||||
typedef struct _lv_windows_window_context_t {
|
||||
lv_display_t * display_device_object;
|
||||
lv_timer_t * display_timer_object;
|
||||
|
||||
int32_t window_dpi;
|
||||
int32_t zoom_level;
|
||||
bool allow_dpi_override;
|
||||
bool simulator_mode;
|
||||
bool display_resolution_changed;
|
||||
lv_point_t requested_display_resolution;
|
||||
|
||||
HDC display_framebuffer_context_handle;
|
||||
uint32_t * display_framebuffer_base;
|
||||
size_t display_framebuffer_size;
|
||||
|
||||
lv_windows_pointer_context_t pointer;
|
||||
lv_windows_keypad_context_t keypad;
|
||||
lv_windows_encoder_context_t encoder;
|
||||
|
||||
} lv_windows_window_context_t;
|
||||
|
||||
typedef struct _lv_windows_create_display_data_t {
|
||||
const wchar_t * title;
|
||||
int32_t hor_res;
|
||||
int32_t ver_res;
|
||||
int32_t zoom_level;
|
||||
bool allow_dpi_override;
|
||||
bool simulator_mode;
|
||||
HANDLE mutex;
|
||||
lv_display_t * display;
|
||||
} lv_windows_create_display_data_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* @brief Initialize the LVGL Windows backend.
|
||||
* @remark This is a private API which is used for LVGL Windows backend
|
||||
* implementation. LVGL users shouldn't use that because the
|
||||
* LVGL has already used it in lv_init.
|
||||
*/
|
||||
void lv_windows_platform_init(void);
|
||||
|
||||
/**
|
||||
* @brief Get the window context from specific LVGL display window.
|
||||
* @param window_handle The window handle of specific LVGL display window.
|
||||
* @return The window context from specific LVGL display window.
|
||||
* @remark This is a private API which is used for LVGL Windows backend
|
||||
* implementation. LVGL users shouldn't use that because the
|
||||
* maintainer doesn't promise the application binary interface
|
||||
* compatibility for this API.
|
||||
*/
|
||||
lv_windows_window_context_t * lv_windows_get_window_context(
|
||||
HWND window_handle);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif // LV_USE_WINDOWS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_WINDOWS_CONTEXT_H*/
|
170
src/dev/windows/lv_windows_display.c
Normal file
170
src/dev/windows/lv_windows_display.c
Normal file
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @file lv_windows_display.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_windows_display.h"
|
||||
#if LV_USE_WINDOWS
|
||||
|
||||
#include "lv_windows_context.h"
|
||||
|
||||
#include <process.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static unsigned int __stdcall lv_windows_display_thread_entrypoint(
|
||||
void * parameter);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_display_t * lv_windows_create_display(
|
||||
const wchar_t * title,
|
||||
int32_t hor_res,
|
||||
int32_t ver_res,
|
||||
int32_t zoom_level,
|
||||
bool allow_dpi_override,
|
||||
bool simulator_mode)
|
||||
{
|
||||
lv_windows_create_display_data_t data;
|
||||
|
||||
lv_memzero(&data, sizeof(lv_windows_create_display_data_t));
|
||||
data.title = title;
|
||||
data.hor_res = hor_res;
|
||||
data.ver_res = ver_res;
|
||||
data.zoom_level = zoom_level;
|
||||
data.allow_dpi_override = allow_dpi_override;
|
||||
data.simulator_mode = simulator_mode;
|
||||
data.mutex = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
|
||||
data.display = NULL;
|
||||
if(!data.mutex) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HANDLE thread = (HANDLE)_beginthreadex(
|
||||
NULL,
|
||||
0,
|
||||
lv_windows_display_thread_entrypoint,
|
||||
&data,
|
||||
0,
|
||||
NULL);
|
||||
LV_ASSERT_NULL(thread);
|
||||
|
||||
WaitForSingleObjectEx(data.mutex, INFINITE, FALSE);
|
||||
|
||||
if(thread) {
|
||||
CloseHandle(thread);
|
||||
}
|
||||
|
||||
if(data.mutex) {
|
||||
CloseHandle(data.mutex);
|
||||
}
|
||||
|
||||
return data.display;
|
||||
}
|
||||
|
||||
HWND lv_windows_get_display_window_handle(lv_display_t * display)
|
||||
{
|
||||
return (HWND)lv_display_get_driver_data(display);
|
||||
}
|
||||
|
||||
int32_t lv_windows_zoom_to_logical(int32_t physical, int32_t zoom_level)
|
||||
{
|
||||
return MulDiv(physical, LV_WINDOWS_ZOOM_BASE_LEVEL, zoom_level);
|
||||
}
|
||||
|
||||
int32_t lv_windows_zoom_to_physical(int32_t logical, int32_t zoom_level)
|
||||
{
|
||||
return MulDiv(logical, zoom_level, LV_WINDOWS_ZOOM_BASE_LEVEL);
|
||||
}
|
||||
|
||||
int32_t lv_windows_dpi_to_logical(int32_t physical, int32_t dpi)
|
||||
{
|
||||
return MulDiv(physical, USER_DEFAULT_SCREEN_DPI, dpi);
|
||||
}
|
||||
|
||||
int32_t lv_windows_dpi_to_physical(int32_t logical, int32_t dpi)
|
||||
{
|
||||
return MulDiv(logical, dpi, USER_DEFAULT_SCREEN_DPI);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static unsigned int __stdcall lv_windows_display_thread_entrypoint(
|
||||
void * parameter)
|
||||
{
|
||||
lv_windows_create_display_data_t * data = parameter;
|
||||
LV_ASSERT_NULL(data);
|
||||
|
||||
DWORD window_style = WS_OVERLAPPEDWINDOW;
|
||||
if(data->simulator_mode) {
|
||||
window_style &= ~(WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME);
|
||||
}
|
||||
|
||||
HWND window_handle = CreateWindowExW(
|
||||
WS_EX_CLIENTEDGE,
|
||||
L"LVGL.Window",
|
||||
data->title,
|
||||
window_style,
|
||||
CW_USEDEFAULT,
|
||||
0,
|
||||
data->hor_res,
|
||||
data->ver_res,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
data);
|
||||
if(!window_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->display = context->display_device_object;
|
||||
|
||||
ShowWindow(window_handle, SW_SHOW);
|
||||
UpdateWindow(window_handle);
|
||||
|
||||
LV_ASSERT_NULL(SetEvent(data->mutex));
|
||||
|
||||
data = NULL;
|
||||
|
||||
MSG message;
|
||||
while(GetMessageW(&message, NULL, 0, 0)) {
|
||||
TranslateMessage(&message);
|
||||
DispatchMessageW(&message);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // LV_USE_WINDOWS
|
127
src/dev/windows/lv_windows_display.h
Normal file
127
src/dev/windows/lv_windows_display.h
Normal file
@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file lv_windows_display.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_WINDOWS_DISPLAY_H
|
||||
#define LV_WINDOWS_DISPLAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../display/lv_display.h"
|
||||
#include "../../indev/lv_indev.h"
|
||||
|
||||
#if LV_USE_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_WINDOWS_ZOOM_BASE_LEVEL 100
|
||||
|
||||
#ifndef USER_DEFAULT_SCREEN_DPI
|
||||
#define USER_DEFAULT_SCREEN_DPI 96
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* @brief Create a LVGL display object.
|
||||
* @param title The window title of LVGL display.
|
||||
* @param hor_res The horizontal resolution value of LVGL display.
|
||||
* @param ver_res The vertical resolution value of LVGL display.
|
||||
* @param zoom_level The zoom level value. Base value is 100 a.k.a 100%.
|
||||
* @param allow_dpi_override Allow DPI override if true, or follow the
|
||||
* Windows DPI scaling setting dynamically.
|
||||
* @param simulator_mode Create simulator mode display if true, or create
|
||||
* application mode display.
|
||||
* @return The created LVGL display object.
|
||||
*/
|
||||
lv_display_t * lv_windows_create_display(
|
||||
const wchar_t * title,
|
||||
int32_t hor_res,
|
||||
int32_t ver_res,
|
||||
int32_t zoom_level,
|
||||
bool allow_dpi_override,
|
||||
bool simulator_mode);
|
||||
|
||||
/**
|
||||
* @brief Get the window handle from specific LVGL display object.
|
||||
* @param display The specific LVGL display object.
|
||||
* @return The window handle from specific LVGL display object.
|
||||
*/
|
||||
HWND lv_windows_get_display_window_handle(lv_display_t * display);
|
||||
|
||||
/**
|
||||
* @brief Get logical pixel value from physical pixel value taken account
|
||||
* with zoom level.
|
||||
* @param physical The physical pixel value taken account with zoom level.
|
||||
* @param zoom_level The zoom level value. Base value is 100 a.k.a 100%.
|
||||
* @return The logical pixel value.
|
||||
* @remark It uses the same calculation style as Windows OS implementation.
|
||||
* It will be useful for integrate LVGL Windows backend to other
|
||||
* Windows applications.
|
||||
*/
|
||||
int32_t lv_windows_zoom_to_logical(int32_t physical, int32_t zoom_level);
|
||||
|
||||
/**
|
||||
* @brief Get physical pixel value taken account with zoom level from
|
||||
* logical pixel value.
|
||||
* @param logical The logical pixel value.
|
||||
* @param zoom_level The zoom level value. Base value is 100 a.k.a 100%.
|
||||
* @return The physical pixel value taken account with zoom level.
|
||||
* @remark It uses the same calculation style as Windows OS implementation.
|
||||
* It will be useful for integrate LVGL Windows backend to other
|
||||
* Windows applications.
|
||||
*/
|
||||
int32_t lv_windows_zoom_to_physical(int32_t logical, int32_t zoom_level);
|
||||
|
||||
/**
|
||||
* @brief Get logical pixel value from physical pixel value taken account
|
||||
* with DPI scaling.
|
||||
* @param physical The physical pixel value taken account with DPI scaling.
|
||||
* @param dpi The DPI scaling value. Base value is USER_DEFAULT_SCREEN_DPI.
|
||||
* @return The logical pixel value.
|
||||
* @remark It uses the same calculation style as Windows OS implementation.
|
||||
* It will be useful for integrate LVGL Windows backend to other
|
||||
* Windows applications.
|
||||
*/
|
||||
int32_t lv_windows_dpi_to_logical(int32_t physical, int32_t dpi);
|
||||
|
||||
/**
|
||||
* @brief Get physical pixel value taken account with DPI scaling from
|
||||
* logical pixel value.
|
||||
* @param logical The logical pixel value.
|
||||
* @param dpi The DPI scaling value. Base value is USER_DEFAULT_SCREEN_DPI.
|
||||
* @return The physical pixel value taken account with DPI scaling.
|
||||
* @remark It uses the same calculation style as Windows OS implementation.
|
||||
* It will be useful for integrate LVGL Windows backend to other
|
||||
* Windows applications.
|
||||
*/
|
||||
int32_t lv_windows_dpi_to_physical(int32_t logical, int32_t dpi);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif // LV_USE_WINDOWS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_WINDOWS_DISPLAY_H*/
|
749
src/dev/windows/lv_windows_input.c
Normal file
749
src/dev/windows/lv_windows_input.c
Normal file
@ -0,0 +1,749 @@
|
||||
/**
|
||||
* @file lv_windows_input.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_windows_input.h"
|
||||
#if LV_USE_WINDOWS
|
||||
|
||||
#include "lv_windows_context.h"
|
||||
#include "lv_windows_display.h"
|
||||
|
||||
#include <windowsx.h>
|
||||
|
||||
#if _MSC_VER >= 1200
|
||||
#pragma comment(lib, "Imm32.lib")
|
||||
#endif
|
||||
|
||||
#include "../../widgets/textarea/lv_textarea.h"
|
||||
#include "../../widgets/keyboard/lv_keyboard.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void lv_windows_pointer_driver_read_callback(
|
||||
lv_indev_t * indev,
|
||||
lv_indev_data_t * data);
|
||||
|
||||
static void lv_windows_release_pointer_device_event_callback(lv_event_t * e);
|
||||
|
||||
static void lv_windows_keypad_driver_read_callback(
|
||||
lv_indev_t * indev,
|
||||
lv_indev_data_t * data);
|
||||
|
||||
static void lv_windows_release_keypad_device_event_callback(lv_event_t * e);
|
||||
|
||||
static void lv_windows_encoder_driver_read_callback(
|
||||
lv_indev_t * indev,
|
||||
lv_indev_data_t * data);
|
||||
|
||||
static void lv_windows_release_encoder_device_event_callback(lv_event_t * e);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
HWND lv_windows_get_indev_window_handle(lv_indev_t * indev)
|
||||
{
|
||||
return lv_windows_get_display_window_handle(lv_indev_get_display(indev));
|
||||
}
|
||||
|
||||
lv_indev_t * lv_windows_acquire_pointer_indev(lv_display_t * display)
|
||||
{
|
||||
HWND window_handle = lv_windows_get_display_window_handle(display);
|
||||
if(!window_handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!context->pointer.indev) {
|
||||
context->pointer.state = LV_INDEV_STATE_RELEASED;
|
||||
context->pointer.point.x = 0;
|
||||
context->pointer.point.y = 0;
|
||||
|
||||
context->pointer.indev = lv_indev_create();
|
||||
if(context->pointer.indev) {
|
||||
lv_indev_set_type(
|
||||
context->pointer.indev,
|
||||
LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(
|
||||
context->pointer.indev,
|
||||
lv_windows_pointer_driver_read_callback);
|
||||
lv_indev_set_display(
|
||||
context->pointer.indev,
|
||||
context->display_device_object);
|
||||
lv_indev_add_event_cb(
|
||||
context->pointer.indev,
|
||||
lv_windows_release_pointer_device_event_callback,
|
||||
LV_EVENT_DELETE,
|
||||
context->pointer.indev);
|
||||
lv_indev_set_group(
|
||||
context->pointer.indev,
|
||||
lv_group_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
return context->pointer.indev;
|
||||
}
|
||||
|
||||
lv_indev_t * lv_windows_acquire_keypad_indev(lv_display_t * display)
|
||||
{
|
||||
HWND window_handle = lv_windows_get_display_window_handle(display);
|
||||
if(!window_handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!context->keypad.indev) {
|
||||
InitializeCriticalSection(&context->keypad.mutex);
|
||||
_lv_ll_init(
|
||||
&context->keypad.queue,
|
||||
sizeof(lv_windows_keypad_queue_item_t));
|
||||
context->keypad.utf16_high_surrogate = 0;
|
||||
context->keypad.utf16_low_surrogate = 0;
|
||||
|
||||
context->keypad.indev = lv_indev_create();
|
||||
if(context->keypad.indev) {
|
||||
lv_indev_set_type(
|
||||
context->keypad.indev,
|
||||
LV_INDEV_TYPE_KEYPAD);
|
||||
lv_indev_set_read_cb(
|
||||
context->keypad.indev,
|
||||
lv_windows_keypad_driver_read_callback);
|
||||
lv_indev_set_display(
|
||||
context->keypad.indev,
|
||||
context->display_device_object);
|
||||
lv_indev_add_event_cb(
|
||||
context->keypad.indev,
|
||||
lv_windows_release_keypad_device_event_callback,
|
||||
LV_EVENT_DELETE,
|
||||
context->keypad.indev);
|
||||
lv_indev_set_group(
|
||||
context->keypad.indev,
|
||||
lv_group_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
return context->keypad.indev;
|
||||
}
|
||||
|
||||
lv_indev_t * lv_windows_acquire_encoder_indev(lv_display_t * display)
|
||||
{
|
||||
HWND window_handle = lv_windows_get_display_window_handle(display);
|
||||
if(!window_handle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!context->encoder.indev) {
|
||||
context->encoder.state = LV_INDEV_STATE_RELEASED;
|
||||
context->encoder.enc_diff = 0;
|
||||
|
||||
context->encoder.indev = lv_indev_create();
|
||||
if(context->encoder.indev) {
|
||||
lv_indev_set_type(
|
||||
context->encoder.indev,
|
||||
LV_INDEV_TYPE_ENCODER);
|
||||
lv_indev_set_read_cb(
|
||||
context->encoder.indev,
|
||||
lv_windows_encoder_driver_read_callback);
|
||||
lv_indev_set_display(
|
||||
context->encoder.indev,
|
||||
context->display_device_object);
|
||||
lv_indev_add_event_cb(
|
||||
context->encoder.indev,
|
||||
lv_windows_release_encoder_device_event_callback,
|
||||
LV_EVENT_DELETE,
|
||||
context->encoder.indev);
|
||||
lv_indev_set_group(
|
||||
context->encoder.indev,
|
||||
lv_group_get_default());
|
||||
}
|
||||
}
|
||||
|
||||
return context->encoder.indev;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_windows_pointer_driver_read_callback(
|
||||
lv_indev_t * indev,
|
||||
lv_indev_data_t * data)
|
||||
{
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
lv_windows_get_indev_window_handle(indev));
|
||||
if(!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->state = context->pointer.state;
|
||||
data->point = context->pointer.point;
|
||||
}
|
||||
|
||||
static void lv_windows_release_pointer_device_event_callback(lv_event_t * e)
|
||||
{
|
||||
lv_indev_t * indev = (lv_indev_t *)lv_event_get_user_data(e);
|
||||
if(!indev) {
|
||||
return;
|
||||
}
|
||||
|
||||
HWND window_handle = lv_windows_get_indev_window_handle(indev);
|
||||
if(!window_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
context->pointer.state = LV_INDEV_STATE_RELEASED;
|
||||
context->pointer.point.x = 0;
|
||||
context->pointer.point.y = 0;
|
||||
|
||||
context->pointer.indev = NULL;
|
||||
}
|
||||
|
||||
static BOOL lv_windows_get_touch_input_info(
|
||||
HTOUCHINPUT touch_input_handle,
|
||||
UINT input_count,
|
||||
PTOUCHINPUT inputs,
|
||||
int item_size)
|
||||
{
|
||||
HMODULE module_handle = GetModuleHandleW(L"user32.dll");
|
||||
if(!module_handle) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI * function_type)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
|
||||
|
||||
function_type function = (function_type)(
|
||||
GetProcAddress(module_handle, "GetTouchInputInfo"));
|
||||
if(!function) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return function(touch_input_handle, input_count, inputs, item_size);
|
||||
}
|
||||
|
||||
static BOOL lv_windows_close_touch_input_handle(
|
||||
HTOUCHINPUT touch_input_handle)
|
||||
{
|
||||
HMODULE module_handle = GetModuleHandleW(L"user32.dll");
|
||||
if(!module_handle) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef BOOL(WINAPI * function_type)(HTOUCHINPUT);
|
||||
|
||||
function_type function = (function_type)(
|
||||
GetProcAddress(module_handle, "CloseTouchInputHandle"));
|
||||
if(!function) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return function(touch_input_handle);
|
||||
}
|
||||
|
||||
bool lv_windows_pointer_device_window_message_handler(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT * plResult)
|
||||
{
|
||||
switch(uMsg) {
|
||||
case WM_MOUSEMOVE: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
int32_t hor_res = lv_display_get_horizontal_resolution(
|
||||
context->display_device_object);
|
||||
int32_t ver_res = lv_display_get_vertical_resolution(
|
||||
context->display_device_object);
|
||||
|
||||
context->pointer.point.x = lv_windows_zoom_to_logical(
|
||||
GET_X_LPARAM(lParam),
|
||||
context->zoom_level);
|
||||
context->pointer.point.y = lv_windows_zoom_to_logical(
|
||||
GET_Y_LPARAM(lParam),
|
||||
context->zoom_level);
|
||||
if(context->simulator_mode) {
|
||||
context->pointer.point.x = lv_windows_dpi_to_logical(
|
||||
context->pointer.point.x,
|
||||
context->window_dpi);
|
||||
context->pointer.point.y = lv_windows_dpi_to_logical(
|
||||
context->pointer.point.y,
|
||||
context->window_dpi);
|
||||
}
|
||||
if(context->pointer.point.x < 0) {
|
||||
context->pointer.point.x = 0;
|
||||
}
|
||||
if(context->pointer.point.x > hor_res - 1) {
|
||||
context->pointer.point.x = hor_res - 1;
|
||||
}
|
||||
if(context->pointer.point.y < 0) {
|
||||
context->pointer.point.y = 0;
|
||||
}
|
||||
if(context->pointer.point.y > ver_res - 1) {
|
||||
context->pointer.point.y = ver_res - 1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
context->pointer.state = (
|
||||
uMsg == WM_LBUTTONDOWN
|
||||
? LV_INDEV_STATE_PRESSED
|
||||
: LV_INDEV_STATE_RELEASED);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_TOUCH: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
UINT input_count = LOWORD(wParam);
|
||||
HTOUCHINPUT touch_input_handle = (HTOUCHINPUT)(lParam);
|
||||
|
||||
PTOUCHINPUT inputs = malloc(input_count * sizeof(TOUCHINPUT));
|
||||
if(inputs) {
|
||||
if(lv_windows_get_touch_input_info(
|
||||
touch_input_handle,
|
||||
input_count,
|
||||
inputs,
|
||||
sizeof(TOUCHINPUT))) {
|
||||
for(UINT i = 0; i < input_count; ++i) {
|
||||
POINT Point;
|
||||
Point.x = TOUCH_COORD_TO_PIXEL(inputs[i].x);
|
||||
Point.y = TOUCH_COORD_TO_PIXEL(inputs[i].y);
|
||||
if(!ScreenToClient(hWnd, &Point)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
context->pointer.point.x = lv_windows_zoom_to_logical(
|
||||
Point.x,
|
||||
context->zoom_level);
|
||||
context->pointer.point.y = lv_windows_zoom_to_logical(
|
||||
Point.y,
|
||||
context->zoom_level);
|
||||
if(context->simulator_mode) {
|
||||
context->pointer.point.x = lv_windows_dpi_to_logical(
|
||||
context->pointer.point.x,
|
||||
context->window_dpi);
|
||||
context->pointer.point.y = lv_windows_dpi_to_logical(
|
||||
context->pointer.point.y,
|
||||
context->window_dpi);
|
||||
}
|
||||
|
||||
DWORD MousePressedMask =
|
||||
TOUCHEVENTF_MOVE | TOUCHEVENTF_DOWN;
|
||||
|
||||
context->pointer.state = (
|
||||
inputs[i].dwFlags & MousePressedMask
|
||||
? LV_INDEV_STATE_PRESSED
|
||||
: LV_INDEV_STATE_RELEASED);
|
||||
}
|
||||
}
|
||||
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
lv_windows_close_touch_input_handle(touch_input_handle);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Not Handled
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handled
|
||||
*plResult = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lv_windows_keypad_driver_read_callback(
|
||||
lv_indev_t * indev,
|
||||
lv_indev_data_t * data)
|
||||
{
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
lv_windows_get_indev_window_handle(indev));
|
||||
if(!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&context->keypad.mutex);
|
||||
|
||||
lv_windows_keypad_queue_item_t * current = (lv_windows_keypad_queue_item_t *)(
|
||||
_lv_ll_get_head(&context->keypad.queue));
|
||||
if(current) {
|
||||
data->key = current->key;
|
||||
data->state = current->state;
|
||||
|
||||
_lv_ll_remove(&context->keypad.queue, current);
|
||||
lv_free(current);
|
||||
|
||||
data->continue_reading = true;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&context->keypad.mutex);
|
||||
}
|
||||
|
||||
static void lv_windows_release_keypad_device_event_callback(lv_event_t * e)
|
||||
{
|
||||
lv_indev_t * indev = (lv_indev_t *)lv_event_get_user_data(e);
|
||||
if(!indev) {
|
||||
return;
|
||||
}
|
||||
|
||||
HWND window_handle = lv_windows_get_indev_window_handle(indev);
|
||||
if(!window_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&context->keypad.mutex);
|
||||
_lv_ll_clear(&context->keypad.queue);
|
||||
context->keypad.utf16_high_surrogate = 0;
|
||||
context->keypad.utf16_low_surrogate = 0;
|
||||
|
||||
context->keypad.indev = NULL;
|
||||
}
|
||||
|
||||
static void lv_windows_push_key_to_keyboard_queue(
|
||||
lv_windows_window_context_t * context,
|
||||
uint32_t key,
|
||||
lv_indev_state_t state)
|
||||
{
|
||||
lv_windows_keypad_queue_item_t * current = (lv_windows_keypad_queue_item_t *)(
|
||||
_lv_ll_ins_tail(&context->keypad.queue));
|
||||
if(current) {
|
||||
current->key = key;
|
||||
current->state = state;
|
||||
}
|
||||
}
|
||||
|
||||
bool lv_windows_keypad_device_window_message_handler(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT * plResult)
|
||||
{
|
||||
switch(uMsg) {
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
EnterCriticalSection(&context->keypad.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_windows_push_key_to_keyboard_queue(
|
||||
context,
|
||||
translated_key,
|
||||
((uMsg == WM_KEYUP)
|
||||
? LV_INDEV_STATE_RELEASED
|
||||
: LV_INDEV_STATE_PRESSED));
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&context->keypad.mutex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_CHAR: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
EnterCriticalSection(&context->keypad.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->keypad.utf16_high_surrogate = raw_code_point;
|
||||
}
|
||||
else if(IS_LOW_SURROGATE(raw_code_point)) {
|
||||
context->keypad.utf16_low_surrogate = raw_code_point;
|
||||
}
|
||||
|
||||
uint32_t code_point = raw_code_point;
|
||||
|
||||
if(context->keypad.utf16_high_surrogate &&
|
||||
context->keypad.utf16_low_surrogate) {
|
||||
uint16_t high_surrogate =
|
||||
context->keypad.utf16_high_surrogate;
|
||||
uint16_t low_surrogate =
|
||||
context->keypad.utf16_low_surrogate;
|
||||
|
||||
code_point = (low_surrogate & 0x03FF);
|
||||
code_point += (((high_surrogate & 0x03FF) + 0x40) << 10);
|
||||
|
||||
context->keypad.utf16_high_surrogate = 0;
|
||||
context->keypad.utf16_low_surrogate = 0;
|
||||
}
|
||||
|
||||
uint32_t lvgl_code_point =
|
||||
_lv_text_unicode_to_encoded(code_point);
|
||||
|
||||
lv_windows_push_key_to_keyboard_queue(
|
||||
context,
|
||||
lvgl_code_point,
|
||||
LV_INDEV_STATE_PRESSED);
|
||||
lv_windows_push_key_to_keyboard_queue(
|
||||
context,
|
||||
lvgl_code_point,
|
||||
LV_INDEV_STATE_RELEASED);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&context->keypad.mutex);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_IME_SETCONTEXT: {
|
||||
if(wParam == TRUE) {
|
||||
HIMC input_method_context_handle = ImmGetContext(hWnd);
|
||||
if(input_method_context_handle) {
|
||||
ImmAssociateContext(hWnd, input_method_context_handle);
|
||||
ImmReleaseContext(hWnd, input_method_context_handle);
|
||||
}
|
||||
}
|
||||
|
||||
*plResult = DefWindowProcW(hWnd, uMsg, wParam, wParam);
|
||||
break;
|
||||
}
|
||||
case WM_IME_STARTCOMPOSITION: {
|
||||
HIMC input_method_context_handle = ImmGetContext(hWnd);
|
||||
if(input_method_context_handle) {
|
||||
lv_obj_t * textarea_object = NULL;
|
||||
lv_obj_t * focused_object = lv_group_get_focused(
|
||||
lv_group_get_default());
|
||||
if(focused_object) {
|
||||
const lv_obj_class_t * object_class = lv_obj_get_class(
|
||||
focused_object);
|
||||
|
||||
if(object_class == &lv_textarea_class) {
|
||||
textarea_object = focused_object;
|
||||
}
|
||||
else if(object_class == &lv_keyboard_class) {
|
||||
textarea_object = lv_keyboard_get_textarea(focused_object);
|
||||
}
|
||||
}
|
||||
|
||||
COMPOSITIONFORM composition_form;
|
||||
composition_form.dwStyle = CFS_POINT;
|
||||
composition_form.ptCurrentPos.x = 0;
|
||||
composition_form.ptCurrentPos.y = 0;
|
||||
|
||||
if(textarea_object) {
|
||||
lv_textarea_t * textarea = (lv_textarea_t *)(textarea_object);
|
||||
lv_obj_t * label_object = lv_textarea_get_label(textarea_object);
|
||||
|
||||
composition_form.ptCurrentPos.x =
|
||||
label_object->coords.x1 + textarea->cursor.area.x1;
|
||||
composition_form.ptCurrentPos.y =
|
||||
label_object->coords.y1 + textarea->cursor.area.y1;
|
||||
}
|
||||
|
||||
ImmSetCompositionWindow(
|
||||
input_method_context_handle,
|
||||
&composition_form);
|
||||
ImmReleaseContext(
|
||||
hWnd,
|
||||
input_method_context_handle);
|
||||
}
|
||||
|
||||
*plResult = DefWindowProcW(hWnd, uMsg, wParam, wParam);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Not Handled
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handled
|
||||
*plResult = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void lv_windows_encoder_driver_read_callback(
|
||||
lv_indev_t * indev,
|
||||
lv_indev_data_t * data)
|
||||
{
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
lv_windows_get_indev_window_handle(indev));
|
||||
if(!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->state = context->encoder.state;
|
||||
data->enc_diff = context->encoder.enc_diff;
|
||||
context->encoder.enc_diff = 0;
|
||||
}
|
||||
|
||||
static void lv_windows_release_encoder_device_event_callback(lv_event_t * e)
|
||||
{
|
||||
lv_indev_t * indev = (lv_indev_t *)lv_event_get_user_data(e);
|
||||
if(!indev) {
|
||||
return;
|
||||
}
|
||||
|
||||
HWND window_handle = lv_windows_get_indev_window_handle(indev);
|
||||
if(!window_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_windows_window_context_t * context = lv_windows_get_window_context(
|
||||
window_handle);
|
||||
if(!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
context->encoder.state = LV_INDEV_STATE_RELEASED;
|
||||
context->encoder.enc_diff = 0;
|
||||
|
||||
context->encoder.indev = NULL;
|
||||
}
|
||||
|
||||
bool lv_windows_encoder_device_window_message_handler(
|
||||
HWND hWnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
LRESULT * plResult)
|
||||
{
|
||||
switch(uMsg) {
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MBUTTONUP: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
context->encoder.state = (
|
||||
uMsg == WM_MBUTTONDOWN
|
||||
? LV_INDEV_STATE_PRESSED
|
||||
: LV_INDEV_STATE_RELEASED);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_MOUSEWHEEL: {
|
||||
lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
|
||||
lv_windows_get_window_context(hWnd));
|
||||
if(context) {
|
||||
context->encoder.enc_diff =
|
||||
-(GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Not Handled
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handled
|
||||
*plResult = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // LV_USE_WINDOWS
|
83
src/dev/windows/lv_windows_input.h
Normal file
83
src/dev/windows/lv_windows_input.h
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file lv_windows_input.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_WINDOWS_INPUT_H
|
||||
#define LV_WINDOWS_INPUT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../display/lv_display.h"
|
||||
#include "../../indev/lv_indev.h"
|
||||
|
||||
#if LV_USE_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* @brief Get the window handle from specific LVGL input device object.
|
||||
* @param indev The specific LVGL input device object.
|
||||
* @return The window handle from specific LVGL input device object.
|
||||
*/
|
||||
HWND lv_windows_get_indev_window_handle(lv_indev_t * indev);
|
||||
|
||||
/**
|
||||
* @brief Open a LVGL pointer input device object for the specific LVGL
|
||||
* display object, or create it if the LVGL pointer input device
|
||||
* object is not created or removed before.
|
||||
* @param display The specific LVGL display object.
|
||||
* @return The LVGL pointer input device object for the specific LVGL
|
||||
* display object.
|
||||
*/
|
||||
lv_indev_t * lv_windows_acquire_pointer_indev(lv_display_t * display);
|
||||
|
||||
/**
|
||||
* @brief Open a LVGL keypad input device object for the specific LVGL
|
||||
* display object, or create it if the LVGL keypad input device
|
||||
* object is not created or removed before.
|
||||
* @param display The specific LVGL display object.
|
||||
* @return The LVGL keypad input device object for the specific LVGL
|
||||
* display object.
|
||||
*/
|
||||
lv_indev_t * lv_windows_acquire_keypad_indev(lv_display_t * display);
|
||||
|
||||
/**
|
||||
* @brief Open a LVGL encoder input device object for the specific LVGL
|
||||
* display object, or create it if the LVGL encoder input device
|
||||
* object is not created or removed before.
|
||||
* @param display The specific LVGL display object.
|
||||
* @return The LVGL encoder input device object for the specific LVGL
|
||||
* display object.
|
||||
*/
|
||||
lv_indev_t * lv_windows_acquire_encoder_indev(lv_display_t * display);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif // LV_USE_WINDOWS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_WINDOWS_INPUT_H*/
|
@ -2937,6 +2937,14 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* LVGL Windows backend */
|
||||
#ifndef LV_USE_WINDOWS
|
||||
#ifdef CONFIG_LV_USE_WINDOWS
|
||||
#define LV_USE_WINDOWS CONFIG_LV_USE_WINDOWS
|
||||
#else
|
||||
#define LV_USE_WINDOWS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
|
@ -39,6 +39,9 @@
|
||||
#if LV_USE_DRAW_VG_LITE
|
||||
#include "draw/vg_lite/lv_draw_vg_lite.h"
|
||||
#endif
|
||||
#if LV_USE_WINDOWS
|
||||
#include "src/dev/windows/lv_windows_context.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -185,6 +188,10 @@ void lv_init(void)
|
||||
lv_draw_sdl_init();
|
||||
#endif
|
||||
|
||||
#if LV_USE_WINDOWS
|
||||
lv_windows_platform_init();
|
||||
#endif
|
||||
|
||||
_lv_obj_style_init();
|
||||
|
||||
/*Initialize the screen refresh system*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user