Attempt to make buttons activatable with enter.
This commit is contained in:
1 parent
eb63cfe8bf
commit
3ab834d00c
4 files changed
+107
-1
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
||||||
pkgname=navipy-git
|
pkgname=navipy-git
|
||||||
pkgver=r15.gf39ec4d
|
pkgver=r16.geb63cfe
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc='Accessible Subsonic desktop client tested with Navidrome'
|
pkgdesc='Accessible Subsonic desktop client tested with Navidrome'
|
||||||
arch=('any')
|
arch=('any')
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ srcPath = Path(__file__).parent / 'src'
|
|||||||
sys.path.insert(0, str(srcPath.parent))
|
sys.path.insert(0, str(srcPath.parent))
|
||||||
|
|
||||||
from src.main_window import MainWindow
|
from src.main_window import MainWindow
|
||||||
|
from src.accessibility.button_keyboard import install_button_keyboard_support
|
||||||
from src.config.settings import getDataDir
|
from src.config.settings import getDataDir
|
||||||
|
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ def main():
|
|||||||
app.setApplicationName("NaviPy")
|
app.setApplicationName("NaviPy")
|
||||||
app.setApplicationVersion("0.1.0")
|
app.setApplicationVersion("0.1.0")
|
||||||
app.setOrganizationName("NaviPy")
|
app.setOrganizationName("NaviPy")
|
||||||
|
app.buttonKeyboardFilter = install_button_keyboard_support(app)
|
||||||
|
|
||||||
# Enable accessibility
|
# Enable accessibility
|
||||||
app.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
app.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
"""Keyboard activation support for push buttons."""
|
||||||
|
|
||||||
|
from PySide6.QtCore import QEvent, QObject, Qt
|
||||||
|
from PySide6.QtWidgets import QApplication, QPushButton
|
||||||
|
|
||||||
|
|
||||||
|
class ButtonKeyboardFilter(QObject):
|
||||||
|
"""Make Enter behave like a native activation key on push buttons."""
|
||||||
|
|
||||||
|
def eventFilter(self, watched, event):
|
||||||
|
if not isinstance(watched, QPushButton):
|
||||||
|
return super().eventFilter(watched, event)
|
||||||
|
|
||||||
|
if event.type() not in (QEvent.KeyPress, QEvent.KeyRelease):
|
||||||
|
return super().eventFilter(watched, event)
|
||||||
|
|
||||||
|
if event.key() not in (Qt.Key_Return, Qt.Key_Enter):
|
||||||
|
return super().eventFilter(watched, event)
|
||||||
|
|
||||||
|
if event.modifiers() not in (Qt.NoModifier, Qt.KeypadModifier):
|
||||||
|
return super().eventFilter(watched, event)
|
||||||
|
|
||||||
|
event.accept()
|
||||||
|
if event.type() == QEvent.KeyRelease and not event.isAutoRepeat():
|
||||||
|
watched.click()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def install_button_keyboard_support(app: QApplication) -> ButtonKeyboardFilter:
|
||||||
|
"""Install application-wide Enter-key support for push buttons."""
|
||||||
|
keyboardFilter = ButtonKeyboardFilter(app)
|
||||||
|
app.installEventFilter(keyboardFilter)
|
||||||
|
return keyboardFilter
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
"""Tests for consistent keyboard activation of push buttons."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
from PySide6.QtTest import QTest
|
||||||
|
from PySide6.QtWidgets import QApplication, QCheckBox, QDialogButtonBox, QPushButton
|
||||||
|
|
||||||
|
from src.accessibility.button_keyboard import install_button_keyboard_support
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def app():
|
||||||
|
application = QApplication.instance() or QApplication([])
|
||||||
|
keyboardFilter = install_button_keyboard_support(application)
|
||||||
|
yield application
|
||||||
|
application.removeEventFilter(keyboardFilter)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("key", (Qt.Key_Return, Qt.Key_Enter))
|
||||||
|
def test_enter_activates_focused_push_button(app, key):
|
||||||
|
button = QPushButton("Clear selection")
|
||||||
|
clicks = []
|
||||||
|
button.clicked.connect(lambda: clicks.append(True))
|
||||||
|
button.show()
|
||||||
|
button.setFocus()
|
||||||
|
|
||||||
|
QTest.keyClick(button, key)
|
||||||
|
|
||||||
|
assert clicks == [True]
|
||||||
|
|
||||||
|
|
||||||
|
def test_enter_does_not_activate_disabled_push_button(app):
|
||||||
|
button = QPushButton("Clear play cue")
|
||||||
|
clicks = []
|
||||||
|
button.clicked.connect(lambda: clicks.append(True))
|
||||||
|
button.setEnabled(False)
|
||||||
|
|
||||||
|
QTest.keyClick(button, Qt.Key_Return)
|
||||||
|
|
||||||
|
assert clicks == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_enter_activates_dialog_button_box_buttons(app):
|
||||||
|
buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
|
||||||
|
closeButton = buttonBox.button(QDialogButtonBox.Close)
|
||||||
|
clicks = []
|
||||||
|
closeButton.clicked.connect(lambda: clicks.append(True))
|
||||||
|
|
||||||
|
QTest.keyClick(closeButton, Qt.Key_Return)
|
||||||
|
|
||||||
|
assert clicks == [True]
|
||||||
|
|
||||||
|
|
||||||
|
def test_modified_enter_is_not_treated_as_button_activation(app):
|
||||||
|
button = QPushButton("Clear selection")
|
||||||
|
clicks = []
|
||||||
|
button.clicked.connect(lambda: clicks.append(True))
|
||||||
|
|
||||||
|
QTest.keyClick(button, Qt.Key_Return, Qt.ControlModifier)
|
||||||
|
|
||||||
|
assert clicks == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_enter_handling_is_limited_to_push_buttons(app):
|
||||||
|
checkbox = QCheckBox("Select")
|
||||||
|
checkbox.setChecked(False)
|
||||||
|
|
||||||
|
QTest.keyClick(checkbox, Qt.Key_Return)
|
||||||
|
|
||||||
|
assert not checkbox.isChecked()
|
||||||
Reference in new issue
Block a user