1 /*
2 * Copyright 2023 Fabian Blatz <fabianblatz@gmail.com>
3 * Copyright 2025 Abderrahmane JARMOUNI
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT zephyr_lvgl_pointer_input
9
10 #include "lvgl_common_input.h"
11 #include "lvgl_pointer_input.h"
12
13 #include <lvgl_display.h>
14 #include <zephyr/logging/log.h>
15
16 LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL);
17
18 struct lvgl_pointer_input_config {
19 struct lvgl_common_input_config common_config; /* Needs to be first member */
20 bool swap_xy;
21 bool invert_x;
22 bool invert_y;
23 };
24
25 struct lvgl_pointer_input_data {
26 struct lvgl_common_input_data common_data;
27 uint32_t point_x;
28 uint32_t point_y;
29 };
30
lvgl_pointer_process_event(struct input_event * evt,void * user_data)31 static void lvgl_pointer_process_event(struct input_event *evt, void *user_data)
32 {
33 const struct device *dev = user_data;
34 const struct lvgl_pointer_input_config *cfg = dev->config;
35 struct lvgl_pointer_input_data *data = dev->data;
36 lv_display_t *disp = lv_indev_get_display(data->common_data.indev);
37 struct lvgl_disp_data *disp_data = (struct lvgl_disp_data *)lv_display_get_user_data(disp);
38 struct display_capabilities *cap = &disp_data->cap;
39 lv_point_t *point = &data->common_data.pending_event.point;
40
41 switch (evt->code) {
42 case INPUT_ABS_X:
43 if (cfg->swap_xy) {
44 data->point_y = evt->value;
45 } else {
46 data->point_x = evt->value;
47 }
48 break;
49 case INPUT_ABS_Y:
50 if (cfg->swap_xy) {
51 data->point_x = evt->value;
52 } else {
53 data->point_y = evt->value;
54 }
55 break;
56 case INPUT_BTN_TOUCH:
57 data->common_data.pending_event.state =
58 evt->value ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
59 break;
60 }
61
62 if (!evt->sync) {
63 return;
64 }
65
66 lv_point_t tmp_point = {
67 .x = data->point_x,
68 .y = data->point_y,
69 };
70
71 if (cfg->invert_x) {
72 if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL ||
73 cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
74 tmp_point.x = cap->x_resolution - tmp_point.x;
75 } else {
76 tmp_point.x = cap->y_resolution - tmp_point.x;
77 }
78 }
79
80 if (cfg->invert_y) {
81 if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL ||
82 cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
83 tmp_point.y = cap->y_resolution - tmp_point.y;
84 } else {
85 tmp_point.y = cap->x_resolution - tmp_point.y;
86 }
87 }
88
89 /* rotate touch point to match display rotation */
90 switch (cap->current_orientation) {
91 case DISPLAY_ORIENTATION_NORMAL:
92 point->x = tmp_point.x;
93 point->y = tmp_point.y;
94 break;
95 case DISPLAY_ORIENTATION_ROTATED_90:
96 point->x = tmp_point.y;
97 point->y = cap->y_resolution - tmp_point.x;
98 break;
99 case DISPLAY_ORIENTATION_ROTATED_180:
100 point->x = cap->x_resolution - tmp_point.x;
101 point->y = cap->y_resolution - tmp_point.y;
102 break;
103 case DISPLAY_ORIENTATION_ROTATED_270:
104 point->x = cap->x_resolution - tmp_point.y;
105 point->y = tmp_point.x;
106 break;
107 default:
108 LOG_ERR("Invalid display orientation");
109 break;
110 }
111
112 /* filter readings within display */
113 if (point->x <= 0) {
114 point->x = 0;
115 } else if (point->x >= cap->x_resolution) {
116 point->x = cap->x_resolution - 1;
117 }
118
119 if (point->y <= 0) {
120 point->y = 0;
121 } else if (point->y >= cap->y_resolution) {
122 point->y = cap->y_resolution - 1;
123 }
124
125 if (k_msgq_put(cfg->common_config.event_msgq, &data->common_data.pending_event,
126 K_NO_WAIT) != 0) {
127 LOG_WRN("Could not put input data into queue");
128 }
129 }
130
lvgl_pointer_input_init(const struct device * dev)131 int lvgl_pointer_input_init(const struct device *dev)
132 {
133 return lvgl_input_register_driver(LV_INDEV_TYPE_POINTER, dev);
134 }
135
136 #define LVGL_POINTER_INPUT_DEFINE(inst) \
137 LVGL_INPUT_DEFINE(inst, pointer, CONFIG_LV_Z_POINTER_INPUT_MSGQ_COUNT, \
138 lvgl_pointer_process_event); \
139 static const struct lvgl_pointer_input_config lvgl_pointer_input_config_##inst = { \
140 .common_config.event_msgq = &LVGL_INPUT_EVENT_MSGQ(inst, pointer), \
141 .common_config.display_dev = \
142 DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, display)), \
143 .swap_xy = DT_INST_PROP(inst, swap_xy), \
144 .invert_x = DT_INST_PROP(inst, invert_x), \
145 .invert_y = DT_INST_PROP(inst, invert_y), \
146 }; \
147 static struct lvgl_pointer_input_data lvgl_pointer_input_data_##inst; \
148 DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_pointer_input_data_##inst, \
149 &lvgl_pointer_input_config_##inst, POST_KERNEL, \
150 CONFIG_INPUT_INIT_PRIORITY, NULL);
151
152 DT_INST_FOREACH_STATUS_OKAY(LVGL_POINTER_INPUT_DEFINE)
153