diff --git a/legacy/firmware/Makefile b/legacy/firmware/Makefile
index 1e94db790..15464c8e2 100644
--- a/legacy/firmware/Makefile
+++ b/legacy/firmware/Makefile
@@ -25,6 +25,7 @@ OBJS += recovery.o
OBJS += reset.o
OBJS += signing.o
OBJS += crypto.o
+OBJS += keyboard.o
ifneq ($(BITCOIN_ONLY),1)
OBJS += u2f.o
diff --git a/legacy/firmware/keyboard.c b/legacy/firmware/keyboard.c
new file mode 100644
index 000000000..ca39b884d
--- /dev/null
+++ b/legacy/firmware/keyboard.c
@@ -0,0 +1,441 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (C) 2019 SatoshiLabs
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#include "keyboard.h"
+#include
+#include "buttons.h"
+#include "memzero.h"
+#include "oled.h"
+#include "usb.h"
+
+#define BTN_WIDTH 23
+#define BTN_HEIGHT 11
+#define BTN_X_SEP 4
+#define BTN_Y_SEP 3
+#define KBD_COLS 3
+#define KBD_ROWS 4
+#define KBD_SIZE (KBD_COLS * KBD_ROWS)
+#define KBD_X_OFFSET 26
+#define KBD_Y_OFFSET 10
+#define KBD_HEIGHT (KBD_ROWS * (BTN_HEIGHT + BTN_Y_SEP) - BTN_Y_SEP + 1)
+#define KBD_WIDTH (KBD_COLS * (BTN_WIDTH + BTN_X_SEP) - BTN_X_SEP + 1)
+#define KBD_COUNT 4
+#define MAX_INPUT_LEN 50
+const char *KBD_LABELS[KBD_COUNT][KBD_SIZE] = {
+ {"abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz ", "", "*#",
+ ""},
+ {"ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VWX", "YZ ", "", "*#",
+ ""},
+ {"_<>", ".:@", "/|\\", "!()", "+%&", "-[]", "?{}", ",'`", ";\"~", "",
+ "$^=", ""},
+ {"1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", ""},
+};
+
+#define BTN_BACKSPACE 9
+#define BTN_DONE 11
+#define LABEL_BACKSPACE "Bksp"
+#define LABEL_CANCEL "Exit"
+#define LABEL_DONE "OK"
+
+#define CURSOR_WIDTH 5
+#define CURSOR_HEIGHT 2
+static int select_index = -1;
+static int kbd_layout = 0;
+
+enum {
+ STATUS_IN_PROGRESS = 0,
+ STATUS_DONE = 1,
+ STATUS_CANCELLED = 2,
+} status = STATUS_IN_PROGRESS;
+
+#define INPUT_OFFSET KBD_X_OFFSET
+#define TEXT_OFFSET 0
+CONFIDENTIAL char input[MAX_INPUT_LEN + 1] = "";
+
+static void drawBtn(int i, const char *text) {
+ int x = KBD_X_OFFSET + (i % KBD_COLS) * (BTN_WIDTH + BTN_X_SEP);
+ int y = KBD_Y_OFFSET + (i / KBD_COLS) * (BTN_HEIGHT + BTN_Y_SEP);
+ for (int j = 0; j < BTN_WIDTH; j++) {
+ oledDrawPixel(x + j, y - 1);
+ oledDrawPixel(x + j, y + BTN_HEIGHT);
+ }
+ for (int j = 0; j < BTN_HEIGHT; j++) {
+ oledDrawPixel(x - 1, y + j);
+ oledDrawPixel(x + BTN_WIDTH, y + j);
+ }
+ oledDrawStringCenter(x + BTN_WIDTH / 2 + 1, y + 2, text, FONT_STANDARD);
+}
+
+static void drawBtnLeft(const char *label) {
+ int x = KBD_X_OFFSET - BTN_X_SEP;
+ oledBox(0, OLED_HEIGHT - 9, x, OLED_HEIGHT - 1, false);
+ if (label)
+ oledDrawStringCenter(KBD_X_OFFSET / 2 - 1, OLED_HEIGHT - 8, label,
+ FONT_STANDARD);
+ else
+ oledDrawBitmap(3, OLED_HEIGHT - 7, &bmp_btn_up);
+ oledInvert(0, OLED_HEIGHT - 9, x, OLED_HEIGHT - 1);
+}
+
+static void drawBtnRight(const char *label) {
+ int x = KBD_X_OFFSET + KBD_COLS * (BTN_WIDTH + BTN_X_SEP) - 1;
+ oledBox(x, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1, false);
+ if (label)
+ oledDrawStringCenter((OLED_WIDTH + x + 1) / 2, OLED_HEIGHT - 8, label,
+ FONT_STANDARD);
+ else
+ oledDrawBitmap(OLED_WIDTH - 14, OLED_HEIGHT - 8, &bmp_btn_right);
+ oledInvert(x, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1);
+}
+
+static void drawKeyboard(void) {
+ oledBox(KBD_X_OFFSET, KBD_Y_OFFSET, KBD_X_OFFSET + KBD_WIDTH - 1,
+ KBD_Y_OFFSET + KBD_HEIGHT - 1, false);
+
+ for (int i = 0; i < KBD_SIZE; ++i) {
+ drawBtn(i, KBD_LABELS[kbd_layout][i]);
+ }
+
+ int x = KBD_X_OFFSET + 0 * (BTN_WIDTH + BTN_X_SEP);
+ int y = KBD_Y_OFFSET + 3 * (BTN_HEIGHT + BTN_Y_SEP);
+ if (input[0] == '\0') {
+ oledDrawBitmap(x + 8, y + 2, &bmp_btn_cancel);
+ } else {
+ oledDrawBitmap(x + 3, y + 1, &bmp_btn_backspace);
+ }
+
+ x = KBD_X_OFFSET + 2 * (BTN_WIDTH + BTN_X_SEP);
+ y = KBD_Y_OFFSET + 3 * (BTN_HEIGHT + BTN_Y_SEP);
+ oledDrawBitmap(x + 8, y + 2, &bmp_btn_confirm);
+}
+
+static void drawCursor(void) {
+ int x = INPUT_OFFSET + oledStringWidth(input, FONT_STANDARD);
+ oledBox(x, FONT_HEIGHT - CURSOR_HEIGHT, x + CURSOR_WIDTH - 1, FONT_HEIGHT - 1,
+ true);
+}
+
+static void invertBtn(int i, int j) {
+ int x = KBD_X_OFFSET + i * (BTN_WIDTH + BTN_X_SEP);
+ int y = KBD_Y_OFFSET + j * (BTN_HEIGHT + BTN_Y_SEP);
+ oledInvert(x, y, x + BTN_WIDTH - 1, y + BTN_HEIGHT - 1);
+ oledRefresh();
+}
+
+static void pressBtn(int btn) {
+ int len = strlen(input);
+ if (btn == BTN_DONE) {
+ status = STATUS_DONE;
+ } else if (btn == BTN_BACKSPACE) {
+ if (len > 0) {
+ input[len - 1] = '\0';
+ if (len == 1) {
+ // Replace backspace with cancel button.
+ drawKeyboard();
+ select_index = -2; // Avoid accidentally pressing the cancel button.
+ }
+ } else if (select_index == -1) {
+ // Cancel only if this is not a repeated pressing of backspace.
+ status = STATUS_CANCELLED;
+ }
+ } else {
+ int btn_len = strlen(KBD_LABELS[kbd_layout][btn]);
+ int pos = len;
+ if (select_index >= 0) {
+ pos -= 1;
+ select_index = (select_index + 1) % btn_len;
+ } else {
+ select_index = 0;
+ }
+ if (pos < MAX_INPUT_LEN) {
+ input[pos] = KBD_LABELS[kbd_layout][btn][select_index];
+ input[pos + 1] = '\0';
+ }
+
+ if (len == 0 && pos == 0) {
+ // Replace cancel button with backspace.
+ drawKeyboard();
+ }
+
+ if (btn_len == 1) {
+ // If the button has only one symbol, then pressing it repeatedly should
+ // cause the symbol to be typed repeatedly.
+ select_index = -1;
+ }
+ }
+ oledBox(TEXT_OFFSET, 0, OLED_WIDTH - 1, FONT_HEIGHT, false);
+ oledDrawString(INPUT_OFFSET, 0, input, FONT_STANDARD);
+ if (select_index < 0) drawCursor();
+}
+
+const char *pin_keyboard(const char *text) {
+ input[0] = '\0';
+ select_index = -1;
+ status = STATUS_IN_PROGRESS;
+ kbd_layout = 3;
+
+ oledClear();
+ oledDrawString(TEXT_OFFSET, 0, text, FONT_STANDARD);
+ drawKeyboard();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+
+ int i = 0;
+ int j = 0;
+ bool left_shift = false;
+ bool right_shift = false;
+ invertBtn(i, j);
+ while (status == STATUS_IN_PROGRESS) {
+ usbSleep(5);
+ bool refresh = false;
+
+ buttonUpdate();
+ if (button.YesReleased) {
+ if (right_shift) {
+ right_shift = false;
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ invertBtn(i, j);
+ if (button.YesDown > button.NoDown) {
+ // Right
+ if (i == KBD_COLS - 1) {
+ i = 0;
+ j = (j + 1) % KBD_ROWS;
+ } else {
+ i = i + 1;
+ }
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ // Shift + Right
+ pressBtn(i + j * KBD_COLS);
+ left_shift = true;
+ drawBtnLeft("");
+ }
+ invertBtn(i, j);
+ }
+ refresh = true;
+ } else if (button.NoReleased) {
+ if (left_shift) {
+ left_shift = false;
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ invertBtn(i, j);
+ if (button.NoDown > button.YesDown) {
+ // Left
+ i = 0;
+ j = (j - 1 + KBD_ROWS) % KBD_ROWS;
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ // Shift + Left
+ pressBtn(i + j * KBD_COLS);
+ right_shift = true;
+ drawBtnRight("");
+ }
+ invertBtn(i, j);
+ }
+ refresh = true;
+ }
+
+ if (button.NoDown == 1 && button.YesDown <= 1) {
+ int btn = i + j * KBD_COLS;
+ const char *label = NULL;
+ if (btn == BTN_BACKSPACE) {
+ if (input[0] == '\0') {
+ label = LABEL_CANCEL;
+ } else {
+ label = LABEL_BACKSPACE;
+ }
+ } else if (btn == BTN_DONE) {
+ label = LABEL_DONE;
+ } else {
+ label = KBD_LABELS[kbd_layout][btn];
+ }
+ drawBtnRight(label);
+ refresh = true;
+ }
+
+ if (button.YesDown == 1 && button.NoDown <= 1) {
+ int btn = i + j * KBD_COLS;
+ const char *label = NULL;
+ if (btn == BTN_BACKSPACE) {
+ if (input[0] == '\0') {
+ label = LABEL_CANCEL;
+ } else {
+ label = LABEL_BACKSPACE;
+ }
+ } else if (btn == BTN_DONE) {
+ label = LABEL_DONE;
+ } else {
+ label = KBD_LABELS[kbd_layout][btn];
+ }
+ drawBtnLeft(label);
+ refresh = true;
+ }
+
+ if (refresh) {
+ oledRefresh();
+ }
+ }
+
+ // Wait for buttons to be released.
+ while (button.NoDown || button.YesDown) {
+ usbSleep(5);
+ buttonUpdate();
+ }
+
+ if (status == STATUS_DONE) {
+ return input;
+ } else {
+ return NULL;
+ }
+}
+
+const char *passphrase_keyboard(const char *text) {
+ input[0] = '\0';
+ select_index = -1;
+ status = STATUS_IN_PROGRESS;
+ kbd_layout = 0;
+
+ oledClear();
+ oledDrawString(TEXT_OFFSET, 0, text, FONT_STANDARD);
+ drawKeyboard();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+
+ int i = 0;
+ int j = 0;
+ bool left_shift = false;
+ bool right_shift = false;
+ invertBtn(i, j);
+ while (status == STATUS_IN_PROGRESS) {
+ usbSleep(5);
+ bool refresh = false;
+
+ buttonUpdate();
+ if (button.YesReleased) {
+ if (right_shift) {
+ right_shift = false;
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ invertBtn(i, j);
+ if (button.YesDown > button.NoDown) {
+ // Right
+ if (i == KBD_COLS - 1) {
+ i = 0;
+ j = (j + 1) % KBD_ROWS;
+ } else {
+ i = i + 1;
+ }
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ // Shift + Right
+ pressBtn(i + j * KBD_COLS);
+ left_shift = true;
+ drawBtnLeft("");
+ }
+ invertBtn(i, j);
+ }
+ refresh = true;
+ } else if (button.NoReleased) {
+ if (left_shift) {
+ left_shift = false;
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ invertBtn(i, j);
+ if (button.NoDown > button.YesDown) {
+ // Left
+ i = 0;
+ j = (j - 1 + KBD_ROWS) % KBD_ROWS;
+ select_index = -1;
+ drawCursor();
+ drawBtnLeft(NULL);
+ drawBtnRight(NULL);
+ } else {
+ // Shift + Left
+ kbd_layout = (kbd_layout + 1) % KBD_COUNT;
+ drawKeyboard();
+ right_shift = true;
+ drawBtnRight("");
+ }
+ invertBtn(i, j);
+ }
+ refresh = true;
+ }
+
+ if (button.NoDown == 1 && button.YesDown <= 1) {
+ int btn = i + j * KBD_COLS;
+ const char *label = NULL;
+ if (btn == BTN_BACKSPACE) {
+ if (input[0] == '\0') {
+ label = LABEL_CANCEL;
+ } else {
+ label = LABEL_BACKSPACE;
+ }
+ } else if (btn == BTN_DONE) {
+ label = LABEL_DONE;
+ } else {
+ label = KBD_LABELS[kbd_layout][btn];
+ }
+ drawBtnRight(label);
+ refresh = true;
+ }
+
+ if (button.YesDown == 1 && button.NoDown <= 1) {
+ drawBtnLeft("0aA!");
+ refresh = true;
+ }
+
+ if (refresh) {
+ oledRefresh();
+ }
+ }
+
+ // Wait for buttons to be released.
+ while (button.NoDown || button.YesDown) {
+ usbSleep(5);
+ buttonUpdate();
+ }
+
+ if (status == STATUS_DONE) {
+ return input;
+ } else {
+ return NULL;
+ }
+}
diff --git a/legacy/firmware/keyboard.h b/legacy/firmware/keyboard.h
new file mode 100644
index 000000000..7d142c835
--- /dev/null
+++ b/legacy/firmware/keyboard.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (C) 2019 SatoshiLabs
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see .
+ */
+
+#ifndef __KEYBOARD_H__
+#define __KEYBOARD_H__
+
+const char *passphrase_keyboard(const char *text);
+const char *pin_keyboard(const char *text);
+
+#endif
diff --git a/legacy/firmware/protect.c b/legacy/firmware/protect.c
index e58e8ac38..7df3e2c89 100644
--- a/legacy/firmware/protect.c
+++ b/legacy/firmware/protect.c
@@ -23,6 +23,7 @@
#include "debug.h"
#include "fsm.h"
#include "gettext.h"
+#include "keyboard.h"
#include "layout2.h"
#include "memory.h"
#include "memzero.h"
@@ -33,8 +34,6 @@
#include "usb.h"
#include "util.h"
-#define MAX_WRONG_PINS 15
-
bool protectAbortedByCancel = false;
bool protectAbortedByInitialize = false;
@@ -112,6 +111,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only) {
}
const char *requestPin(PinMatrixRequestType type, const char *text) {
+ return pin_keyboard(text);
PinMatrixRequest resp = {0};
memzero(&resp, sizeof(PinMatrixRequest));
resp.has_type = true;
diff --git a/legacy/gen/bitmaps.c b/legacy/gen/bitmaps.c
index f1da68e47..277d7b81e 100644
--- a/legacy/gen/bitmaps.c
+++ b/legacy/gen/bitmaps.c
@@ -1,8 +1,14 @@
// clang-format off
#include "bitmaps.h"
+const uint8_t bmp_btn_backspace_data[] = { 0x07, 0xfe, 0x0e, 0xee, 0x1c, 0x46, 0x3e, 0x0e, 0x7f, 0x1e, 0x3e, 0x0e, 0x1c, 0x46, 0x0e, 0xee, 0x07, 0xfe, };
const uint8_t bmp_btn_cancel_data[] = { 0x44, 0xee, 0x7c, 0x38, 0x7c, 0xee, 0x44, 0x00, };
const uint8_t bmp_btn_confirm_data[] = { 0x02, 0x04, 0x08, 0xd8, 0xf0, 0x60, 0x20, 0x00, };
+const uint8_t bmp_btn_down_data[] = { 0x08, 0x20, 0x1c, 0x70, 0x0e, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, };
+const uint8_t bmp_btn_left_data[] = { 0x0e, 0x1c, 0x38, 0x70, 0x38, 0x1c, 0x0e, };
+const uint8_t bmp_btn_right_data[] = { 0x70, 0x38, 0x1c, 0x0e, 0x1c, 0x38, 0x70, };
+const uint8_t bmp_btn_up_data[] = { 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0x70, 0x0e, 0x38, 0x04, 0x10, };
+const uint8_t bmp_btn_upleft_data[] = { 0xfe, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, };
const uint8_t bmp_digit0_data[] = { 0xff, 0xff, 0xf8, 0x1f, 0xf0, 0x0f, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xe1, 0x87, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, };
const uint8_t bmp_digit1_data[] = { 0xff, 0xff, 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x3f, 0xf0, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xff, 0xff, };
const uint8_t bmp_digit2_data[] = { 0xff, 0xff, 0xe0, 0x1f, 0xe0, 0x0f, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xff, 0x87, 0xf8, 0x0f, 0xf0, 0x1f, 0xe1, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0x07, 0xe0, 0x07, 0xff, 0xff, };
@@ -28,8 +34,14 @@ const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x
const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x07, 0xe0, 0x10, 0x00, 0x00, 0x10, 0x08, 0x10, 0x08, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x20, 0x20, 0x04, 0x04, 0x00, 0x00, 0x20, 0x40, 0x02, 0x04, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x00, 0x40, 0x80, 0x01, 0x02, 0x00, 0x1f, 0xc0, 0xff, 0xff, 0x03, 0xf8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x3f, 0xff, 0xff, 0xfc, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x04, 0x08, 0x10, 0x18, 0x00, 0x00, 0x18, 0x08, 0x10, 0x06, 0x00, 0x00, 0x60, 0x08, 0x10, 0x01, 0x80, 0x01, 0x80, 0x08, 0x10, 0x00, 0x60, 0x06, 0x00, 0x08, 0x18, 0x00, 0x18, 0x18, 0x00, 0x18, 0x06, 0x00, 0x06, 0x60, 0x00, 0x60, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
const uint8_t bmp_webauthn_data[] = { 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x03, 0xfe, 0x1c, 0x00, 0x03, 0xfc, 0x0c, 0x00, 0x07, 0xf8, 0x06, 0x00, 0x07, 0xf8, 0x06, 0x00, 0x0f, 0xf8, 0x06, 0x00, 0x0f, 0xf8, 0x07, 0x00, 0x0f, 0xfc, 0x0f, 0x00, 0x0f, 0xfe, 0x1f, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xdf, 0x80, 0x03, 0xff, 0x80, 0x00, 0x07, 0xff, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, };
+const BITMAP bmp_btn_backspace = {16, 9, bmp_btn_backspace_data};
const BITMAP bmp_btn_cancel = {8, 8, bmp_btn_cancel_data};
const BITMAP bmp_btn_confirm = {8, 8, bmp_btn_confirm_data};
+const BITMAP bmp_btn_down = {16, 6, bmp_btn_down_data};
+const BITMAP bmp_btn_left = {8, 7, bmp_btn_left_data};
+const BITMAP bmp_btn_right = {8, 7, bmp_btn_right_data};
+const BITMAP bmp_btn_up = {16, 6, bmp_btn_up_data};
+const BITMAP bmp_btn_upleft = {8, 7, bmp_btn_upleft_data};
const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data};
const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data};
const BITMAP bmp_digit2 = {16, 16, bmp_digit2_data};
diff --git a/legacy/gen/bitmaps.h b/legacy/gen/bitmaps.h
index 08809e118..c1810fbcb 100644
--- a/legacy/gen/bitmaps.h
+++ b/legacy/gen/bitmaps.h
@@ -8,8 +8,14 @@ typedef struct {
const uint8_t *data;
} BITMAP;
+extern const BITMAP bmp_btn_backspace;
extern const BITMAP bmp_btn_cancel;
extern const BITMAP bmp_btn_confirm;
+extern const BITMAP bmp_btn_down;
+extern const BITMAP bmp_btn_left;
+extern const BITMAP bmp_btn_right;
+extern const BITMAP bmp_btn_up;
+extern const BITMAP bmp_btn_upleft;
extern const BITMAP bmp_digit0;
extern const BITMAP bmp_digit1;
extern const BITMAP bmp_digit2;
diff --git a/legacy/gen/bitmaps/btn_backspace.png b/legacy/gen/bitmaps/btn_backspace.png
new file mode 100644
index 000000000..d84ec1101
Binary files /dev/null and b/legacy/gen/bitmaps/btn_backspace.png differ
diff --git a/legacy/gen/bitmaps/btn_down.png b/legacy/gen/bitmaps/btn_down.png
new file mode 100644
index 000000000..16587b39b
Binary files /dev/null and b/legacy/gen/bitmaps/btn_down.png differ
diff --git a/legacy/gen/bitmaps/btn_left.png b/legacy/gen/bitmaps/btn_left.png
new file mode 100644
index 000000000..f4a7dae12
Binary files /dev/null and b/legacy/gen/bitmaps/btn_left.png differ
diff --git a/legacy/gen/bitmaps/btn_right.png b/legacy/gen/bitmaps/btn_right.png
new file mode 100644
index 000000000..7429da4c3
Binary files /dev/null and b/legacy/gen/bitmaps/btn_right.png differ
diff --git a/legacy/gen/bitmaps/btn_up.png b/legacy/gen/bitmaps/btn_up.png
new file mode 100644
index 000000000..a74a3d938
Binary files /dev/null and b/legacy/gen/bitmaps/btn_up.png differ
diff --git a/legacy/gen/bitmaps/btn_upleft.png b/legacy/gen/bitmaps/btn_upleft.png
new file mode 100644
index 000000000..0b982a94e
Binary files /dev/null and b/legacy/gen/bitmaps/btn_upleft.png differ