diff --git a/controller/Changelog.md b/controller/Changelog.md index 4f3d03ba..077bf21d 100644 --- a/controller/Changelog.md +++ b/controller/Changelog.md @@ -2,6 +2,7 @@ ## Added +- kiosk: Open settings with a long press on the Menu key - controller: Enable spatial navigation using the arrow keys ## Removed diff --git a/docs/user-manual/Readme.org b/docs/user-manual/Readme.org index 4b5c824d..167a3811 100644 --- a/docs/user-manual/Readme.org +++ b/docs/user-manual/Readme.org @@ -33,7 +33,7 @@ When a remote control with a power button is connected, the system may be shut d * Administration -<>A menu for system administration may be accessed with the key combination ~Ctrl-Shift-F12~. +<>A menu for system administration may be accessed with the key combination ~Ctrl-Shift-F12~, or with a long press on the Menu key. The administration interface opens to a page displaying basic system information. diff --git a/kiosk/kiosk_browser/__init__.py b/kiosk/kiosk_browser/__init__.py index 2a9a0fa8..c1025913 100644 --- a/kiosk/kiosk_browser/__init__.py +++ b/kiosk/kiosk_browser/__init__.py @@ -1,6 +1,7 @@ import sys import logging -from PyQt5.QtCore import Qt, QUrl +import signal +from PyQt5.QtCore import Qt, QUrl, QSize from PyQt5.QtGui import QKeySequence from PyQt5.QtWidgets import QApplication @@ -20,9 +21,25 @@ def start(kiosk_url, settings_url, toggle_settings_key, fullscreen = True): mainWidget.setContextMenuPolicy(Qt.NoContextMenu) + screen_size = app.primaryScreen().size() + if fullscreen: - set_fullscreen(app, mainWidget) + # Without a Window Manager, showFullScreen does not work under X, + # so set the window size to the primary screen size. + mainWidget.resize(screen_size) + mainWidget.showFullScreen() + else: + mainWidget.resize(QSize(round(screen_size.width() / 2), round(screen_size.height() / 2))) + mainWidget.show() + # Quit application when receiving SIGINT + def on_SIGINT(signum, frame): + print('Exiting…') + app.quit() + sys.exit(130) + signal.signal(signal.SIGINT, on_SIGINT) + + # Start application app.exec_() def parseUrl(url): @@ -31,10 +48,3 @@ def parseUrl(url): raise InvalidUrl('Failed to parse URL "%s"' % url) from Exception else: return parsed_url - -def set_fullscreen(app, mainWidget): - # Without a Window Manager, showFullScreen does not work under X, - # so set the window size to the primary screen size. - screen_size = app.primaryScreen().size() - mainWidget.resize(screen_size) - mainWidget.showFullScreen() diff --git a/kiosk/kiosk_browser/browser_widget.py b/kiosk/kiosk_browser/browser_widget.py index de06dae8..22f13d39 100644 --- a/kiosk/kiosk_browser/browser_widget.py +++ b/kiosk/kiosk_browser/browser_widget.py @@ -54,17 +54,18 @@ def __init__(self, url, get_current_proxy, parent): # Allow sound playback without user gesture self._webview.page().settings().setAttribute(QtWebEngineWidgets.QWebEngineSettings.PlaybackRequiresUserGesture, False) + # Prevent opening context menu on right click or pressing menu + self._webview.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) + # Load url self._webview.setUrl(url) self._view(Status.LOADING) self._webview.loadFinished.connect(self._load_finished) # Shortcut to manually reload - self._reload_shortcut = QtWidgets.QShortcut('CTRL+R', self) - self._reload_shortcut.activated.connect(self.reload) + QtWidgets.QShortcut('CTRL+R', self).activated.connect(self.reload) # Shortcut to perform a hard refresh - self._hard_refresh_shortcut = QtWidgets.QShortcut('CTRL+SHIFT+R', self) - self._hard_refresh_shortcut.activated.connect(self._hard_refresh) + QtWidgets.QShortcut('CTRL+SHIFT+R', self).activated.connect(self._hard_refresh) # Prepare reload timer self._reload_timer = QtCore.QTimer(self) diff --git a/kiosk/kiosk_browser/main_widget.py b/kiosk/kiosk_browser/main_widget.py index c3bb8f75..1d7e4af9 100644 --- a/kiosk/kiosk_browser/main_widget.py +++ b/kiosk/kiosk_browser/main_widget.py @@ -1,12 +1,13 @@ from PyQt5 import QtWidgets, QtCore +import time from kiosk_browser import browser_widget, captive_portal, dialogable_widget, proxy as proxy_module class MainWidget(QtWidgets.QWidget): - """ Show website at kiosk_url. + """ Show website from kiosk_url. - - Show settings in dialog using shortcut. - - Show message when captive portal is detected, allowing to show in dialog. + - Show settings in a dialog using a shortcut or long pressing Menu. + - Show toolbar message when captive portal is detected, opening it in a dialog. - Use proxy configured in Connman. """ @@ -17,14 +18,18 @@ def __init__(self, kiosk_url: str, settings_url: str, toggle_settings_key: str): proxy = proxy_module.Proxy() proxy.start_monitoring_daemon() + # Menu press + self._menu_press_since = None + self._menu_press_delay_seconds = 1.5 + # Browser widget self._kiosk_url = kiosk_url self._settings_url = settings_url self._dialogable_browser = dialogable_widget.DialogableWidget( parent = self, inner_widget = browser_widget.BrowserWidget( - url = kiosk_url, - get_current_proxy = proxy.get_current, + url = kiosk_url, + get_current_proxy = proxy.get_current, parent = self), on_close = self._close_dialog) @@ -43,9 +48,12 @@ def __init__(self, kiosk_url: str, settings_url: str, toggle_settings_key: str): self._layout.addWidget(self._dialogable_browser) self.setLayout(self._layout) - # Shortcuts + # Shortcut to toggle settings QtWidgets.QShortcut(toggle_settings_key, self).activated.connect(self._toggle_settings) + # Look at events with the eventFilter function + self.installEventFilter(self) + # Private def _toggle_settings(self): @@ -73,3 +81,18 @@ def _close_dialog(self): self._dialogable_browser.inner_widget().load(self._kiosk_url) if self._is_captive_portal_open: self._is_captive_portal_open = False + + def eventFilter(self, source, event): + # Toggle settings with a long press on the Menu key + if event.type() == QtCore.QEvent.ShortcutOverride: + if event.key() == QtCore.Qt.Key_Menu: + if not event.isAutoRepeat(): + self._menu_press_since = time.time() + elif self._menu_press_since is not None and time.time() - self._menu_press_since > self._menu_press_delay_seconds: + self._menu_press_since = None + self._toggle_settings() + elif event.type() == QtCore.QEvent.KeyRelease: + if event.key() == QtCore.Qt.Key_Menu and not event.isAutoRepeat(): + self._menu_press_since = None + + return super(MainWidget, self).eventFilter(source, event)