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