1 /**
2  * @file lv_hal_indev.c
3  *
4  * @description Input device HAL interface
5  *
6  */
7 
8 /*********************
9  *      INCLUDES
10  *********************/
11 #include "../misc/lv_assert.h"
12 #include "../hal/lv_hal_indev.h"
13 #include "../core/lv_indev.h"
14 #include "../misc/lv_mem.h"
15 #include "../misc/lv_gc.h"
16 #include "lv_hal_disp.h"
17 
18 /*********************
19  *      DEFINES
20  *********************/
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  GLOBAL PROTOTYPES
28  **********************/
29 
30 /**********************
31  *  STATIC PROTOTYPES
32  **********************/
33 
34 /**********************
35  *  STATIC VARIABLES
36  **********************/
37 
38 /**********************
39  *      MACROS
40  **********************/
41 #if LV_LOG_TRACE_INDEV
42     #define INDEV_TRACE(...) LV_LOG_TRACE(__VA_ARGS__)
43 #else
44     #define INDEV_TRACE(...)
45 #endif
46 
47 /**********************
48  *   GLOBAL FUNCTIONS
49  **********************/
50 
51 /**
52  * Initialize an input device driver with default values.
53  * It is used to surly have known values in the fields ant not memory junk.
54  * After it you can set the fields.
55  * @param driver pointer to driver variable to initialize
56  */
lv_indev_drv_init(lv_indev_drv_t * driver)57 void lv_indev_drv_init(lv_indev_drv_t * driver)
58 {
59     lv_memset_00(driver, sizeof(lv_indev_drv_t));
60 
61     driver->type                 = LV_INDEV_TYPE_NONE;
62     driver->scroll_limit         = LV_INDEV_DEF_SCROLL_LIMIT;
63     driver->scroll_throw         = LV_INDEV_DEF_SCROLL_THROW;
64     driver->long_press_time      = LV_INDEV_DEF_LONG_PRESS_TIME;
65     driver->long_press_repeat_time  = LV_INDEV_DEF_LONG_PRESS_REP_TIME;
66     driver->gesture_limit        = LV_INDEV_DEF_GESTURE_LIMIT;
67     driver->gesture_min_velocity = LV_INDEV_DEF_GESTURE_MIN_VELOCITY;
68 }
69 
70 /**
71  * Register an initialized input device driver.
72  * @param driver pointer to an initialized 'lv_indev_drv_t' variable.
73  * Only pointer is saved, so the driver should be static or dynamically allocated.
74  * @return pointer to the new input device or NULL on error
75  */
lv_indev_drv_register(lv_indev_drv_t * driver)76 lv_indev_t * lv_indev_drv_register(lv_indev_drv_t * driver)
77 {
78 
79     if(driver->disp == NULL) driver->disp = lv_disp_get_default();
80 
81     if(driver->disp == NULL) {
82         LV_LOG_WARN("lv_indev_drv_register: no display registered hence can't attach the indev to "
83                     "a display");
84         return NULL;
85     }
86 
87     lv_indev_t * indev = _lv_ll_ins_head(&LV_GC_ROOT(_lv_indev_ll));
88     if(!indev) {
89         LV_ASSERT_MALLOC(indev);
90         return NULL;
91     }
92 
93     lv_memset_00(indev, sizeof(lv_indev_t));
94     indev->driver = driver;
95 
96     indev->proc.reset_query  = 1;
97     indev->driver->read_timer = lv_timer_create(lv_indev_read_timer_cb, LV_INDEV_DEF_READ_PERIOD, indev);
98 
99     return indev;
100 }
101 
102 /**
103  * Update the driver in run time.
104  * @param indev pointer to a input device. (return value of `lv_indev_drv_register`)
105  * @param new_drv pointer to the new driver
106  */
lv_indev_drv_update(lv_indev_t * indev,lv_indev_drv_t * new_drv)107 void lv_indev_drv_update(lv_indev_t * indev, lv_indev_drv_t * new_drv)
108 {
109     LV_ASSERT_NULL(indev);
110     LV_ASSERT_NULL(indev->driver);
111     LV_ASSERT_NULL(indev->driver->read_timer);
112     lv_timer_del(indev->driver->read_timer);
113 
114     LV_ASSERT_NULL(new_drv);
115     if(new_drv->disp == NULL) {
116         new_drv->disp = lv_disp_get_default();
117     }
118     if(new_drv->disp == NULL) {
119         LV_LOG_WARN("lv_indev_drv_register: no display registered hence can't attach the indev to "
120                     "a display");
121         indev->proc.disabled = true;
122         return;
123     }
124 
125     indev->driver = new_drv;
126     indev->driver->read_timer = lv_timer_create(lv_indev_read_timer_cb, LV_INDEV_DEF_READ_PERIOD, indev);
127     indev->proc.reset_query   = 1;
128 }
129 
130 /**
131 * Remove the provided input device. Make sure not to use the provided input device afterwards anymore.
132 * @param indev pointer to delete
133 */
lv_indev_delete(lv_indev_t * indev)134 void lv_indev_delete(lv_indev_t * indev)
135 {
136     LV_ASSERT_NULL(indev);
137     LV_ASSERT_NULL(indev->driver);
138     LV_ASSERT_NULL(indev->driver->read_timer);
139     /*Clean up the read timer first*/
140     lv_timer_del(indev->driver->read_timer);
141     /*Remove the input device from the list*/
142     _lv_ll_remove(&LV_GC_ROOT(_lv_indev_ll), indev);
143     /*Free the memory of the input device*/
144     lv_mem_free(indev);
145 }
146 
147 /**
148  * Get the next input device.
149  * @param indev pointer to the current input device. NULL to initialize.
150  * @return the next input devise or NULL if no more. Give the first input device when the parameter
151  * is NULL
152  */
lv_indev_get_next(lv_indev_t * indev)153 lv_indev_t * lv_indev_get_next(lv_indev_t * indev)
154 {
155     if(indev == NULL)
156         return _lv_ll_get_head(&LV_GC_ROOT(_lv_indev_ll));
157     else
158         return _lv_ll_get_next(&LV_GC_ROOT(_lv_indev_ll), indev);
159 }
160 
161 /**
162  * Read data from an input device.
163  * @param indev pointer to an input device
164  * @param data input device will write its data here
165  */
_lv_indev_read(lv_indev_t * indev,lv_indev_data_t * data)166 void _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)
167 {
168     lv_memset_00(data, sizeof(lv_indev_data_t));
169 
170     /* For touchpad sometimes users don't set the last pressed coordinate on release.
171      * So be sure a coordinates are initialized to the last point */
172     if(indev->driver->type == LV_INDEV_TYPE_POINTER) {
173         data->point.x = indev->proc.types.pointer.last_raw_point.x;
174         data->point.y = indev->proc.types.pointer.last_raw_point.y;
175     }
176     /*Similarly set at least the last key in case of the user doesn't set it on release*/
177     else if(indev->driver->type == LV_INDEV_TYPE_KEYPAD) {
178         data->key = indev->proc.types.keypad.last_key;
179     }
180     /*For compatibility assume that used button was enter (encoder push)*/
181     else if(indev->driver->type == LV_INDEV_TYPE_ENCODER) {
182         data->key = LV_KEY_ENTER;
183     }
184 
185     if(indev->driver->read_cb) {
186         INDEV_TRACE("calling indev_read_cb");
187         indev->driver->read_cb(indev->driver, data);
188     }
189     else {
190         LV_LOG_WARN("indev_read_cb is not registered");
191     }
192 }
193 
194 /**********************
195  *   STATIC FUNCTIONS
196  **********************/
197