system/ui: add caps lock to keyboard (#35277)

* add new icons shift-fill and capslock-fill, rm capslock

* SHIFT_KEY_ON, SHIFT_KEY_OFF

* capslock

* rm arrow-down

* a lot simpler

* only one

* just use time

* layout name

* rename shift

* CONSTANT
pull/35281/head
Cameron Clough 4 months ago committed by GitHub
parent 6640986622
commit 0c013f6186
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      selfdrive/assets/icons/arrow-down.png
  2. 3
      selfdrive/assets/icons/capslock-fill.png
  3. 3
      selfdrive/assets/icons/capslock.png
  4. 3
      selfdrive/assets/icons/shift-fill.png
  5. 4
      selfdrive/assets/prep-svg.sh
  6. 53
      system/ui/widgets/keyboard.py

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7e12a3cf36fdef107d237457e20b44e16320414f9de8a1791aff1ec5fd85ccef
size 2390

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6872a1047f1a534a037be7b1367640fe1bfb205a6e1c50420a2d1a946cda78ed
size 4397

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c6621d000d9514df1d636e9953941eadec415ff950724f26a61e0fcbaa7a3818
size 5403

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e625ca991746abaaac375b095aa9a586601982232f4aae0fc2b17b2a524e9ce9
size 3946

@ -6,11 +6,11 @@ ICONS_DIR="$DIR/icons"
BOOTSTRAP_SVG="$DIR/../../third_party/bootstrap/bootstrap-icons.svg"
ICON_IDS=(
arrow-down
arrow-right
backspace
capslock
capslock-fill
shift
shift-fill
)
ICON_FILL_COLOR="#fff"

@ -1,3 +1,5 @@
import time
from typing import Literal
import pyray as rl
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.button import ButtonStyle, gui_button
@ -5,30 +7,32 @@ from openpilot.system.ui.lib.inputbox import InputBox
from openpilot.system.ui.lib.label import gui_label
KEY_FONT_SIZE = 96
DOUBLE_CLICK_THRESHOLD = 0.5 # seconds
# Constants for special keys
CONTENT_MARGIN = 50
BACKSPACE_KEY = "<-"
ENTER_KEY = "->"
SPACE_KEY = " "
SHIFT_KEY = ""
SHIFT_DOWN_KEY = ""
SHIFT_INACTIVE_KEY = "SHIFT_OFF"
SHIFT_ACTIVE_KEY = "SHIFT_ON"
CAPS_LOCK_KEY = "CAPS"
NUMERIC_KEY = "123"
SYMBOL_KEY = "#+="
ABC_KEY = "ABC"
# Define keyboard layouts as a dictionary for easier access
keyboard_layouts = {
KEYBOARD_LAYOUTS = {
"lowercase": [
["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"],
["a", "s", "d", "f", "g", "h", "j", "k", "l"],
[SHIFT_KEY, "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY],
[SHIFT_INACTIVE_KEY, "z", "x", "c", "v", "b", "n", "m", BACKSPACE_KEY],
[NUMERIC_KEY, "/", "-", SPACE_KEY, ".", ENTER_KEY],
],
"uppercase": [
["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"],
["A", "S", "D", "F", "G", "H", "J", "K", "L"],
[SHIFT_DOWN_KEY, "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY],
[SHIFT_ACTIVE_KEY, "Z", "X", "C", "V", "B", "N", "M", BACKSPACE_KEY],
[NUMERIC_KEY, "/", "-", SPACE_KEY, ".", ENTER_KEY],
],
"numbers": [
@ -48,7 +52,10 @@ keyboard_layouts = {
class Keyboard:
def __init__(self, max_text_size: int = 255, min_text_size: int = 0, password_mode: bool = False, show_password_toggle: bool = False):
self._layout = keyboard_layouts["lowercase"]
self._layout_name: Literal["lowercase", "uppercase", "numbers", "specials"] = "lowercase"
self._caps_lock = False
self._last_shift_press_time = 0
self._max_text_size = max_text_size
self._min_text_size = min_text_size
self._input_box = InputBox(max_text_size)
@ -59,8 +66,9 @@ class Keyboard:
self._eye_closed_texture = gui_app.texture("icons/eye_closed.png", 81, 54)
self._key_icons = {
BACKSPACE_KEY: gui_app.texture("icons/backspace.png", 80, 80),
SHIFT_KEY: gui_app.texture("icons/shift.png", 80, 80),
SHIFT_DOWN_KEY: gui_app.texture("icons/arrow-down.png", 80, 80),
SHIFT_INACTIVE_KEY: gui_app.texture("icons/shift.png", 80, 80),
SHIFT_ACTIVE_KEY: gui_app.texture("icons/shift-fill.png", 80, 80),
CAPS_LOCK_KEY: gui_app.texture("icons/capslock-fill.png", 80, 80),
ENTER_KEY: gui_app.texture("icons/arrow-right.png", 80, 80),
}
@ -84,13 +92,15 @@ class Keyboard:
input_box_rect = rl.Rectangle(rect.x + input_margin, rect.y + 160, rect.width - input_margin, 100)
self._render_input_area(input_box_rect)
layout = KEYBOARD_LAYOUTS[self._layout_name]
h_space, v_space = 15, 15
row_y_start = rect.y + 300 # Starting Y position for the first row
key_height = (rect.height - 300 - 3 * v_space) / 4
key_max_width = (rect.width - (len(self._layout[2]) - 1) * h_space) / len(self._layout[2])
key_max_width = (rect.width - (len(layout[2]) - 1) * h_space) / len(layout[2])
# Iterate over the rows of keys in the current layout
for row, keys in enumerate(self._layout):
for row, keys in enumerate(layout):
key_width = min((rect.width - (180 if row == 1 else 0) - h_space * (len(keys) - 1)) / len(keys), key_max_width)
start_x = rect.x + (90 if row == 1 else 0)
@ -105,6 +115,8 @@ class Keyboard:
is_enabled = key != ENTER_KEY or len(self._input_box.text) >= self._min_text_size
result = -1
if key in self._key_icons:
if key == SHIFT_ACTIVE_KEY and self._caps_lock:
key = CAPS_LOCK_KEY
texture = self._key_icons[key]
result = gui_button(key_rect, "", icon=texture, button_style=ButtonStyle.PRIMARY if key == ENTER_KEY else ButtonStyle.NORMAL, is_enabled=is_enabled)
else:
@ -148,18 +160,27 @@ class Keyboard:
)
def handle_key_press(self, key):
if key in (SHIFT_DOWN_KEY, ABC_KEY):
self._layout = keyboard_layouts["lowercase"]
elif key == SHIFT_KEY:
self._layout = keyboard_layouts["uppercase"]
if key in (CAPS_LOCK_KEY, ABC_KEY):
self._caps_lock = False
self._layout_name = "lowercase"
elif key == SHIFT_INACTIVE_KEY:
self._last_shift_press_time = time.monotonic()
self._layout_name = "uppercase"
elif key == SHIFT_ACTIVE_KEY:
if time.monotonic() - self._last_shift_press_time < DOUBLE_CLICK_THRESHOLD:
self._caps_lock = True
else:
self._layout_name = "lowercase"
elif key == NUMERIC_KEY:
self._layout = keyboard_layouts["numbers"]
self._layout_name = "numbers"
elif key == SYMBOL_KEY:
self._layout = keyboard_layouts["specials"]
self._layout_name = "specials"
elif key == BACKSPACE_KEY:
self._input_box.delete_char_before_cursor()
else:
self._input_box.add_char_at_cursor(key)
if not self._caps_lock and self._layout_name == "uppercase":
self._layout_name = "lowercase"
if __name__ == "__main__":

Loading…
Cancel
Save