From 4423b47b6c11ca8148b18feaed8e24ca194b339f Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Thu, 22 May 2025 03:44:15 +0800 Subject: [PATCH] system/ui: add password mask delay to InputBox (#35316) add password mask delay to InputBox --- system/ui/lib/inputbox.py | 29 ++++++++++++++++++++++++++--- system/ui/widgets/keyboard.py | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/system/ui/lib/inputbox.py b/system/ui/lib/inputbox.py index 87e0e92d51..367e0dc7e4 100644 --- a/system/ui/lib/inputbox.py +++ b/system/ui/lib/inputbox.py @@ -1,8 +1,10 @@ import pyray as rl +import time from openpilot.system.ui.lib.application import gui_app PASSWORD_MASK_CHAR = "•" +PASSWORD_MASK_DELAY = 1.5 # Seconds to show character before masking class InputBox: @@ -19,6 +21,8 @@ class InputBox: self._repeat_rate = 4 self._text_offset = 0 self._visible_width = 0 + self._last_char_time = 0 # Track when last character was added + self._masked_length = 0 # How many characters are currently masked @property def text(self): @@ -52,7 +56,7 @@ class InputBox: return font = gui_app.font() - display_text = PASSWORD_MASK_CHAR * len(self._input_text) if self._password_mode else self._input_text + display_text = self._get_display_text() padding = 10 if self._cursor_position > 0: @@ -73,6 +77,10 @@ class InputBox: if len(self._input_text) < self._max_text_size: self._input_text = self._input_text[: self._cursor_position] + char + self._input_text[self._cursor_position :] self.set_cursor_position(self._cursor_position + 1) + + if self._password_mode: + self._last_char_time = time.time() + return True return False @@ -114,7 +122,7 @@ class InputBox: # Display text font = gui_app.font() - display_text = PASSWORD_MASK_CHAR * len(self._input_text) if self._password_mode else self._input_text + display_text = self._get_display_text() padding = 10 # Clip text within input box bounds @@ -144,6 +152,21 @@ class InputBox: rl.end_scissor_mode() + def _get_display_text(self): + """Get text to display, applying password masking with delay if needed.""" + if not self._password_mode: + return self._input_text + + # Show character at last edited position if within delay window + masked_text = PASSWORD_MASK_CHAR * len(self._input_text) + recent_edit = time.time() - self._last_char_time < PASSWORD_MASK_DELAY + if recent_edit and self._input_text: + last_pos = max(0, self._cursor_position - 1) + if last_pos < len(self._input_text): + return masked_text[:last_pos] + self._input_text[last_pos] + masked_text[last_pos + 1 :] + + return masked_text + def _handle_mouse_input(self, rect, font_size): """Handle mouse clicks to position cursor.""" mouse_pos = rl.get_mouse_position() @@ -151,7 +174,7 @@ class InputBox: # Calculate cursor position from click if len(self._input_text) > 0: font = gui_app.font() - display_text = PASSWORD_MASK_CHAR * len(self._input_text) if self._password_mode else self._input_text + display_text = self._get_display_text() # Find the closest character position to the click relative_x = mouse_pos.x - (rect.x + 10) + self._text_offset diff --git a/system/ui/widgets/keyboard.py b/system/ui/widgets/keyboard.py index 7836b28184..0e22f1b527 100644 --- a/system/ui/widgets/keyboard.py +++ b/system/ui/widgets/keyboard.py @@ -221,7 +221,7 @@ class Keyboard: if __name__ == "__main__": gui_app.init_window("Keyboard") - keyboard = Keyboard(min_text_size=8) + keyboard = Keyboard(min_text_size=8, show_password_toggle=True) for _ in gui_app.render(): result = keyboard.render("Keyboard", "Type here") if result == 1: