1 /**
2  * @file lv_indev.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  ********************/
9 #include "lv_indev.h"
10 #include "lv_disp.h"
11 #include "lv_obj.h"
12 #include "lv_indev_scroll.h"
13 #include "lv_group.h"
14 #include "lv_refr.h"
15 
16 #include "../hal/lv_hal_tick.h"
17 #include "../misc/lv_timer.h"
18 #include "../misc/lv_math.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 #if LV_INDEV_DEF_SCROLL_THROW <= 0
24     #warning "LV_INDEV_DRAG_THROW must be greater than 0"
25 #endif
26 
27 /**********************
28  *      TYPEDEFS
29  **********************/
30 
31 /**********************
32  *  STATIC PROTOTYPES
33  **********************/
34 static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data);
35 static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data);
36 static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);
37 static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);
38 static void indev_proc_press(_lv_indev_proc_t * proc);
39 static void indev_proc_release(_lv_indev_proc_t * proc);
40 static void indev_proc_reset_query_handler(lv_indev_t * indev);
41 static void indev_click_focus(_lv_indev_proc_t * proc);
42 static void indev_gesture(_lv_indev_proc_t * proc);
43 static bool indev_reset_check(_lv_indev_proc_t * proc);
44 
45 /**********************
46  *  STATIC VARIABLES
47  **********************/
48 static lv_indev_t * indev_act;
49 static lv_obj_t * indev_obj_act = NULL;
50 
51 /**********************
52  *      MACROS
53  **********************/
54 #if LV_LOG_TRACE_INDEV
55     #define INDEV_TRACE(...) LV_LOG_TRACE(__VA_ARGS__)
56 #else
57     #define INDEV_TRACE(...)
58 #endif
59 
60 /**********************
61  *   GLOBAL FUNCTIONS
62  **********************/
63 
lv_indev_read_timer_cb(lv_timer_t * timer)64 void lv_indev_read_timer_cb(lv_timer_t * timer)
65 {
66     INDEV_TRACE("begin");
67 
68     lv_indev_data_t data;
69 
70     indev_act = timer->user_data;
71 
72     /*Read and process all indevs*/
73     if(indev_act->driver->disp == NULL) return; /*Not assigned to any displays*/
74 
75     /*Handle reset query before processing the point*/
76     indev_proc_reset_query_handler(indev_act);
77 
78     if(indev_act->proc.disabled) return;
79     bool continue_reading;
80     do {
81         /*Read the data*/
82         _lv_indev_read(indev_act, &data);
83         continue_reading = data.continue_reading;
84 
85         /*The active object might deleted even in the read function*/
86         indev_proc_reset_query_handler(indev_act);
87         indev_obj_act = NULL;
88 
89         indev_act->proc.state = data.state;
90 
91         /*Save the last activity time*/
92         if(indev_act->proc.state == LV_INDEV_STATE_PRESSED) {
93             indev_act->driver->disp->last_activity_time = lv_tick_get();
94         }
95         else if(indev_act->driver->type == LV_INDEV_TYPE_ENCODER && data.enc_diff) {
96             indev_act->driver->disp->last_activity_time = lv_tick_get();
97         }
98 
99         if(indev_act->driver->type == LV_INDEV_TYPE_POINTER) {
100             indev_pointer_proc(indev_act, &data);
101         }
102         else if(indev_act->driver->type == LV_INDEV_TYPE_KEYPAD) {
103             indev_keypad_proc(indev_act, &data);
104         }
105         else if(indev_act->driver->type == LV_INDEV_TYPE_ENCODER) {
106             indev_encoder_proc(indev_act, &data);
107         }
108         else if(indev_act->driver->type == LV_INDEV_TYPE_BUTTON) {
109             indev_button_proc(indev_act, &data);
110         }
111         /*Handle reset query if it happened in during processing*/
112         indev_proc_reset_query_handler(indev_act);
113     } while(continue_reading);
114 
115     /*End of indev processing, so no act indev*/
116     indev_act     = NULL;
117     indev_obj_act = NULL;
118 
119     INDEV_TRACE("finished");
120 }
121 
lv_indev_enable(lv_indev_t * indev,bool en)122 void lv_indev_enable(lv_indev_t * indev, bool en)
123 {
124     if(!indev) return;
125 
126     indev->proc.disabled = en ? 0 : 1;
127 }
128 
lv_indev_get_act(void)129 lv_indev_t * lv_indev_get_act(void)
130 {
131     return indev_act;
132 }
133 
lv_indev_get_type(const lv_indev_t * indev)134 lv_indev_type_t lv_indev_get_type(const lv_indev_t * indev)
135 {
136     if(indev == NULL) return LV_INDEV_TYPE_NONE;
137 
138     return indev->driver->type;
139 }
140 
lv_indev_reset(lv_indev_t * indev,lv_obj_t * obj)141 void lv_indev_reset(lv_indev_t * indev, lv_obj_t * obj)
142 {
143     if(indev) {
144         indev->proc.reset_query = 1;
145         if(indev_act == indev) indev_obj_act = NULL;
146         if(indev->driver->type == LV_INDEV_TYPE_POINTER || indev->driver->type == LV_INDEV_TYPE_KEYPAD) {
147             if(obj == NULL || indev->proc.types.pointer.last_pressed == obj) {
148                 indev->proc.types.pointer.last_pressed = NULL;
149             }
150             if(obj == NULL || indev->proc.types.pointer.act_obj == obj) {
151                 indev->proc.types.pointer.act_obj = NULL;
152             }
153             if(obj == NULL || indev->proc.types.pointer.last_obj == obj) {
154                 indev->proc.types.pointer.last_obj = NULL;
155             }
156         }
157     }
158     else {
159         lv_indev_t * i = lv_indev_get_next(NULL);
160         while(i) {
161             i->proc.reset_query = 1;
162             if(i->driver->type == LV_INDEV_TYPE_POINTER || i->driver->type == LV_INDEV_TYPE_KEYPAD) {
163                 if(obj == NULL || i->proc.types.pointer.last_pressed == obj) {
164                     i->proc.types.pointer.last_pressed = NULL;
165                 }
166                 if(obj == NULL || i->proc.types.pointer.act_obj == obj) {
167                     i->proc.types.pointer.act_obj = NULL;
168                 }
169                 if(obj == NULL || i->proc.types.pointer.last_obj == obj) {
170                     i->proc.types.pointer.last_obj = NULL;
171                 }
172             }
173             i = lv_indev_get_next(i);
174         }
175         indev_obj_act = NULL;
176     }
177 }
178 
lv_indev_reset_long_press(lv_indev_t * indev)179 void lv_indev_reset_long_press(lv_indev_t * indev)
180 {
181     indev->proc.long_pr_sent         = 0;
182     indev->proc.longpr_rep_timestamp = lv_tick_get();
183     indev->proc.pr_timestamp         = lv_tick_get();
184 }
185 
lv_indev_set_cursor(lv_indev_t * indev,lv_obj_t * cur_obj)186 void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj)
187 {
188     if(indev->driver->type != LV_INDEV_TYPE_POINTER) return;
189 
190     indev->cursor = cur_obj;
191     lv_obj_set_parent(indev->cursor, lv_disp_get_layer_sys(indev->driver->disp));
192     lv_obj_set_pos(indev->cursor, indev->proc.types.pointer.act_point.x, indev->proc.types.pointer.act_point.y);
193     lv_obj_clear_flag(indev->cursor, LV_OBJ_FLAG_CLICKABLE);
194     lv_obj_add_flag(indev->cursor, LV_OBJ_FLAG_IGNORE_LAYOUT | LV_OBJ_FLAG_FLOATING);
195 }
196 
lv_indev_set_group(lv_indev_t * indev,lv_group_t * group)197 void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group)
198 {
199     if(indev->driver->type == LV_INDEV_TYPE_KEYPAD || indev->driver->type == LV_INDEV_TYPE_ENCODER) {
200         indev->group = group;
201     }
202 }
203 
lv_indev_set_button_points(lv_indev_t * indev,const lv_point_t points[])204 void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t points[])
205 {
206     if(indev->driver->type == LV_INDEV_TYPE_BUTTON) {
207         indev->btn_points = points;
208     }
209 }
210 
lv_indev_get_point(const lv_indev_t * indev,lv_point_t * point)211 void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)
212 {
213     if(indev == NULL) {
214         point->x = 0;
215         point->y = 0;
216         return;
217     }
218     if(indev->driver->type != LV_INDEV_TYPE_POINTER && indev->driver->type != LV_INDEV_TYPE_BUTTON) {
219         point->x = -1;
220         point->y = -1;
221     }
222     else {
223         point->x = indev->proc.types.pointer.act_point.x;
224         point->y = indev->proc.types.pointer.act_point.y;
225     }
226 }
227 
lv_indev_get_gesture_dir(const lv_indev_t * indev)228 lv_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev)
229 {
230     return indev->proc.types.pointer.gesture_dir;
231 }
232 
lv_indev_get_key(const lv_indev_t * indev)233 uint32_t lv_indev_get_key(const lv_indev_t * indev)
234 {
235     if(indev->driver->type != LV_INDEV_TYPE_KEYPAD)
236         return 0;
237     else
238         return indev->proc.types.keypad.last_key;
239 }
240 
lv_indev_get_scroll_dir(const lv_indev_t * indev)241 lv_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev)
242 {
243     if(indev == NULL) return false;
244     if(indev->driver->type != LV_INDEV_TYPE_POINTER && indev->driver->type != LV_INDEV_TYPE_BUTTON) return false;
245     return indev->proc.types.pointer.scroll_dir;
246 }
247 
lv_indev_get_scroll_obj(const lv_indev_t * indev)248 lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev)
249 {
250     if(indev == NULL) return NULL;
251     if(indev->driver->type != LV_INDEV_TYPE_POINTER && indev->driver->type != LV_INDEV_TYPE_BUTTON) return NULL;
252     return indev->proc.types.pointer.scroll_obj;
253 }
254 
lv_indev_get_vect(const lv_indev_t * indev,lv_point_t * point)255 void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
256 {
257     point->x = 0;
258     point->y = 0;
259 
260     if(indev == NULL) return;
261 
262     if(indev->driver->type == LV_INDEV_TYPE_POINTER || indev->driver->type == LV_INDEV_TYPE_BUTTON) {
263         point->x = indev->proc.types.pointer.vect.x;
264         point->y = indev->proc.types.pointer.vect.y;
265     }
266 }
267 
lv_indev_wait_release(lv_indev_t * indev)268 void lv_indev_wait_release(lv_indev_t * indev)
269 {
270     if(indev == NULL)return;
271     indev->proc.wait_until_release = 1;
272 }
273 
lv_indev_get_obj_act(void)274 lv_obj_t * lv_indev_get_obj_act(void)
275 {
276     return indev_obj_act;
277 }
278 
lv_indev_get_read_timer(lv_disp_t * indev)279 lv_timer_t * lv_indev_get_read_timer(lv_disp_t * indev)
280 {
281     if(!indev) {
282         LV_LOG_WARN("lv_indev_get_read_timer: indev was NULL");
283         return NULL;
284     }
285 
286     return indev->refr_timer;
287 }
288 
lv_indev_search_obj(lv_obj_t * obj,lv_point_t * point)289 lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
290 {
291     lv_obj_t * found_p = NULL;
292 
293     /*If this obj is hidden the children are hidden too so return immediately*/
294     if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return NULL;
295 
296     bool hit_test_ok = lv_obj_hit_test(obj, point);
297 
298     /*If the point is on this object or has overflow visible check its children too*/
299     if(_lv_area_is_point_on(&obj->coords, point, 0) || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) {
300         int32_t i;
301         uint32_t child_cnt = lv_obj_get_child_cnt(obj);
302         /*If a child matches use it*/
303         for(i = child_cnt - 1; i >= 0; i--) {
304             lv_obj_t * child = obj->spec_attr->children[i];
305             found_p = lv_indev_search_obj(child, point);
306             if(found_p) return found_p;
307         }
308     }
309 
310     /*If not return earlier for a clicked child and this obj's hittest was ok use it
311      *else return NULL*/
312     if(hit_test_ok) return obj;
313     else return NULL;
314 }
315 
316 /**********************
317  *   STATIC FUNCTIONS
318  **********************/
319 
320 /**
321  * Process a new point from LV_INDEV_TYPE_POINTER input device
322  * @param i pointer to an input device
323  * @param data pointer to the data read from the input device
324  */
indev_pointer_proc(lv_indev_t * i,lv_indev_data_t * data)325 static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
326 {
327     lv_disp_t * disp = i->driver->disp;
328     /*Save the raw points so they can be used again in _lv_indev_read*/
329     i->proc.types.pointer.last_raw_point.x = data->point.x;
330     i->proc.types.pointer.last_raw_point.y = data->point.y;
331 
332     if(disp->driver->rotated == LV_DISP_ROT_180 || disp->driver->rotated == LV_DISP_ROT_270) {
333         data->point.x = disp->driver->hor_res - data->point.x - 1;
334         data->point.y = disp->driver->ver_res - data->point.y - 1;
335     }
336     if(disp->driver->rotated == LV_DISP_ROT_90 || disp->driver->rotated == LV_DISP_ROT_270) {
337         lv_coord_t tmp = data->point.y;
338         data->point.y = data->point.x;
339         data->point.x = disp->driver->ver_res - tmp - 1;
340     }
341 
342     /*Simple sanity check*/
343     if(data->point.x < 0) {
344         LV_LOG_WARN("X is %d which is smaller than zero", data->point.x);
345     }
346     if(data->point.x >= lv_disp_get_hor_res(i->driver->disp)) {
347         LV_LOG_WARN("X is %d which is greater than hor. res", data->point.x);
348     }
349     if(data->point.y < 0) {
350         LV_LOG_WARN("Y is %d which is smaller than zero", data->point.y);
351     }
352     if(data->point.y >= lv_disp_get_ver_res(i->driver->disp)) {
353         LV_LOG_WARN("Y is %d which is greater than ver. res", data->point.y);
354     }
355 
356     /*Move the cursor if set and moved*/
357     if(i->cursor != NULL &&
358        (i->proc.types.pointer.last_point.x != data->point.x || i->proc.types.pointer.last_point.y != data->point.y)) {
359         lv_obj_set_pos(i->cursor, data->point.x, data->point.y);
360     }
361 
362     i->proc.types.pointer.act_point.x = data->point.x;
363     i->proc.types.pointer.act_point.y = data->point.y;
364 
365     if(i->proc.state == LV_INDEV_STATE_PRESSED) {
366         indev_proc_press(&i->proc);
367     }
368     else {
369         indev_proc_release(&i->proc);
370     }
371 
372     i->proc.types.pointer.last_point.x = i->proc.types.pointer.act_point.x;
373     i->proc.types.pointer.last_point.y = i->proc.types.pointer.act_point.y;
374 }
375 
376 /**
377  * Process a new point from LV_INDEV_TYPE_KEYPAD input device
378  * @param i pointer to an input device
379  * @param data pointer to the data read from the input device
380  */
indev_keypad_proc(lv_indev_t * i,lv_indev_data_t * data)381 static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
382 {
383     if(data->state == LV_INDEV_STATE_PRESSED && i->proc.wait_until_release) return;
384 
385     if(i->proc.wait_until_release) {
386         i->proc.wait_until_release      = 0;
387         i->proc.pr_timestamp            = 0;
388         i->proc.long_pr_sent            = 0;
389         i->proc.types.keypad.last_state = LV_INDEV_STATE_RELEASED; /*To skip the processing of release*/
390     }
391 
392     lv_group_t * g = i->group;
393     if(g == NULL) return;
394 
395     indev_obj_act = lv_group_get_focused(g);
396     if(indev_obj_act == NULL) return;
397 
398     /*Save the last key to compare it with the current latter on RELEASE*/
399     uint32_t prev_key = i->proc.types.keypad.last_key;
400 
401     /*Save the last key.
402      *It must be done here else `lv_indev_get_key` will return the last key in events*/
403     i->proc.types.keypad.last_key = data->key;
404 
405     /*Save the previous state so we can detect state changes below and also set the last state now
406      *so if any event handler on the way returns `LV_RES_INV` the last state is remembered
407      *for the next time*/
408     uint32_t prev_state             = i->proc.types.keypad.last_state;
409     i->proc.types.keypad.last_state = data->state;
410 
411     /*Key press happened*/
412     if(data->state == LV_INDEV_STATE_PRESSED && prev_state == LV_INDEV_STATE_RELEASED) {
413         LV_LOG_INFO("%d key is pressed", data->key);
414         i->proc.pr_timestamp = lv_tick_get();
415 
416         /*Simulate a press on the object if ENTER was pressed*/
417         if(data->key == LV_KEY_ENTER) {
418             /*Send the ENTER as a normal KEY*/
419             lv_group_send_data(g, LV_KEY_ENTER);
420 
421             lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
422             if(indev_reset_check(&i->proc)) return;
423         }
424         else if(data->key == LV_KEY_ESC) {
425             /*Send the ESC as a normal KEY*/
426             lv_group_send_data(g, LV_KEY_ESC);
427 
428             lv_event_send(indev_obj_act, LV_EVENT_CANCEL, indev_act);
429             if(indev_reset_check(&i->proc)) return;
430         }
431         /*Move the focus on NEXT*/
432         else if(data->key == LV_KEY_NEXT) {
433             lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
434             lv_group_focus_next(g);
435             if(indev_reset_check(&i->proc)) return;
436         }
437         /*Move the focus on PREV*/
438         else if(data->key == LV_KEY_PREV) {
439             lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
440             lv_group_focus_prev(g);
441             if(indev_reset_check(&i->proc)) return;
442         }
443         /*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/
444         else {
445             lv_group_send_data(g, data->key);
446         }
447     }
448     /*Pressing*/
449     else if(data->state == LV_INDEV_STATE_PRESSED && prev_state == LV_INDEV_STATE_PRESSED) {
450 
451         if(data->key == LV_KEY_ENTER) {
452             lv_event_send(indev_obj_act, LV_EVENT_PRESSING, indev_act);
453             if(indev_reset_check(&i->proc)) return;
454         }
455 
456         /*Long press time has elapsed?*/
457         if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver->long_press_time) {
458             i->proc.long_pr_sent = 1;
459             if(data->key == LV_KEY_ENTER) {
460                 i->proc.longpr_rep_timestamp = lv_tick_get();
461                 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
462                 if(indev_reset_check(&i->proc)) return;
463             }
464         }
465         /*Long press repeated time has elapsed?*/
466         else if(i->proc.long_pr_sent != 0 &&
467                 lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver->long_press_repeat_time) {
468 
469             i->proc.longpr_rep_timestamp = lv_tick_get();
470 
471             /*Send LONG_PRESS_REP on ENTER*/
472             if(data->key == LV_KEY_ENTER) {
473                 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
474                 if(indev_reset_check(&i->proc)) return;
475             }
476             /*Move the focus on NEXT again*/
477             else if(data->key == LV_KEY_NEXT) {
478                 lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
479                 lv_group_focus_next(g);
480                 if(indev_reset_check(&i->proc)) return;
481             }
482             /*Move the focus on PREV again*/
483             else if(data->key == LV_KEY_PREV) {
484                 lv_group_set_editing(g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
485                 lv_group_focus_prev(g);
486                 if(indev_reset_check(&i->proc)) return;
487             }
488             /*Just send other keys again to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT)*/
489             else {
490                 lv_group_send_data(g, data->key);
491                 if(indev_reset_check(&i->proc)) return;
492             }
493         }
494     }
495     /*Release happened*/
496     else if(data->state == LV_INDEV_STATE_RELEASED && prev_state == LV_INDEV_STATE_PRESSED) {
497         LV_LOG_INFO("%d key is released", data->key);
498         /*The user might clear the key when it was released. Always release the pressed key*/
499         data->key = prev_key;
500         if(data->key == LV_KEY_ENTER) {
501 
502             lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
503             if(indev_reset_check(&i->proc)) return;
504 
505             if(i->proc.long_pr_sent == 0) {
506                 lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
507                 if(indev_reset_check(&i->proc)) return;
508             }
509 
510             lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
511             if(indev_reset_check(&i->proc)) return;
512 
513         }
514         i->proc.pr_timestamp = 0;
515         i->proc.long_pr_sent = 0;
516     }
517     indev_obj_act = NULL;
518 }
519 
520 /**
521  * Process a new point from LV_INDEV_TYPE_ENCODER input device
522  * @param i pointer to an input device
523  * @param data pointer to the data read from the input device
524  */
indev_encoder_proc(lv_indev_t * i,lv_indev_data_t * data)525 static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
526 {
527     if(data->state == LV_INDEV_STATE_PRESSED && i->proc.wait_until_release) return;
528 
529     if(i->proc.wait_until_release) {
530         i->proc.wait_until_release      = 0;
531         i->proc.pr_timestamp            = 0;
532         i->proc.long_pr_sent            = 0;
533         i->proc.types.keypad.last_state = LV_INDEV_STATE_RELEASED; /*To skip the processing of release*/
534     }
535 
536     /*Save the last keys before anything else.
537      *They need to be already saved if the function returns for any reason*/
538     lv_indev_state_t last_state     = i->proc.types.keypad.last_state;
539     i->proc.types.keypad.last_state = data->state;
540     i->proc.types.keypad.last_key   = data->key;
541 
542     lv_group_t * g = i->group;
543     if(g == NULL) return;
544 
545     indev_obj_act = lv_group_get_focused(g);
546     if(indev_obj_act == NULL) return;
547 
548     /*Process the steps they are valid only with released button*/
549     if(data->state != LV_INDEV_STATE_RELEASED) {
550         data->enc_diff = 0;
551     }
552 
553     /*Refresh the focused object. It might change due to lv_group_focus_prev/next*/
554     indev_obj_act = lv_group_get_focused(g);
555     if(indev_obj_act == NULL) return;
556 
557     /*Button press happened*/
558     if(data->state == LV_INDEV_STATE_PRESSED && last_state == LV_INDEV_STATE_RELEASED) {
559         LV_LOG_INFO("pressed");
560 
561         i->proc.pr_timestamp = lv_tick_get();
562 
563         if(data->key == LV_KEY_ENTER) {
564             bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
565                                           lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
566             if(lv_group_get_editing(g) == true || editable_or_scrollable == false) {
567                 lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
568                 if(indev_reset_check(&i->proc)) return;
569             }
570         }
571         else if(data->key == LV_KEY_LEFT) {
572             /*emulate encoder left*/
573             data->enc_diff--;
574         }
575         else if(data->key == LV_KEY_RIGHT) {
576             /*emulate encoder right*/
577             data->enc_diff++;
578         }
579         else if(data->key == LV_KEY_ESC) {
580             /*Send the ESC as a normal KEY*/
581             lv_group_send_data(g, LV_KEY_ESC);
582 
583             lv_event_send(indev_obj_act, LV_EVENT_CANCEL, indev_act);
584             if(indev_reset_check(&i->proc)) return;
585         }
586         /*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/
587         else {
588             lv_group_send_data(g, data->key);
589         }
590     }
591     /*Pressing*/
592     else if(data->state == LV_INDEV_STATE_PRESSED && last_state == LV_INDEV_STATE_PRESSED) {
593         /*Long press*/
594         if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver->long_press_time) {
595 
596             i->proc.long_pr_sent = 1;
597             i->proc.longpr_rep_timestamp = lv_tick_get();
598 
599             if(data->key == LV_KEY_ENTER) {
600                 bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
601                                               lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
602 
603                 /*On enter long press toggle edit mode.*/
604                 if(editable_or_scrollable) {
605                     /*Don't leave edit mode if there is only one object (nowhere to navigate)*/
606                     if(lv_group_get_obj_count(g) > 1) {
607                         LV_LOG_INFO("toggling edit mode");
608                         lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/
609                         lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED);    /*Remove the pressed state manually*/
610                     }
611                 }
612                 /*If not editable then just send a long press Call the ancestor's event handler*/
613                 else {
614                     lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
615                     if(indev_reset_check(&i->proc)) return;
616                 }
617             }
618 
619             i->proc.long_pr_sent = 1;
620         }
621         /*Long press repeated time has elapsed?*/
622         else if(i->proc.long_pr_sent != 0 && lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver->long_press_repeat_time) {
623 
624             i->proc.longpr_rep_timestamp = lv_tick_get();
625 
626             if(data->key == LV_KEY_ENTER) {
627                 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
628                 if(indev_reset_check(&i->proc)) return;
629             }
630             else if(data->key == LV_KEY_LEFT) {
631                 /*emulate encoder left*/
632                 data->enc_diff--;
633             }
634             else if(data->key == LV_KEY_RIGHT) {
635                 /*emulate encoder right*/
636                 data->enc_diff++;
637             }
638             else {
639                 lv_group_send_data(g, data->key);
640                 if(indev_reset_check(&i->proc)) return;
641             }
642 
643         }
644 
645     }
646     /*Release happened*/
647     else if(data->state == LV_INDEV_STATE_RELEASED && last_state == LV_INDEV_STATE_PRESSED) {
648         LV_LOG_INFO("released");
649 
650         if(data->key == LV_KEY_ENTER) {
651             bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
652                                           lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
653 
654             /*The button was released on a non-editable object. Just send enter*/
655             if(editable_or_scrollable == false) {
656                 lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
657                 if(indev_reset_check(&i->proc)) return;
658 
659                 if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
660                 if(indev_reset_check(&i->proc)) return;
661 
662                 lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
663                 if(indev_reset_check(&i->proc)) return;
664 
665             }
666             /*An object is being edited and the button is released.*/
667             else if(lv_group_get_editing(g)) {
668                 /*Ignore long pressed enter release because it comes from mode switch*/
669                 if(!i->proc.long_pr_sent || lv_group_get_obj_count(g) <= 1) {
670                     lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
671                     if(indev_reset_check(&i->proc)) return;
672 
673                     lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
674                     if(indev_reset_check(&i->proc)) return;
675 
676                     lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
677                     if(indev_reset_check(&i->proc)) return;
678 
679 
680                     lv_group_send_data(g, LV_KEY_ENTER);
681                 }
682                 else {
683                     lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED);    /*Remove the pressed state manually*/
684                 }
685             }
686             /*If the focused object is editable and now in navigate mode then on enter switch edit
687                mode*/
688             else if(!i->proc.long_pr_sent) {
689                 LV_LOG_INFO("entering edit mode");
690                 lv_group_set_editing(g, true); /*Set edit mode*/
691             }
692         }
693 
694         i->proc.pr_timestamp = 0;
695         i->proc.long_pr_sent = 0;
696     }
697     indev_obj_act = NULL;
698 
699     /*if encoder steps or simulated steps via left/right keys*/
700     if(data->enc_diff != 0) {
701         /*In edit mode send LEFT/RIGHT keys*/
702         if(lv_group_get_editing(g)) {
703             LV_LOG_INFO("rotated by %+d (edit)", data->enc_diff);
704             int32_t s;
705             if(data->enc_diff < 0) {
706                 for(s = 0; s < -data->enc_diff; s++) lv_group_send_data(g, LV_KEY_LEFT);
707             }
708             else if(data->enc_diff > 0) {
709                 for(s = 0; s < data->enc_diff; s++) lv_group_send_data(g, LV_KEY_RIGHT);
710             }
711         }
712         /*In navigate mode focus on the next/prev objects*/
713         else {
714             LV_LOG_INFO("rotated by %+d (nav)", data->enc_diff);
715             int32_t s;
716             if(data->enc_diff < 0) {
717                 for(s = 0; s < -data->enc_diff; s++) lv_group_focus_prev(g);
718             }
719             else if(data->enc_diff > 0) {
720                 for(s = 0; s < data->enc_diff; s++) lv_group_focus_next(g);
721             }
722         }
723     }
724 }
725 
726 /**
727  * Process new points from an input device. indev->state.pressed has to be set
728  * @param indev pointer to an input device state
729  * @param x x coordinate of the next point
730  * @param y y coordinate of the next point
731  */
indev_button_proc(lv_indev_t * i,lv_indev_data_t * data)732 static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
733 {
734     /*Die gracefully if i->btn_points is NULL*/
735     if(i->btn_points == NULL) {
736         LV_LOG_WARN("btn_points is NULL");
737         return;
738     }
739 
740     lv_coord_t x = i->btn_points[data->btn_id].x;
741     lv_coord_t y = i->btn_points[data->btn_id].y;
742 
743     static lv_indev_state_t prev_state = LV_INDEV_STATE_RELEASED;
744     if(prev_state != data->state) {
745         if(data->state == LV_INDEV_STATE_PRESSED) {
746             LV_LOG_INFO("button %d is pressed (x:%d y:%d)", data->btn_id, x, y);
747         }
748         else {
749             LV_LOG_INFO("button %d is released (x:%d y:%d)", data->btn_id, x, y);
750         }
751     }
752 
753     /*If a new point comes always make a release*/
754     if(data->state == LV_INDEV_STATE_PRESSED) {
755         if(i->proc.types.pointer.last_point.x != x ||
756            i->proc.types.pointer.last_point.y != y) {
757             indev_proc_release(&i->proc);
758         }
759     }
760 
761     if(indev_reset_check(&i->proc)) return;
762 
763     /*Save the new points*/
764     i->proc.types.pointer.act_point.x = x;
765     i->proc.types.pointer.act_point.y = y;
766 
767     if(data->state == LV_INDEV_STATE_PRESSED) indev_proc_press(&i->proc);
768     else indev_proc_release(&i->proc);
769 
770     if(indev_reset_check(&i->proc)) return;
771 
772     i->proc.types.pointer.last_point.x = i->proc.types.pointer.act_point.x;
773     i->proc.types.pointer.last_point.y = i->proc.types.pointer.act_point.y;
774 }
775 
776 /**
777  * Process the pressed state of LV_INDEV_TYPE_POINTER input devices
778  * @param indev pointer to an input device 'proc'
779  * @return LV_RES_OK: no indev reset required; LV_RES_INV: indev reset is required
780  */
indev_proc_press(_lv_indev_proc_t * proc)781 static void indev_proc_press(_lv_indev_proc_t * proc)
782 {
783     LV_LOG_INFO("pressed at x:%d y:%d", proc->types.pointer.act_point.x, proc->types.pointer.act_point.y);
784     indev_obj_act = proc->types.pointer.act_obj;
785 
786     if(proc->wait_until_release != 0) return;
787 
788     lv_disp_t * disp = indev_act->driver->disp;
789     bool new_obj_searched = false;
790 
791     /*If there is no last object then search*/
792     if(indev_obj_act == NULL) {
793         indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_sys(disp), &proc->types.pointer.act_point);
794         if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_top(disp),
795                                                                           &proc->types.pointer.act_point);
796         if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_scr_act(disp),
797                                                                           &proc->types.pointer.act_point);
798         new_obj_searched = true;
799     }
800     /*If there is last object but it is not scrolled and not protected also search*/
801     else if(proc->types.pointer.scroll_obj == NULL &&
802             lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_PRESS_LOCK) == false) {
803         indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_sys(disp), &proc->types.pointer.act_point);
804         if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_top(disp),
805                                                                           &proc->types.pointer.act_point);
806         if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_scr_act(disp),
807                                                                           &proc->types.pointer.act_point);
808         new_obj_searched = true;
809     }
810 
811     /*The last object might have scroll throw. Stop it manually*/
812     if(new_obj_searched && proc->types.pointer.last_obj) {
813         proc->types.pointer.scroll_throw_vect.x = 0;
814         proc->types.pointer.scroll_throw_vect.y = 0;
815         _lv_indev_scroll_throw_handler(proc);
816         if(indev_reset_check(proc)) return;
817     }
818 
819     /*If a new object was found reset some variables and send a pressed Call the ancestor's event handler*/
820     if(indev_obj_act != proc->types.pointer.act_obj) {
821         proc->types.pointer.last_point.x = proc->types.pointer.act_point.x;
822         proc->types.pointer.last_point.y = proc->types.pointer.act_point.y;
823 
824         /*If a new object found the previous was lost, so send a Call the ancestor's event handler*/
825         if(proc->types.pointer.act_obj != NULL) {
826             /*Save the obj because in special cases `act_obj` can change in the Call the ancestor's event handler function*/
827             lv_obj_t * last_obj = proc->types.pointer.act_obj;
828 
829             lv_event_send(last_obj, LV_EVENT_PRESS_LOST, indev_act);
830             if(indev_reset_check(proc)) return;
831         }
832 
833         proc->types.pointer.act_obj  = indev_obj_act; /*Save the pressed object*/
834         proc->types.pointer.last_obj = indev_obj_act;
835 
836         if(indev_obj_act != NULL) {
837             /*Save the time when the obj pressed to count long press time.*/
838             proc->pr_timestamp                 = lv_tick_get();
839             proc->long_pr_sent                 = 0;
840             proc->types.pointer.scroll_sum.x     = 0;
841             proc->types.pointer.scroll_sum.y     = 0;
842             proc->types.pointer.scroll_dir = LV_DIR_NONE;
843             proc->types.pointer.gesture_dir = LV_DIR_NONE;
844             proc->types.pointer.gesture_sent   = 0;
845             proc->types.pointer.gesture_sum.x  = 0;
846             proc->types.pointer.gesture_sum.y  = 0;
847             proc->types.pointer.vect.x         = 0;
848             proc->types.pointer.vect.y         = 0;
849 
850             /*Call the ancestor's event handler about the press*/
851             lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
852             if(indev_reset_check(proc)) return;
853 
854             if(indev_act->proc.wait_until_release) return;
855 
856             /*Handle focus*/
857             indev_click_focus(&indev_act->proc);
858             if(indev_reset_check(proc)) return;
859 
860         }
861     }
862 
863     /*Calculate the vector and apply a low pass filter: new value = 0.5 * old_value + 0.5 * new_value*/
864     proc->types.pointer.vect.x = proc->types.pointer.act_point.x - proc->types.pointer.last_point.x;
865     proc->types.pointer.vect.y = proc->types.pointer.act_point.y - proc->types.pointer.last_point.y;
866 
867     proc->types.pointer.scroll_throw_vect.x = (proc->types.pointer.scroll_throw_vect.x * 4) >> 3;
868     proc->types.pointer.scroll_throw_vect.y = (proc->types.pointer.scroll_throw_vect.y * 4) >> 3;
869 
870     proc->types.pointer.scroll_throw_vect.x += (proc->types.pointer.vect.x * 4) >> 3;
871     proc->types.pointer.scroll_throw_vect.y += (proc->types.pointer.vect.y * 4) >> 3;
872 
873     proc->types.pointer.scroll_throw_vect_ori = proc->types.pointer.scroll_throw_vect;
874 
875     if(indev_obj_act) {
876         lv_event_send(indev_obj_act, LV_EVENT_PRESSING, indev_act);
877         if(indev_reset_check(proc)) return;
878 
879         if(indev_act->proc.wait_until_release) return;
880 
881         _lv_indev_scroll_handler(proc);
882         if(indev_reset_check(proc)) return;
883         indev_gesture(proc);
884         if(indev_reset_check(proc)) return;
885 
886         /*If there is no scrolling then check for long press time*/
887         if(proc->types.pointer.scroll_obj == NULL && proc->long_pr_sent == 0) {
888             /*Call the ancestor's event handler about the long press if enough time elapsed*/
889             if(lv_tick_elaps(proc->pr_timestamp) > indev_act->driver->long_press_time) {
890                 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
891                 if(indev_reset_check(proc)) return;
892 
893                 /*Mark the Call the ancestor's event handler sending to do not send it again*/
894                 proc->long_pr_sent = 1;
895 
896                 /*Save the long press time stamp for the long press repeat handler*/
897                 proc->longpr_rep_timestamp = lv_tick_get();
898             }
899         }
900 
901         /*Send long press repeated Call the ancestor's event handler*/
902         if(proc->types.pointer.scroll_obj == NULL && proc->long_pr_sent == 1) {
903             /*Call the ancestor's event handler about the long press repeat if enough time elapsed*/
904             if(lv_tick_elaps(proc->longpr_rep_timestamp) > indev_act->driver->long_press_repeat_time) {
905                 lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
906                 if(indev_reset_check(proc)) return;
907                 proc->longpr_rep_timestamp = lv_tick_get();
908             }
909         }
910     }
911 }
912 
913 /**
914  * Process the released state of LV_INDEV_TYPE_POINTER input devices
915  * @param proc pointer to an input device 'proc'
916  */
indev_proc_release(_lv_indev_proc_t * proc)917 static void indev_proc_release(_lv_indev_proc_t * proc)
918 {
919     if(proc->wait_until_release != 0) {
920         proc->types.pointer.act_obj  = NULL;
921         proc->types.pointer.last_obj = NULL;
922         proc->pr_timestamp           = 0;
923         proc->longpr_rep_timestamp   = 0;
924         proc->wait_until_release     = 0;
925     }
926     indev_obj_act = proc->types.pointer.act_obj;
927     lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj;
928 
929     /*Forget the act obj and send a released Call the ancestor's event handler*/
930     if(indev_obj_act) {
931         LV_LOG_INFO("released");
932 
933         /*Send RELEASE Call the ancestor's event handler and event*/
934         lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
935         if(indev_reset_check(proc)) return;
936 
937         /*Send CLICK if no scrolling*/
938         if(scroll_obj == NULL) {
939             if(proc->long_pr_sent == 0) {
940                 lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
941                 if(indev_reset_check(proc)) return;
942             }
943 
944             lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
945             if(indev_reset_check(proc)) return;
946         }
947 
948         proc->types.pointer.act_obj = NULL;
949         proc->pr_timestamp          = 0;
950         proc->longpr_rep_timestamp  = 0;
951 
952     }
953 
954     /*The reset can be set in the Call the ancestor's event handler function.
955      * In case of reset query ignore the remaining parts.*/
956     if(scroll_obj) {
957         _lv_indev_scroll_throw_handler(proc);
958         if(indev_reset_check(proc)) return;
959     }
960 }
961 
962 /**
963  * Process a new point from LV_INDEV_TYPE_BUTTON input device
964  * @param i pointer to an input device
965  * @param data pointer to the data read from the input device
966  * Reset input device if a reset query has been sent to it
967  * @param indev pointer to an input device
968  */
indev_proc_reset_query_handler(lv_indev_t * indev)969 static void indev_proc_reset_query_handler(lv_indev_t * indev)
970 {
971     if(indev->proc.reset_query) {
972         indev->proc.types.pointer.act_obj           = NULL;
973         indev->proc.types.pointer.last_obj          = NULL;
974         indev->proc.types.pointer.scroll_obj          = NULL;
975         indev->proc.long_pr_sent                    = 0;
976         indev->proc.pr_timestamp                    = 0;
977         indev->proc.longpr_rep_timestamp            = 0;
978         indev->proc.types.pointer.scroll_sum.x        = 0;
979         indev->proc.types.pointer.scroll_sum.y        = 0;
980         indev->proc.types.pointer.scroll_dir = LV_DIR_NONE;
981         indev->proc.types.pointer.scroll_throw_vect.x = 0;
982         indev->proc.types.pointer.scroll_throw_vect.y = 0;
983         indev->proc.types.pointer.gesture_sum.x     = 0;
984         indev->proc.types.pointer.gesture_sum.y     = 0;
985         indev->proc.reset_query                     = 0;
986         indev_obj_act                               = NULL;
987     }
988 }
989 
990 /**
991  * Handle focus/defocus on click for POINTER input devices
992  * @param proc pointer to the state of the indev
993  */
indev_click_focus(_lv_indev_proc_t * proc)994 static void indev_click_focus(_lv_indev_proc_t * proc)
995 {
996     /*Handle click focus*/
997     if(lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_CLICK_FOCUSABLE) == false ||
998        proc->types.pointer.last_pressed == indev_obj_act) {
999         return;
1000     }
1001 
1002     lv_group_t * g_act = lv_obj_get_group(indev_obj_act);
1003     lv_group_t * g_prev = proc->types.pointer.last_pressed ? lv_obj_get_group(proc->types.pointer.last_pressed) : NULL;
1004 
1005     /*If both the last and act. obj. are in the same group (or have no group)*/
1006     if(g_act == g_prev) {
1007         /*The objects are in a group*/
1008         if(g_act) {
1009             lv_group_focus_obj(indev_obj_act);
1010             if(indev_reset_check(proc)) return;
1011         }
1012         /*The object are not in group*/
1013         else {
1014             if(proc->types.pointer.last_pressed) {
1015                 lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, indev_act);
1016                 if(indev_reset_check(proc)) return;
1017             }
1018 
1019             lv_event_send(indev_obj_act, LV_EVENT_FOCUSED, indev_act);
1020             if(indev_reset_check(proc)) return;
1021         }
1022     }
1023     /*The object are not in the same group (in different groups or one has no group)*/
1024     else {
1025         /*If the prev. obj. is not in a group then defocus it.*/
1026         if(g_prev == NULL && proc->types.pointer.last_pressed) {
1027             lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, indev_act);
1028             if(indev_reset_check(proc)) return;
1029         }
1030         /*Focus on a non-group object*/
1031         else {
1032             if(proc->types.pointer.last_pressed) {
1033                 /*If the prev. object also wasn't in a group defocus it*/
1034                 if(g_prev == NULL) {
1035                     lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, indev_act);
1036                     if(indev_reset_check(proc)) return;
1037                 }
1038                 /*If the prev. object also was in a group at least "LEAVE" it instead of defocus*/
1039                 else {
1040                     lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_LEAVE, indev_act);
1041                     if(indev_reset_check(proc)) return;
1042                 }
1043             }
1044         }
1045 
1046         /*Focus to the act. in its group*/
1047         if(g_act) {
1048             lv_group_focus_obj(indev_obj_act);
1049             if(indev_reset_check(proc)) return;
1050         }
1051         else {
1052             lv_event_send(indev_obj_act, LV_EVENT_FOCUSED, indev_act);
1053             if(indev_reset_check(proc)) return;
1054         }
1055     }
1056     proc->types.pointer.last_pressed = indev_obj_act;
1057 }
1058 
1059 /**
1060 * Handle the gesture of indev_proc_p->types.pointer.act_obj
1061 * @param indev pointer to an input device state
1062 */
indev_gesture(_lv_indev_proc_t * proc)1063 void indev_gesture(_lv_indev_proc_t * proc)
1064 {
1065 
1066     if(proc->types.pointer.scroll_obj) return;
1067     if(proc->types.pointer.gesture_sent) return;
1068 
1069     lv_obj_t * gesture_obj = proc->types.pointer.act_obj;
1070 
1071     /*If gesture parent is active check recursively the gesture attribute*/
1072     while(gesture_obj && lv_obj_has_flag(gesture_obj, LV_OBJ_FLAG_GESTURE_BUBBLE)) {
1073         gesture_obj = lv_obj_get_parent(gesture_obj);
1074     }
1075 
1076     if(gesture_obj == NULL) return;
1077 
1078     if((LV_ABS(proc->types.pointer.vect.x) < indev_act->driver->gesture_min_velocity) &&
1079        (LV_ABS(proc->types.pointer.vect.y) < indev_act->driver->gesture_min_velocity)) {
1080         proc->types.pointer.gesture_sum.x = 0;
1081         proc->types.pointer.gesture_sum.y = 0;
1082     }
1083 
1084     /*Count the movement by gesture*/
1085     proc->types.pointer.gesture_sum.x += proc->types.pointer.vect.x;
1086     proc->types.pointer.gesture_sum.y += proc->types.pointer.vect.y;
1087 
1088     if((LV_ABS(proc->types.pointer.gesture_sum.x) > indev_act->driver->gesture_limit) ||
1089        (LV_ABS(proc->types.pointer.gesture_sum.y) > indev_act->driver->gesture_limit)) {
1090 
1091         proc->types.pointer.gesture_sent = 1;
1092 
1093         if(LV_ABS(proc->types.pointer.gesture_sum.x) > LV_ABS(proc->types.pointer.gesture_sum.y)) {
1094             if(proc->types.pointer.gesture_sum.x > 0)
1095                 proc->types.pointer.gesture_dir = LV_DIR_RIGHT;
1096             else
1097                 proc->types.pointer.gesture_dir = LV_DIR_LEFT;
1098         }
1099         else {
1100             if(proc->types.pointer.gesture_sum.y > 0)
1101                 proc->types.pointer.gesture_dir = LV_DIR_BOTTOM;
1102             else
1103                 proc->types.pointer.gesture_dir = LV_DIR_TOP;
1104         }
1105 
1106         lv_event_send(gesture_obj, LV_EVENT_GESTURE, indev_act);
1107         if(indev_reset_check(proc)) return;
1108     }
1109 }
1110 
1111 /**
1112  * Checks if the reset_query flag has been set. If so, perform necessary global indev cleanup actions
1113  * @param proc pointer to an input device 'proc'
1114  * @return true if indev query should be immediately truncated.
1115  */
indev_reset_check(_lv_indev_proc_t * proc)1116 static bool indev_reset_check(_lv_indev_proc_t * proc)
1117 {
1118     if(proc->reset_query) {
1119         indev_obj_act = NULL;
1120     }
1121 
1122     return proc->reset_query ? true : false;
1123 }
1124