What changed, and why it matters
This commit fixes the direction of PIN-entry wheel navigation on TTGO hardware variants of the Blockstream Jade hardware wallet so it matches the rest of the device's user interface. It is a device-specific usability fix, not a cryptographic or network security fix. There is no indication it allows an attacker to steal funds, bypass the PIN, or access private keys.
No security action required; treat as a normal usability/UX fix. Users of TTGO-based Jade devices may update to obtain consistent PIN-entry navigation.
Security signals we found
No security-relevant signals present in the diff
Change is limited to UI event mapping for a specific hardware board type
Evidence from the diff
The change adds a compile-time helper pin_entry_invert_navigation() that returns true for TTGO_TDISPLAY and TTGO_TDISPLAYS3 board types. In run_pin_entry_loop(), when this helper is true, incoming GUI_WHEEL_LEFT_EVENT and GUI_WHEEL_RIGHT_EVENT IDs are swapped before the existing switch statement processes them. This makes the on-screen PIN entry cursor move in the same direction as other UI screens on these boards. The patch is purely a UI navigation-direction correction; it does not alter PIN validation, storage, encryption, or any security-critical logic.
Changed components
main/ui/pin.cTTGO T-Display and TTGO T-Display S3 variants of Blockstream JadeInspect captured patch +18 / −0
diff --git a/main/ui/pin.c b/main/ui/pin.c
index 8bf9f45..72075d7 100644
--- a/main/ui/pin.c
+++ b/main/ui/pin.c
@@ -11,6 +11,16 @@ static const char PIN_CHARS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '
static const uint32_t NUM_PIN_CHARS = sizeof(PIN_CHARS) / sizeof(PIN_CHARS[0]);
static const uint32_t NUM_PIN_VALUES = NUM_PIN_CHARS - 1; // ie. not including backspace
+static inline bool pin_entry_invert_navigation(void)
+{
+#if defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAYS3)
+ // TTGO boards need to locally invert navigation so PIN entry matches the rest of the UI.
+ return true;
+#else
+ return false;
+#endif
+}
+
static inline char get_pin_value(size_t index)
{
JADE_ASSERT(index < NUM_PIN_CHARS);
@@ -194,6 +204,14 @@ bool run_pin_entry_loop(pin_insert_t* pin_insert)
while (true) {
// wait for a GUI event
gui_activity_wait_event(pin_insert->activity, GUI_EVENT, ESP_EVENT_ANY_ID, NULL, &ev_id, NULL, 0);
+ if (pin_entry_invert_navigation()) {
+ // Swap left/right wheel events
+ if (ev_id == GUI_WHEEL_LEFT_EVENT) {
+ ev_id = GUI_WHEEL_RIGHT_EVENT;
+ } else if (ev_id == GUI_WHEEL_RIGHT_EVENT) {
+ ev_id = GUI_WHEEL_LEFT_EVENT;
+ }
+ }
switch (ev_id) {
case GUI_WHEEL_LEFT_EVENT:
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.