From 1a75c53ea4fa1b743b6d268c8c181efb35c19c28 Mon Sep 17 00:00:00 2001 From: royjr Date: Sun, 16 Aug 2026 16:18:09 -0400 Subject: [PATCH] ui: handle custom steering button on comma 4 --- openpilot/selfdrive/ui/custom_button.py | 25 +++++++++++++++++++ openpilot/selfdrive/ui/layouts/main.py | 25 ++----------------- openpilot/selfdrive/ui/mici/layouts/main.py | 3 +++ .../selfdrive/ui/tests/test_custom_button.py | 19 ++++++-------- 4 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 openpilot/selfdrive/ui/custom_button.py diff --git a/openpilot/selfdrive/ui/custom_button.py b/openpilot/selfdrive/ui/custom_button.py new file mode 100644 index 0000000000..20aadff5b1 --- /dev/null +++ b/openpilot/selfdrive/ui/custom_button.py @@ -0,0 +1,25 @@ +from enum import IntEnum + +from opendbc.car.structs import car + + +class CustomButtonAction(IntEnum): + NONE = 0 + BOOKMARK = 1 + QUIET_MODE = 2 + + +def handle_custom_button(sm, params, bookmark_callback): + if not sm.updated['carState']: + return + + custom_pressed = any(be.type == car.CarState.ButtonEvent.Type.altButton2 and be.pressed + for be in sm['carState'].buttonEvents) + if not custom_pressed: + return + + action = CustomButtonAction(params.get('SteeringCustomButtonMapping', return_default=True)) + if action == CustomButtonAction.BOOKMARK: + bookmark_callback() + elif action == CustomButtonAction.QUIET_MODE: + params.put_bool('QuietMode', not params.get_bool('QuietMode')) diff --git a/openpilot/selfdrive/ui/layouts/main.py b/openpilot/selfdrive/ui/layouts/main.py index 5b2b9bc9f5..b56c8136c2 100644 --- a/openpilot/selfdrive/ui/layouts/main.py +++ b/openpilot/selfdrive/ui/layouts/main.py @@ -1,9 +1,9 @@ import pyray as rl from enum import IntEnum import openpilot.cereal.messaging as messaging -from opendbc.car.structs import car from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.widgets import Widget +from openpilot.selfdrive.ui.custom_button import handle_custom_button from openpilot.selfdrive.ui.layouts.sidebar import Sidebar, SIDEBAR_WIDTH from openpilot.selfdrive.ui.layouts.home import HomeLayout from openpilot.selfdrive.ui.layouts.settings.settings import SettingsLayout, PanelType @@ -23,12 +23,6 @@ class MainState(IntEnum): ONROAD = 2 -class CustomButtonAction(IntEnum): - NONE = 0 - BOOKMARK = 1 - QUIET_MODE = 2 - - class MainLayout(Widget): def __init__(self): super().__init__() @@ -62,7 +56,7 @@ class MainLayout(Widget): gui_app.push_widget(self._onboarding_window) def _render(self, _): - self._handle_custom_button() + handle_custom_button(ui_state.sm, ui_state.params, self._on_bookmark_clicked) self._handle_onroad_transition() self._render_main_content() @@ -127,21 +121,6 @@ class MainLayout(Widget): msg = messaging.new_message(service, valid=True) self._pm.send(service, msg) - def _handle_custom_button(self): - if not ui_state.sm.updated['carState']: - return - - custom_pressed = any(be.type == car.CarState.ButtonEvent.Type.altButton2 and be.pressed - for be in ui_state.sm['carState'].buttonEvents) - if not custom_pressed: - return - - action = CustomButtonAction(ui_state.params.get('SteeringCustomButtonMapping', return_default=True)) - if action == CustomButtonAction.BOOKMARK: - self._on_bookmark_clicked() - elif action == CustomButtonAction.QUIET_MODE: - ui_state.params.put_bool('QuietMode', not ui_state.params.get_bool('QuietMode')) - def _on_onroad_clicked(self): self._sidebar.set_visible(not self._sidebar.is_visible) diff --git a/openpilot/selfdrive/ui/mici/layouts/main.py b/openpilot/selfdrive/ui/mici/layouts/main.py index 7b96366894..4766c8c976 100644 --- a/openpilot/selfdrive/ui/mici/layouts/main.py +++ b/openpilot/selfdrive/ui/mici/layouts/main.py @@ -4,6 +4,7 @@ from openpilot.selfdrive.ui.mici.layouts.home import MiciHomeLayout from openpilot.selfdrive.ui.mici.layouts.settings.settings import SettingsLayout from openpilot.selfdrive.ui.mici.layouts.offroad_alerts import MiciOffroadAlerts from openpilot.selfdrive.ui.mici.onroad.augmented_road_view import AugmentedRoadView +from openpilot.selfdrive.ui.custom_button import handle_custom_button from openpilot.selfdrive.ui.ui_state import device, ui_state from openpilot.selfdrive.ui.mici.layouts.onboarding import OnboardingWindow from openpilot.selfdrive.ui.body.layouts.onroad import BodyLayout @@ -95,6 +96,8 @@ class MiciMainLayout(Scroller): self._alerts_layout._update_state() def _render(self, _): + handle_custom_button(ui_state.sm, ui_state.params, self._on_bookmark_clicked) + if not self._setup: if self._alerts_layout.active_alerts() > 0: self._scroller.scroll_to(self._alerts_layout.rect.x) diff --git a/openpilot/selfdrive/ui/tests/test_custom_button.py b/openpilot/selfdrive/ui/tests/test_custom_button.py index efaa90e0f0..6a8ed3abf1 100644 --- a/openpilot/selfdrive/ui/tests/test_custom_button.py +++ b/openpilot/selfdrive/ui/tests/test_custom_button.py @@ -3,7 +3,7 @@ from unittest.mock import Mock from opendbc.car.structs import car -from openpilot.selfdrive.ui.layouts import main +from openpilot.selfdrive.ui.custom_button import CustomButtonAction, handle_custom_button class FakeSubMaster: @@ -15,7 +15,7 @@ class FakeSubMaster: return self.messages[key] -def test_custom_button_actions(monkeypatch): +def test_custom_button_actions(): params = Mock() params.get_bool.return_value = False sm = FakeSubMaster({ @@ -24,15 +24,12 @@ def test_custom_button_actions(monkeypatch): pressed=True, )]), }) - monkeypatch.setattr(main, 'ui_state', SimpleNamespace(sm=sm, params=params)) + bookmark_callback = Mock() - layout = main.MainLayout.__new__(main.MainLayout) - layout._on_bookmark_clicked = Mock() + params.get.return_value = CustomButtonAction.BOOKMARK + handle_custom_button(sm, params, bookmark_callback) + bookmark_callback.assert_called_once() - params.get.return_value = main.CustomButtonAction.BOOKMARK - layout._handle_custom_button() - layout._on_bookmark_clicked.assert_called_once() - - params.get.return_value = main.CustomButtonAction.QUIET_MODE - layout._handle_custom_button() + params.get.return_value = CustomButtonAction.QUIET_MODE + handle_custom_button(sm, params, bookmark_callback) params.put_bool.assert_called_once_with('QuietMode', True)