feat(input_manager): Added QMenu handler for Gamepad
All checks were successful
Code and build check / Check code (push) Successful in 1m21s
Code and build check / Build with uv (push) Successful in 46s

Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
Boris Yumankulov 2025-06-07 11:21:51 +05:00
parent 2ae3831662
commit c037af4314
Signed by: Boria138
GPG Key ID: 14B4A5673FD39C76

View File

@ -3,7 +3,7 @@ import threading
from typing import Protocol, cast from typing import Protocol, cast
from evdev import InputDevice, ecodes, list_devices from evdev import InputDevice, ecodes, list_devices
import pyudev import pyudev
from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog, QMenu
from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot
from PySide6.QtGui import QKeyEvent from PySide6.QtGui import QKeyEvent
from portprotonqt.logger import get_logger from portprotonqt.logger import get_logger
@ -37,8 +37,8 @@ BUTTONS = {
'confirm': {ecodes.BTN_A}, 'confirm': {ecodes.BTN_A},
'back': {ecodes.BTN_B}, 'back': {ecodes.BTN_B},
'add_game': {ecodes.BTN_Y}, 'add_game': {ecodes.BTN_Y},
'prev_tab': {ecodes.BTN_TL, ecodes.BTN_TRIGGER_HAPPY7}, 'prev_tab': {ecodes.BTN_TL},
'next_tab': {ecodes.BTN_TR, ecodes.BTN_TRIGGER_HAPPY5}, 'next_tab': {ecodes.BTN_TR},
'confirm_stick': {ecodes.BTN_THUMBL, ecodes.BTN_THUMBR}, 'confirm_stick': {ecodes.BTN_THUMBL, ecodes.BTN_THUMBR},
'context_menu': {ecodes.BTN_START}, 'context_menu': {ecodes.BTN_START},
'menu': {ecodes.BTN_SELECT}, 'menu': {ecodes.BTN_SELECT},
@ -129,6 +129,21 @@ class InputManager(QObject):
return return
active = QApplication.activeWindow() active = QApplication.activeWindow()
focused = QApplication.focusWidget() focused = QApplication.focusWidget()
popup = QApplication.activePopupWidget()
# Handle QMenu (context menu)
if isinstance(popup, QMenu):
if button_code in BUTTONS['confirm'] or button_code in BUTTONS['confirm_stick']:
# Trigger the currently highlighted menu action and close the menu
if popup.activeAction():
popup.activeAction().trigger()
popup.close()
return
elif button_code in BUTTONS['back'] or button_code in BUTTONS['menu']:
# Close the menu
popup.close()
return
return
# Закрытие AddGameDialog на кнопку B # Закрытие AddGameDialog на кнопку B
if button_code in BUTTONS['back'] and isinstance(active, QDialog): if button_code in BUTTONS['back'] and isinstance(active, QDialog):
@ -149,7 +164,9 @@ class InputManager(QObject):
if isinstance(focused, GameCard): if isinstance(focused, GameCard):
if button_code in BUTTONS['context_menu']: if button_code in BUTTONS['context_menu']:
pos = QPoint(focused.width() // 2, focused.height() // 2) pos = QPoint(focused.width() // 2, focused.height() // 2)
focused._show_context_menu(pos) menu = focused._show_context_menu(pos)
if menu:
menu.setFocus(Qt.FocusReason.OtherFocusReason)
return return
# Game launch on detail page # Game launch on detail page
@ -188,6 +205,22 @@ class InputManager(QObject):
if not app: if not app:
return return
active = QApplication.activeWindow() active = QApplication.activeWindow()
popup = QApplication.activePopupWidget()
# Handle QMenu navigation with D-pad
if isinstance(popup, QMenu):
if code == ecodes.ABS_HAT0Y and value != 0:
actions = popup.actions()
if actions:
current_idx = actions.index(popup.activeAction()) if popup.activeAction() in actions else 0
if value < 0: # Up
next_idx = (current_idx - 1) % len(actions)
popup.setActiveAction(actions[next_idx])
elif value > 0: # Down
next_idx = (current_idx + 1) % len(actions)
popup.setActiveAction(actions[next_idx])
return
return
# Fullscreen horizontal navigation # Fullscreen horizontal navigation
if isinstance(active, FullscreenDialog) and code == ecodes.ABS_HAT0X: if isinstance(active, FullscreenDialog) and code == ecodes.ABS_HAT0X: