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