diff --git a/ports/RGSX/__main__.py b/ports/RGSX/__main__.py index df6d4b9..39945c0 100644 --- a/ports/RGSX/__main__.py +++ b/ports/RGSX/__main__.py @@ -24,7 +24,7 @@ from display import ( draw_extension_warning, draw_pause_menu, draw_controls_help, draw_game_list, draw_display_menu, draw_history_list, draw_clear_history_dialog, draw_cancel_download_dialog, - draw_confirm_dialog, draw_redownload_game_cache_dialog, draw_popup, draw_gradient, + draw_confirm_dialog, draw_reload_games_data_dialog, draw_popup, draw_gradient, THEME_COLORS ) from language import _ @@ -204,6 +204,12 @@ else: logger.debug(f"Joysticks détectés: {joystick_names}") for idx, name in enumerate(joystick_names): lname = name.lower() + # Détection spécifique Elite AVANT la détection générique Xbox + if ("microsoft xbox controller" in lname): + config.xbox_elite_controller = True + logger.debug(f"Controller detected (Xbox Elite): {name}") + print(f"Controller detected (Xbox Elite): {name}") + break if ("xbox" in lname) or ("x-box" in lname) or ("xinput" in lname) or ("microsoft x-box" in lname) or ("x-box 360" in lname) or ("360" in lname): config.xbox_controller = True logger.debug(f"Controller detected : {name}") @@ -500,10 +506,10 @@ async def main(): config.needs_redraw = True continue - if config.menu_state == "redownload_game_cache": + if config.menu_state == "reload_games_data": action = handle_controls(event, sources, joystick, screen) config.needs_redraw = True - #logger.debug(f"Événement transmis à handle_controls dans redownload_game_cache: {event.type}") + #logger.debug(f"Événement transmis à handle_controls dans reload_games_data: {event.type}") continue if config.menu_state == "extension_warning": @@ -666,106 +672,7 @@ async def main(): config.menu_state = "history" # Passer à l'historique config.needs_redraw = True logger.debug(f"Téléchargement démarré pour {game_name}, passage à l'historique") - elif action == "redownload" and config.menu_state == "history" and config.history: - entry = config.history[config.current_history_item] - platform_name = entry["platform"] - game_name = entry["game_name"] - for game in config.games: - if isinstance(game, (list, tuple)) and game and game[0] == game_name and config.platforms[config.current_platform] == platform_name: - url = game[1] if len(game) > 1 else None - else: - continue - if not url: - logger.debug(f"Vérification pour retéléchargement de {game_name}, URL: {url}") - if is_1fichier_url(url): - if not config.API_KEY_1FICHIER: - # Fallback AllDebrid - try: - from utils import load_api_key_alldebrid - config.API_KEY_ALLDEBRID = load_api_key_alldebrid() - except Exception: - config.API_KEY_ALLDEBRID = getattr(config, "API_KEY_ALLDEBRID", "") - if not config.API_KEY_1FICHIER and not getattr(config, "API_KEY_ALLDEBRID", ""): - config.previous_menu_state = config.menu_state - config.menu_state = "error" - try: - both_paths = f"{os.path.join(config.SAVE_FOLDER,'1FichierAPI.txt')} or {os.path.join(config.SAVE_FOLDER,'AllDebridAPI.txt')}" - config.error_message = _("error_api_key").format(both_paths) - except Exception: - config.error_message = "Please enter API key (1fichier or AllDebrid)" - config.needs_redraw = True - logger.error("Clé API 1fichier et AllDebrid absentes") - config.pending_download = None - continue - pending = check_extension_before_download(url, platform_name, game_name) - if not pending: - config.menu_state = "error" - config.error_message = _("error_invalid_download_data") if _ else "Invalid download data" - config.needs_redraw = True - logger.error(f"check_extension_before_download a échoué pour {game_name}") - else: - from utils import is_extension_supported, load_extensions_json, sanitize_filename - from rgsx_settings import get_allow_unknown_extensions - is_supported = is_extension_supported(sanitize_filename(game_name), platform_name, load_extensions_json()) - zip_ok = bool(pending[3]) - allow_unknown = False - try: - allow_unknown = get_allow_unknown_extensions() - except Exception: - allow_unknown = False - if (not is_supported and not zip_ok) and not allow_unknown: - config.pending_download = pending - config.menu_state = "extension_warning" - config.extension_confirm_selection = 0 - config.needs_redraw = True - logger.debug(f"Extension non reconnue pour lien 1fichier, passage à extension_warning pour {game_name}") - else: - config.previous_menu_state = config.menu_state - logger.debug(f"Previous menu state défini: {config.previous_menu_state}") - success, message = download_from_1fichier(url, platform_name, game_name, zip_ok) - # Ancien popup download_result supprimé : retour direct à l'historique - config.download_result_message = message - config.download_result_error = not success - config.download_progress.clear() - config.pending_download = None - config.menu_state = "history" - config.needs_redraw = True - logger.debug(f"Retéléchargement 1fichier terminé pour {game_name}, succès={success}, message={message}, retour direct history") - else: - pending = check_extension_before_download(url, platform_name, game_name) - if not pending: - config.menu_state = "error" - config.error_message = _("error_invalid_download_data") if _ else "Invalid download data" - config.needs_redraw = True - logger.error(f"check_extension_before_download a échoué pour {game_name}") - else: - from utils import is_extension_supported, load_extensions_json, sanitize_filename - from rgsx_settings import get_allow_unknown_extensions - is_supported = is_extension_supported(sanitize_filename(game_name), platform_name, load_extensions_json()) - zip_ok = bool(pending[3]) - allow_unknown = False - try: - allow_unknown = get_allow_unknown_extensions() - except Exception: - allow_unknown = False - if (not is_supported and not zip_ok) and not allow_unknown: - config.pending_download = pending - config.menu_state = "extension_warning" - config.extension_confirm_selection = 0 - config.needs_redraw = True - logger.debug(f"Extension non reconnue pour retéléchargement, passage à extension_warning pour {game_name}") - else: - config.previous_menu_state = config.menu_state - logger.debug(f"Previous menu state défini: {config.previous_menu_state}") - success, message = download_rom(url, platform_name, game_name, zip_ok) - config.download_result_message = message - config.download_result_error = not success - config.download_progress.clear() - config.pending_download = None - config.menu_state = "history" - config.needs_redraw = True - logger.debug(f"Retéléchargement terminé pour {game_name}, succès={success}, message={message}, retour direct history") - break + elif action in ("clear_history", "delete_history") and config.menu_state == "history": # Ouvrir le dialogue de confirmation config.previous_menu_state = config.menu_state @@ -906,8 +813,8 @@ async def main(): draw_clear_history_dialog(screen) elif config.menu_state == "confirm_cancel_download": draw_cancel_download_dialog(screen) - elif config.menu_state == "redownload_game_cache": - draw_redownload_game_cache_dialog(screen) + elif config.menu_state == "reload_games_data": + draw_reload_games_data_dialog(screen) elif config.menu_state == "restart_popup": draw_popup(screen) elif config.menu_state == "accessibility_menu": diff --git a/ports/RGSX/assets/controls/xbox_elite_controller.json b/ports/RGSX/assets/controls/xbox_elite_controller.json new file mode 100644 index 0000000..3592391 --- /dev/null +++ b/ports/RGSX/assets/controls/xbox_elite_controller.json @@ -0,0 +1,19 @@ +{ + "confirm": { "type": "button", "button": 1, "display": "A" }, + "cancel": { "type": "button", "button": 2, "display": "B" }, + "clear_history": { "type": "button", "button": 3, "display": "X" }, + "history": { "type": "button", "button": 4, "display": "Y" }, + "delete": { "type": "button", "button": 5, "display": "LB" }, + "space": { "type": "button", "button": 6, "display": "RB" }, + "start": { "type": "button", "button": 8, "display": "Start" }, + "filter": { "type": "button", "button": 7, "display": "Select" }, + "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" }, + "page_up": { "type": "axis", "axis": 5, "direction": -1, "display": "RT" }, + "page_down": { "type": "axis", "axis": 2, "direction": -1, "display": "LT" }, + "meta": { + "notes": "Mapping spécifique Xbox Elite basé sur log fourni. Triggers décalés: LEFT_TRIGGER=AXIS2 -, RIGHT_TRIGGER=AXIS5 -. Les boutons semblent décalés de +1 vs profil 360 standard." + } +} diff --git a/ports/RGSX/config.py b/ports/RGSX/config.py index 0214cfe..f5a69a0 100644 --- a/ports/RGSX/config.py +++ b/ports/RGSX/config.py @@ -13,7 +13,7 @@ except Exception: pygame = None # type: ignore # Version actuelle de l'application -app_version = "2.2.0.7" +app_version = "2.2.0.8" def get_operating_system(): """Renvoie le nom du système d'exploitation.""" @@ -202,7 +202,6 @@ last_state_change_time = 0 # Temps du dernier changement d'état pour debounce debounce_delay = 200 # Délai de debounce en millisecondes platform_dicts = [] # Liste des dictionnaires de plateformes selected_key = (0, 0) # Position du curseur dans le clavier virtuel -redownload_confirm_selection = 0 # Sélection pour la confirmation de redownload popup_message = "" # Message à afficher dans les popups popup_timer = 0 # Temps restant pour le popup en millisecondes (0 = inactif) last_frame_time = pygame.time.get_ticks() if pygame is not None else 0 @@ -224,6 +223,7 @@ eightbitdo_controller = False steam_controller = False trimui_controller = False generic_controller = False +xbox_elite_controller = False # Flag spécifique manette Xbox Elite # --- Filtre plateformes (UI) --- selected_filter_index = 0 # index dans la liste visible triée diff --git a/ports/RGSX/controls.py b/ports/RGSX/controls.py index ed30377..2199430 100644 --- a/ports/RGSX/controls.py +++ b/ports/RGSX/controls.py @@ -33,7 +33,7 @@ key_states = {} # Dictionnaire pour suivre l'état des touches VALID_STATES = [ "platform", "game", "confirm_exit", "extension_warning", "pause_menu", "controls_help", "history", "controls_mapping", - "redownload_game_cache", "restart_popup", "error", "loading", "confirm_clear_history", + "reload_games_data", "restart_popup", "error", "loading", "confirm_clear_history", "language_select", "filter_platforms", "display_menu" ] @@ -105,7 +105,9 @@ def load_controls_config(path=CONTROLS_CONFIG_PATH): candidates.append('steam_controller.json') if getattr(config, 'trimui_controller', False): candidates.append('trimui_controller.json') - if getattr(config, 'xbox_controller', False): + if getattr(config, 'xbox_elite_controller', False): + candidates.append('xbox_elite_controller.json') + elif getattr(config, 'xbox_controller', False): candidates.append('xbox_controller.json') if getattr(config, 'nintendo_controller', False): candidates.append('nintendo_controller.json') @@ -188,7 +190,7 @@ def handle_controls(event, sources, joystick, screen): return "quit" # Menu pause - if is_input_matched(event, "start") and config.menu_state not in ("pause_menu", "controls_mapping", "redownload_game_cache"): + if is_input_matched(event, "start") and config.menu_state not in ("pause_menu", "controls_mapping", "reload_games_data"): config.previous_menu_state = config.menu_state config.menu_state = "pause_menu" config.selected_option = 0 @@ -529,11 +531,11 @@ def handle_controls(event, sources, joystick, screen): config.scroll_offset = 0 config.needs_redraw = True logger.debug("Retour à platform") - elif is_input_matched(event, "redownload_game_cache"): + elif is_input_matched(event, "reload_games_data"): config.previous_menu_state = config.menu_state - config.menu_state = "redownload_game_cache" + config.menu_state = "reload_games_data" config.needs_redraw = True - logger.debug("Passage à redownload_game_cache depuis game") + logger.debug("Passage à reload_games_data depuis game") # Télécharger les jeux sélectionnés (multi) ou le jeu courant elif is_input_matched(event, "confirm"): # Batch multi-sélection @@ -1208,10 +1210,10 @@ def handle_controls(event, sources, joystick, screen): logger.error(f"Erreur changement mode sources: {e}") elif config.selected_option == 6: # Redownload game cache config.previous_menu_state = validate_menu_state(config.previous_menu_state) - config.menu_state = "redownload_game_cache" + config.menu_state = "reload_games_data" config.redownload_confirm_selection = 0 config.needs_redraw = True - logger.debug(f"Passage à redownload_game_cache depuis pause_menu") + logger.debug(f"Passage à reload_games_data depuis pause_menu") elif config.selected_option == 7: # Music toggle config.music_enabled = not config.music_enabled save_music_config() @@ -1354,13 +1356,13 @@ def handle_controls(event, sources, joystick, screen): logger.debug("Retour à pause_menu depuis controls_mapping") # Redownload game cache - elif config.menu_state == "redownload_game_cache": + elif config.menu_state == "reload_games_data": if is_input_matched(event, "left") or is_input_matched(event, "right"): config.redownload_confirm_selection = 1 - config.redownload_confirm_selection config.needs_redraw = True - logger.debug(f"Changement sélection redownload_game_cache: {config.redownload_confirm_selection}") + logger.debug(f"Changement sélection reload_games_data: {config.redownload_confirm_selection}") elif is_input_matched(event, "confirm"): - logger.debug(f"Action confirm dans redownload_game_cache, sélection={config.redownload_confirm_selection}") + logger.debug(f"Action confirm dans reload_games_data, sélection={config.redownload_confirm_selection}") if config.redownload_confirm_selection == 1: # Oui logger.debug("Début du redownload des jeux") config.download_tasks.clear() @@ -1409,7 +1411,7 @@ def handle_controls(event, sources, joystick, screen): elif is_input_matched(event, "cancel"): config.menu_state = validate_menu_state(config.previous_menu_state) config.needs_redraw = True - logger.debug(f"Retour à {config.menu_state} depuis redownload_game_cache") + logger.debug(f"Retour à {config.menu_state} depuis reload_games_data") # Popup de redémarrage diff --git a/ports/RGSX/display.py b/ports/RGSX/display.py index c9e4fe7..acd7138 100644 --- a/ports/RGSX/display.py +++ b/ports/RGSX/display.py @@ -1774,14 +1774,13 @@ def draw_confirm_dialog(screen): draw_stylized_button(screen, _("button_yes"), rect_x + rect_width // 2 - button_width - 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_selection == 1) draw_stylized_button(screen, _("button_no"), rect_x + rect_width // 2 + 10, rect_y + text_height + margin_top_bottom, button_width, button_height, selected=config.confirm_selection == 0) -# draw_redownload_game_cache_dialog -def draw_redownload_game_cache_dialog(screen): + +def draw_reload_games_data_dialog(screen): """Affiche la boîte de dialogue de confirmation pour retélécharger le cache des jeux.""" global OVERLAY if OVERLAY is None or OVERLAY.get_size() != (config.screen_width, config.screen_height): OVERLAY = pygame.Surface((config.screen_width, config.screen_height), pygame.SRCALPHA) OVERLAY.fill((0, 0, 0, 150)) - logger.debug("OVERLAY recréé dans draw_redownload_game_cache_dialog") screen.blit(OVERLAY, (0, 0)) message = _("confirm_redownload_cache")