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 enum {
24  UX_CTX = 0,
26  NB_CTXS
27 };
28 
29 /**********************
30  * TYPEDEFS
31  **********************/
32 typedef struct nbgl_touchCtx_s {
34  uint32_t lastPressedTime;
35  uint32_t lastCurrentTime;
40 
41 /**********************
42  * STATIC PROTOTYPES
43  **********************/
44 
45 /**********************
46  * STATIC VARIABLES
47  **********************/
48 static nbgl_touchCtx_t touchCtxs[NB_CTXS];
49 
50 /**********************
51  * VARIABLES
52  **********************/
53 
54 /**********************
55  * STATIC PROTOTYPES
56  **********************/
57 
64 static void applytouchStatePosition(nbgl_obj_t *obj, nbgl_touchType_t eventType)
65 {
67  LOG_DEBUG(TOUCH_LOGGER, "Apply event %d on object of type %d\n", eventType, obj->type);
68  if (!obj) {
69  return;
70  }
71  /* the first action is the one provided by the application */
72  if ((obj->touchMask & (1 << eventType)) != 0) {
73  // for some specific objects, call directly a specific callback
74  switch (obj->type) {
75 #ifdef NBGL_KEYBOARD
76  case KEYBOARD:
77  nbgl_keyboardTouchCallback(obj, eventType);
78  break;
79 #endif // NBGL_KEYBOARD
80 #ifdef NBGL_KEYPAD
81  case KEYPAD:
82  nbgl_keypadTouchCallback(obj, eventType);
83  break;
84 #endif // NBGL_KEYPAD
85  default:
86  if (screen->touchCallback != NULL) {
87  ((nbgl_touchCallback_t) PIC(screen->touchCallback))((void *) obj, eventType);
88  }
89  break;
90  }
91  }
92 }
93 
103 static nbgl_obj_t *getTouchedObject(nbgl_obj_t *obj, nbgl_touchStatePosition_t *event)
104 {
105  if (obj == NULL) {
106  return NULL;
107  }
108  /* check coordinates
109  no need to go further if the touched point is not within the object
110  And because the children are also within the object, no need to check them either */
111  if ((event->x < obj->area.x0) || (event->x >= (obj->area.x0 + obj->area.width))
112  || (event->y < obj->area.y0) || (event->y >= (obj->area.y0 + obj->area.height))) {
113  return NULL;
114  }
115  if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
116  nbgl_container_t *container = (nbgl_container_t *) obj;
117  // parse the children, if any
118  if (container->children != NULL) {
119  uint8_t i;
120  for (i = 0; i < container->nbChildren; i++) {
121  nbgl_obj_t *current = container->children[i];
122  if (current != NULL) {
123  current = getTouchedObject(current, event);
124  if (current != NULL) {
125  return current;
126  }
127  }
128  }
129  }
130  }
131  /* now see if the object is interested by touch events (any of them) */
132  if (obj->touchMask != 0) {
133  // LOG_DEBUG(TOUCH_LOGGER,"%d %d \n",clickableObjectTypes ,(1<<obj->type));
134  return obj;
135  }
136  else {
137  return NULL;
138  }
139 }
140 
148 static nbgl_obj_t *getSwipableObjectAtPos(nbgl_obj_t *obj,
150  nbgl_touchType_t detectedSwipe)
151 {
152  if (obj == NULL) {
153  return NULL;
154  }
155 
156  // Check if pos position belongs to obj
157  if ((pos->x < obj->area.x0) || (pos->x >= (obj->area.x0 + obj->area.width))
158  || (pos->y < obj->area.y0) || (pos->y >= (obj->area.y0 + obj->area.height))) {
159  return NULL;
160  }
161 
162  if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
163  nbgl_container_t *container = (nbgl_container_t *) obj;
164  for (uint8_t i = 0; i < container->nbChildren; i++) {
165  nbgl_obj_t *current = container->children[i];
166  if (current != NULL) {
167  nbgl_obj_t *child = getSwipableObjectAtPos(current, pos, detectedSwipe);
168  if (child) {
169  return child;
170  }
171  }
172  }
173  }
174  if (obj->touchMask & (1 << detectedSwipe)) {
175  return obj;
176  }
177  return NULL;
178 }
179 
194 static nbgl_obj_t *getSwipableObject(nbgl_obj_t *obj,
197  nbgl_touchType_t detectedSwipe)
198 {
199  if (obj == NULL) {
200  return NULL;
201  }
202 
203  nbgl_obj_t *first_obj = getSwipableObjectAtPos(obj, first, detectedSwipe);
204 
205  if (first_obj == NULL) {
206  return NULL;
207  }
208 
209  nbgl_obj_t *last_obj = getSwipableObjectAtPos(obj, last, detectedSwipe);
210 
211  // Swipable objects match
212  if (first_obj == last_obj) {
213  return first_obj;
214  }
215 
216  return NULL;
217 }
218 
219 // Swipe detection
220 
221 #ifndef HAVE_HW_TOUCH_SWIPE
222 #define SWIPE_THRESHOLD_X 10
223 #define SWIPE_THRESHOLD_Y 20
224 #else
225 // Mapping between nbgl_hardwareSwipe_t and nbgl_touchEvent_t
226 const nbgl_touchType_t SWIPE_GESTURES[] = {[HARDWARE_SWIPE_UP] = SWIPED_UP,
230 #endif // HAVE_HW_TOUCH_SWIPE
231 
232 static nbgl_touchType_t nbgl_detectSwipe(nbgl_touchStatePosition_t *last,
234 {
235 #ifdef HAVE_HW_TOUCH_SWIPE
236  // Swipe is detected by hardware
237  (void) first;
238 
239  if (last->swipe >= NO_HARDWARE_SWIPE) {
240  return NB_TOUCH_TYPES;
241  }
242 
243  return SWIPE_GESTURES[last->swipe];
244 
245 #else
246  // Swipe is detected by software
247  nbgl_touchType_t detected_swipe = NB_TOUCH_TYPES;
248  if ((last->x - first->x) >= SWIPE_THRESHOLD_X) {
249  detected_swipe = SWIPED_RIGHT;
250  }
251  else if ((first->x - last->x) >= SWIPE_THRESHOLD_X) {
252  detected_swipe = SWIPED_LEFT;
253  }
254  else if ((last->y - first->y) >= SWIPE_THRESHOLD_Y) {
255  detected_swipe = SWIPED_DOWN;
256  }
257  else if ((first->y - last->y) >= SWIPE_THRESHOLD_Y) {
258  detected_swipe = SWIPED_UP;
259  }
260 
261  return detected_swipe;
262 #endif // HAVE_HW_TOUCH_SWIPE
263 }
264 
265 /**********************
266  * GLOBAL FUNCTIONS
267  **********************/
272 void nbgl_touchInit(bool fromUx)
273 {
274  nbgl_touchCtx_t *ctx = fromUx ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
275  memset(ctx, 0, sizeof(nbgl_touchCtx_t));
276 }
277 
285 void nbgl_touchHandler(bool fromUx,
286  nbgl_touchStatePosition_t *touchStatePosition,
287  uint32_t currentTime)
288 {
289  nbgl_obj_t *foundObj;
290  nbgl_touchCtx_t *ctx = fromUx ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
291 
292  // save last received currentTime
293  ctx->lastCurrentTime = currentTime;
294 
295  if (ctx->lastState == RELEASED) {
296  // filter out not realistic cases (successive RELEASE events)
297  if (RELEASED == touchStatePosition->state) {
298  ctx->lastState = touchStatePosition->state;
299  return;
300  }
301  // memorize first touched position
302  memcpy(&ctx->firstTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t));
303  }
304  // LOG_DEBUG(TOUCH_LOGGER,"state = %s, x = %d, y=%d\n",(touchStatePosition->state ==
305  // RELEASED)?"RELEASED":"PRESSED",touchStatePosition->x,touchStatePosition->y);
306 
307  // parse the whole screen to find proper object
308  foundObj = getTouchedObject(nbgl_screenGetTop(), touchStatePosition);
309 
310  // LOG_DEBUG(TOUCH_LOGGER,"nbgl_touchHandler: found obj %p, type = %d\n",foundObj,
311  // foundObj->type);
312  if (foundObj == NULL) {
313  LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchHandler: no found obj\n");
314  if ((touchStatePosition->state == PRESSED) && (ctx->lastState == PRESSED)
315  && (ctx->lastPressedObj != NULL)) {
316  // finger has moved out of an object
317  // make sure lastPressedObj still belongs to current screen before warning it
319  applytouchStatePosition(ctx->lastPressedObj, OUT_OF_TOUCH);
320  }
321  }
322  // Released event has been handled, forget lastPressedObj
323  ctx->lastPressedObj = NULL;
324  }
325 
326  // memorize last touched position
327  memcpy(&ctx->lastTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t));
328 
329  if (touchStatePosition->state == RELEASED) {
330  nbgl_touchType_t swipe = nbgl_detectSwipe(touchStatePosition, &ctx->firstTouchedPosition);
331  bool consumed = false;
332 
333  ctx->lastState = touchStatePosition->state;
334  if (swipe != NB_TOUCH_TYPES) {
335  // Swipe detected
336  nbgl_obj_t *swipedObj = getSwipableObject(
338  // if a swipable object has been found
339  if (swipedObj) {
340  applytouchStatePosition(swipedObj, swipe);
341  consumed = true;
342  }
343  }
344  if (!consumed && (ctx->lastPressedObj != NULL)
345  && ((foundObj == ctx->lastPressedObj)
347  // very strange if lastPressedObj != foundObj, let's consider that it's a normal release
348  // on lastPressedObj make sure lastPressedObj still belongs to current screen before
349  // "releasing" it
350  applytouchStatePosition(ctx->lastPressedObj, TOUCH_RELEASED);
351  if (currentTime >= (ctx->lastPressedTime + LONG_TOUCH_DURATION)) {
352  applytouchStatePosition(ctx->lastPressedObj, LONG_TOUCHED);
353  }
354  else if (currentTime >= (ctx->lastPressedTime + SHORT_TOUCH_DURATION)) {
355  applytouchStatePosition(ctx->lastPressedObj, TOUCHED);
356  }
357  }
358  // Released event has been handled, forget lastPressedObj
359  ctx->lastPressedObj = NULL;
360  }
361  else { // PRESSED
362  if ((ctx->lastState == PRESSED) && (ctx->lastPressedObj != NULL)) {
363  ctx->lastState = touchStatePosition->state;
364  if (foundObj != ctx->lastPressedObj) {
365  // finger has moved out of an object
366  // make sure lastPressedObj still belongs to current screen before warning it
368  applytouchStatePosition(ctx->lastPressedObj, OUT_OF_TOUCH);
369  }
370  ctx->lastPressedObj = NULL;
371  }
372  else {
373  // warn the concerned object that it is still touched
374  applytouchStatePosition(foundObj, TOUCHING);
375  }
376  }
377  else if (ctx->lastState == RELEASED) {
378  ctx->lastState = touchStatePosition->state;
379  // newly touched object
380  ctx->lastPressedObj = foundObj;
381  ctx->lastPressedTime = currentTime;
382  applytouchStatePosition(foundObj, TOUCH_PRESSED);
383  applytouchStatePosition(foundObj, TOUCHING);
384  }
385  }
386 }
387 
389  nbgl_touchStatePosition_t **firstPos,
390  nbgl_touchStatePosition_t **lastPos)
391 {
392  nbgl_touchCtx_t *ctx = nbgl_objIsUx(obj) ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
393  LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchGetTouchedPosition: %p %p\n", obj, ctx->lastPressedObj);
394  if (obj == ctx->lastPressedObj) {
395  *firstPos = &ctx->firstTouchedPosition;
396  *lastPos = &ctx->lastTouchedPosition;
397  return true;
398  }
399  return false;
400 }
401 
403 {
404  nbgl_touchCtx_t *ctx = nbgl_objIsUx(obj) ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
405  if (obj == ctx->lastPressedObj) {
406  return (ctx->lastCurrentTime - ctx->lastPressedTime);
407  }
408  return 0;
409 }
410 
420 {
421  if (obj == NULL) {
422  return NULL;
423  }
424  if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
425  nbgl_container_t *container = (nbgl_container_t *) obj;
426  // parse the children, if any
427  if (container->children != NULL) {
428  uint8_t i;
429  for (i = 0; i < container->nbChildren; i++) {
430  nbgl_obj_t *current = container->children[i];
431  if (current != NULL) {
432  current = nbgl_touchGetObjectFromId(current, id);
433  if (current != NULL) {
434  return current;
435  }
436  }
437  }
438  }
439  }
440  /* now see if the object is interested by touch events (any of them) */
441  if ((obj->touchMask != 0) && (obj->touchId == id)) {
442  LOG_DEBUG(TOUCH_LOGGER, "found %p: id = %d, type = %d \n", obj, obj->touchId, obj->type);
443  return obj;
444  }
445  else {
446  return NULL;
447  }
448 }
449 #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
bool nbgl_objIsUx(nbgl_obj_t *obj)
This function returns true if the object belongs to a UxScreen.
Definition: nbgl_obj.c:1671
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:223
@ APP_CTX
Definition: nbgl_touch.c:25
@ UX_CTX
Definition: nbgl_touch.c:24
@ NB_CTXS
Definition: nbgl_touch.c:26
#define SWIPE_THRESHOLD_X
Definition: nbgl_touch.c:222
bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, nbgl_touchStatePosition_t **firstPos, nbgl_touchStatePosition_t **lastPos)
Definition: nbgl_touch.c:388
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:419
uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj)
Definition: nbgl_touch.c:402
struct nbgl_touchCtx_s nbgl_touchCtx_t
void nbgl_touchHandler(bool fromUx, nbgl_touchStatePosition_t *touchStatePosition, uint32_t currentTime)
Function to be called periodically to check touchscreen state and coordinates.
Definition: nbgl_touch.c:285
void nbgl_touchInit(bool fromUx)
Function to initialize the touch context.
Definition: nbgl_touch.c:272
#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
nbgl_touchStatePosition_t firstTouchedPosition
Definition: nbgl_touch.c:37
nbgl_obj_t * lastPressedObj
Definition: nbgl_touch.c:36
nbgl_touchStatePosition_t lastTouchedPosition
Definition: nbgl_touch.c:38
uint32_t lastCurrentTime
Definition: nbgl_touch.c:35
uint32_t lastPressedTime
Definition: nbgl_touch.c:34
nbgl_touchState_t lastState
Definition: nbgl_touch.c:33
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