1 /**
2 * @file lv_windows_input.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "lv_windows_input.h"
11 #if LV_USE_WINDOWS
12
13 #ifdef __GNUC__
14 #pragma GCC diagnostic ignored "-Wcast-function-type"
15 #endif
16
17 #include "lv_windows_context.h"
18 #include "lv_windows_display.h"
19 #include "lv_windows_input_private.h"
20 #include "../../misc/lv_text_private.h"
21 #include "../../core/lv_obj_private.h"
22
23 #include <windowsx.h>
24
25 #include "../../widgets/textarea/lv_textarea_private.h"
26 #include "../../widgets/keyboard/lv_keyboard.h"
27
28 /*********************
29 * DEFINES
30 *********************/
31
32 /**********************
33 * TYPEDEFS
34 **********************/
35
36 /**********************
37 * STATIC PROTOTYPES
38 **********************/
39
40 static void lv_windows_pointer_driver_read_callback(
41 lv_indev_t * indev,
42 lv_indev_data_t * data);
43
44 static void lv_windows_release_pointer_device_event_callback(lv_event_t * e);
45
46 static void lv_windows_keypad_driver_read_callback(
47 lv_indev_t * indev,
48 lv_indev_data_t * data);
49
50 static void lv_windows_release_keypad_device_event_callback(lv_event_t * e);
51
52 static void lv_windows_encoder_driver_read_callback(
53 lv_indev_t * indev,
54 lv_indev_data_t * data);
55
56 static void lv_windows_release_encoder_device_event_callback(lv_event_t * e);
57
58 /**********************
59 * STATIC VARIABLES
60 **********************/
61
62 /**********************
63 * MACROS
64 **********************/
65
66 /**********************
67 * GLOBAL FUNCTIONS
68 **********************/
69
lv_windows_get_indev_window_handle(lv_indev_t * indev)70 HWND lv_windows_get_indev_window_handle(lv_indev_t * indev)
71 {
72 return lv_windows_get_display_window_handle(lv_indev_get_display(indev));
73 }
74
lv_windows_acquire_pointer_indev(lv_display_t * display)75 lv_indev_t * lv_windows_acquire_pointer_indev(lv_display_t * display)
76 {
77 HWND window_handle = lv_windows_get_display_window_handle(display);
78 if(!window_handle) {
79 return NULL;
80 }
81
82 lv_windows_window_context_t * context = lv_windows_get_window_context(
83 window_handle);
84 if(!context) {
85 return NULL;
86 }
87
88 if(!context->pointer.indev) {
89 context->pointer.state = LV_INDEV_STATE_RELEASED;
90 context->pointer.point.x = 0;
91 context->pointer.point.y = 0;
92
93 context->pointer.indev = lv_indev_create();
94 if(context->pointer.indev) {
95 lv_indev_set_type(
96 context->pointer.indev,
97 LV_INDEV_TYPE_POINTER);
98 lv_indev_set_read_cb(
99 context->pointer.indev,
100 lv_windows_pointer_driver_read_callback);
101 lv_indev_set_display(
102 context->pointer.indev,
103 context->display_device_object);
104 lv_indev_add_event_cb(
105 context->pointer.indev,
106 lv_windows_release_pointer_device_event_callback,
107 LV_EVENT_DELETE,
108 context->pointer.indev);
109 lv_indev_set_group(
110 context->pointer.indev,
111 lv_group_get_default());
112 }
113 }
114
115 return context->pointer.indev;
116 }
117
lv_windows_acquire_keypad_indev(lv_display_t * display)118 lv_indev_t * lv_windows_acquire_keypad_indev(lv_display_t * display)
119 {
120 HWND window_handle = lv_windows_get_display_window_handle(display);
121 if(!window_handle) {
122 return NULL;
123 }
124
125 lv_windows_window_context_t * context = lv_windows_get_window_context(
126 window_handle);
127 if(!context) {
128 return NULL;
129 }
130
131 if(!context->keypad.indev) {
132 lv_ll_init(
133 &context->keypad.queue,
134 sizeof(lv_windows_keypad_queue_item_t));
135 context->keypad.utf16_high_surrogate = 0;
136 context->keypad.utf16_low_surrogate = 0;
137
138 context->keypad.indev = lv_indev_create();
139 if(context->keypad.indev) {
140 lv_indev_set_type(
141 context->keypad.indev,
142 LV_INDEV_TYPE_KEYPAD);
143 lv_indev_set_read_cb(
144 context->keypad.indev,
145 lv_windows_keypad_driver_read_callback);
146 lv_indev_set_display(
147 context->keypad.indev,
148 context->display_device_object);
149 lv_indev_add_event_cb(
150 context->keypad.indev,
151 lv_windows_release_keypad_device_event_callback,
152 LV_EVENT_DELETE,
153 context->keypad.indev);
154 lv_indev_set_group(
155 context->keypad.indev,
156 lv_group_get_default());
157 }
158 }
159
160 return context->keypad.indev;
161 }
162
lv_windows_acquire_encoder_indev(lv_display_t * display)163 lv_indev_t * lv_windows_acquire_encoder_indev(lv_display_t * display)
164 {
165 HWND window_handle = lv_windows_get_display_window_handle(display);
166 if(!window_handle) {
167 return NULL;
168 }
169
170 lv_windows_window_context_t * context = lv_windows_get_window_context(
171 window_handle);
172 if(!context) {
173 return NULL;
174 }
175
176 if(!context->encoder.indev) {
177 context->encoder.state = LV_INDEV_STATE_RELEASED;
178 context->encoder.enc_diff = 0;
179
180 context->encoder.indev = lv_indev_create();
181 if(context->encoder.indev) {
182 lv_indev_set_type(
183 context->encoder.indev,
184 LV_INDEV_TYPE_ENCODER);
185 lv_indev_set_read_cb(
186 context->encoder.indev,
187 lv_windows_encoder_driver_read_callback);
188 lv_indev_set_display(
189 context->encoder.indev,
190 context->display_device_object);
191 lv_indev_add_event_cb(
192 context->encoder.indev,
193 lv_windows_release_encoder_device_event_callback,
194 LV_EVENT_DELETE,
195 context->encoder.indev);
196 lv_indev_set_group(
197 context->encoder.indev,
198 lv_group_get_default());
199 }
200 }
201
202 return context->encoder.indev;
203 }
204
205 /**********************
206 * STATIC FUNCTIONS
207 **********************/
208
lv_windows_pointer_driver_read_callback(lv_indev_t * indev,lv_indev_data_t * data)209 static void lv_windows_pointer_driver_read_callback(
210 lv_indev_t * indev,
211 lv_indev_data_t * data)
212 {
213 lv_windows_window_context_t * context = lv_windows_get_window_context(
214 lv_windows_get_indev_window_handle(indev));
215 if(!context) {
216 return;
217 }
218
219 data->state = context->pointer.state;
220 data->point = context->pointer.point;
221 }
222
lv_windows_release_pointer_device_event_callback(lv_event_t * e)223 static void lv_windows_release_pointer_device_event_callback(lv_event_t * e)
224 {
225 lv_indev_t * indev = (lv_indev_t *)lv_event_get_user_data(e);
226 if(!indev) {
227 return;
228 }
229
230 HWND window_handle = lv_windows_get_indev_window_handle(indev);
231 if(!window_handle) {
232 return;
233 }
234
235 lv_windows_window_context_t * context = lv_windows_get_window_context(
236 window_handle);
237 if(!context) {
238 return;
239 }
240
241 context->pointer.state = LV_INDEV_STATE_RELEASED;
242 context->pointer.point.x = 0;
243 context->pointer.point.y = 0;
244
245 context->pointer.indev = NULL;
246 }
247
lv_windows_get_touch_input_info(HTOUCHINPUT touch_input_handle,UINT input_count,PTOUCHINPUT inputs,int item_size)248 static BOOL lv_windows_get_touch_input_info(
249 HTOUCHINPUT touch_input_handle,
250 UINT input_count,
251 PTOUCHINPUT inputs,
252 int item_size)
253 {
254 HMODULE module_handle = GetModuleHandleW(L"user32.dll");
255 if(!module_handle) {
256 return FALSE;
257 }
258
259 typedef BOOL(WINAPI * function_type)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
260
261 function_type function = (function_type)(
262 GetProcAddress(module_handle, "GetTouchInputInfo"));
263 if(!function) {
264 return FALSE;
265 }
266
267 return function(touch_input_handle, input_count, inputs, item_size);
268 }
269
lv_windows_close_touch_input_handle(HTOUCHINPUT touch_input_handle)270 static BOOL lv_windows_close_touch_input_handle(
271 HTOUCHINPUT touch_input_handle)
272 {
273 HMODULE module_handle = GetModuleHandleW(L"user32.dll");
274 if(!module_handle) {
275 return FALSE;
276 }
277
278 typedef BOOL(WINAPI * function_type)(HTOUCHINPUT);
279
280 function_type function = (function_type)(
281 GetProcAddress(module_handle, "CloseTouchInputHandle"));
282 if(!function) {
283 return FALSE;
284 }
285
286 return function(touch_input_handle);
287 }
288
lv_windows_pointer_device_window_message_handler(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT * plResult)289 bool lv_windows_pointer_device_window_message_handler(
290 HWND hWnd,
291 UINT uMsg,
292 WPARAM wParam,
293 LPARAM lParam,
294 LRESULT * plResult)
295 {
296 switch(uMsg) {
297 case WM_MOUSEMOVE: {
298 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
299 lv_windows_get_window_context(hWnd));
300 if(context) {
301 int32_t hor_res = lv_display_get_horizontal_resolution(
302 context->display_device_object);
303 int32_t ver_res = lv_display_get_vertical_resolution(
304 context->display_device_object);
305
306 context->pointer.point.x = lv_windows_zoom_to_logical(
307 GET_X_LPARAM(lParam),
308 context->zoom_level);
309 context->pointer.point.y = lv_windows_zoom_to_logical(
310 GET_Y_LPARAM(lParam),
311 context->zoom_level);
312 if(context->simulator_mode) {
313 context->pointer.point.x = lv_windows_dpi_to_logical(
314 context->pointer.point.x,
315 context->window_dpi);
316 context->pointer.point.y = lv_windows_dpi_to_logical(
317 context->pointer.point.y,
318 context->window_dpi);
319 }
320 if(context->pointer.point.x < 0) {
321 context->pointer.point.x = 0;
322 }
323 if(context->pointer.point.x > hor_res - 1) {
324 context->pointer.point.x = hor_res - 1;
325 }
326 if(context->pointer.point.y < 0) {
327 context->pointer.point.y = 0;
328 }
329 if(context->pointer.point.y > ver_res - 1) {
330 context->pointer.point.y = ver_res - 1;
331 }
332 }
333
334 break;
335 }
336 case WM_LBUTTONDOWN:
337 case WM_LBUTTONUP: {
338 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
339 lv_windows_get_window_context(hWnd));
340 if(context) {
341 context->pointer.state = (
342 uMsg == WM_LBUTTONDOWN
343 ? LV_INDEV_STATE_PRESSED
344 : LV_INDEV_STATE_RELEASED);
345 }
346
347 break;
348 }
349 case WM_TOUCH: {
350 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
351 lv_windows_get_window_context(hWnd));
352 if(context) {
353 UINT input_count = LOWORD(wParam);
354 HTOUCHINPUT touch_input_handle = (HTOUCHINPUT)(lParam);
355
356 PTOUCHINPUT inputs = malloc(input_count * sizeof(TOUCHINPUT));
357 if(inputs) {
358 if(lv_windows_get_touch_input_info(
359 touch_input_handle,
360 input_count,
361 inputs,
362 sizeof(TOUCHINPUT))) {
363 for(UINT i = 0; i < input_count; ++i) {
364 POINT Point;
365 Point.x = TOUCH_COORD_TO_PIXEL(inputs[i].x);
366 Point.y = TOUCH_COORD_TO_PIXEL(inputs[i].y);
367 if(!ScreenToClient(hWnd, &Point)) {
368 continue;
369 }
370
371 context->pointer.point.x = lv_windows_zoom_to_logical(
372 Point.x,
373 context->zoom_level);
374 context->pointer.point.y = lv_windows_zoom_to_logical(
375 Point.y,
376 context->zoom_level);
377 if(context->simulator_mode) {
378 context->pointer.point.x = lv_windows_dpi_to_logical(
379 context->pointer.point.x,
380 context->window_dpi);
381 context->pointer.point.y = lv_windows_dpi_to_logical(
382 context->pointer.point.y,
383 context->window_dpi);
384 }
385
386 DWORD MousePressedMask =
387 TOUCHEVENTF_MOVE | TOUCHEVENTF_DOWN;
388
389 context->pointer.state = (
390 inputs[i].dwFlags & MousePressedMask
391 ? LV_INDEV_STATE_PRESSED
392 : LV_INDEV_STATE_RELEASED);
393 }
394 }
395
396 free(inputs);
397 }
398
399 lv_windows_close_touch_input_handle(touch_input_handle);
400 }
401
402 break;
403 }
404 default:
405 // Not Handled
406 return false;
407 }
408
409 // Handled
410 *plResult = 0;
411 return true;
412 }
413
lv_windows_keypad_driver_read_callback(lv_indev_t * indev,lv_indev_data_t * data)414 static void lv_windows_keypad_driver_read_callback(
415 lv_indev_t * indev,
416 lv_indev_data_t * data)
417 {
418 lv_windows_window_context_t * context = lv_windows_get_window_context(
419 lv_windows_get_indev_window_handle(indev));
420 if(!context) {
421 return;
422 }
423
424 lv_windows_keypad_queue_item_t * current = (lv_windows_keypad_queue_item_t *)(
425 lv_ll_get_head(&context->keypad.queue));
426 if(current) {
427 data->key = current->key;
428 data->state = current->state;
429
430 lv_ll_remove(&context->keypad.queue, current);
431 lv_free(current);
432
433 data->continue_reading = true;
434 }
435 }
436
lv_windows_release_keypad_device_event_callback(lv_event_t * e)437 static void lv_windows_release_keypad_device_event_callback(lv_event_t * e)
438 {
439 lv_indev_t * indev = (lv_indev_t *)lv_event_get_user_data(e);
440 if(!indev) {
441 return;
442 }
443
444 HWND window_handle = lv_windows_get_indev_window_handle(indev);
445 if(!window_handle) {
446 return;
447 }
448
449 lv_windows_window_context_t * context = lv_windows_get_window_context(
450 window_handle);
451 if(!context) {
452 return;
453 }
454
455 lv_ll_clear(&context->keypad.queue);
456 context->keypad.utf16_high_surrogate = 0;
457 context->keypad.utf16_low_surrogate = 0;
458
459 context->keypad.indev = NULL;
460 }
461
lv_windows_push_key_to_keyboard_queue(lv_windows_window_context_t * context,uint32_t key,lv_indev_state_t state)462 static void lv_windows_push_key_to_keyboard_queue(
463 lv_windows_window_context_t * context,
464 uint32_t key,
465 lv_indev_state_t state)
466 {
467 lv_windows_keypad_queue_item_t * current = (lv_windows_keypad_queue_item_t *)(
468 lv_ll_ins_tail(&context->keypad.queue));
469 if(current) {
470 current->key = key;
471 current->state = state;
472 }
473 }
474
lv_windows_imm_get_context(HWND window_handle)475 static HIMC lv_windows_imm_get_context(
476 HWND window_handle)
477 {
478 HMODULE module_handle = GetModuleHandleW(L"imm32.dll");
479 if(!module_handle) {
480 return FALSE;
481 }
482
483 typedef HIMC(WINAPI * function_type)(HWND);
484
485 function_type function = (function_type)(
486 GetProcAddress(module_handle, "ImmGetContext"));
487 if(!function) {
488 return FALSE;
489 }
490
491 return function(window_handle);
492 }
493
lv_windows_imm_release_context(HWND window_handle,HIMC imm_context_handle)494 static BOOL lv_windows_imm_release_context(
495 HWND window_handle,
496 HIMC imm_context_handle)
497 {
498 HMODULE module_handle = GetModuleHandleW(L"imm32.dll");
499 if(!module_handle) {
500 return FALSE;
501 }
502
503 typedef BOOL(WINAPI * function_type)(HWND, HIMC);
504
505 function_type function = (function_type)(
506 GetProcAddress(module_handle, "ImmReleaseContext"));
507 if(!function) {
508 return FALSE;
509 }
510
511 return function(window_handle, imm_context_handle);
512 }
513
lv_windows_imm_associate_context(HWND window_handle,HIMC imm_context_handle)514 static HIMC lv_windows_imm_associate_context(
515 HWND window_handle,
516 HIMC imm_context_handle)
517 {
518 HMODULE module_handle = GetModuleHandleW(L"imm32.dll");
519 if(!module_handle) {
520 return FALSE;
521 }
522
523 typedef HIMC(WINAPI * function_type)(HWND, HIMC);
524
525 function_type function = (function_type)(
526 GetProcAddress(module_handle, "ImmAssociateContext"));
527 if(!function) {
528 return FALSE;
529 }
530
531 return function(window_handle, imm_context_handle);
532 }
533
lv_windows_imm_set_composition_window(HIMC imm_context_handle,LPCOMPOSITIONFORM composition_form)534 static BOOL lv_windows_imm_set_composition_window(
535 HIMC imm_context_handle,
536 LPCOMPOSITIONFORM composition_form)
537 {
538 HMODULE module_handle = GetModuleHandleW(L"imm32.dll");
539 if(!module_handle) {
540 return FALSE;
541 }
542
543 typedef BOOL(WINAPI * function_type)(HIMC, LPCOMPOSITIONFORM);
544
545 function_type function = (function_type)(
546 GetProcAddress(module_handle, "ImmSetCompositionWindow"));
547 if(!function) {
548 return FALSE;
549 }
550
551 return function(imm_context_handle, composition_form);
552 }
553
lv_windows_keypad_device_window_message_handler(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT * plResult)554 bool lv_windows_keypad_device_window_message_handler(
555 HWND hWnd,
556 UINT uMsg,
557 WPARAM wParam,
558 LPARAM lParam,
559 LRESULT * plResult)
560 {
561 LV_UNUSED(lParam);
562
563 switch(uMsg) {
564 case WM_KEYDOWN:
565 case WM_KEYUP: {
566 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
567 lv_windows_get_window_context(hWnd));
568 if(context) {
569 bool skip_translation = false;
570 uint32_t translated_key = 0;
571
572 switch(wParam) {
573 case VK_UP:
574 translated_key = LV_KEY_UP;
575 break;
576 case VK_DOWN:
577 translated_key = LV_KEY_DOWN;
578 break;
579 case VK_LEFT:
580 translated_key = LV_KEY_LEFT;
581 break;
582 case VK_RIGHT:
583 translated_key = LV_KEY_RIGHT;
584 break;
585 case VK_ESCAPE:
586 translated_key = LV_KEY_ESC;
587 break;
588 case VK_DELETE:
589 translated_key = LV_KEY_DEL;
590 break;
591 case VK_BACK:
592 translated_key = LV_KEY_BACKSPACE;
593 break;
594 case VK_RETURN:
595 translated_key = LV_KEY_ENTER;
596 break;
597 case VK_TAB:
598 case VK_NEXT:
599 translated_key = LV_KEY_NEXT;
600 break;
601 case VK_PRIOR:
602 translated_key = LV_KEY_PREV;
603 break;
604 case VK_HOME:
605 translated_key = LV_KEY_HOME;
606 break;
607 case VK_END:
608 translated_key = LV_KEY_END;
609 break;
610 default:
611 skip_translation = true;
612 break;
613 }
614
615 if(!skip_translation) {
616 lv_windows_push_key_to_keyboard_queue(
617 context,
618 translated_key,
619 ((uMsg == WM_KEYUP)
620 ? LV_INDEV_STATE_RELEASED
621 : LV_INDEV_STATE_PRESSED));
622 }
623 }
624
625 break;
626 }
627 case WM_CHAR: {
628 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
629 lv_windows_get_window_context(hWnd));
630 if(context) {
631 uint16_t raw_code_point = (uint16_t)(wParam);
632
633 if(raw_code_point >= 0x20 && raw_code_point != 0x7F) {
634 if(IS_HIGH_SURROGATE(raw_code_point)) {
635 context->keypad.utf16_high_surrogate = raw_code_point;
636 }
637 else if(IS_LOW_SURROGATE(raw_code_point)) {
638 context->keypad.utf16_low_surrogate = raw_code_point;
639 }
640
641 uint32_t code_point = raw_code_point;
642
643 if(context->keypad.utf16_high_surrogate &&
644 context->keypad.utf16_low_surrogate) {
645 uint16_t high_surrogate =
646 context->keypad.utf16_high_surrogate;
647 uint16_t low_surrogate =
648 context->keypad.utf16_low_surrogate;
649
650 code_point = (low_surrogate & 0x03FF);
651 code_point += (((high_surrogate & 0x03FF) + 0x40) << 10);
652
653 context->keypad.utf16_high_surrogate = 0;
654 context->keypad.utf16_low_surrogate = 0;
655 }
656
657 uint32_t lvgl_code_point =
658 lv_text_unicode_to_encoded(code_point);
659
660 lv_windows_push_key_to_keyboard_queue(
661 context,
662 lvgl_code_point,
663 LV_INDEV_STATE_PRESSED);
664 lv_windows_push_key_to_keyboard_queue(
665 context,
666 lvgl_code_point,
667 LV_INDEV_STATE_RELEASED);
668 }
669 }
670
671 break;
672 }
673 case WM_IME_SETCONTEXT: {
674 if(wParam == TRUE) {
675 HIMC imm_context_handle = lv_windows_imm_get_context(hWnd);
676 if(imm_context_handle) {
677 lv_windows_imm_associate_context(
678 hWnd,
679 imm_context_handle);
680 lv_windows_imm_release_context(
681 hWnd,
682 imm_context_handle);
683 }
684 }
685
686 *plResult = DefWindowProcW(hWnd, uMsg, wParam, wParam);
687 break;
688 }
689 case WM_IME_STARTCOMPOSITION: {
690 HIMC imm_context_handle = lv_windows_imm_get_context(hWnd);
691 if(imm_context_handle) {
692 lv_obj_t * textarea_object = NULL;
693 lv_obj_t * focused_object = lv_group_get_focused(
694 lv_group_get_default());
695 if(focused_object) {
696 const lv_obj_class_t * object_class = lv_obj_get_class(
697 focused_object);
698
699 if(object_class == &lv_textarea_class) {
700 textarea_object = focused_object;
701 }
702 else if(object_class == &lv_keyboard_class) {
703 textarea_object = lv_keyboard_get_textarea(focused_object);
704 }
705 }
706
707 COMPOSITIONFORM composition_form;
708 composition_form.dwStyle = CFS_POINT;
709 composition_form.ptCurrentPos.x = 0;
710 composition_form.ptCurrentPos.y = 0;
711
712 if(textarea_object) {
713 lv_textarea_t * textarea = (lv_textarea_t *)(textarea_object);
714 lv_obj_t * label_object = lv_textarea_get_label(textarea_object);
715
716 composition_form.ptCurrentPos.x =
717 label_object->coords.x1 + textarea->cursor.area.x1;
718 composition_form.ptCurrentPos.y =
719 label_object->coords.y1 + textarea->cursor.area.y1;
720 }
721
722 lv_windows_imm_set_composition_window(
723 imm_context_handle,
724 &composition_form);
725 lv_windows_imm_release_context(
726 hWnd,
727 imm_context_handle);
728 }
729
730 *plResult = DefWindowProcW(hWnd, uMsg, wParam, wParam);
731 break;
732 }
733 default:
734 // Not Handled
735 return false;
736 }
737
738 // Handled
739 *plResult = 0;
740 return true;
741 }
742
lv_windows_encoder_driver_read_callback(lv_indev_t * indev,lv_indev_data_t * data)743 static void lv_windows_encoder_driver_read_callback(
744 lv_indev_t * indev,
745 lv_indev_data_t * data)
746 {
747 lv_windows_window_context_t * context = lv_windows_get_window_context(
748 lv_windows_get_indev_window_handle(indev));
749 if(!context) {
750 return;
751 }
752
753 data->state = context->encoder.state;
754 data->enc_diff = context->encoder.enc_diff;
755 context->encoder.enc_diff = 0;
756 }
757
lv_windows_release_encoder_device_event_callback(lv_event_t * e)758 static void lv_windows_release_encoder_device_event_callback(lv_event_t * e)
759 {
760 lv_indev_t * indev = (lv_indev_t *)lv_event_get_user_data(e);
761 if(!indev) {
762 return;
763 }
764
765 HWND window_handle = lv_windows_get_indev_window_handle(indev);
766 if(!window_handle) {
767 return;
768 }
769
770 lv_windows_window_context_t * context = lv_windows_get_window_context(
771 window_handle);
772 if(!context) {
773 return;
774 }
775
776 context->encoder.state = LV_INDEV_STATE_RELEASED;
777 context->encoder.enc_diff = 0;
778
779 context->encoder.indev = NULL;
780 }
781
lv_windows_encoder_device_window_message_handler(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT * plResult)782 bool lv_windows_encoder_device_window_message_handler(
783 HWND hWnd,
784 UINT uMsg,
785 WPARAM wParam,
786 LPARAM lParam,
787 LRESULT * plResult)
788 {
789 LV_UNUSED(lParam);
790
791 switch(uMsg) {
792 case WM_MBUTTONDOWN:
793 case WM_MBUTTONUP: {
794 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
795 lv_windows_get_window_context(hWnd));
796 if(context) {
797 context->encoder.state = (
798 uMsg == WM_MBUTTONDOWN
799 ? LV_INDEV_STATE_PRESSED
800 : LV_INDEV_STATE_RELEASED);
801 }
802
803 break;
804 }
805 case WM_MOUSEWHEEL: {
806 lv_windows_window_context_t * context = (lv_windows_window_context_t *)(
807 lv_windows_get_window_context(hWnd));
808 if(context) {
809 context->encoder.enc_diff =
810 -(GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA);
811 }
812
813 break;
814 }
815 default:
816 // Not Handled
817 return false;
818 }
819
820 // Handled
821 *plResult = 0;
822 return true;
823 }
824
825 #endif // LV_USE_WINDOWS
826