1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-24 15:38:22 +00:00

fix(core/eckhart): fix passphrase keyboard bug

- when multi tab key timer expires, the buttons are resetted only if the passphrase reached the max length
- when the passphrase keyboard layout is swapped, the buttons are resetted
[no changelog]
This commit is contained in:
Lukas Bielesch 2025-05-13 10:35:03 +02:00 committed by Lukáš Bielesch
parent 26a52a5ed4
commit 9494ba8896
4 changed files with 7743 additions and 7727 deletions

View File

@ -139,6 +139,7 @@ pub(crate) enum DisplayStyle {
Hidden,
Shown,
LastOnly,
LastWithMarker,
}
/// The number and colors of fading icons to display.

View File

@ -362,9 +362,14 @@ impl Component for Keypad {
self.pressed = None;
return Some(KeypadMsg::EraseLong);
}
// Detect press of all special buttons for rendering purposes
// Detect press/release of all special buttons for rendering purposes
Some(ButtonMsg::Pressed) => {
self.pressed = Some(button);
return None;
}
Some(ButtonMsg::Released) => {
self.pressed = None;
return None;
}
_ => {}
}
@ -377,9 +382,14 @@ impl Component for Keypad {
self.pressed = None;
return Some(KeypadMsg::Key(idx));
}
// Detect press of all key buttons for rendering purposes
// Detect press/release of all key buttons for rendering purposes
Some(ButtonMsg::Pressed) => {
self.pressed = Some(KeypadButton::Key(idx));
return None;
}
Some(ButtonMsg::Released) => {
self.pressed = None;
return None;
}
_ => {}
}

View File

@ -106,7 +106,7 @@ const KEYBOARD: [[&str; KEY_COUNT]; PAGE_COUNT] = [
const MAX_LENGTH: usize = 50; // max length of the passphrase
const MAX_SHOWN_LEN: usize = 14; // max number of icons per line
const LAST_DIGIT_TIMEOUT_S: u32 = 1;
const LAST_DIGIT_TIMEOUT: Duration = Duration::from_secs(1);
const NEXT_BTN_WIDTH: i16 = 103;
const NEXT_BTN_PADDING: i16 = 14;
@ -176,14 +176,13 @@ impl PassphraseKeyboard {
if self.multi_tap.pending_key().is_some() {
// Clear the pending state.
self.multi_tap.clear_pending_state(ctx);
self.input.marker = false;
self.input.display_style = DisplayStyle::LastOnly;
// the character has been added, show it for a bit and then hide it
self.input
.last_char_timer
.start(ctx, Duration::from_secs(LAST_DIGIT_TIMEOUT_S));
self.input.last_char_timer.start(ctx, LAST_DIGIT_TIMEOUT);
}
// Update keys.
self.replace_keys_contents();
self.update_keypad_state(ctx);
}
fn replace_keys_contents(&mut self) {
@ -200,6 +199,8 @@ impl PassphraseKeyboard {
}
}
/// Update the keypad state based on the current passphrase and input state
/// Can be used only when no key is pressed
fn update_keypad_state(&mut self, ctx: &mut EventCtx) {
let keypad_state = match self.input.display_style {
DisplayStyle::Shown => {
@ -304,21 +305,45 @@ impl Component for PassphraseKeyboard {
}
Event::Timer(_) if self.multi_tap.timeout_event(event) => {
self.multi_tap.clear_pending_state(ctx);
self.input
.last_char_timer
.start(ctx, Duration::from_secs(LAST_DIGIT_TIMEOUT_S));
self.input.marker = false;
self.update_keypad_state(ctx);
self.input.last_char_timer.start(ctx, LAST_DIGIT_TIMEOUT);
self.input.display_style = DisplayStyle::LastOnly;
// Disable keypad when the passphrase reached the max length
if self.passphrase().len() == MAX_LENGTH {
self.update_keypad_state(ctx);
}
return None;
}
_ => {}
}
// Input event has to be handled before the swipe so that swipe in the input
// area is not processed
match self.input.event(ctx, event) {
Some(PassphraseInputMsg::TouchStart) => {
self.multi_tap.clear_pending_state(ctx);
// Disable keypad.
self.update_keypad_state(ctx);
return None;
}
Some(PassphraseInputMsg::TouchEnd) => {
// Enable keypad.
self.update_keypad_state(ctx);
return None;
}
_ => {}
}
// Swipe event has to be handled before the individual button events
if let Some(swipe) = self.page_swipe.event(ctx, event) {
// We have detected a horizontal swipe. Change the keyboard page.
self.on_page_change(ctx, swipe);
return None;
match swipe {
Direction::Left | Direction::Right => {
// We have detected a horizontal swipe. Change the keyboard page.
self.on_page_change(ctx, swipe);
return None;
}
_ => {}
}
}
if let Some(ButtonMsg::Clicked) = self.next_btn.event(ctx, event) {
@ -333,16 +358,13 @@ impl Component for PassphraseKeyboard {
if text.len() == 1 {
// If the key has just one character, it is immediately applied and the last
// digit timer should be started
self.input.marker = false;
self.input
.last_char_timer
.start(ctx, Duration::from_secs(LAST_DIGIT_TIMEOUT_S));
self.input.display_style = DisplayStyle::LastOnly;
self.input.last_char_timer.start(ctx, LAST_DIGIT_TIMEOUT);
} else {
// multi tap timer is runnig, the last digit timer should be stopped
self.input.last_char_timer.stop();
self.input.marker = true;
self.input.display_style = DisplayStyle::LastWithMarker;
}
self.input.display_style = DisplayStyle::LastOnly;
self.update_keypad_state(ctx);
}
return None;
@ -372,21 +394,6 @@ impl Component for PassphraseKeyboard {
_ => {}
}
match self.input.event(ctx, event) {
Some(PassphraseInputMsg::TouchStart) => {
self.multi_tap.clear_pending_state(ctx);
// Disable keypad.
self.update_keypad_state(ctx);
return None;
}
Some(PassphraseInputMsg::TouchEnd) => {
// Enable keypad.
self.update_keypad_state(ctx);
return None;
}
_ => {}
}
None
}
@ -433,7 +440,6 @@ struct PassphraseInput {
area: Rect,
textbox: TextBox,
display_style: DisplayStyle,
marker: bool,
last_char_timer: Timer,
shown_area: Rect,
}
@ -451,8 +457,7 @@ impl PassphraseInput {
Self {
area: Rect::zero(),
textbox: TextBox::empty(MAX_LENGTH),
display_style: DisplayStyle::LastOnly,
marker: false,
display_style: DisplayStyle::Hidden,
last_char_timer: Timer::new(),
shown_area: Rect::zero(),
}
@ -503,7 +508,7 @@ impl PassphraseInput {
let hidden_area: Rect = self.area.inset(KEYBOARD_INPUT_INSETS);
let style = theme::TEXT_MEDIUM;
let pp_len = self.passphrase().len();
let last_char = self.display_style == DisplayStyle::LastOnly;
let last_char = self.display_style != DisplayStyle::Hidden;
let mut cursor = hidden_area.left_center().ofs(Offset::x(12));
@ -560,7 +565,7 @@ impl PassphraseInput {
.render(target);
// Paint the pending marker.
if self.marker {
if self.display_style == DisplayStyle::LastWithMarker {
render_pending_marker(target, cursor, last, style.text_font, style.text_color);
}
}

File diff suppressed because it is too large Load Diff