Embedded SDK
Embedded SDK
nbgl_touch.c
Go to the documentation of this file.
1 
6 #include "app_config.h"
7 
8 #ifdef HAVE_SE_TOUCH
9 /*********************
10  * INCLUDES
11  *********************/
12 #include <string.h>
13 #include "nbgl_obj.h"
14 #include "nbgl_debug.h"
15 #include "nbgl_touch.h"
16 #include "nbgl_screen.h"
17 #include "os_pic.h"
18 #include "os_io_seproxyhal.h"
19 
20 /*********************
21  * DEFINES
22  *********************/
23 
24 /**********************
25  * TYPEDEFS
26  **********************/
27 
28 /**********************
29  * STATIC PROTOTYPES
30  **********************/
31 
32 /**********************
33  * STATIC VARIABLES
34  **********************/
35 static uint32_t lastPressedTime = 0;
36 static uint32_t lastCurrentTime = 0;
37 static nbgl_obj_t *lastPressedObj = NULL;
38 static nbgl_touchStatePosition_t firstTouchedPosition, lastTouchedPosition;
39 
40 /**********************
41  * VARIABLES
42  **********************/
43 
44 /**********************
45  * STATIC PROTOTYPES
46  **********************/
47 
54 static void applytouchStatePosition(nbgl_obj_t *obj, nbgl_touchType_t eventType)
55 {
57  LOG_DEBUG(TOUCH_LOGGER, "Apply event %d on object of type %d\n", eventType, obj->type);
58  if (!obj) {
59  return;
60  }
61  /* the first action is the one provided by the application */
62  if ((obj->touchMask & (1 << eventType)) != 0) {
63  // for some specific objects, call directly a specific callback
64  switch (obj->type) {
65 #ifdef NBGL_KEYBOARD
66  case KEYBOARD:
67  nbgl_keyboardTouchCallback(obj, eventType);
68  break;
69 #endif // NBGL_KEYBOARD
70 #ifdef NBGL_KEYPAD
71  case KEYPAD:
72  nbgl_keypadTouchCallback(obj, eventType);
73  break;
74 #endif // NBGL_KEYPAD
75  default:
76  if (screen->touchCallback != NULL) {
77  ((nbgl_touchCallback_t) PIC(screen->touchCallback))((void *) obj, eventType);
78  }
79  break;
80  }
81  }
82 }
83 
93 static nbgl_obj_t *getTouchedObject(nbgl_obj_t *obj, nbgl_touchStatePosition_t *event)
94 {
95  if (obj == NULL) {
96  return NULL;
97  }
98  /* check coordinates
99  no need to go further if the touched point is not within the object
100  And because the children are also within the object, no need to check them either */
101  if ((event->x < obj->area.x0) || (event->x >= (obj->area.x0 + obj->area.width))
102  || (event->y < obj->area.y0) || (event->y >= (obj->area.y0 + obj->area.height))) {
103  return NULL;
104  }
105  if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
106  nbgl_container_t *container = (nbgl_container_t *) obj;
107  // parse the children, if any
108  if (container->children != NULL) {
109  uint8_t i;
110  for (i = 0; i < container->nbChildren; i++) {
111  nbgl_obj_t *current = container->children[i];
112  if (current != NULL) {
113  current = getTouchedObject(current, event);
114  if (current != NULL) {
115  return current;
116  }
117  }
118  }
119  }
120  }
121  /* now see if the object is interested by touch events (any of them) */
122  if (obj->touchMask != 0) {
123  // LOG_DEBUG(TOUCH_LOGGER,"%d %d \n",clickableObjectTypes ,(1<<obj->type));
124  return obj;
125  }
126  else {
127  return NULL;
128  }
129 }
130 
138 static nbgl_obj_t *getSwipableObjectAtPos(nbgl_obj_t *obj,
140  nbgl_touchType_t detectedSwipe)
141 {
142  if (obj == NULL) {
143  return NULL;
144  }
145 
146  // Check if pos position belongs to obj
147  if ((pos->x < obj->area.x0) || (pos->x >= (obj->area.x0 + obj->area.width))
148  || (pos->y < obj->area.y0) || (pos->y >= (obj->area.y0 + obj->area.height))) {
149  return NULL;
150  }
151 
152  if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
153  nbgl_container_t *container = (nbgl_container_t *) obj;
154  for (uint8_t i = 0; i < container->nbChildren; i++) {
155  nbgl_obj_t *current = container->children[i];
156  if (current != NULL) {
157  nbgl_obj_t *child = getSwipableObjectAtPos(current, pos, detectedSwipe);
158  if (child) {
159  return child;
160  }
161  }
162  }
163  }
164  if (obj->touchMask & (1 << detectedSwipe)) {
165  return obj;
166  }
167  return NULL;
168 }
169 
184 static nbgl_obj_t *getSwipableObject(nbgl_obj_t *obj,
187  nbgl_touchType_t detectedSwipe)
188 {
189  if (obj == NULL) {
190  return NULL;
191  }
192 
193  nbgl_obj_t *first_obj = getSwipableObjectAtPos(obj, first, detectedSwipe);
194 
195  if (first_obj == NULL) {
196  return NULL;
197  }
198 
199  nbgl_obj_t *last_obj = getSwipableObjectAtPos(obj, last, detectedSwipe);
200 
201  // Swipable objects match
202  if (first_obj == last_obj) {
203  return first_obj;
204  }
205 
206  return NULL;
207 }
208 
209 // Swipe detection
210 
211 #ifndef HAVE_HW_TOUCH_SWIPE
212 #define SWIPE_THRESHOLD_X 10
213 #define SWIPE_THRESHOLD_Y 20
214 #else
215 // Mapping between nbgl_hardwareSwipe_t and nbgl_touchEvent_t
216 const nbgl_touchType_t SWIPE_GESTURES[] = {[HARDWARE_SWIPE_UP] = SWIPED_UP,
220 #endif // HAVE_HW_TOUCH_SWIPE
221 
222 static nbgl_touchType_t nbgl_detectSwipe(nbgl_touchStatePosition_t *last,
224 {
225 #ifdef HAVE_HW_TOUCH_SWIPE
226  // Swipe is detected by hardware
227  (void) first;
228 
229  if (last->swipe >= NO_HARDWARE_SWIPE) {
230  return NB_TOUCH_TYPES;
231  }
232 
233  return SWIPE_GESTURES[last->swipe];
234 
235 #else
236  // Swipe is detected by software
237  nbgl_touchType_t detected_swipe = NB_TOUCH_TYPES;
238  if ((last->x - first->x) >= SWIPE_THRESHOLD_X) {
239  detected_swipe = SWIPED_RIGHT;
240  }
241  else if ((first->x - last->x) >= SWIPE_THRESHOLD_X) {
242  detected_swipe = SWIPED_LEFT;
243  }
244  else if ((last->y - first->y) >= SWIPE_THRESHOLD_Y) {
245  detected_swipe = SWIPED_DOWN;
246  }
247  else if ((first->y - last->y) >= SWIPE_THRESHOLD_Y) {
248  detected_swipe = SWIPED_UP;
249  }
250 
251  return detected_swipe;
252 #endif // HAVE_HW_TOUCH_SWIPE
253 }
254 
255 /**********************
256  * GLOBAL FUNCTIONS
257  **********************/
258 
265 void nbgl_touchHandler(nbgl_touchStatePosition_t *touchStatePosition, uint32_t currentTime)
266 {
267  static nbgl_touchState_t lastState = RELEASED;
268  nbgl_obj_t *foundObj;
269 
270  // save last received currentTime
271  lastCurrentTime = currentTime;
272 
273  if (lastState == RELEASED) {
274  // filter out not realistic cases (successive RELEASE events)
275  if (RELEASED == touchStatePosition->state) {
276  lastState = touchStatePosition->state;
277  return;
278  }
279  // memorize first touched position
280  memcpy(&firstTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t));
281  }
282  // LOG_DEBUG(TOUCH_LOGGER,"state = %s, x = %d, y=%d\n",(touchStatePosition->state ==
283  // RELEASED)?"RELEASED":"PRESSED",touchStatePosition->x,touchStatePosition->y);
284 
285  // parse the whole screen to find proper object
286  foundObj = getTouchedObject(nbgl_screenGetTop(), touchStatePosition);
287 
288  // LOG_DEBUG(TOUCH_LOGGER,"nbgl_touchHandler: found obj %p, type = %d\n",foundObj,
289  // foundObj->type);
290  if (foundObj == NULL) {
291  LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchHandler: no found obj\n");
292  if ((touchStatePosition->state == PRESSED) && (lastState == PRESSED)
293  && (lastPressedObj != NULL)) {
294  // finger has moved out of an object
295  // make sure lastPressedObj still belongs to current screen before warning it
296  if (nbgl_screenContainsObj(lastPressedObj)) {
297  applytouchStatePosition(lastPressedObj, OUT_OF_TOUCH);
298  }
299  }
300  // Released event has been handled, forget lastPressedObj
301  lastPressedObj = NULL;
302  }
303 
304  // memorize last touched position
305  memcpy(&lastTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t));
306 
307  if (touchStatePosition->state == RELEASED) {
308  nbgl_touchType_t swipe = nbgl_detectSwipe(touchStatePosition, &firstTouchedPosition);
309  bool consumed = false;
310 
311  if (swipe != NB_TOUCH_TYPES) {
312  // Swipe detected
313  nbgl_obj_t *swipedObj = getSwipableObject(
314  nbgl_screenGetTop(), &firstTouchedPosition, &lastTouchedPosition, swipe);
315  // if a swipable object has been found
316  if (swipedObj) {
317  applytouchStatePosition(swipedObj, swipe);
318  consumed = true;
319  }
320  }
321  if (!consumed && (lastPressedObj != NULL)
322  && ((foundObj == lastPressedObj) || (nbgl_screenContainsObj(lastPressedObj)))) {
323  // very strange if lastPressedObj != foundObj, let's consider that it's a normal release
324  // on lastPressedObj make sure lastPressedObj still belongs to current screen before
325  // "releasing" it
326  applytouchStatePosition(lastPressedObj, TOUCH_RELEASED);
327  if (currentTime >= (lastPressedTime + LONG_TOUCH_DURATION)) {
328  applytouchStatePosition(lastPressedObj, LONG_TOUCHED);
329  }
330  else if (currentTime >= (lastPressedTime + SHORT_TOUCH_DURATION)) {
331  applytouchStatePosition(lastPressedObj, TOUCHED);
332  }
333  }
334  // Released event has been handled, forget lastPressedObj
335  lastPressedObj = NULL;
336  }
337  else { // PRESSED
338  if ((lastState == PRESSED) && (lastPressedObj != NULL)) {
339  if (foundObj != lastPressedObj) {
340  // finger has moved out of an object
341  // make sure lastPressedObj still belongs to current screen before warning it
342  if (nbgl_screenContainsObj(lastPressedObj)) {
343  applytouchStatePosition(lastPressedObj, OUT_OF_TOUCH);
344  }
345  lastPressedObj = NULL;
346  }
347  else {
348  // warn the concerned object that it is still touched
349  applytouchStatePosition(foundObj, TOUCHING);
350  }
351  }
352  else if (lastState == RELEASED) {
353  // newly touched object
354  lastPressedObj = foundObj;
355  lastPressedTime = currentTime;
356  applytouchStatePosition(foundObj, TOUCH_PRESSED);
357  applytouchStatePosition(foundObj, TOUCHING);
358  }
359  }
360 
361  lastState = touchStatePosition->state;
362 }
363 
365  nbgl_touchStatePosition_t **firstPos,
366  nbgl_touchStatePosition_t **lastPos)
367 {
368  LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchGetTouchedPosition: %p %p\n", obj, lastPressedObj);
369  if (obj == lastPressedObj) {
370  *firstPos = &firstTouchedPosition;
371  *lastPos = &lastTouchedPosition;
372  return true;
373  }
374  return false;
375 }
376 
378 {
379  if (obj == lastPressedObj) {
380  return (lastCurrentTime - lastPressedTime);
381  }
382  return 0;
383 }
384 
394 {
395  if (obj == NULL) {
396  return NULL;
397  }
398  if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
399  nbgl_container_t *container = (nbgl_container_t *) obj;
400  // parse the children, if any
401  if (container->children != NULL) {
402  uint8_t i;
403  for (i = 0; i < container->nbChildren; i++) {
404  nbgl_obj_t *current = container->children[i];
405  if (current != NULL) {
406  current = nbgl_touchGetObjectFromId(current, id);
407  if (current != NULL) {
408  return current;
409  }
410  }
411  }
412  }
413  }
414  /* now see if the object is interested by touch events (any of them) */
415  if ((obj->touchMask != 0) && (obj->touchId == id)) {
416  LOG_DEBUG(TOUCH_LOGGER, "found %p: id = %d, type = %d \n", obj, obj->touchId, obj->type);
417  return obj;
418  }
419  else {
420  return NULL;
421  }
422 }
423 #endif // HAVE_SE_TOUCH
debug traces management
#define LOG_DEBUG(__logger,...)
Definition: nbgl_debug.h:86
@ TOUCH_LOGGER
Definition: nbgl_debug.h:36
API to draw all basic graphic objects.
void(* nbgl_touchCallback_t)(void *obj, nbgl_touchType_t eventType)
prototype of function to be called when a touch event is received by an object
Definition: nbgl_obj.h:221
void nbgl_keyboardTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
function to be called when the keyboard object is touched
void nbgl_keypadTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
function to be called when the keypad object is touched
struct PACKED__ nbgl_container_s nbgl_container_t
struct to represent a container (CONTAINER type)
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
API to manage screens.
nbgl_obj_t * nbgl_screenGetTop(void)
Returns the screen on top layer, as a generic object.
Definition: nbgl_screen.c:102
bool nbgl_screenContainsObj(nbgl_obj_t *obj)
return true if the given obj can be found in refObj or any of its children
Definition: nbgl_screen.c:568
struct PACKED__ nbgl_screen_s nbgl_screen_t
struct to represent a screen (SCREEN type)
#define SWIPE_THRESHOLD_Y
Definition: nbgl_touch.c:213
#define SWIPE_THRESHOLD_X
Definition: nbgl_touch.c:212
bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, nbgl_touchStatePosition_t **firstPos, nbgl_touchStatePosition_t **lastPos)
Definition: nbgl_touch.c:364
nbgl_obj_t * nbgl_touchGetObjectFromId(nbgl_obj_t *obj, uint8_t id)
parse all the children of the given object, recursively, until an object with the given touch if is f...
Definition: nbgl_touch.c:393
uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj)
Definition: nbgl_touch.c:377
void nbgl_touchHandler(nbgl_touchStatePosition_t *touchStatePosition, uint32_t currentTime)
Function to be called periodically to check touchscreen state and coordinates.
Definition: nbgl_touch.c:265
#define SHORT_TOUCH_DURATION
Definition: nbgl_touch.h:24
#define LONG_TOUCH_DURATION
Definition: nbgl_touch.h:26
nbgl_touchType_t
The different types of Touchscreen events.
Definition: nbgl_types.h:220
@ SWIPED_LEFT
Definition: nbgl_types.h:236
@ LONG_TOUCHED
Definition: nbgl_types.h:223
@ SWIPED_UP
Definition: nbgl_types.h:233
@ SWIPED_DOWN
Definition: nbgl_types.h:234
@ SWIPED_RIGHT
Definition: nbgl_types.h:235
@ NB_TOUCH_TYPES
Definition: nbgl_types.h:237
@ TOUCH_RELEASED
Definition: nbgl_types.h:230
@ TOUCHED
Definition: nbgl_types.h:221
@ TOUCHING
corresponding to an object that is currently touched
Definition: nbgl_types.h:225
@ TOUCH_PRESSED
Definition: nbgl_types.h:228
@ OUT_OF_TOUCH
Definition: nbgl_types.h:226
@ HARDWARE_SWIPE_RIGHT
Definition: nbgl_types.h:211
@ NO_HARDWARE_SWIPE
Definition: nbgl_types.h:213
@ HARDWARE_SWIPE_LEFT
Definition: nbgl_types.h:212
@ HARDWARE_SWIPE_DOWN
Definition: nbgl_types.h:210
@ HARDWARE_SWIPE_UP
Definition: nbgl_types.h:209
@ KEYPAD
Keypad.
Definition: nbgl_types.h:128
@ KEYBOARD
Keyboard.
Definition: nbgl_types.h:127
@ CONTAINER
Empty container.
Definition: nbgl_types.h:117
@ SCREEN
Main screen.
Definition: nbgl_types.h:116
nbgl_touchState_t
the 2 possible states of a finger on the Touchscreen
Definition: nbgl_types.h:200
@ PRESSED
the finger is currently pressing the screen
Definition: nbgl_types.h:202
@ RELEASED
the finger has been released from the screen
Definition: nbgl_types.h:201
The low level Touchscreen event, coming from driver.
Definition: nbgl_obj.h:206
int16_t y
vertical position of the touch (or for a RELEASED the last touched point)
Definition: nbgl_obj.h:213
int16_t x
horizontal position of the touch (or for a RELEASED the last touched point)
Definition: nbgl_obj.h:212
nbgl_touchState_t state
state of the touch event, e.g PRESSED or RELEASED
Definition: nbgl_obj.h:207
unsigned char uint8_t
Definition: usbd_conf.h:53