Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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 *********************/
23enum {
24 UX_CTX = 0,
27};
28
29/**********************
30 * TYPEDEFS
31 **********************/
40
41/**********************
42 * STATIC PROTOTYPES
43 **********************/
44
45/**********************
46 * STATIC VARIABLES
47 **********************/
48static nbgl_touchCtx_t touchCtxs[NB_CTXS];
49
50/**********************
51 * VARIABLES
52 **********************/
53
54/**********************
55 * STATIC PROTOTYPES
56 **********************/
57
64static 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
103static 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
148static 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
194static 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
226const nbgl_touchType_t SWIPE_GESTURES[] = {[HARDWARE_SWIPE_UP] = SWIPED_UP,
230#endif // HAVE_HW_TOUCH_SWIPE
231
232static 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 **********************/
272void 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
285void 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,
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:242
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:1669
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.
bool nbgl_screenContainsObj(nbgl_obj_t *obj)
return true if the given obj can be found in refObj or any of its children
struct PACKED__ nbgl_screen_s nbgl_screen_t
struct to represent a screen (SCREEN type)
nbgl_obj_t * nbgl_screenGetTop(void)
Returns the screen on top layer, as a generic object.
@ APP_CTX
Definition nbgl_touch.c:25
@ UX_CTX
Definition nbgl_touch.c:24
@ NB_CTXS
Definition nbgl_touch.c:26
#define SWIPE_THRESHOLD_Y
Definition nbgl_touch.c:223
#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:239
@ SWIPED_LEFT
Definition nbgl_types.h:255
@ LONG_TOUCHED
Definition nbgl_types.h:242
@ SWIPED_UP
Definition nbgl_types.h:252
@ SWIPED_DOWN
Definition nbgl_types.h:253
@ SWIPED_RIGHT
Definition nbgl_types.h:254
@ NB_TOUCH_TYPES
Definition nbgl_types.h:256
@ TOUCH_RELEASED
Definition nbgl_types.h:249
@ TOUCHED
Definition nbgl_types.h:240
@ TOUCHING
corresponding to an object that is currently touched
Definition nbgl_types.h:244
@ TOUCH_PRESSED
Definition nbgl_types.h:247
@ OUT_OF_TOUCH
Definition nbgl_types.h:245
@ HARDWARE_SWIPE_RIGHT
Definition nbgl_types.h:230
@ NO_HARDWARE_SWIPE
Definition nbgl_types.h:232
@ HARDWARE_SWIPE_LEFT
Definition nbgl_types.h:231
@ HARDWARE_SWIPE_DOWN
Definition nbgl_types.h:229
@ HARDWARE_SWIPE_UP
Definition nbgl_types.h:228
@ KEYPAD
Keypad.
Definition nbgl_types.h:147
@ KEYBOARD
Keyboard.
Definition nbgl_types.h:146
@ CONTAINER
Empty container.
Definition nbgl_types.h:136
@ SCREEN
Main screen.
Definition nbgl_types.h:135
nbgl_touchState_t
the 2 possible states of a finger on the Touchscreen
Definition nbgl_types.h:219
@ PRESSED
the finger is currently pressing the screen
Definition nbgl_types.h:221
@ RELEASED
the finger has been released from the screen
Definition nbgl_types.h:220
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:227
int16_t y
vertical position of the touch (or for a RELEASED the last touched point)
Definition nbgl_obj.h:234
int16_t x
horizontal position of the touch (or for a RELEASED the last touched point)
Definition nbgl_obj.h:233
nbgl_touchState_t state
state of the touch event, e.g PRESSED or RELEASED
Definition nbgl_obj.h:228
unsigned char uint8_t
Definition usbd_conf.h:53