diff --git a/ports/RGSX/__main__.py b/ports/RGSX/__main__.py index 944d304..d334b5a 100644 --- a/ports/RGSX/__main__.py +++ b/ports/RGSX/__main__.py @@ -10,6 +10,7 @@ import datetime import subprocess import sys import config +import shutil from display import ( init_display, draw_loading_screen, draw_error_screen, draw_platform_grid, @@ -109,31 +110,41 @@ else: logger.debug(f"Joysticks détectés: {joystick_names}, utilisation du joystick par défaut.") # Test des boutons du joystick for name in joystick_names: - if "Xbox" in name or "PlayStation" in name or "Logitech" in name: + if "Xbox" in name: config.xbox_controller = True - logger.debug(f"Manette Xbox/PlayStation/Logitech détectée: {name}") - print(f"Manette Xbox/PlayStation/Logitech détectée: {name}") + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") + break + elif "PlayStation" in name: + config.playstation_controller = True + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") break elif "Nintendo" in name: config.nintendo_controller = True - logger.debug(f"Manette Nintendo détectée: {name}") - print(f"Manette Nintendo détectée: {name}") + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") + elif "Logitech" in name: + config.logitech_controller = True + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") elif "8Bitdo" in name: config.eightbitdo_controller = True - logger.debug(f"Manette 8Bitdo détectée: {name}") - print(f"Manette 8Bitdo détectée: {name}") + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") elif "Steam" in name: config.steam_controller = True - logger.debug(f"Manette Steam détectée: {name}") - print(f"Manette Steam détectée: {name}") + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") elif "TRIMUI Smart Pro" in name: config.trimui_controller = True - logger.debug(f"TRIMUI Smart Pro détectée: {name}") - print(f"TRIMUI Smart Pro détectée: {name}") + logger.debug(f"Controller detected : {name}") + print(f"Controller detected : {name}") else: config.generic_controller = True - logger.debug(f"Manette générique détectée: {name}") - print(f"Manette générique détectée: {name}") + logger.debug(f"Generic controller detected : {name}") + print(f"Generic controller detected : {name}") + # Chargement des paramètres d'accessibilité config.accessibility_settings = load_accessibility_settings() # Appliquer la grille d'affichage depuis les paramètres @@ -233,6 +244,49 @@ config.current_music = current_music # Met à jour la musique en cours dans con config.history = load_history() logger.debug(f"Historique de téléchargement : {len(config.history)} entrées") +# Appliquer un préréglage de contrôles si une manette connue est détectée et qu'aucune config n'existe encore +try: + # Copier uniquement si controls.json est absent ou vide + need_preset = (not os.path.exists(config.CONTROLS_CONFIG_PATH)) or (os.path.getsize(config.CONTROLS_CONFIG_PATH) == 0) + if need_preset: + os.makedirs(os.path.dirname(config.CONTROLS_CONFIG_PATH), exist_ok=True) + + # Cartographie des flags -> fichiers de préconfig + preset_candidates = [] + if getattr(config, 'steam_controller', False): + preset_candidates.append('steam_controller.json') + if getattr(config, 'trimui_controller', False): + preset_candidates.append('trimui_controller.json') + if getattr(config, 'xbox_controller', False): + preset_candidates.append('xbox_controller.json') + if getattr(config, 'playstation_controller', False): + preset_candidates.append('playstation_controller.json') + if getattr(config, 'logitech_controller', False): + preset_candidates.append('logitech_controller.json') + if getattr(config, 'nintendo_controller', False): + preset_candidates.append('nintendo_controller.json') + if getattr(config, 'eightbitdo_controller', False): + preset_candidates.append('8bitdo_controller.json') + if getattr(config, 'generic_controller', False): + preset_candidates.append('generic_controller.json') + + # Toujours tenter un générique en dernier recours + if 'generic_controller.json' not in preset_candidates: + preset_candidates.append('generic_controller.json') + + for fname in preset_candidates: + src = os.path.join(config.PRECONF_CONTROLS_PATH, fname) + if os.path.exists(src): + try: + shutil.copyfile(src, config.CONTROLS_CONFIG_PATH) + logger.info(f"Préconfiguration des contrôles appliquée depuis {src}") + print(f"Préconfiguration des contrôles appliquée: {fname}") + break + except Exception as e: + logger.error(f"Échec de la copie du préréglage {src} -> {config.CONTROLS_CONFIG_PATH}: {e}") +except Exception as e: + logger.error(f"Erreur lors de l'application d'un préréglage de contrôles: {e}") + # Vérification et chargement de la configuration des contrôles config.controls_config = load_controls_config() @@ -241,8 +295,8 @@ if config.controls_config is None: config.controls_config = {} logger.debug("Initialisation de config.controls_config avec un dictionnaire vide") -# Vérifier simplement si le fichier controls.json existe -if not os.path.exists(config.CONTROLS_CONFIG_PATH) or not config.controls_config: +# Vérifier si une configuration utilisateur est absente ET qu'aucune config n'a été chargée (préréglage) +if (not os.path.exists(config.CONTROLS_CONFIG_PATH)) and (not config.controls_config): logger.warning("Fichier controls.json manquant ou vide, configuration manuelle nécessaire") # Ajouter une configuration minimale de secours pour pouvoir naviguer config.controls_config = get_emergency_controls() diff --git a/ports/RGSX/assets/controls/eightbitdo_controller.json b/ports/RGSX/assets/controls/eightbitdo_controller.json new file mode 100644 index 0000000..d050482 --- /dev/null +++ b/ports/RGSX/assets/controls/eightbitdo_controller.json @@ -0,0 +1,74 @@ +{ + "confirm": { + "type": "button", + "button": 0, + "display": "A" + }, + "cancel": { + "type": "button", + "button": 1, + "display": "B" + }, + "up": { + "type": "hat", + "value": [0, 1], + "display": "↑" + }, + "down": { + "type": "hat", + "value": [0, -1], + "display": "↓" + }, + "left": { + "type": "hat", + "value": [-1, 0], + "display": "←" + }, + "right": { + "type": "hat", + "value": [1, 0], + "display": "→" + }, + "start": { + "type": "button", + "button": 7, + "display": "Start" + }, + "filter": { + "type": "button", + "button": 6, + "display": "Select" + }, + "page_up": { + "type": "axis", + "axis": 4, + "direction": 1, + "display": "RT" + }, + "page_down": { + "type": "axis", + "axis": 5, + "direction": -1, + "display": "LT" + }, + "history": { + "type": "button", + "button": 3, + "display": "Y" + }, + "clear_history": { + "type": "button", + "button": 2, + "display": "X" + }, + "delete": { + "type": "button", + "button": 4, + "display": "LB" + }, + "space": { + "type": "button", + "button": 5, + "display": "RB" + } +} diff --git a/ports/RGSX/assets/controls/generic_controller.json b/ports/RGSX/assets/controls/generic_controller.json new file mode 100644 index 0000000..d050482 --- /dev/null +++ b/ports/RGSX/assets/controls/generic_controller.json @@ -0,0 +1,74 @@ +{ + "confirm": { + "type": "button", + "button": 0, + "display": "A" + }, + "cancel": { + "type": "button", + "button": 1, + "display": "B" + }, + "up": { + "type": "hat", + "value": [0, 1], + "display": "↑" + }, + "down": { + "type": "hat", + "value": [0, -1], + "display": "↓" + }, + "left": { + "type": "hat", + "value": [-1, 0], + "display": "←" + }, + "right": { + "type": "hat", + "value": [1, 0], + "display": "→" + }, + "start": { + "type": "button", + "button": 7, + "display": "Start" + }, + "filter": { + "type": "button", + "button": 6, + "display": "Select" + }, + "page_up": { + "type": "axis", + "axis": 4, + "direction": 1, + "display": "RT" + }, + "page_down": { + "type": "axis", + "axis": 5, + "direction": -1, + "display": "LT" + }, + "history": { + "type": "button", + "button": 3, + "display": "Y" + }, + "clear_history": { + "type": "button", + "button": 2, + "display": "X" + }, + "delete": { + "type": "button", + "button": 4, + "display": "LB" + }, + "space": { + "type": "button", + "button": 5, + "display": "RB" + } +} diff --git a/ports/RGSX/assets/controls/keyboard.json b/ports/RGSX/assets/controls/keyboard.json new file mode 100644 index 0000000..82108a5 --- /dev/null +++ b/ports/RGSX/assets/controls/keyboard.json @@ -0,0 +1,72 @@ +{ + "confirm": { + "type": "key", + "key": 13, + "display": "Enter" + }, + "cancel": { + "type": "key", + "key": 27, + "display": "\u00c9chap" + }, + "up": { + "type": "key", + "key": 1073741906, + "display": "\u2191" + }, + "down": { + "type": "key", + "key": 1073741905, + "display": "\u2193" + }, + "left": { + "type": "key", + "key": 1073741904, + "display": "\u2190" + }, + "right": { + "type": "key", + "key": 1073741903, + "display": "\u2192" + }, + "start": { + "type": "key", + "key": 1073742054, + "display": "AltGR" + }, + "filter": { + "type": "key", + "key": 102, + "display": "F" + }, + "page_up": { + "type": "key", + "key": 1073741899, + "display": "Page+" + }, + "page_down": { + "type": "key", + "key": 1073741902, + "display": "Page-" + }, + "history": { + "type": "key", + "key": 104, + "display": "H" + }, + "clear_history": { + "type": "key", + "key": 120, + "display": "X" + }, + "delete": { + "type": "key", + "key": 8, + "display": "Backspace" + }, + "space": { + "type": "key", + "key": 32, + "display": "Espace" + } +} \ No newline at end of file diff --git a/ports/RGSX/assets/controls/nintendo_controller.json b/ports/RGSX/assets/controls/nintendo_controller.json new file mode 100644 index 0000000..cdcd087 --- /dev/null +++ b/ports/RGSX/assets/controls/nintendo_controller.json @@ -0,0 +1,74 @@ +{ + "confirm": { + "type": "button", + "button": 1, + "display": "B" + }, + "cancel": { + "type": "button", + "button": 0, + "display": "A" + }, + "up": { + "type": "hat", + "value": [0, 1], + "display": "↑" + }, + "down": { + "type": "hat", + "value": [0, -1], + "display": "↓" + }, + "left": { + "type": "hat", + "value": [-1, 0], + "display": "←" + }, + "right": { + "type": "hat", + "value": [1, 0], + "display": "→" + }, + "start": { + "type": "button", + "button": 7, + "display": "Start" + }, + "filter": { + "type": "button", + "button": 6, + "display": "Select" + }, + "page_up": { + "type": "axis", + "axis": 4, + "direction": 1, + "display": "ZR" + }, + "page_down": { + "type": "axis", + "axis": 5, + "direction": -1, + "display": "ZL" + }, + "history": { + "type": "button", + "button": 3, + "display": "Y" + }, + "clear_history": { + "type": "button", + "button": 2, + "display": "X" + }, + "delete": { + "type": "button", + "button": 4, + "display": "L" + }, + "space": { + "type": "button", + "button": 5, + "display": "R" + } +} diff --git a/ports/RGSX/assets/controls/steam_controller.json b/ports/RGSX/assets/controls/steam_controller.json new file mode 100644 index 0000000..6cf3cf0 --- /dev/null +++ b/ports/RGSX/assets/controls/steam_controller.json @@ -0,0 +1,74 @@ +{ + "confirm": { + "type": "button", + "button": 3, + "display": "A" + }, + "cancel": { + "type": "button", + "button": 4, + "display": "B" + }, + "up": { + "type": "button", + "button": 16, + "display": "↑" + }, + "down": { + "type": "button", + "button": 17, + "display": "↓" + }, + "left": { + "type": "button", + "button": 18, + "display": "←" + }, + "right": { + "type": "button", + "button": 19, + "display": "→" + }, + "start": { + "type": "button", + "button": 12, + "display": "Start" + }, + "filter": { + "type": "button", + "button": 11, + "display": "Select" + }, + "page_up": { + "type": "axis", + "axis": 2, + "direction": -1, + "display": "L2" + }, + "page_down": { + "type": "axis", + "axis": 5, + "direction": -1, + "display": "R2" + }, + "history": { + "type": "button", + "button": 6, + "display": "Y" + }, + "clear_history": { + "type": "button", + "button": 5, + "display": "X" + }, + "delete": { + "type": "button", + "button": 7, + "display": "L1" + }, + "space": { + "type": "button", + "button": 8, + "display": "R1" + } +} \ No newline at end of file diff --git a/ports/RGSX/assets/controls/trimui_controller.json b/ports/RGSX/assets/controls/trimui_controller.json new file mode 100644 index 0000000..f6fb76b --- /dev/null +++ b/ports/RGSX/assets/controls/trimui_controller.json @@ -0,0 +1,84 @@ +{ + "confirm": { + "type": "button", + "button": 0, + "display": "B" + }, + "cancel": { + "type": "button", + "button": 1, + "display": "A" + }, + "up": { + "type": "hat", + "value": [ + 0, + 1 + ], + "display": "↑" + }, + "down": { + "type": "hat", + "value": [ + 0, + -1 + ], + "display": "↓" + }, + "left": { + "type": "hat", + "value": [ + -1, + 0 + ], + "display": "←" + }, + "right": { + "type": "hat", + "value": [ + 1, + 0 + ], + "display": "→" + }, + "start": { + "type": "button", + "button": 9, + "display": "Start" + }, + "filter": { + "type": "button", + "button": 8, + "display": "Select" + }, + "page_up": { + "type": "button", + "button": 7, + "display": "R2" + }, + "page_down": { + "type": "button", + "button": 6, + "display": "L2" + }, + "history": { + "type": "button", + "button": 2, + "display": "X" + }, + "clear_history": { + "type": "button", + "button": 3, + "display": "Y" + }, + "delete": { + "type": "button", + "button": 5, + "display": "L1" + }, + "space": { + "type": "button", + "button": 4, + "display": "R1" + } +} \ No newline at end of file diff --git a/ports/RGSX/assets/controls/xbox_controller.json b/ports/RGSX/assets/controls/xbox_controller.json new file mode 100644 index 0000000..98f56c5 --- /dev/null +++ b/ports/RGSX/assets/controls/xbox_controller.json @@ -0,0 +1,86 @@ +{ + "confirm": { + "type": "button", + "button": 0, + "display": "A" + }, + "cancel": { + "type": "button", + "button": 1, + "display": "B" + }, + "up": { + "type": "hat", + "value": [ + 0, + 1 + ], + "display": "\u2191" + }, + "down": { + "type": "hat", + "value": [ + 0, + -1 + ], + "display": "\u2193" + }, + "left": { + "type": "hat", + "value": [ + -1, + 0 + ], + "display": "\u2190" + }, + "right": { + "type": "hat", + "value": [ + 1, + 0 + ], + "display": "\u2192" + }, + "start": { + "type": "button", + "button": 7, + "display": "Start" + }, + "filter": { + "type": "button", + "button": 6, + "display": "Select" + }, + "page_up": { + "type": "axis", + "axis": 4, + "direction": 1, + "display": "RT" + }, + "page_down": { + "type": "axis", + "axis": 5, + "direction": -1, + "display": "LT" + }, + "history": { + "type": "button", + "button": 3, + "display": "Select" + }, + "clear_history": { + "type": "button", + "button": 2, + "display": "X" + }, + "delete": { + "type": "button", + "button": 4, + "display": "LB" + }, + "space": { + "type": "button", + "button": 5, + "display": "RB" + } +} \ No newline at end of file diff --git a/ports/RGSX/config.py b/ports/RGSX/config.py index a63b419..6479924 100644 --- a/ports/RGSX/config.py +++ b/ports/RGSX/config.py @@ -4,7 +4,7 @@ import logging import platform # Version actuelle de l'application -app_version = "2.1.0.2" +app_version = "2.2.0.0" def get_operating_system(): """Renvoie le nom du système d'exploitation.""" @@ -87,6 +87,7 @@ IMAGES_FOLDER = os.path.join(SAVE_FOLDER, "images") GAMES_FOLDER = os.path.join(SAVE_FOLDER, "games") SOURCES_FILE = os.path.join(SAVE_FOLDER, "systems_list.json") JSON_EXTENSIONS = os.path.join(SAVE_FOLDER, "rom_extensions.json") +PRECONF_CONTROLS_PATH = os.path.join(APP_FOLDER, "assets", "controls") CONTROLS_CONFIG_PATH = os.path.join(SAVE_FOLDER, "controls.json") HISTORY_PATH = os.path.join(SAVE_FOLDER, "history.json") API_KEY_1FICHIER = os.path.join(SAVE_FOLDER, "1fichierAPI.txt") diff --git a/ports/RGSX/controls.py b/ports/RGSX/controls.py index 2e48594..10a3317 100644 --- a/ports/RGSX/controls.py +++ b/ports/RGSX/controls.py @@ -47,7 +47,12 @@ def validate_menu_state(state): def load_controls_config(path=CONTROLS_CONFIG_PATH): - """Charge la configuration des contrôles depuis un fichier JSON.""" + """Charge la configuration des contrôles. + Priorité: + 1) Fichier utilisateur dans SAVE_FOLDER (controls.json) + 2) Préréglage correspondant dans PRECONF_CONTROLS_PATH (sans copie) + 3) Configuration clavier par défaut + """ default_config = { "confirm": {"type": "key", "key": pygame.K_RETURN}, "cancel": {"type": "key", "key": pygame.K_ESCAPE}, @@ -66,24 +71,65 @@ def load_controls_config(path=CONTROLS_CONFIG_PATH): } try: + # 1) Fichier utilisateur if os.path.exists(path): with open(path, "r", encoding="utf-8") as f: data = json.load(f) if not isinstance(data, dict): data = {} - else: - data = {} - changed = False - for k, v in default_config.items(): - if k not in data: - data[k] = v - changed = True - if changed: - os.makedirs(os.path.dirname(path), exist_ok=True) - with open(path, "w", encoding="utf-8") as f: - json.dump(data, f, indent=2) - logging.getLogger(__name__).debug(f"controls.json complété avec les actions manquantes: {path}") - return data + # Compléter les actions manquantes, et sauve seulement si le fichier utilisateur existe + changed = False + for k, v in default_config.items(): + if k not in data: + data[k] = v + changed = True + if changed: + try: + os.makedirs(os.path.dirname(path), exist_ok=True) + with open(path, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2) + logging.getLogger(__name__).debug(f"controls.json complété avec les actions manquantes: {path}") + except Exception as e: + logging.getLogger(__name__).warning(f"Impossible d'écrire les actions manquantes dans {path}: {e}") + return data + + # 2) Préréglages sans copie si aucun fichier utilisateur + try: + candidates = [] + # Si aucun contrôleur détecté, privilégier le préréglage clavier + if not getattr(config, 'joystick', False) or getattr(config, 'keyboard', False): + candidates.append('keyboard.json') + # Déterminer les préréglages disponibles selon les flags détectés au démarrage + if getattr(config, 'steam_controller', False): + candidates.append('steam_controller.json') + if getattr(config, 'trimui_controller', False): + candidates.append('trimui_controller.json') + if getattr(config, 'xbox_controller', False): + candidates.append('xbox_controller.json') + if getattr(config, 'nintendo_controller', False): + candidates.append('nintendo_controller.json') + if getattr(config, 'eightbitdo_controller', False): + candidates.append('8bitdo_controller.json') + # Fallbacks génériques + if 'generic_controller.json' not in candidates: + candidates.append('generic_controller.json') + if 'xbox_controller.json' not in candidates: + candidates.append('xbox_controller.json') + + for fname in candidates: + src = os.path.join(config.PRECONF_CONTROLS_PATH, fname) + if os.path.exists(src): + with open(src, "r", encoding="utf-8") as f: + data = json.load(f) + if isinstance(data, dict) and data: + logging.getLogger(__name__).info(f"Chargement des contrôles préréglés: {fname}") + return data + except Exception as e: + logging.getLogger(__name__).warning(f"Échec du chargement des contrôles préréglés: {e}") + + # 3) Fallback clavier par défaut + logging.getLogger(__name__).info("Aucun fichier utilisateur ou préréglage trouvé, utilisation des contrôles par défaut") + return default_config.copy() except Exception as e: logging.getLogger(__name__).error(f"Erreur load_controls_config: {e}") return default_config.copy() diff --git a/ports/RGSX/languages/fr.json b/ports/RGSX/languages/fr.json index f0fe2df..0bffcfe 100644 --- a/ports/RGSX/languages/fr.json +++ b/ports/RGSX/languages/fr.json @@ -9,7 +9,7 @@ "loading_test_connection": "Test de la connexion...", "loading_download_data": "Téléchargement des jeux et images...", "loading_progress": "Progression : {0}%", - "loading_check_updates": "Vérification des mises à jour... Veuillez patienter...", + "loading_check_updates": "Mise à jour... Veuillez patienter...", "error_check_updates_failed": "Échec de la vérification des mises à jour.", "loading_downloading_games_images": "Téléchargement des jeux et images...", "loading_extracting_data": "Extraction du dossier de données initial...",