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 if (!obj) {
68 return;
69 }
70 LOG_DEBUG(TOUCH_LOGGER, "Apply event %d on object of type %d\n", eventType, obj->type);
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 int8_t i = container->nbChildren - 1;
120 // parse children from the latest, because they are drawn from the first
121 while (i >= 0) {
122 nbgl_obj_t *current = container->children[i];
123 if (current != NULL) {
124 current = getTouchedObject(current, event);
125 if (current != NULL) {
126 return current;
127 }
128 }
129 i--;
130 }
131 }
132 }
133 /* now see if the object is interested by touch events (any of them) */
134 if (obj->touchMask != 0) {
135 // LOG_DEBUG(TOUCH_LOGGER,"%d %d \n",clickableObjectTypes ,(1<<obj->type));
136 return obj;
137 }
138 else {
139 return NULL;
140 }
141}
142
150static nbgl_obj_t *getSwipableObjectAtPos(nbgl_obj_t *obj,
152 nbgl_touchType_t detectedSwipe)
153{
154 if (obj == NULL) {
155 return NULL;
156 }
157
158 // Check if pos position belongs to obj
159 if ((pos->x < obj->area.x0) || (pos->x >= (obj->area.x0 + obj->area.width))
160 || (pos->y < obj->area.y0) || (pos->y >= (obj->area.y0 + obj->area.height))) {
161 return NULL;
162 }
163
164 if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
165 nbgl_container_t *container = (nbgl_container_t *) obj;
166 for (uint8_t i = 0; i < container->nbChildren; i++) {
167 nbgl_obj_t *current = container->children[i];
168 if (current != NULL) {
169 nbgl_obj_t *child = getSwipableObjectAtPos(current, pos, detectedSwipe);
170 if (child) {
171 return child;
172 }
173 }
174 }
175 }
176 if (obj->touchMask & (1 << detectedSwipe)) {
177 return obj;
178 }
179 return NULL;
180}
181
196static nbgl_obj_t *getSwipableObject(nbgl_obj_t *obj,
199 nbgl_touchType_t detectedSwipe)
200{
201 if (obj == NULL) {
202 return NULL;
203 }
204
205 nbgl_obj_t *first_obj = getSwipableObjectAtPos(obj, first, detectedSwipe);
206
207 if (first_obj == NULL) {
208 return NULL;
209 }
210
211 nbgl_obj_t *last_obj = getSwipableObjectAtPos(obj, last, detectedSwipe);
212
213 // Swipable objects match
214 if (first_obj == last_obj) {
215 return first_obj;
216 }
217
218 return NULL;
219}
220
221// Swipe detection
222
223#ifndef HAVE_HW_TOUCH_SWIPE
224#define SWIPE_THRESHOLD_X 10
225#define SWIPE_THRESHOLD_Y 20
226#else
227// Mapping between nbgl_hardwareSwipe_t and nbgl_touchEvent_t
228const nbgl_touchType_t SWIPE_GESTURES[] = {[HARDWARE_SWIPE_UP] = SWIPED_UP,
232#endif // HAVE_HW_TOUCH_SWIPE
233
234static nbgl_touchType_t nbgl_detectSwipe(nbgl_touchStatePosition_t *last,
236{
237#ifdef HAVE_HW_TOUCH_SWIPE
238 // Swipe is detected by hardware
239 (void) first;
240
241 if (last->swipe >= NO_HARDWARE_SWIPE) {
242 return NB_TOUCH_TYPES;
243 }
244
245 return SWIPE_GESTURES[last->swipe];
246
247#else
248 // Swipe is detected by software
249 nbgl_touchType_t detected_swipe = NB_TOUCH_TYPES;
250 if ((last->x - first->x) >= SWIPE_THRESHOLD_X) {
251 detected_swipe = SWIPED_RIGHT;
252 }
253 else if ((first->x - last->x) >= SWIPE_THRESHOLD_X) {
254 detected_swipe = SWIPED_LEFT;
255 }
256 else if ((last->y - first->y) >= SWIPE_THRESHOLD_Y) {
257 detected_swipe = SWIPED_DOWN;
258 }
259 else if ((first->y - last->y) >= SWIPE_THRESHOLD_Y) {
260 detected_swipe = SWIPED_UP;
261 }
262
263 return detected_swipe;
264#endif // HAVE_HW_TOUCH_SWIPE
265}
266
267/**********************
268 * GLOBAL FUNCTIONS
269 **********************/
274void nbgl_touchInit(bool fromUx)
275{
276 nbgl_touchCtx_t *ctx = fromUx ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
277 memset(ctx, 0, sizeof(nbgl_touchCtx_t));
278}
279
287void nbgl_touchHandler(bool fromUx,
288 nbgl_touchStatePosition_t *touchStatePosition,
289 uint32_t currentTime)
290{
291 nbgl_obj_t *foundObj;
292 nbgl_touchCtx_t *ctx = fromUx ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
293
294 // save last received currentTime
295 ctx->lastCurrentTime = currentTime;
296
297 if (ctx->lastState == RELEASED) {
298 // filter out not realistic cases (successive RELEASE events)
299 if (RELEASED == touchStatePosition->state) {
300 ctx->lastState = touchStatePosition->state;
301 return;
302 }
303 // memorize first touched position
304 memcpy(&ctx->firstTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t));
305 }
306 // LOG_DEBUG(TOUCH_LOGGER,"state = %s, x = %d, y=%d\n",(touchStatePosition->state ==
307 // RELEASED)?"RELEASED":"PRESSED",touchStatePosition->x,touchStatePosition->y);
308
309 // parse the whole screen to find proper object
310 foundObj = getTouchedObject(nbgl_screenGetTop(), touchStatePosition);
311
312 // LOG_DEBUG(TOUCH_LOGGER,"nbgl_touchHandler: found obj %p, type = %d\n",foundObj,
313 // foundObj->type);
314 if (foundObj == NULL) {
315 LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchHandler: no found obj\n");
316 if ((touchStatePosition->state == PRESSED) && (ctx->lastState == PRESSED)
317 && (ctx->lastPressedObj != NULL)) {
318 // finger has moved out of an object
319 // make sure lastPressedObj still belongs to current screen before warning it
321 applytouchStatePosition(ctx->lastPressedObj, OUT_OF_TOUCH);
322 }
323 }
324 // Released event has been handled, forget lastPressedObj
325 ctx->lastPressedObj = NULL;
326 }
327
328 // memorize last touched position
329 memcpy(&ctx->lastTouchedPosition, touchStatePosition, sizeof(nbgl_touchStatePosition_t));
330
331 if (touchStatePosition->state == RELEASED) {
332 nbgl_touchType_t swipe = nbgl_detectSwipe(touchStatePosition, &ctx->firstTouchedPosition);
333 bool consumed = false;
334
335 ctx->lastState = touchStatePosition->state;
336 if (swipe != NB_TOUCH_TYPES) {
337 // Swipe detected
338 nbgl_obj_t *swipedObj = getSwipableObject(
340 // if a swipable object has been found
341 if (swipedObj) {
342 applytouchStatePosition(swipedObj, swipe);
343 consumed = true;
344 }
345 }
346 if (!consumed && (ctx->lastPressedObj != NULL)
347 && ((foundObj == ctx->lastPressedObj)
349 // very strange if lastPressedObj != foundObj, let's consider that it's a normal release
350 // on lastPressedObj make sure lastPressedObj still belongs to current screen before
351 // "releasing" it
352 applytouchStatePosition(ctx->lastPressedObj, TOUCH_RELEASED);
353 if (currentTime >= (ctx->lastPressedTime + LONG_TOUCH_DURATION)) {
354 applytouchStatePosition(ctx->lastPressedObj, LONG_TOUCHED);
355 }
356 else if (currentTime >= (ctx->lastPressedTime + SHORT_TOUCH_DURATION)) {
357 applytouchStatePosition(ctx->lastPressedObj, TOUCHED);
358 }
359 }
360 // Released event has been handled, forget lastPressedObj
361 ctx->lastPressedObj = NULL;
362 }
363 else { // PRESSED
364 if ((ctx->lastState == PRESSED) && (ctx->lastPressedObj != NULL)) {
365 ctx->lastState = touchStatePosition->state;
366 if (foundObj != ctx->lastPressedObj) {
367 // finger has moved out of an object
368 // make sure lastPressedObj still belongs to current screen before warning it
370 applytouchStatePosition(ctx->lastPressedObj, OUT_OF_TOUCH);
371 }
372 ctx->lastPressedObj = NULL;
373 }
374 else {
375 // warn the concerned object that it is still touched
376 applytouchStatePosition(foundObj, TOUCHING);
377 }
378 }
379 else if (ctx->lastState == RELEASED) {
380 ctx->lastState = touchStatePosition->state;
381 // newly touched object
382 ctx->lastPressedObj = foundObj;
383 ctx->lastPressedTime = currentTime;
384 applytouchStatePosition(foundObj, TOUCH_PRESSED);
385 applytouchStatePosition(foundObj, TOUCHING);
386 }
387 }
388}
389
391 nbgl_touchStatePosition_t **firstPos,
393{
394 nbgl_touchCtx_t *ctx = nbgl_objIsUx(obj) ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
395 LOG_DEBUG(TOUCH_LOGGER, "nbgl_touchGetTouchedPosition: %p %p\n", obj, ctx->lastPressedObj);
396 if (obj == ctx->lastPressedObj) {
397 *firstPos = &ctx->firstTouchedPosition;
398 *lastPos = &ctx->lastTouchedPosition;
399 return true;
400 }
401 return false;
402}
403
405{
406 nbgl_touchCtx_t *ctx = nbgl_objIsUx(obj) ? &touchCtxs[UX_CTX] : &touchCtxs[APP_CTX];
407 if (obj == ctx->lastPressedObj) {
408 return (ctx->lastCurrentTime - ctx->lastPressedTime);
409 }
410 return 0;
411}
412
422{
423 if (obj == NULL) {
424 return NULL;
425 }
426 if ((obj->type == SCREEN) || (obj->type == CONTAINER)) {
427 nbgl_container_t *container = (nbgl_container_t *) obj;
428 // parse the children, if any
429 if (container->children != NULL) {
430 uint8_t i;
431 for (i = 0; i < container->nbChildren; i++) {
432 nbgl_obj_t *current = container->children[i];
433 if (current != NULL) {
434 current = nbgl_touchGetObjectFromId(current, id);
435 if (current != NULL) {
436 return current;
437 }
438 }
439 }
440 }
441 }
442 /* now see if the object is interested by touch events (any of them) */
443 if ((obj->touchMask != 0) && (obj->touchId == id)) {
444 LOG_DEBUG(TOUCH_LOGGER, "found %p: id = %d, type = %d \n", obj, obj->touchId, obj->type);
445 return obj;
446 }
447 else {
448 return NULL;
449 }
450}
451#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:1760
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:225
#define SWIPE_THRESHOLD_X
Definition nbgl_touch.c:224
bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, nbgl_touchStatePosition_t **firstPos, nbgl_touchStatePosition_t **lastPos)
Definition nbgl_touch.c:390
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:421
uint32_t nbgl_touchGetTouchDuration(nbgl_obj_t *obj)
Definition nbgl_touch.c:404
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:287
void nbgl_touchInit(bool fromUx)
Function to initialize the touch context.
Definition nbgl_touch.c:274
#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: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: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
unsigned char uint8_t
Definition usbd_conf.h:53
signed char int8_t
Definition usbd_conf.h:49