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