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;
39 lv_point_t *point;
40
41 if (disp_data == NULL) {
42 LOG_WRN_ONCE("disp_data is NULL");
43 return;
44 }
45
46 cap = &disp_data->cap;
47 point = &data->common_data.pending_event.point;
48
49 switch (evt->code) {
50 case INPUT_ABS_X:
51 if (cfg->swap_xy) {
52 data->point_y = evt->value;
53 } else {
54 data->point_x = evt->value;
55 }
56 break;
57 case INPUT_ABS_Y:
58 if (cfg->swap_xy) {
59 data->point_x = evt->value;
60 } else {
61 data->point_y = evt->value;
62 }
63 break;
64 case INPUT_BTN_TOUCH:
65 data->common_data.pending_event.state =
66 evt->value ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
67 break;
68 default:
69 return;
70 }
71
72 if (!evt->sync) {
73 return;
74 }
75
76 lv_point_t tmp_point = {
77 .x = data->point_x,
78 .y = data->point_y,
79 };
80
81 if (cfg->invert_x) {
82 if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL ||
83 cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
84 tmp_point.x = cap->x_resolution - tmp_point.x;
85 } else {
86 tmp_point.x = cap->y_resolution - tmp_point.x;
87 }
88 }
89
90 if (cfg->invert_y) {
91 if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL ||
92 cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
93 tmp_point.y = cap->y_resolution - tmp_point.y;
94 } else {
95 tmp_point.y = cap->x_resolution - tmp_point.y;
96 }
97 }
98
99 /* rotate touch point to match display rotation */
100 switch (cap->current_orientation) {
101 case DISPLAY_ORIENTATION_NORMAL:
102 point->x = tmp_point.x;
103 point->y = tmp_point.y;
104 break;
105 case DISPLAY_ORIENTATION_ROTATED_90:
106 point->x = tmp_point.y;
107 point->y = cap->y_resolution - tmp_point.x;
108 break;
109 case DISPLAY_ORIENTATION_ROTATED_180:
110 point->x = cap->x_resolution - tmp_point.x;
111 point->y = cap->y_resolution - tmp_point.y;
112 break;
113 case DISPLAY_ORIENTATION_ROTATED_270:
114 point->x = cap->x_resolution - tmp_point.y;
115 point->y = tmp_point.x;
116 break;
117 default:
118 LOG_ERR("Invalid display orientation");
119 break;
120 }
121
122 /* filter readings within display */
123 if (point->x <= 0) {
124 point->x = 0;
125 } else if (point->x >= cap->x_resolution) {
126 point->x = cap->x_resolution - 1;
127 }
128
129 if (point->y <= 0) {
130 point->y = 0;
131 } else if (point->y >= cap->y_resolution) {
132 point->y = cap->y_resolution - 1;
133 }
134
135 if (k_msgq_put(cfg->common_config.event_msgq, &data->common_data.pending_event,
136 K_NO_WAIT) != 0) {
137 LOG_WRN("Could not put input data into queue");
138 }
139 }
140
lvgl_pointer_input_init(const struct device * dev)141 int lvgl_pointer_input_init(const struct device *dev)
142 {
143 return lvgl_input_register_driver(LV_INDEV_TYPE_POINTER, dev);
144 }
145
146 #define LVGL_POINTER_INPUT_DEFINE(inst) \
147 LVGL_INPUT_INST_DEFINE(inst, pointer, CONFIG_LV_Z_POINTER_INPUT_MSGQ_COUNT, \
148 lvgl_pointer_process_event); \
149 static const struct lvgl_pointer_input_config lvgl_pointer_input_config_##inst = { \
150 .common_config.event_msgq = &LVGL_INPUT_EVENT_MSGQ(inst, pointer), \
151 .common_config.display_dev = \
152 DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, display)), \
153 .swap_xy = DT_INST_PROP(inst, swap_xy), \
154 .invert_x = DT_INST_PROP(inst, invert_x), \
155 .invert_y = DT_INST_PROP(inst, invert_y), \
156 }; \
157 static struct lvgl_pointer_input_data lvgl_pointer_input_data_##inst; \
158 DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_pointer_input_data_##inst, \
159 &lvgl_pointer_input_config_##inst, POST_KERNEL, \
160 CONFIG_INPUT_INIT_PRIORITY, NULL);
161
162 DT_INST_FOREACH_STATUS_OKAY(LVGL_POINTER_INPUT_DEFINE)
163
164 #ifdef CONFIG_LV_Z_POINTER_FROM_CHOSEN_TOUCH
165
166 #define CHOSEN_TOUCH_DEV DEVICE_DT_GET(DT_CHOSEN(zephyr_touch))
167 #define LVGL_CHOSEN_TOUCH_POINTER_DEV_ID pointer_chosen_zephyr_touch
168
169 DEVICE_DECLARE(LVGL_CHOSEN_TOUCH_POINTER_DEV_ID);
170
171 LVGL_INPUT_DEFINE(CHOSEN_TOUCH_DEV, DEVICE_GET(LVGL_CHOSEN_TOUCH_POINTER_DEV_ID),
172 LVGL_CHOSEN_TOUCH_POINTER_DEV_ID, pointer, CONFIG_LV_Z_POINTER_INPUT_MSGQ_COUNT,
173 lvgl_pointer_process_event);
174
175 static const struct lvgl_pointer_input_config chosen_touch_pointer_config = {
176 .common_config.event_msgq =
177 &LVGL_INPUT_EVENT_MSGQ(LVGL_CHOSEN_TOUCH_POINTER_DEV_ID, pointer),
178 #ifdef CONFIG_LV_Z_POINTER_FROM_CHOSEN_TOUCH_INFER_DISPLAY
179 .common_config.display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)),
180 #endif /* CONFIG_LV_Z_POINTER_FROM_CHOSEN_TOUCH_INFER_DISPLAY */
181 };
182 static struct lvgl_pointer_input_data chosen_touch_pointer_data;
183
184 DEVICE_DEFINE(LVGL_CHOSEN_TOUCH_POINTER_DEV_ID, STRINGIFY(LVGL_CHOSEN_TOUCH_POINTER_DEV_ID), NULL,
185 NULL, &chosen_touch_pointer_data,
186 &chosen_touch_pointer_config, POST_KERNEL,
187 CONFIG_INPUT_INIT_PRIORITY, NULL);
188
lvgl_pointer_from_chosen_get(void)189 const struct device *lvgl_pointer_from_chosen_get(void)
190 {
191 return DEVICE_GET(LVGL_CHOSEN_TOUCH_POINTER_DEV_ID);
192 }
193
194 #endif /* CONFIG_LV_Z_POINTER_FROM_CHOSEN_TOUCH */
195