4 Commits

Author SHA1 Message Date
60d6f0734d chore(changelog): update
All checks were successful
Code and build check / Check code (push) Successful in 1m26s
Code and build check / Build with uv (push) Successful in 48s
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-05 19:47:00 +05:00
57d499fab2 feat(input_manager): close AddGameDialog with B or Esc
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-05 19:43:47 +05:00
bc91b03843 fix(main_window): prevent multiple AddGameDialog openings on gamepad
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-05 19:37:57 +05:00
aabf8cb30f fix(input_manager): prevent gamepad input handling during game execution
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-06-05 19:33:08 +05:00
3 changed files with 38 additions and 2 deletions

View File

@@ -15,6 +15,7 @@
- Стили в AddGameDialog
- Переключение полноэкранного режима через F11
- Выбор QCheckBox через Enter или кнопку A геймпада
- Закрытие диалога добавления игры через ESC или кнопку B геймпада
- Закрытие окна приложения по комбинации клавиш Ctrl+Q
- Сохранение и восстановление размера при рестарте
- Переключатель полноэкранного режима приложения
@@ -47,6 +48,8 @@
- traceback при загрузке placeholder при отсутствии обложек
- Утечки памяти при загрузке обложек
- Ошибки при подключении геймпада из-за работы в разных потоках
- Множественное открытие диалога добавления игры на геймпаде
- Перехват событий геймпада во время работы игры
---

View File

@@ -3,7 +3,7 @@ import threading
from typing import Protocol, cast
from evdev import InputDevice, ecodes, list_devices
import pyudev
from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit
from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog
from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot
from PySide6.QtGui import QKeyEvent
from portprotonqt.logger import get_logger
@@ -30,6 +30,7 @@ class MainWindowProtocol(Protocol):
gamesListWidget: QWidget
currentDetailPage: QWidget | None
current_exec_line: str | None
current_add_game_dialog: QDialog | None # Добавляем для отслеживания диалога
# Mapping of actions to evdev button codes, includes PlayStation, Xbox, and Switch controllers
BUTTONS = {
@@ -67,6 +68,7 @@ class InputManager(QObject):
# Ensure attributes exist on main_window
self._parent.currentDetailPage = getattr(self._parent, 'currentDetailPage', None)
self._parent.current_exec_line = getattr(self._parent, 'current_exec_line', None)
self._parent.current_add_game_dialog = getattr(self._parent, 'current_add_game_dialog', None)
self.axis_deadzone = axis_deadzone
self.initial_axis_move_delay = initial_axis_move_delay
@@ -134,6 +136,11 @@ class InputManager(QObject):
app.quit()
return True
# Закрытие AddGameDialog на Esc
if key == Qt.Key.Key_Escape and isinstance(popup, QDialog):
popup.reject() # Закрываем диалог
return True
# Skip navigation keys if a popup is open
if popup:
return False
@@ -357,12 +364,21 @@ class InputManager(QObject):
@Slot(int)
def handle_button_slot(self, button_code: int) -> None:
try:
# Игнорировать события геймпада, если игра запущена
if getattr(self._parent, '_gameLaunched', False):
return
app = QApplication.instance()
if not app:
return
active = QApplication.activeWindow()
focused = QApplication.focusWidget()
# Закрытие AddGameDialog на кнопку B
if button_code in BUTTONS['back'] and isinstance(active, QDialog):
active.reject() # Закрываем диалог
return
# FullscreenDialog
if isinstance(active, FullscreenDialog):
if button_code in BUTTONS['prev_tab']:
@@ -407,6 +423,10 @@ class InputManager(QObject):
@Slot(int, int, float)
def handle_dpad_slot(self, code: int, value: int, current_time: float) -> None:
try:
# Игнорировать события геймпада, если игра запущена
if getattr(self._parent, '_gameLaunched', False):
return
app = QApplication.instance()
if not app:
return

View File

@@ -60,6 +60,7 @@ class MainWindow(QMainWindow):
self.games_load_timer.setSingleShot(True)
self.games_load_timer.timeout.connect(self.finalize_game_loading)
self.games_loaded.connect(self.on_games_loaded)
self.current_add_game_dialog = None
# Добавляем таймер для дебаунсинга сохранения настроек
self.settingsDebounceTimer = QTimer(self)
@@ -730,7 +731,14 @@ class MainWindow(QMainWindow):
def openAddGameDialog(self, exe_path=None):
"""Открывает диалоговое окно 'Add Game' с текущей темой."""
# Проверяем, открыт ли уже диалог
if self.current_add_game_dialog is not None and self.current_add_game_dialog.isVisible():
self.current_add_game_dialog.activateWindow() # Активируем существующий диалог
self.current_add_game_dialog.raise_() # Поднимаем окно
return
dialog = AddGameDialog(self, self.theme)
self.current_add_game_dialog = dialog # Сохраняем ссылку на диалог
# Предзаполняем путь к .exe при drag-and-drop
if exe_path:
@@ -738,6 +746,12 @@ class MainWindow(QMainWindow):
dialog.nameEdit.setText(os.path.splitext(os.path.basename(exe_path))[0])
dialog.updatePreview()
# Обработчик закрытия диалога
def on_dialog_finished():
self.current_add_game_dialog = None # Сбрасываем ссылку при закрытии
dialog.finished.connect(on_dialog_finished)
if dialog.exec() == QDialog.DialogCode.Accepted:
name = dialog.nameEdit.text().strip()
exe_path = dialog.exeEdit.text().strip()
@@ -774,7 +788,6 @@ class MainWindow(QMainWindow):
self.games = self.loadGames()
self.updateGameGrid()
def createAutoInstallTab(self):
"""Вкладка 'Auto Install'."""
self.autoInstallWidget = QWidget()