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