diff --git a/portprotonqt/input_manager.py b/portprotonqt/input_manager.py index 3fc1557..0719e52 100644 --- a/portprotonqt/input_manager.py +++ b/portprotonqt/input_manager.py @@ -3,6 +3,7 @@ import threading import os from typing import Protocol, cast from evdev import InputDevice, InputEvent, ecodes, list_devices, ff +from enum import Enum from pyudev import Context, Monitor, MonitorObserver, Device from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog, QMenu, QComboBox, QListView, QMessageBox, QListWidget from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot, QTimer @@ -38,23 +39,29 @@ class MainWindowProtocol(Protocol): current_exec_line: str | None current_add_game_dialog: AddGameDialog | None -# Mapping of actions to evdev button codes, includes Xbox and PlayStation controllers +# Mapping of actions to evdev button codes, includes Xbox, PlayStation and Nintendo Switch controllers # https://github.com/torvalds/linux/blob/master/drivers/hid/hid-playstation.c # https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c +# https://github.com/torvalds/linux/blob/master/drivers/hid/hid-nintendo BUTTONS = { - 'confirm': {ecodes.BTN_SOUTH}, # A (Xbox) / Cross (PS) - 'back': {ecodes.BTN_EAST}, # B (Xbox) / Circle (PS) - 'add_game': {ecodes.BTN_NORTH}, # X (Xbox) / Triangle (PS) - 'prev_dir': {ecodes.BTN_WEST}, # Y (Xbox) / Square (PS) - 'prev_tab': {ecodes.BTN_TL}, # LB (Xbox) / L1 (PS) - 'next_tab': {ecodes.BTN_TR}, # RB (Xbox) / R1 (PS) - 'context_menu': {ecodes.BTN_START}, # Start (Xbox) / Options (PS) - 'menu': {ecodes.BTN_SELECT}, # Select (Xbox) / Share (PS) - 'guide': {ecodes.BTN_MODE}, # Xbox Button / PS Button - 'increase_size': {ecodes.BTN_TR2}, # RT (Xbox) / R2 (PS) - 'decrease_size': {ecodes.BTN_TL2}, # LT (Xbox) / L2 (PS) + 'confirm': {ecodes.BTN_SOUTH}, # A (Xbox) / Cross (PS) / B (Switch) + 'back': {ecodes.BTN_EAST}, # B (Xbox) / Circle (PS) / A (Switch) + 'add_game': {ecodes.BTN_NORTH}, # X (Xbox) / Triangle (PS) / Y (Switch) + 'prev_dir': {ecodes.BTN_WEST}, # Y (Xbox) / Square (PS) / X (Switch) + 'prev_tab': {ecodes.BTN_TL}, # LB (Xbox) / L1 (PS) / L (Switch) + 'next_tab': {ecodes.BTN_TR}, # RB (Xbox) / R1 (PS) / R (Switch) + 'context_menu': {ecodes.BTN_START}, # Start (Xbox) / Options (PS) / + (Switch) + 'menu': {ecodes.BTN_SELECT}, # Select (Xbox) / Share (PS) / - (Switch) + 'guide': {ecodes.BTN_MODE}, # Xbox Button / PS Button / Home (Switch) + 'increase_size': {ecodes.BTN_TR2}, # RT (Xbox) / R2 (PS) / ZR (Switch) + 'decrease_size': {ecodes.BTN_TL2}, # LT (Xbox) / L2 (PS) / ZL (Switch) } +class GamepadType(Enum): + XBOX = "Xbox" + PLAYSTATION = "PlayStation" + UNKNOWN = "Unknown" + class InputManager(QObject): """ Manages input from gamepads and keyboards for navigating the application interface. @@ -76,6 +83,7 @@ class InputManager(QObject): super().__init__(cast(QObject, main_window)) self._parent = main_window self._gamepad_handling_enabled = True + self.gamepad_type = GamepadType.UNKNOWN # 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) @@ -132,6 +140,38 @@ class InputManager(QObject): # Initialize evdev + hotplug self.init_gamepad() + def detect_gamepad_type(self, device: InputDevice) -> GamepadType: + """ + Определяет тип геймпада по capabilities + """ + caps = device.capabilities() + keys = set(caps.get(ecodes.EV_KEY, [])) + + # Для EV_ABS вытаскиваем только коды (первый элемент кортежа) + abs_axes = {a if isinstance(a, int) else a[0] for a in caps.get(ecodes.EV_ABS, [])} + + # Xbox layout + if {ecodes.BTN_SOUTH, ecodes.BTN_EAST, ecodes.BTN_NORTH, ecodes.BTN_WEST}.issubset(keys): + if {ecodes.ABS_X, ecodes.ABS_Y, ecodes.ABS_RX, ecodes.ABS_RY}.issubset(abs_axes): + self.gamepad_type = GamepadType.XBOX + return GamepadType.XBOX + + # PlayStation layout + if ecodes.BTN_TOUCH in keys or (ecodes.BTN_DPAD_UP in keys and ecodes.BTN_EAST in keys): + self.gamepad_type = GamepadType.PLAYSTATION + logger.info(f"Detected {self.gamepad_type.value} controller: {device.name}") + return GamepadType.PLAYSTATION + + # Steam Controller / Deck (трекпады) + if any(a for a in abs_axes if a >= ecodes.ABS_MT_SLOT): + self.gamepad_type = GamepadType.XBOX + logger.info(f"Detected {self.gamepad_type.value} controller: {device.name}") + return GamepadType.XBOX + + # Fallback + self.gamepad_type = GamepadType.XBOX + return GamepadType.XBOX + def enable_file_explorer_mode(self, file_explorer): """Настройка обработки геймпада для FileExplorer""" try: @@ -1043,6 +1083,8 @@ class InputManager(QObject): new_gamepad = self.find_gamepad() if new_gamepad and new_gamepad != self.gamepad: logger.info(f"Gamepad connected: {new_gamepad.name}") + self.detect_gamepad_type(new_gamepad) + logger.info(f"Detected gamepad type: {self.gamepad_type.value}") self.stop_rumble() self.gamepad = new_gamepad if self.gamepad_thread: @@ -1137,5 +1179,7 @@ class InputManager(QObject): self.gamepad_thread.join() if self.gamepad: self.gamepad.close() + self.gamepad = None + self.gamepad_type = GamepadType.UNKNOWN except Exception as e: logger.error(f"Error during cleanup: {e}", exc_info=True) diff --git a/portprotonqt/main_window.py b/portprotonqt/main_window.py index 183f0b7..7931e75 100644 --- a/portprotonqt/main_window.py +++ b/portprotonqt/main_window.py @@ -15,6 +15,7 @@ from portprotonqt.portproton_api import PortProtonAPI from portprotonqt.input_manager import InputManager from portprotonqt.context_menu_manager import ContextMenuManager, CustomLineEdit from portprotonqt.system_overlay import SystemOverlay +from portprotonqt.input_manager import GamepadType from portprotonqt.image_utils import load_pixmap_async, round_corners, ImageCarousel from portprotonqt.steam_api import get_steam_game_info_async, get_full_steam_game_info_async, get_steam_installed_games @@ -221,6 +222,50 @@ class MainWindow(QMainWindow): else: self.showNormal() + def get_button_icon(self, action: str, gtype: GamepadType) -> str: + """Get the icon name for a specific action and gamepad type.""" + mappings = { + 'confirm': { + GamepadType.XBOX: "xbox_a", + GamepadType.PLAYSTATION: "ps_cross", + }, + 'back': { + GamepadType.XBOX: "xbox_b", + GamepadType.PLAYSTATION: "ps_circle", + }, + 'add_game': { + GamepadType.XBOX: "xbox_x", + GamepadType.PLAYSTATION: "ps_triangle", + }, + 'context_menu': { + GamepadType.XBOX: "xbox_start", + GamepadType.PLAYSTATION: "ps_options", + }, + 'menu': { + GamepadType.XBOX: "xbox_view", + GamepadType.PLAYSTATION: "ps_share", + }, + } + return mappings.get(action, {}).get(gtype, "placeholder") + + def get_nav_icon(self, direction: str, gtype: GamepadType) -> str: + """Get the icon name for navigation direction and gamepad type.""" + if direction == 'left': + action = 'prev_tab' + else: + action = 'next_tab' + mappings = { + 'prev_tab': { + GamepadType.XBOX: "xbox_lb", + GamepadType.PLAYSTATION: "ps_l1", + }, + 'next_tab': { + GamepadType.XBOX: "xbox_rb", + GamepadType.PLAYSTATION: "ps_r1", + }, + } + return mappings.get(action, {}).get(gtype, "placeholder") + def createControlHintsWidget(self) -> QWidget: from portprotonqt.localization import _ """Creates a widget displaying control hints for gamepad and keyboard.""" @@ -232,12 +277,12 @@ class MainWindow(QMainWindow): hintsLayout.setContentsMargins(10, 0, 10, 0) hintsLayout.setSpacing(20) - gamepad_hints = [ - ("button_a", _("Select")), - ("button_b", _("Back")), - ("button_x", _("Add Game")), - ("button_start", _("Menu")), - ("button_select", _("Fullscreen")), + gamepad_actions = [ + ("confirm", _("Select")), + ("back", _("Back")), + ("add_game", _("Add Game")), + ("context_menu", _("Menu")), + ("menu", _("Fullscreen")), ] keyboard_hints = [ @@ -250,7 +295,7 @@ class MainWindow(QMainWindow): self.hintsLabels = [] - def makeHint(icon_name: str, action: str, visible: bool): + def makeHint(icon_name: str, action_text: str, is_gamepad: bool, action: str | None = None,): container = QWidget() layout = QHBoxLayout(container) layout.setContentsMargins(0, 0, 0, 0) @@ -262,12 +307,12 @@ class MainWindow(QMainWindow): icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter) pixmap = QPixmap() - icon_path = self.theme_manager.get_theme_image(icon_name, self.current_theme_name) - if not icon_path: - icon_path = self.theme_manager.get_theme_image("placeholder", self.current_theme_name) - - if icon_path: - pixmap.load(str(icon_path)) + for candidate in ( + self.theme_manager.get_theme_image(icon_name, self.current_theme_name), + self.theme_manager.get_theme_image("placeholder", self.current_theme_name), + ): + if candidate is not None and pixmap.load(str(candidate)): + break if not pixmap.isNull(): icon_label.setPixmap(pixmap.scaled( @@ -279,33 +324,43 @@ class MainWindow(QMainWindow): layout.addWidget(icon_label) # текст действия - text_label = QLabel(action) + text_label = QLabel(action_text) text_label.setStyleSheet(self.theme.LAST_LAUNCH_VALUE_STYLE) text_label.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft) layout.addWidget(text_label) - container.setVisible(visible) - self.hintsLabels.append((container, icon_name)) + if is_gamepad: + container.setVisible(False) + self.hintsLabels.append((container, icon_label, action)) # Store action for dynamic update + else: + container.setVisible(True) + self.hintsLabels.append((container, icon_label, None)) # Keyboard, no action + hintsLayout.addWidget(container) - for icon, action in gamepad_hints: - makeHint(icon, action, visible=False) + # Create gamepad hints + for action, text in gamepad_actions: + makeHint("placeholder", text, True, action) # Initial placeholder - for icon, action in keyboard_hints: - makeHint(icon, action, visible=True) + # Create keyboard hints + for icon, text in keyboard_hints: + makeHint(icon, text, False) - hintsLayout.addStretch() # растянуть вправо + hintsLayout.addStretch() return hintsWidget - def updateNavButtons(self, *args) -> None: - """Updates control hints and navigation buttons based on gamepad connection status.""" + """Updates navigation buttons based on gamepad connection status and type.""" is_gamepad_connected = self.input_manager.gamepad is not None - logger.debug("Updating control hints, gamepad connected: %s", is_gamepad_connected) + gtype = self.input_manager.gamepad_type + logger.debug("Updating nav buttons, gamepad connected: %s, type: %s", is_gamepad_connected, gtype.value) # Left navigation button left_pix = QPixmap() - left_icon_name = "button_lb" if is_gamepad_connected else "key_left" + if is_gamepad_connected: + left_icon_name = self.get_nav_icon('left', gtype) + else: + left_icon_name = "key_left" left_icon = self.theme_manager.get_theme_image(left_icon_name, self.current_theme_name) if left_icon: left_pix.load(str(left_icon)) @@ -315,11 +370,14 @@ class MainWindow(QMainWindow): Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation )) - self.leftNavButton.setVisible(is_gamepad_connected or not is_gamepad_connected) + self.leftNavButton.setVisible(True) # Always visible, icon changes # Right navigation button right_pix = QPixmap() - right_icon_name = "button_rb" if is_gamepad_connected else "key_right" + if is_gamepad_connected: + right_icon_name = self.get_nav_icon('right', gtype) + else: + right_icon_name = "key_right" right_icon = self.theme_manager.get_theme_image(right_icon_name, self.current_theme_name) if right_icon: right_pix.load(str(right_icon)) @@ -329,17 +387,41 @@ class MainWindow(QMainWindow): Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation )) - self.rightNavButton.setVisible(is_gamepad_connected or not is_gamepad_connected) + self.rightNavButton.setVisible(True) # Always visible, icon changes def updateControlHints(self, *args) -> None: - """Updates control hints and navigation buttons based on gamepad connection status.""" + """Updates control hints based on gamepad connection status and type.""" is_gamepad_connected = self.input_manager.gamepad is not None - logger.debug("Updating control hints, gamepad connected: %s", is_gamepad_connected) + gtype = self.input_manager.gamepad_type + logger.debug("Updating control hints, gamepad connected: %s, type: %s", is_gamepad_connected, gtype.value) - for container, icon_name in self.hintsLabels: - if icon_name.startswith("button_"): # геймпад - container.setVisible(is_gamepad_connected) - else: # клавиатура + gamepad_actions = ['confirm', 'back', 'add_game', 'context_menu', 'menu'] + + for container, icon_label, action in self.hintsLabels: + if action in gamepad_actions: # Gamepad hint + if is_gamepad_connected: + container.setVisible(True) + # Update icon based on type + icon_name = self.get_button_icon(action, gtype) + icon_path = self.theme_manager.get_theme_image(icon_name, self.current_theme_name) + pixmap = QPixmap() + if icon_path: + pixmap.load(str(icon_path)) + if not pixmap.isNull(): + icon_label.setPixmap(pixmap.scaled( + 32, 32, + Qt.AspectRatioMode.KeepAspectRatio, + Qt.TransformationMode.SmoothTransformation + )) + else: + # Fallback to placeholder + placeholder = self.theme_manager.get_theme_image("placeholder", self.current_theme_name) + if placeholder: + pixmap.load(str(placeholder)) + icon_label.setPixmap(pixmap.scaled(32, 32, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + else: + container.setVisible(False) + else: # Keyboard hint container.setVisible(not is_gamepad_connected) # Update navigation buttons diff --git a/portprotonqt/themes/standart/images/button_a.png b/portprotonqt/themes/standart/images/button_a.png deleted file mode 100644 index e22bb29..0000000 Binary files a/portprotonqt/themes/standart/images/button_a.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/button_b.png b/portprotonqt/themes/standart/images/button_b.png deleted file mode 100644 index 9312c26..0000000 Binary files a/portprotonqt/themes/standart/images/button_b.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/button_lb.png b/portprotonqt/themes/standart/images/button_lb.png deleted file mode 100644 index f6c414b..0000000 Binary files a/portprotonqt/themes/standart/images/button_lb.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/button_rb.png b/portprotonqt/themes/standart/images/button_rb.png deleted file mode 100644 index 5dcfc6d..0000000 Binary files a/portprotonqt/themes/standart/images/button_rb.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/button_select.png b/portprotonqt/themes/standart/images/button_select.png deleted file mode 100644 index 066086a..0000000 Binary files a/portprotonqt/themes/standart/images/button_select.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/button_start.png b/portprotonqt/themes/standart/images/button_start.png deleted file mode 100644 index 190780e..0000000 Binary files a/portprotonqt/themes/standart/images/button_start.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/button_x.png b/portprotonqt/themes/standart/images/button_x.png deleted file mode 100644 index e944b3e..0000000 Binary files a/portprotonqt/themes/standart/images/button_x.png and /dev/null differ diff --git a/portprotonqt/themes/standart/images/key_backspace.png b/portprotonqt/themes/standart/images/key_backspace.png index be1a758..425addc 100644 Binary files a/portprotonqt/themes/standart/images/key_backspace.png and b/portprotonqt/themes/standart/images/key_backspace.png differ diff --git a/portprotonqt/themes/standart/images/key_context.png b/portprotonqt/themes/standart/images/key_context.png index cc24f92..03014ef 100644 Binary files a/portprotonqt/themes/standart/images/key_context.png and b/portprotonqt/themes/standart/images/key_context.png differ diff --git a/portprotonqt/themes/standart/images/key_e.png b/portprotonqt/themes/standart/images/key_e.png index 34b7be1..cd95f3b 100644 Binary files a/portprotonqt/themes/standart/images/key_e.png and b/portprotonqt/themes/standart/images/key_e.png differ diff --git a/portprotonqt/themes/standart/images/key_enter.png b/portprotonqt/themes/standart/images/key_enter.png index 1f144f5..d9d2911 100644 Binary files a/portprotonqt/themes/standart/images/key_enter.png and b/portprotonqt/themes/standart/images/key_enter.png differ diff --git a/portprotonqt/themes/standart/images/key_f11.png b/portprotonqt/themes/standart/images/key_f11.png index 18001d0..10be86f 100644 Binary files a/portprotonqt/themes/standart/images/key_f11.png and b/portprotonqt/themes/standart/images/key_f11.png differ diff --git a/portprotonqt/themes/standart/images/key_left.png b/portprotonqt/themes/standart/images/key_left.png index 3425005..e199d9c 100644 Binary files a/portprotonqt/themes/standart/images/key_left.png and b/portprotonqt/themes/standart/images/key_left.png differ diff --git a/portprotonqt/themes/standart/images/key_right.png b/portprotonqt/themes/standart/images/key_right.png index 929cb35..b8c71f2 100644 Binary files a/portprotonqt/themes/standart/images/key_right.png and b/portprotonqt/themes/standart/images/key_right.png differ diff --git a/portprotonqt/themes/standart/images/placeholder.jpg b/portprotonqt/themes/standart/images/placeholder.jpg index bd38ac7..b913173 100644 Binary files a/portprotonqt/themes/standart/images/placeholder.jpg and b/portprotonqt/themes/standart/images/placeholder.jpg differ diff --git a/portprotonqt/themes/standart/images/ps_circle.png b/portprotonqt/themes/standart/images/ps_circle.png new file mode 100644 index 0000000..f84f7ef Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_circle.png differ diff --git a/portprotonqt/themes/standart/images/ps_cross.png b/portprotonqt/themes/standart/images/ps_cross.png new file mode 100644 index 0000000..de8039c Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_cross.png differ diff --git a/portprotonqt/themes/standart/images/ps_l1.png b/portprotonqt/themes/standart/images/ps_l1.png new file mode 100644 index 0000000..709677f Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_l1.png differ diff --git a/portprotonqt/themes/standart/images/ps_options.png b/portprotonqt/themes/standart/images/ps_options.png new file mode 100644 index 0000000..0a87765 Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_options.png differ diff --git a/portprotonqt/themes/standart/images/ps_r1.png b/portprotonqt/themes/standart/images/ps_r1.png new file mode 100644 index 0000000..78a9be3 Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_r1.png differ diff --git a/portprotonqt/themes/standart/images/ps_share.png b/portprotonqt/themes/standart/images/ps_share.png new file mode 100644 index 0000000..428f031 Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_share.png differ diff --git a/portprotonqt/themes/standart/images/ps_triangle.png b/portprotonqt/themes/standart/images/ps_triangle.png new file mode 100644 index 0000000..c8b579a Binary files /dev/null and b/portprotonqt/themes/standart/images/ps_triangle.png differ diff --git a/portprotonqt/themes/standart/images/screenshots/Библиотека.png b/portprotonqt/themes/standart/images/screenshots/Библиотека.png index f40be7c..16b251c 100644 Binary files a/portprotonqt/themes/standart/images/screenshots/Библиотека.png and b/portprotonqt/themes/standart/images/screenshots/Библиотека.png differ diff --git a/portprotonqt/themes/standart/images/screenshots/Карточка.png b/portprotonqt/themes/standart/images/screenshots/Карточка.png index a974675..94d2d97 100644 Binary files a/portprotonqt/themes/standart/images/screenshots/Карточка.png and b/portprotonqt/themes/standart/images/screenshots/Карточка.png differ diff --git a/portprotonqt/themes/standart/images/screenshots/Карусель скриншотов.png b/portprotonqt/themes/standart/images/screenshots/Карусель скриншотов.png index 6ad956b..404b1e0 100644 Binary files a/portprotonqt/themes/standart/images/screenshots/Карусель скриншотов.png and b/portprotonqt/themes/standart/images/screenshots/Карусель скриншотов.png differ diff --git a/portprotonqt/themes/standart/images/screenshots/Контекстное меню.png b/portprotonqt/themes/standart/images/screenshots/Контекстное меню.png index 802353c..3d6caa4 100644 Binary files a/portprotonqt/themes/standart/images/screenshots/Контекстное меню.png and b/portprotonqt/themes/standart/images/screenshots/Контекстное меню.png differ diff --git a/portprotonqt/themes/standart/images/screenshots/Настройки.png b/portprotonqt/themes/standart/images/screenshots/Настройки.png index 2126667..8997046 100644 Binary files a/portprotonqt/themes/standart/images/screenshots/Настройки.png and b/portprotonqt/themes/standart/images/screenshots/Настройки.png differ diff --git a/portprotonqt/themes/standart/images/screenshots/Оверлей.png b/portprotonqt/themes/standart/images/screenshots/Оверлей.png index e99372d..6ec7657 100644 Binary files a/portprotonqt/themes/standart/images/screenshots/Оверлей.png and b/portprotonqt/themes/standart/images/screenshots/Оверлей.png differ diff --git a/portprotonqt/themes/standart/images/xbox_a.png b/portprotonqt/themes/standart/images/xbox_a.png new file mode 100644 index 0000000..a058ddc Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_a.png differ diff --git a/portprotonqt/themes/standart/images/xbox_b.png b/portprotonqt/themes/standart/images/xbox_b.png new file mode 100644 index 0000000..0c21c3f Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_b.png differ diff --git a/portprotonqt/themes/standart/images/xbox_lb.png b/portprotonqt/themes/standart/images/xbox_lb.png new file mode 100644 index 0000000..70e528c Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_lb.png differ diff --git a/portprotonqt/themes/standart/images/xbox_rb.png b/portprotonqt/themes/standart/images/xbox_rb.png new file mode 100644 index 0000000..a05fd57 Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_rb.png differ diff --git a/portprotonqt/themes/standart/images/xbox_start.png b/portprotonqt/themes/standart/images/xbox_start.png new file mode 100644 index 0000000..835c2ff Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_start.png differ diff --git a/portprotonqt/themes/standart/images/xbox_view.png b/portprotonqt/themes/standart/images/xbox_view.png new file mode 100644 index 0000000..31e644c Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_view.png differ diff --git a/portprotonqt/themes/standart/images/xbox_x.png b/portprotonqt/themes/standart/images/xbox_x.png new file mode 100644 index 0000000..4761f03 Binary files /dev/null and b/portprotonqt/themes/standart/images/xbox_x.png differ