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