Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
nbgl_obj_keypad.c
Go to the documentation of this file.
1
8#ifdef NBGL_KEYPAD
9#ifdef HAVE_SE_TOUCH
10
11/*********************
12 * INCLUDES
13 *********************/
14#include "nbgl_debug.h"
15#include "nbgl_front.h"
16#include "nbgl_draw.h"
17#include "nbgl_obj.h"
18#include "nbgl_fonts.h"
19#include "nbgl_touch.h"
20#include "glyphs.h"
21#include "os_io_seproxyhal.h"
22#include "lcx_rng.h"
23
24/*********************
25 * DEFINES
26 *********************/
27#define KEY_WIDTH (SCREEN_WIDTH / 3)
28#if defined(TARGET_STAX)
29#define DIGIT_OFFSET_Y (((KEYPAD_KEY_HEIGHT - 48) / 2) & 0xFFC)
30#elif defined(TARGET_FLEX)
31#define DIGIT_OFFSET_Y (((KEYPAD_KEY_HEIGHT - 48) / 2) & 0xFFC)
32#endif // TARGETS
33
34#define BACKSPACE_KEY_IDX 10
35#define VALIDATE_KEY_IDX 11
36
37// to save RAM we use 5 uint8, and 4 bits per digit (MSBs for odd digits, LSBs for even ones)
38#define GET_DIGIT_INDEX(_keypad, _digit) \
39 ((_digit & 1) ? (_keypad->digitIndexes[_digit >> 1] >> 4) \
40 : (_keypad->digitIndexes[_digit >> 1] & 0xF))
41#define SET_DIGIT_INDEX(_keypad, _digit, _index) \
42 (_keypad->digitIndexes[_digit >> 1] |= (_digit & 1) ? (_index << 4) : _index)
43
45
46/**********************
47 * TYPEDEFS
48 **********************/
49
50/**********************
51 * STATIC VARIABLES
52 **********************/
53
54/**********************
55 * VARIABLES
56 **********************/
57
58/**********************
59 * STATIC FUNCTIONS
60 **********************/
61
62static uint8_t getKeypadIndex(uint16_t x, uint16_t y)
63{
64 uint8_t i = 0;
65 // get index of key pressed
66 if (y < KEYPAD_KEY_HEIGHT) {
67 // 1st line:
68 i = 1 + x / KEY_WIDTH;
69 }
70 else if (y < (2 * KEYPAD_KEY_HEIGHT)) {
71 // 2nd line:
72 i = 4 + x / KEY_WIDTH;
73 }
74 else if (y < (3 * KEYPAD_KEY_HEIGHT)) {
75 // 3rd line:
76 i = 7 + x / KEY_WIDTH;
77 }
78 else if (y < (4 * KEYPAD_KEY_HEIGHT)) {
79 // 4th line
80 if (x < KEY_WIDTH) {
82 }
83 else if (x < (2 * KEY_WIDTH)) {
84 i = 0;
85 }
86 else {
88 }
89 }
90 return i;
91}
92
93static void keypadDrawGrid(nbgl_keypad_t *keypad)
94{
95 nbgl_area_t rectArea;
96
97 // clean full area
98 rectArea.backgroundColor = keypad->obj.area.backgroundColor;
99 rectArea.x0 = keypad->obj.area.x0;
100 rectArea.y0 = keypad->obj.area.y0;
101 rectArea.width = keypad->obj.area.width;
102 rectArea.height = keypad->obj.area.height;
103 nbgl_frontDrawRect(&rectArea);
104
106 rectArea.backgroundColor = keypad->obj.area.backgroundColor;
107 rectArea.x0 = keypad->obj.area.x0;
108 rectArea.y0 = keypad->obj.area.y0;
109 rectArea.width = keypad->obj.area.width;
110 rectArea.height = VERTICAL_ALIGNMENT;
111 nbgl_frontDrawHorizontalLine(&rectArea, 0x1, keypad->borderColor); // 1st line (top)
112 rectArea.y0 += KEYPAD_KEY_HEIGHT;
113 nbgl_frontDrawHorizontalLine(&rectArea, 0x1, keypad->borderColor); // 2nd line
114 rectArea.y0 += KEYPAD_KEY_HEIGHT;
115 nbgl_frontDrawHorizontalLine(&rectArea, 0x1, keypad->borderColor); // 3rd line
116 rectArea.y0 += KEYPAD_KEY_HEIGHT;
117 nbgl_frontDrawHorizontalLine(&rectArea, 0x1, keypad->borderColor); // 4th line
118
120 rectArea.backgroundColor = keypad->borderColor;
121 rectArea.x0 = keypad->obj.area.x0;
122 rectArea.y0 = keypad->obj.area.y0;
123 rectArea.width = 1;
124 rectArea.height = KEYPAD_KEY_HEIGHT * 4;
125 nbgl_frontDrawRect(&rectArea); // 1st full line, on the left
126 rectArea.x0 += KEY_WIDTH;
127 nbgl_frontDrawRect(&rectArea); // 2nd line
128 rectArea.x0 += KEY_WIDTH;
129 nbgl_frontDrawRect(&rectArea); // 3rd line
130}
131
132static void keypadDrawDigits(nbgl_keypad_t *keypad)
133{
134 uint8_t i;
135 nbgl_area_t rectArea;
136 char key_value;
137
138 rectArea.backgroundColor = keypad->obj.area.backgroundColor;
139 // only draw digits if not a partial refresh
140 if (!keypad->partial) {
141 rectArea.y0 = keypad->obj.area.y0 + DIGIT_OFFSET_Y;
142
143 // First row of keys: 1 2 3
144 for (i = 0; i < 3; i++) {
145 key_value = GET_DIGIT_INDEX(keypad, (i + 1)) + 0x30;
146
147 rectArea.x0 = keypad->obj.area.x0 + i * KEY_WIDTH;
148 rectArea.x0 += (KEY_WIDTH - nbgl_getCharWidth(LARGE_MEDIUM_FONT, &key_value)) / 2;
150 &rectArea, &key_value, 1, LARGE_MEDIUM_FONT, keypad->enableDigits ? BLACK : WHITE);
151 }
152 // Second row: 4 5 6
153 rectArea.y0 += KEYPAD_KEY_HEIGHT;
154 for (; i < 6; i++) {
155 key_value = GET_DIGIT_INDEX(keypad, (i + 1)) + 0x30;
156 rectArea.x0 = keypad->obj.area.x0 + (i - 3) * KEY_WIDTH;
157 rectArea.x0 += (KEY_WIDTH - nbgl_getCharWidth(LARGE_MEDIUM_FONT, &key_value)) / 2;
159 &rectArea, &key_value, 1, LARGE_MEDIUM_FONT, keypad->enableDigits ? BLACK : WHITE);
160 }
161 // Third row: 7 8 9
162 rectArea.y0 += KEYPAD_KEY_HEIGHT;
163 for (; i < 9; i++) {
164 key_value = GET_DIGIT_INDEX(keypad, (i + 1)) + 0x30;
165 rectArea.x0 = keypad->obj.area.x0 + (i - 6) * KEY_WIDTH;
166 rectArea.x0 += (KEY_WIDTH - nbgl_getCharWidth(LARGE_MEDIUM_FONT, &key_value)) / 2;
168 &rectArea, &key_value, 1, LARGE_MEDIUM_FONT, keypad->enableDigits ? BLACK : WHITE);
169 }
170 }
171 // 4th raw, Backspace, 0 and Validate
172 // draw backspace
173 rectArea.width = BACKSPACE_ICON.width;
174 rectArea.height = BACKSPACE_ICON.height;
175 rectArea.bpp = NBGL_BPP_1;
176 rectArea.x0 = keypad->obj.area.x0 + (KEY_WIDTH - rectArea.width) / 2;
177 rectArea.y0
178 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3 + (KEYPAD_KEY_HEIGHT - rectArea.height) / 2;
179 if (BACKSPACE_ICON.isFile) {
180 nbgl_frontDrawImageFile(&rectArea,
181 (uint8_t *) BACKSPACE_ICON.bitmap,
182 keypad->enableBackspace ? BLACK : WHITE,
183 ramBuffer);
184 }
185 else {
186 nbgl_frontDrawImage(&rectArea,
187 (uint8_t *) BACKSPACE_ICON.bitmap,
189 keypad->enableBackspace ? BLACK : WHITE);
190 }
191
192 // only draw '0' if not a partial refresh
193 if (!keypad->partial) {
194 // draw 0
195 key_value = GET_DIGIT_INDEX(keypad, 0) + 0x30;
196 rectArea.x0 = keypad->obj.area.x0 + KEY_WIDTH;
197 rectArea.x0 += (KEY_WIDTH - nbgl_getCharWidth(LARGE_MEDIUM_FONT, &key_value)) / 2;
198 rectArea.y0 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3 + DIGIT_OFFSET_Y;
200 &rectArea, &key_value, 1, LARGE_MEDIUM_FONT, keypad->enableDigits ? BLACK : WHITE);
201 }
202
203 // draw white background if validate not enabled
204 if (!keypad->enableValidate) {
205 rectArea.width = KEY_WIDTH - 1;
206 rectArea.height = KEYPAD_KEY_HEIGHT - 4;
207 rectArea.bpp = NBGL_BPP_1;
208 rectArea.x0 = keypad->obj.area.x0 + 2 * KEY_WIDTH + 1;
209 rectArea.y0 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3 + 4;
210 rectArea.backgroundColor = WHITE;
211 nbgl_frontDrawRect(&rectArea);
213 rectArea.backgroundColor = keypad->obj.area.backgroundColor;
214 rectArea.x0 = keypad->obj.area.x0 + 2 * KEY_WIDTH;
215 rectArea.y0 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3;
216 rectArea.width = KEY_WIDTH;
217 rectArea.height = VERTICAL_ALIGNMENT;
218 nbgl_frontDrawHorizontalLine(&rectArea, 0x1, keypad->borderColor); // 1st line (top)
220 rectArea.backgroundColor = keypad->borderColor;
221 rectArea.x0 = keypad->obj.area.x0 + 2 * KEY_WIDTH;
222 rectArea.y0 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3;
223 rectArea.width = 1;
224 rectArea.height = KEYPAD_KEY_HEIGHT;
225 nbgl_frontDrawRect(&rectArea); // 1st full line, on the left
226 }
227 else {
228 const nbgl_icon_details_t *icon;
229
230 if (keypad->softValidation) {
231 icon = &RIGHT_ARROW_ICON;
232 }
233 else {
234 icon = &VALIDATE_ICON;
235 }
236 // if enabled, draw icon in white on a black background
237 rectArea.backgroundColor = BLACK;
238 rectArea.x0 = keypad->obj.area.x0 + 2 * KEY_WIDTH;
239 rectArea.y0 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3;
240 rectArea.width = KEY_WIDTH;
241 rectArea.height = KEYPAD_KEY_HEIGHT;
242 nbgl_frontDrawRect(&rectArea);
243 rectArea.width = icon->width;
244 rectArea.height = icon->height;
245 rectArea.bpp = NBGL_BPP_1;
246 rectArea.x0 = keypad->obj.area.x0 + 2 * KEY_WIDTH + (KEY_WIDTH - rectArea.width) / 2;
247 rectArea.y0 = keypad->obj.area.y0 + KEYPAD_KEY_HEIGHT * 3
248 + (KEYPAD_KEY_HEIGHT - rectArea.height) / 2;
249 if (icon->isFile) {
250 nbgl_frontDrawImageFile(&rectArea, (uint8_t *) icon->bitmap, WHITE, ramBuffer);
251 }
252 else {
253 nbgl_frontDrawImage(&rectArea, (uint8_t *) icon->bitmap, NO_TRANSFORMATION, WHITE);
254 }
255 }
256}
257
258static void keypadDraw(nbgl_keypad_t *keypad)
259{
260 if (!keypad->partial) {
261 // At first, draw grid
262 keypadDrawGrid(keypad);
263 }
264
265 // then draw key content
266 keypadDrawDigits(keypad);
267 keypad->partial = false;
268}
269
270/**********************
271 * GLOBAL FUNCTIONS
272 **********************/
273
282{
283 uint8_t firstIndex, lastIndex;
284 nbgl_touchStatePosition_t *firstPosition, *lastPosition;
285 nbgl_keypad_t *keypad = (nbgl_keypad_t *) obj;
286
287 LOG_DEBUG(MISC_LOGGER, "nbgl_keypadTouchCallback(): eventType = %d\n", eventType);
288 if ((eventType != TOUCHED) && (eventType != TOUCH_PRESSED)) {
289 return;
290 }
291 if (nbgl_touchGetTouchedPosition(obj, &firstPosition, &lastPosition) == false) {
292 return;
293 }
294
295 // use positions relative to keypad position
296 firstIndex = getKeypadIndex(firstPosition->x - obj->area.x0, firstPosition->y - obj->area.y0);
297 if (firstIndex > VALIDATE_KEY_IDX) {
298 return;
299 }
300 lastIndex = getKeypadIndex(lastPosition->x - obj->area.x0, lastPosition->y - obj->area.y0);
301 if (lastIndex > VALIDATE_KEY_IDX) {
302 return;
303 }
304
305 // if position of finger has moved during press to another "key", drop it
306 if (lastIndex != firstIndex) {
307 return;
308 }
309
310 if ((firstIndex < 10) && (keypad->enableDigits)) {
311 // only call callback if event is TOUCHED, otherwise play tune on touch event (and not on
312 // release)
313 if (eventType == TOUCHED) {
314 keypad->callback(GET_DIGIT_INDEX(keypad, firstIndex) + 0x30);
315 }
316 else {
317 io_seproxyhal_play_tune(TUNE_TAP_CASUAL);
318 }
319 }
320 if ((firstIndex == BACKSPACE_KEY_IDX) && (keypad->enableBackspace)) { // backspace
321 // only call callback if event is TOUCHED, otherwise play tune on touch event (and not on
322 // release)
323 if (eventType == TOUCHED) {
324 keypad->callback(BACKSPACE_KEY);
325 }
326 else {
327 io_seproxyhal_play_tune(TUNE_TAP_CASUAL);
328 }
329 }
330 else if ((firstIndex == VALIDATE_KEY_IDX) && (keypad->enableValidate)) { // validate
331 // only call callback if event is TOUCHED
332 if (eventType == TOUCHED) {
333 keypad->callback(VALIDATE_KEY);
334 }
335 }
336}
337
349{
350 // if in first line
351 if ((index >= '1') && (index <= '3')) {
352 *x = kpd->obj.area.x0 + (index - '1') * KEY_WIDTH;
353 *y = kpd->obj.area.y0;
354 }
355 else if ((index >= '4') && (index <= '6')) {
356 *x = kpd->obj.area.x0 + (index - '4') * KEY_WIDTH;
357 *y = kpd->obj.area.y0 + KEYPAD_KEY_HEIGHT;
358 }
359 else if ((index >= '7') && (index <= '9')) {
360 *x = kpd->obj.area.x0 + (index - '7') * KEY_WIDTH;
361 *y = kpd->obj.area.y0 + (2 * KEYPAD_KEY_HEIGHT);
362 }
363 else if (index == BACKSPACE_KEY) { // backspace
364 *x = kpd->obj.area.x0;
365 *y = kpd->obj.area.y0 + (3 * KEYPAD_KEY_HEIGHT);
366 }
367 else if (index == '0') {
368 *x = kpd->obj.area.x0 + KEY_WIDTH;
369 *y = kpd->obj.area.y0 + (3 * KEYPAD_KEY_HEIGHT);
370 }
371 else if (index == VALIDATE_KEY) { // validate
372 *x = kpd->obj.area.x0 + (2 * KEY_WIDTH);
373 *y = kpd->obj.area.y0 + (3 * KEYPAD_KEY_HEIGHT);
374 }
375 else {
376 return false;
377 }
378 return true;
379}
380
388{
389 kpd->obj.touchMask = (1 << TOUCHED) | (1 << TOUCH_PRESSED);
390 kpd->obj.touchId = KEYPAD_ID;
391
392 // if the object has not been already used, prepare indexes of digits
393 if (kpd->digitIndexes[0] == 0) {
394 uint32_t i;
395 if (kpd->shuffled) {
396 uint8_t shuffledDigits[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
397
398 // modern version of the Fisher-Yates shuffle
399 for (i = 0; i < 9; i++) {
400 // pick a random number k in [i:9] intervale
401 uint32_t j = cx_rng_u32_range(i, 10);
402 uint8_t tmp = shuffledDigits[j];
403
404 // exchange shuffledDigits[i] and shuffledDigits[j]
405 shuffledDigits[j] = shuffledDigits[i];
406 shuffledDigits[i] = tmp;
407 }
408 for (i = 0; i < 10; i++) {
409 // apply the permuted value to digit i
410 SET_DIGIT_INDEX(kpd, i, shuffledDigits[i]);
411 }
412 }
413 else {
414 // no shuffling
415 for (i = 0; i < 10; i++) {
416 SET_DIGIT_INDEX(kpd, i, i);
417 }
418 }
419 }
420 keypadDraw(kpd);
421}
422
423#endif // HAVE_SE_TOUCH
424#endif // NBGL_KEYPAD
Random Number Generation.
debug traces management
#define LOG_DEBUG(__logger,...)
Definition nbgl_debug.h:86
@ MISC_LOGGER
Definition nbgl_debug.h:39
Middle Level API of the new BOLOS Graphical Library.
nbgl_font_id_e nbgl_drawText(const nbgl_area_t *area, const char *text, uint16_t textLen, nbgl_font_id_e fontId, color_t fontColor)
This function draws the given single-line text, with the given parameters.
Definition nbgl_draw.c:538
uint8_t nbgl_getCharWidth(nbgl_font_id_e fontId, const char *text)
return the width in pixels of the given UTF-8 character
Definition nbgl_fonts.c:362
Font screen low-Level driver API, to draw elementary forms.
void nbgl_frontDrawImage(const nbgl_area_t *area, const uint8_t *buffer, nbgl_transformation_t transformation, nbgl_color_map_t colorMap)
void nbgl_frontDrawImageFile(const nbgl_area_t *area, const uint8_t *buffer, nbgl_color_map_t colorMap, const uint8_t *uzlib_chunk_buffer)
void nbgl_frontDrawHorizontalLine(const nbgl_area_t *area, uint8_t mask, color_t lineColor)
void nbgl_frontDrawRect(const nbgl_area_t *area)
API to draw all basic graphic objects.
struct PACKED__ nbgl_keypad_s nbgl_keypad_t
struct to represent a keypad (KEYPAD type)
#define BACKSPACE_KEY
Definition nbgl_obj.h:26
@ KEYPAD_ID
Definition nbgl_obj.h:577
#define VALIDATE_KEY
Definition nbgl_obj.h:27
struct PACKED__ nbgl_obj_s nbgl_obj_t
Common structure for all graphical objects.
#define GET_DIGIT_INDEX(_keypad, _digit)
#define KEY_WIDTH
void nbgl_objDrawKeypad(nbgl_keypad_t *kpd)
This function draws a keypad object.
#define BACKSPACE_KEY_IDX
#define SET_DIGIT_INDEX(_keypad, _digit, _index)
void nbgl_keypadTouchCallback(nbgl_obj_t *obj, nbgl_touchType_t eventType)
function to be called when the keypad object is touched
#define VALIDATE_KEY_IDX
bool nbgl_keypadGetPosition(nbgl_keypad_t *kpd, char index, uint16_t *x, uint16_t *y)
This function gets the position (top-left corner) of the key at the given index. (to be used for Test...
uint8_t ramBuffer[GZLIB_UNCOMPRESSED_CHUNK]
Definition nbgl_obj.c:131
bool nbgl_touchGetTouchedPosition(nbgl_obj_t *obj, nbgl_touchStatePosition_t **firstPos, nbgl_touchStatePosition_t **lastPos)
Definition nbgl_touch.c:388
@ WHITE
Definition nbgl_types.h:124
@ BLACK
Definition nbgl_types.h:121
nbgl_touchType_t
The different types of Touchscreen events.
Definition nbgl_types.h:239
@ TOUCHED
Definition nbgl_types.h:240
@ TOUCH_PRESSED
Definition nbgl_types.h:247
struct PACKED__ nbgl_icon_details_s nbgl_icon_details_t
Represents all information about an icon.
#define GZLIB_UNCOMPRESSED_CHUNK
size of gzlib uncompression buffer in bytes
Definition nbgl_types.h:285
#define NO_TRANSFORMATION
Definition nbgl_types.h:74
@ NBGL_BPP_1
1 bit per pixel
Definition nbgl_types.h:264
struct PACKED__ nbgl_area_s nbgl_area_t
Represents a rectangle area of the screen.
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
unsigned short uint16_t
Definition usbd_conf.h:54
unsigned char uint8_t
Definition usbd_conf.h:53