forked from Mirrors/RGSX
v1.9.7.2 - Mappage auto des controles grace au fichier es_input (en test) et correction de bug téléchargement sur myrient
This commit is contained in:
66
__main__.py
66
__main__.py
@@ -40,10 +40,7 @@ logger = logging.getLogger(__name__)
|
||||
pygame.init()
|
||||
config.init_font()
|
||||
pygame.joystick.init()
|
||||
pygame.mouse.set_visible(True)
|
||||
|
||||
# Initialisation du sélecteur de langue
|
||||
update_valid_states()
|
||||
|
||||
# Chargement et initialisation de la langue
|
||||
from language import initialize_language
|
||||
@@ -55,9 +52,10 @@ config.is_non_pc = detect_non_pc()
|
||||
|
||||
# Initialisation de l’écran
|
||||
screen = init_display()
|
||||
pygame.display.set_caption("RGSX")
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
pygame.display.set_caption("RGSX")
|
||||
|
||||
# Initialisation des polices
|
||||
try:
|
||||
font_path = os.path.join(config.APP_FOLDER, "assets", "Pixel-UniCode.ttf")
|
||||
@@ -66,18 +64,18 @@ try:
|
||||
config.search_font = pygame.font.Font(font_path, 48) # Police pour la recherche
|
||||
config.progress_font = pygame.font.Font(font_path, 36) # Police pour l'affichage de la progression
|
||||
config.small_font = pygame.font.Font(font_path, 28) # Police pour les petits textes
|
||||
logger.debug("Police Pixel-UniCode chargée")
|
||||
#logger.debug("Police Pixel-UniCode chargée")
|
||||
except:
|
||||
config.font = pygame.font.SysFont("arial", 48) # Police fallback
|
||||
config.title_font = pygame.font.SysFont("arial", 60) # Police fallback pour les titres
|
||||
config.search_font = pygame.font.SysFont("arial", 60) # Police fallback pour la recherche
|
||||
config.progress_font = pygame.font.SysFont("arial", 36) # Police fallback pour l'affichage de la progression
|
||||
config.small_font = pygame.font.SysFont("arial", 28) # Police fallback pour les petits textes
|
||||
logger.debug("Police Arial chargée")
|
||||
#logger.debug("Police Arial chargée")
|
||||
|
||||
# Mise à jour de la résolution dans config
|
||||
config.screen_width, config.screen_height = pygame.display.get_surface().get_size()
|
||||
logger.debug(f"Résolution réelle : {config.screen_width}x{config.screen_height}")
|
||||
logger.debug(f"Résolution d'écran : {config.screen_width}x{config.screen_height}")
|
||||
|
||||
# Initialisation des variables de grille
|
||||
config.current_page = 0
|
||||
@@ -106,21 +104,17 @@ else:
|
||||
|
||||
# Chargement de l'historique
|
||||
config.history = load_history()
|
||||
logger.debug(f"Historique chargé: {len(config.history)} entrées")
|
||||
|
||||
# Vérifier si le fichier de configuration des contrôles existe
|
||||
controls_file_exists = os.path.exists(config.CONTROLS_CONFIG_PATH)
|
||||
logger.debug(f"Fichier controls.json existe: {controls_file_exists} à {config.CONTROLS_CONFIG_PATH}")
|
||||
logger.debug(f"Historique de téléchargement : {len(config.history)} entrées")
|
||||
|
||||
# Vérification et chargement de la configuration des contrôles
|
||||
config.controls_config = load_controls_config()
|
||||
|
||||
# Déterminer l'état initial de l'application
|
||||
if not controls_file_exists:
|
||||
# Si pas de fichier de contrôles, on commence par les configurer
|
||||
# Vérifier si la configuration est vide (pas de fichier ou importation échouée)
|
||||
if not config.controls_config:
|
||||
# Si pas de configuration, on commence par les configurer
|
||||
config.menu_state = "controls_mapping"
|
||||
config.needs_redraw = True # Forcer le redraw immédiatement
|
||||
logger.info(f"Pas de fichier de contrôles à {config.CONTROLS_CONFIG_PATH}, configuration des contrôles")
|
||||
logger.info("Aucune configuration de contrôles disponible, configuration manuelle nécessaire")
|
||||
logger.debug("Menu initial: mappage des contrôles")
|
||||
else:
|
||||
# Sinon, chargement normal
|
||||
@@ -153,8 +147,6 @@ async def main():
|
||||
last_redraw_time = pygame.time.get_ticks()
|
||||
config.last_frame_time = pygame.time.get_ticks() # Initialisation pour éviter erreur
|
||||
|
||||
screen = init_display()
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while running:
|
||||
clock.tick(30) # Limite à 60 FPS
|
||||
@@ -219,11 +211,11 @@ async def main():
|
||||
|
||||
start_config = config.controls_config.get("start", {})
|
||||
if start_config and (
|
||||
(event.type == pygame.KEYDOWN and start_config.get("type") == "key" and event.key == start_config.get("value")) or
|
||||
(event.type == pygame.JOYBUTTONDOWN and start_config.get("type") == "button" and event.button == start_config.get("value")) or
|
||||
(event.type == pygame.JOYAXISMOTION and start_config.get("type") == "axis" and event.axis == start_config.get("value")[0] and abs(event.value) > 0.5 and (1 if event.value > 0 else -1) == start_config.get("value")[1]) or
|
||||
(event.type == pygame.JOYHATMOTION and start_config.get("type") == "hat" and event.value == tuple(start_config.get("value"))) or
|
||||
(event.type == pygame.MOUSEBUTTONDOWN and start_config.get("type") == "mouse" and event.button == start_config.get("value"))
|
||||
(event.type == pygame.KEYDOWN and start_config.get("type") == "key" and event.key == start_config.get("key")) or
|
||||
(event.type == pygame.JOYBUTTONDOWN and start_config.get("type") == "button" and event.button == start_config.get("button")) or
|
||||
(event.type == pygame.JOYAXISMOTION and start_config.get("type") == "axis" and event.axis == start_config.get("axis") and abs(event.value) > 0.5 and (1 if event.value > 0 else -1) == start_config.get("direction")) or
|
||||
(event.type == pygame.JOYHATMOTION and start_config.get("type") == "hat" and event.value == tuple(start_config.get("value") if isinstance(start_config.get("value"), list) else start_config.get("value"))) or
|
||||
(event.type == pygame.MOUSEBUTTONDOWN and start_config.get("type") == "mouse" and event.button == start_config.get("button"))
|
||||
):
|
||||
if config.menu_state not in ["pause_menu", "controls_help", "controls_mapping", "history", "confirm_clear_history"]:
|
||||
config.previous_menu_state = config.menu_state
|
||||
@@ -236,33 +228,25 @@ async def main():
|
||||
if config.menu_state == "pause_menu":
|
||||
action = handle_controls(event, sources, joystick, screen)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Événement transmis à handle_controls dans pause_menu: {event.type}")
|
||||
#logger.debug(f"Événement transmis à handle_controls dans pause_menu: {event.type}")
|
||||
continue
|
||||
|
||||
if config.menu_state == "controls_help":
|
||||
cancel_config = config.controls_config.get("cancel", {})
|
||||
if (
|
||||
(event.type == pygame.KEYDOWN and cancel_config and event.key == cancel_config.get("value")) or
|
||||
(event.type == pygame.JOYBUTTONDOWN and cancel_config and cancel_config.get("type") == "button" and event.button == cancel_config.get("value")) or
|
||||
(event.type == pygame.JOYAXISMOTION and cancel_config and cancel_config.get("type") == "axis" and event.axis == cancel_config.get("value")[0] and abs(event.value) > 0.5 and (1 if event.value > 0 else -1) == cancel_config.get("value")[1]) or
|
||||
(event.type == pygame.JOYHATMOTION and cancel_config and cancel_config.get("type") == "hat" and event.value == tuple(cancel_config.get("value")))
|
||||
):
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "pause_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug("Controls_help: Annulation, retour à pause_menu")
|
||||
action = handle_controls(event, sources, joystick, screen)
|
||||
config.needs_redraw = True
|
||||
#logger.debug(f"Événement transmis à handle_controls dans controls_help: {event.type}")
|
||||
continue
|
||||
|
||||
if config.menu_state == "confirm_clear_history":
|
||||
action = handle_controls(event, sources, joystick, screen)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Événement transmis à handle_controls dans confirm_clear_history: {event.type}")
|
||||
#logger.debug(f"Événement transmis à handle_controls dans confirm_clear_history: {event.type}")
|
||||
continue
|
||||
|
||||
if config.menu_state == "redownload_game_cache":
|
||||
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 redownload_game_cache: {event.type}")
|
||||
continue
|
||||
|
||||
if config.menu_state == "extension_warning":
|
||||
@@ -570,7 +554,7 @@ async def main():
|
||||
draw_extension_warning(screen)
|
||||
elif config.menu_state == "pause_menu":
|
||||
draw_pause_menu(screen, config.selected_option)
|
||||
logger.debug("Rendu de draw_pause_menu")
|
||||
#logger.debug("Rendu de draw_pause_menu")
|
||||
elif config.menu_state == "controls_help":
|
||||
draw_controls_help(screen, config.previous_menu_state)
|
||||
elif config.menu_state == "history":
|
||||
@@ -582,10 +566,6 @@ async def main():
|
||||
draw_redownload_game_cache_dialog(screen)
|
||||
elif config.menu_state == "restart_popup":
|
||||
draw_popup(screen)
|
||||
elif config.menu_state == "language_select":
|
||||
draw_language_menu(screen)
|
||||
# Ajout de log pour déboguer
|
||||
logger.debug(f"Affichage du sélecteur de langue, index={config.selected_language_index}")
|
||||
else:
|
||||
config.menu_state = "platform"
|
||||
draw_platform_grid(screen)
|
||||
@@ -646,7 +626,7 @@ async def main():
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Étape chargement : {loading_step}, progress={config.loading_progress}")
|
||||
elif loading_step == "test_internet":
|
||||
logger.debug("Exécution de test_internet()")
|
||||
#logger.debug("Exécution de test_internet()")
|
||||
if test_internet():
|
||||
loading_step = "check_ota"
|
||||
config.current_loading_system = "Verification Mise à jour en cours... Patientez..."
|
||||
|
||||
BIN
assets/music/game_8bit.mp3
Normal file
BIN
assets/music/game_8bit.mp3
Normal file
Binary file not shown.
BIN
assets/music/level_IV.mp3
Normal file
BIN
assets/music/level_IV.mp3
Normal file
Binary file not shown.
BIN
assets/music/retro_chill.mp3
Normal file
BIN
assets/music/retro_chill.mp3
Normal file
Binary file not shown.
@@ -5,7 +5,7 @@ import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Version actuelle de l'application
|
||||
app_version = "1.9.7.1"
|
||||
app_version = "1.9.7.2"
|
||||
|
||||
# Langue par défaut
|
||||
current_language = "fr"
|
||||
@@ -117,6 +117,10 @@ small_font = None
|
||||
|
||||
def init_font():
|
||||
"""Initialise les polices après pygame.init()."""
|
||||
logger.debug("--------------------------------------------------------------------")
|
||||
logger.debug("---------------------------DEBUT LOG--------------------------------")
|
||||
logger.debug("--------------------------------------------------------------------")
|
||||
|
||||
global FONT, progress_font, title_font, search_font, small_font
|
||||
try:
|
||||
FONT = pygame.font.Font(None, 36)
|
||||
|
||||
144
controls.py
144
controls.py
@@ -98,23 +98,22 @@ def is_input_matched(event, action_name):
|
||||
return False
|
||||
mapping = config.controls_config[action_name]
|
||||
input_type = mapping["type"]
|
||||
input_value = mapping["value"]
|
||||
|
||||
# Convertir input_value en tuple si c'est une liste (pour JOYHATMOTION)
|
||||
if input_type == "hat" and isinstance(input_value, list):
|
||||
input_value = tuple(input_value)
|
||||
|
||||
|
||||
if input_type == "key" and event.type == pygame.KEYDOWN:
|
||||
return event.key == input_value
|
||||
return event.key == mapping.get("key")
|
||||
elif input_type == "button" and event.type == pygame.JOYBUTTONDOWN:
|
||||
return event.button == input_value
|
||||
return event.button == mapping.get("button")
|
||||
elif input_type == "axis" and event.type == pygame.JOYAXISMOTION:
|
||||
axis, direction = input_value
|
||||
axis = mapping.get("axis")
|
||||
direction = mapping.get("direction")
|
||||
return event.axis == axis and abs(event.value) > 0.5 and (1 if event.value > 0 else -1) == direction
|
||||
elif input_type == "hat" and event.type == pygame.JOYHATMOTION:
|
||||
return event.value == input_value
|
||||
hat_value = mapping.get("value")
|
||||
if isinstance(hat_value, list):
|
||||
hat_value = tuple(hat_value)
|
||||
return event.value == hat_value
|
||||
elif input_type == "mouse" and event.type == pygame.MOUSEBUTTONDOWN:
|
||||
return event.button == input_value
|
||||
return event.button == mapping.get("button")
|
||||
return False
|
||||
|
||||
def handle_controls(event, sources, joystick, screen):
|
||||
@@ -146,7 +145,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_help", "controls_mapping", "redownload_game_cache"):
|
||||
if is_input_matched(event, "start") and config.menu_state not in ("pause_menu", "controls_mapping", "redownload_game_cache"):
|
||||
config.previous_menu_state = config.menu_state
|
||||
config.menu_state = "pause_menu"
|
||||
config.selected_option = 0
|
||||
@@ -375,13 +374,30 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug("Sortie du mode recherche")
|
||||
elif is_input_matched(event, "filter"):
|
||||
elif is_input_matched(event, "filter") or is_input_matched(event, "confirm"):
|
||||
config.search_mode = False
|
||||
config.filter_active = bool(config.search_query)
|
||||
config.needs_redraw = True
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Validation du filtre avec manette: query={config.search_query}, filter_active={config.filter_active}")
|
||||
elif config.search_mode and not config.is_non_pc:
|
||||
# Gestion de la recherche sur PC
|
||||
if event.type == pygame.KEYDOWN:
|
||||
# Gestion de la recherche sur PC (clavier et manette)
|
||||
if is_input_matched(event, "filter"):
|
||||
config.search_mode = False
|
||||
config.filter_active = True
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Validation du filtre avec bouton filter sur PC: query={config.search_query}")
|
||||
elif is_input_matched(event, "cancel"):
|
||||
config.search_mode = False
|
||||
config.search_query = ""
|
||||
config.filtered_games = config.games
|
||||
config.filter_active = False
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug("Sortie du mode recherche avec bouton cancel sur PC")
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
# Saisie de texte alphanumérique
|
||||
if event.unicode.isalnum() or event.unicode == ' ':
|
||||
config.search_query += event.unicode
|
||||
@@ -416,6 +432,14 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug("Sortie du mode recherche")
|
||||
# Gestion de la validation avec le bouton filter
|
||||
elif is_input_matched(event, "filter"):
|
||||
config.search_mode = False
|
||||
config.filter_active = True
|
||||
config.current_game = 0
|
||||
config.scroll_offset = 0
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Validation du filtre avec bouton filter: query={config.search_query}, jeux filtrés={len(config.filtered_games)}")
|
||||
|
||||
else:
|
||||
if is_input_matched(event, "up"):
|
||||
@@ -813,27 +837,27 @@ def handle_controls(event, sources, joystick, screen):
|
||||
|
||||
# Menu pause
|
||||
elif config.menu_state == "pause_menu":
|
||||
logger.debug(f"État pause_menu, selected_option={config.selected_option}, événement={event.type}, valeur={getattr(event, 'value', None)}")
|
||||
#logger.debug(f"État pause_menu, selected_option={config.selected_option}, événement={event.type}, valeur={getattr(event, 'value', None)}")
|
||||
if is_input_matched(event, "up"):
|
||||
config.selected_option = max(0, config.selected_option - 1)
|
||||
# La répétition est gérée par update_key_state
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Navigation vers le haut: selected_option={config.selected_option}")
|
||||
#logger.debug(f"Navigation vers le haut: selected_option={config.selected_option}")
|
||||
elif is_input_matched(event, "down"):
|
||||
config.selected_option = min(5, config.selected_option + 1)
|
||||
# La répétition est gérée par update_key_state
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Navigation vers le bas: selected_option={config.selected_option}")
|
||||
#logger.debug(f"Navigation vers le bas: selected_option={config.selected_option}")
|
||||
elif is_input_matched(event, "confirm"):
|
||||
logger.debug(f"Confirmation dans pause_menu avec selected_option={config.selected_option}")
|
||||
#logger.debug(f"Confirmation dans pause_menu avec selected_option={config.selected_option}")
|
||||
if config.selected_option == 0: # Controls
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "controls_help"
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Passage à controls_help depuis pause_menu")
|
||||
#logger.debug(f"Passage à controls_help depuis pause_menu")
|
||||
elif config.selected_option == 1: # Remap controls
|
||||
config.previous_menu_state = validate_menu_state(config.previous_menu_state)
|
||||
logger.debug(f"Previous menu state avant controls_mapping: {config.previous_menu_state}")
|
||||
#logger.debug(f"Previous menu state avant controls_mapping: {config.previous_menu_state}")
|
||||
#Supprimer le fichier de configuration des contrôles s'il existe
|
||||
if os.path.exists(config.CONTROLS_CONFIG_PATH):
|
||||
try:
|
||||
@@ -878,9 +902,9 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Aide contrôles
|
||||
elif config.menu_state == "controls_help":
|
||||
if is_input_matched(event, "cancel"):
|
||||
config.menu_state = validate_menu_state(config.previous_menu_state)
|
||||
config.menu_state = "pause_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Retour à {config.menu_state} depuis controls_help")
|
||||
logger.debug("Retour au menu pause depuis controls_help")
|
||||
|
||||
# Remap controls
|
||||
elif config.menu_state == "controls_mapping":
|
||||
@@ -962,41 +986,33 @@ def handle_controls(event, sources, joystick, screen):
|
||||
config.needs_redraw = True
|
||||
return action
|
||||
|
||||
# Navigation directe avec les touches du clavier
|
||||
if event.type == pygame.KEYDOWN:
|
||||
# Navigation vers le haut
|
||||
if event.key == pygame.K_UP:
|
||||
config.selected_language_index = (config.selected_language_index - 1) % len(available_languages)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Navigation vers le haut dans le sélecteur de langue: {config.selected_language_index}")
|
||||
|
||||
# Navigation vers le bas
|
||||
elif event.key == pygame.K_DOWN:
|
||||
config.selected_language_index = (config.selected_language_index + 1) % len(available_languages)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Navigation vers le bas dans le sélecteur de langue: {config.selected_language_index}")
|
||||
|
||||
# Sélection de la langue
|
||||
elif event.key == pygame.K_RETURN:
|
||||
lang_code = available_languages[config.selected_language_index]
|
||||
if set_language(lang_code):
|
||||
logger.info(f"Langue changée pour {lang_code}")
|
||||
config.current_language = lang_code
|
||||
# Afficher un message de confirmation
|
||||
config.menu_state = "restart_popup"
|
||||
config.popup_message = _("language_changed").format(lang_code)
|
||||
config.popup_timer = 2000 # 2 secondes
|
||||
else:
|
||||
# Retour au menu pause en cas d'erreur
|
||||
config.menu_state = "pause_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Sélection de la langue: {lang_code}")
|
||||
|
||||
# Annulation
|
||||
elif event.key == pygame.K_ESCAPE:
|
||||
# Navigation avec clavier et manette
|
||||
if is_input_matched(event, "up"):
|
||||
config.selected_language_index = (config.selected_language_index - 1) % len(available_languages)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Navigation vers le haut dans le sélecteur de langue: {config.selected_language_index}")
|
||||
elif is_input_matched(event, "down"):
|
||||
config.selected_language_index = (config.selected_language_index + 1) % len(available_languages)
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Navigation vers le bas dans le sélecteur de langue: {config.selected_language_index}")
|
||||
elif is_input_matched(event, "confirm"):
|
||||
lang_code = available_languages[config.selected_language_index]
|
||||
if set_language(lang_code):
|
||||
logger.info(f"Langue changée pour {lang_code}")
|
||||
config.current_language = lang_code
|
||||
# Afficher un message de confirmation
|
||||
config.menu_state = "restart_popup"
|
||||
config.popup_message = _("language_changed").format(lang_code)
|
||||
config.popup_timer = 2000 # 2 secondes
|
||||
else:
|
||||
# Retour au menu pause en cas d'erreur
|
||||
config.menu_state = "pause_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug("Annulation de la sélection de langue, retour au menu pause")
|
||||
config.needs_redraw = True
|
||||
logger.debug(f"Sélection de la langue: {lang_code}")
|
||||
elif is_input_matched(event, "cancel"):
|
||||
config.menu_state = "pause_menu"
|
||||
config.needs_redraw = True
|
||||
logger.debug("Annulation de la sélection de langue, retour au menu pause")
|
||||
|
||||
|
||||
# Gestion des relâchements de touches
|
||||
@@ -1004,21 +1020,27 @@ def handle_controls(event, sources, joystick, screen):
|
||||
# Vérifier quelle touche a été relâchée
|
||||
for action_name in ["up", "down", "left", "right", "confirm", "cancel"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "key" and \
|
||||
config.controls_config.get(action_name, {}).get("value") == event.key:
|
||||
config.controls_config.get(action_name, {}).get("key") == event.key:
|
||||
update_key_state(action_name, False)
|
||||
|
||||
elif event.type == pygame.JOYBUTTONUP:
|
||||
# Vérifier quel bouton a été relâché
|
||||
for action_name in ["up", "down", "left", "right", "confirm", "cancel"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "button" and \
|
||||
config.controls_config.get(action_name, {}).get("value") == event.button:
|
||||
config.controls_config.get(action_name, {}).get("button") == event.button:
|
||||
update_key_state(action_name, False)
|
||||
|
||||
elif event.type == pygame.JOYAXISMOTION and abs(event.value) < 0.5:
|
||||
# Vérifier quel axe a été relâché
|
||||
for action_name in ["up", "down", "left", "right"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "axis" and \
|
||||
config.controls_config.get(action_name, {}).get("value")[0] == event.axis:
|
||||
config.controls_config.get(action_name, {}).get("axis") == event.axis:
|
||||
update_key_state(action_name, False)
|
||||
|
||||
elif event.type == pygame.JOYHATMOTION and event.value == (0, 0):
|
||||
# Vérifier quel hat a été relâché
|
||||
for action_name in ["up", "down", "left", "right"]:
|
||||
if config.controls_config.get(action_name, {}).get("type") == "hat":
|
||||
update_key_state(action_name, False)
|
||||
|
||||
return action
|
||||
|
||||
@@ -203,7 +203,7 @@ HOLD_DURATION = 1000
|
||||
JOYHAT_DEBOUNCE = 200 # Délai anti-rebond pour JOYHATMOTION (ms)
|
||||
|
||||
def load_controls_config():
|
||||
#Charge la configuration des contrôles depuis controls.json
|
||||
"""Charge la configuration des contrôles depuis controls.json ou EmulationStation"""
|
||||
try:
|
||||
if os.path.exists(CONTROLS_CONFIG_PATH):
|
||||
with open(CONTROLS_CONFIG_PATH, "r") as f:
|
||||
@@ -211,8 +211,17 @@ def load_controls_config():
|
||||
logger.debug(f"Configuration des contrôles chargée : {config}")
|
||||
return config
|
||||
else:
|
||||
logger.debug("Aucun fichier controls.json trouvé, configuration par défaut.")
|
||||
return {}
|
||||
logger.debug("Aucun fichier controls.json trouvé, tentative d'importation depuis EmulationStation")
|
||||
# Essayer d'importer depuis EmulationStation
|
||||
from es_input_parser import parse_es_input_config
|
||||
es_config = parse_es_input_config()
|
||||
if es_config:
|
||||
logger.info("Configuration importée depuis EmulationStation")
|
||||
save_controls_config(es_config)
|
||||
return es_config
|
||||
else:
|
||||
logger.debug("Importation depuis EmulationStation échouée, configuration par défaut")
|
||||
return {}
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du chargement de controls.json : {e}")
|
||||
return {}
|
||||
|
||||
240
display.py
240
display.py
@@ -240,7 +240,58 @@ def get_control_display(action, default):
|
||||
if not config.controls_config:
|
||||
logger.warning(f"controls_config vide pour l'action {action}, utilisation de la valeur par défaut")
|
||||
return default
|
||||
return config.controls_config.get(action, {}).get('display', default)
|
||||
|
||||
control_config = config.controls_config.get(action, {})
|
||||
control_type = control_config.get('type', '')
|
||||
|
||||
# Générer le nom d'affichage basé sur la configuration réelle
|
||||
if control_type == 'key':
|
||||
key_code = control_config.get('key')
|
||||
key_names = {
|
||||
pygame.K_RETURN: "Entrée",
|
||||
pygame.K_BACKSPACE: "Retour",
|
||||
pygame.K_UP: "↑",
|
||||
pygame.K_DOWN: "↓",
|
||||
pygame.K_LEFT: "←",
|
||||
pygame.K_RIGHT: "→",
|
||||
pygame.K_SPACE: "Espace",
|
||||
pygame.K_DELETE: "Suppr",
|
||||
pygame.K_PAGEUP: "PgUp",
|
||||
pygame.K_PAGEDOWN: "PgDn",
|
||||
pygame.K_p: "P",
|
||||
pygame.K_h: "H",
|
||||
pygame.K_f: "F",
|
||||
pygame.K_x: "X"
|
||||
}
|
||||
return key_names.get(key_code, chr(key_code) if 32 <= key_code <= 126 else f"Key{key_code}")
|
||||
|
||||
elif control_type == 'button':
|
||||
button_id = control_config.get('button')
|
||||
button_names = {
|
||||
0: "A", 1: "B", 2: "X", 3: "Y",
|
||||
4: "LB", 5: "RB", 6: "Select", 7: "Start"
|
||||
}
|
||||
return button_names.get(button_id, f"Btn{button_id}")
|
||||
|
||||
elif control_type == 'hat':
|
||||
hat_value = control_config.get('value', (0, 0))
|
||||
hat_names = {
|
||||
(0, 1): "D↑", (0, -1): "D↓",
|
||||
(-1, 0): "D←", (1, 0): "D→"
|
||||
}
|
||||
return hat_names.get(tuple(hat_value) if isinstance(hat_value, list) else hat_value, "D-Pad")
|
||||
|
||||
elif control_type == 'axis':
|
||||
axis_id = control_config.get('axis')
|
||||
direction = control_config.get('direction')
|
||||
axis_names = {
|
||||
(0, -1): "J←", (0, 1): "J→",
|
||||
(1, -1): "J↑", (1, 1): "J↓"
|
||||
}
|
||||
return axis_names.get((axis_id, direction), f"Joy{axis_id}")
|
||||
|
||||
# Fallback vers l'ancien système ou valeur par défaut
|
||||
return control_config.get('display', default)
|
||||
|
||||
# Cache pour les images des plateformes
|
||||
platform_images_cache = {}
|
||||
@@ -901,9 +952,8 @@ def draw_extension_warning(screen):
|
||||
def draw_controls(screen, menu_state):
|
||||
"""Affiche les contrôles sur une seule ligne en bas de l’écran."""
|
||||
start_button = get_control_display('start', 'START')
|
||||
history_button = get_control_display('history', 'H')
|
||||
filter_button = get_control_display('filter', 'F')
|
||||
control_text = _("footer_version").format(config.app_version, start_button, history_button, filter_button)
|
||||
start_text = _("controls_action_start")
|
||||
control_text = f"RGSX v{config.app_version} - {start_button} : {start_text}"
|
||||
max_width = config.screen_width - 40
|
||||
wrapped_controls = wrap_text(control_text, config.small_font, max_width)
|
||||
line_height = config.small_font.get_height() + 5
|
||||
@@ -1029,18 +1079,20 @@ def draw_controls_help(screen, previous_state):
|
||||
space_text = _("controls_action_space")
|
||||
|
||||
common_controls = {
|
||||
"confirm": lambda action: f"{get_control_display('confirm', confirm_text)} : {action}",
|
||||
"cancel": lambda action: f"{get_control_display('cancel', cancel_text)} : {action}",
|
||||
"start": lambda: f"{get_control_display('start', start_text)} : {start_text}",
|
||||
"progress": lambda action: f"{get_control_display('progress', progress_text)} : {action}",
|
||||
"up": lambda action: f"{get_control_display('up', up_text)} : {action}",
|
||||
"down": lambda action: f"{get_control_display('down', down_text)} : {action}",
|
||||
"page_up": lambda action: f"{get_control_display('page_up', page_up_text)} : {action}",
|
||||
"page_down": lambda action: f"{get_control_display('page_down', page_down_text)} : {action}",
|
||||
"filter": lambda action: f"{get_control_display('filter', filter_text)} : {action}",
|
||||
"history": lambda action: f"{get_control_display('history', history_text)} : {action}",
|
||||
"delete": lambda: f"{get_control_display('delete', delete_text)} : {delete_text}",
|
||||
"space": lambda: f"{get_control_display('space', space_text)} : {space_text}"
|
||||
"confirm": lambda action: f"{get_control_display('confirm', 'A')} : {action}",
|
||||
"cancel": lambda action: f"{get_control_display('cancel', 'B')} : {action}",
|
||||
"start": lambda: f"{get_control_display('start', 'Start')} : {start_text}",
|
||||
"progress": lambda action: f"{get_control_display('progress', 'X')} : {action}",
|
||||
"up": lambda action: f"{get_control_display('up', '↑')} : {action}",
|
||||
"down": lambda action: f"{get_control_display('down', '↓')} : {action}",
|
||||
"left": lambda action: f"{get_control_display('left', '←')} : {action}",
|
||||
"right": lambda action: f"{get_control_display('right', '→')} : {action}",
|
||||
"page_up": lambda action: f"{get_control_display('page_up', 'LB')} : {action}",
|
||||
"page_down": lambda action: f"{get_control_display('page_down', 'RB')} : {action}",
|
||||
"filter": lambda action: f"{get_control_display('filter', 'Select')} : {action}",
|
||||
"history": lambda action: f"{get_control_display('history', 'Y')} : {action}",
|
||||
"delete": lambda: f"{get_control_display('delete', 'Suppr')} : {delete_text}",
|
||||
"space": lambda: f"{get_control_display('space', 'Espace')} : {space_text}"
|
||||
}
|
||||
|
||||
# Utiliser des variables pour les traductions d'actions
|
||||
@@ -1063,91 +1115,109 @@ def draw_controls_help(screen, previous_state):
|
||||
"clear_history": _("action_clear_history")
|
||||
}
|
||||
|
||||
state_controls = {
|
||||
"error": [
|
||||
common_controls["confirm"](action_translations["retry"]),
|
||||
common_controls["cancel"](action_translations["quit"])
|
||||
# Catégories de contrôles
|
||||
control_categories = {
|
||||
"Navigation": [
|
||||
f"{get_control_display('up', '↑')} {get_control_display('down', '↓')} {get_control_display('left', '←')} {get_control_display('right', '→')} : Navigation",
|
||||
f"{get_control_display('page_up', 'LB')} {get_control_display('page_down', 'RB')} : Pages"
|
||||
],
|
||||
"platform": [
|
||||
common_controls["confirm"](action_translations["select"]),
|
||||
common_controls["cancel"](action_translations["quit"]),
|
||||
common_controls["start"](),
|
||||
common_controls["history"](action_translations["history"]),
|
||||
*( [common_controls["progress"](action_translations["progress"])] if config.download_tasks else [])
|
||||
"Actions principales": [
|
||||
f"{get_control_display('confirm', 'A')} : Confirmer/Sélectionner",
|
||||
f"{get_control_display('cancel', 'B')} : Annuler/Retour",
|
||||
f"{get_control_display('start', 'Start')} : {start_text}"
|
||||
],
|
||||
"game": [
|
||||
common_controls["confirm"](action_translations["select"] if config.search_mode else action_translations["download"]),
|
||||
common_controls["filter"](action_translations["filter"]),
|
||||
common_controls["cancel"](action_translations["cancel"] if config.search_mode else action_translations["back"]),
|
||||
common_controls["history"](action_translations["history"]),
|
||||
*( [
|
||||
common_controls["delete"](),
|
||||
common_controls["space"]()
|
||||
] if config.search_mode and config.is_non_pc else []),
|
||||
*( [
|
||||
f"{common_controls['up'](action_translations['navigate'])} / {common_controls['down'](action_translations['navigate'])}",
|
||||
f"{common_controls['page_up'](action_translations['page'])} / {common_controls['page_down'](action_translations['page'])}",
|
||||
common_controls["filter"](action_translations["filter"])
|
||||
] if not config.is_non_pc or not config.search_mode else []),
|
||||
common_controls["start"](),
|
||||
*( [common_controls["progress"](action_translations["progress"])] if config.download_tasks and not config.search_mode else [])
|
||||
"Téléchargements": [
|
||||
f"{get_control_display('history', 'Y')} : Historique",
|
||||
f"{get_control_display('progress', 'X')} : Effacer historique"
|
||||
],
|
||||
"download_progress": [
|
||||
common_controls["cancel"](action_translations["cancel_download"]),
|
||||
common_controls["progress"](action_translations["background"]),
|
||||
common_controls["start"]()
|
||||
],
|
||||
"download_result": [
|
||||
common_controls["confirm"](action_translations["back"])
|
||||
],
|
||||
"confirm_exit": [
|
||||
common_controls["confirm"](action_translations["confirm"])
|
||||
],
|
||||
"extension_warning": [
|
||||
common_controls["confirm"](action_translations["confirm"])
|
||||
],
|
||||
"history": [
|
||||
common_controls["confirm"](action_translations["redownload"]),
|
||||
common_controls["cancel"](action_translations["back"]),
|
||||
common_controls["progress"](action_translations["clear_history"]),
|
||||
f"{common_controls['up'](action_translations['navigate'])} / {common_controls['down'](action_translations['navigate'])}",
|
||||
f"{common_controls['page_up'](action_translations['page'])} / {common_controls['page_down'](action_translations['page'])}",
|
||||
common_controls["start"]()
|
||||
"Recherche": [
|
||||
f"{get_control_display('filter', 'Select')} : Filtrer/Rechercher",
|
||||
f"{get_control_display('delete', 'Suppr')} : {delete_text}",
|
||||
f"{get_control_display('space', 'Espace')} : {space_text}"
|
||||
]
|
||||
}
|
||||
|
||||
state_controls = {
|
||||
"error": control_categories,
|
||||
"platform": control_categories,
|
||||
"game": control_categories,
|
||||
"download_progress": control_categories,
|
||||
"download_result": control_categories,
|
||||
"confirm_exit": control_categories,
|
||||
"extension_warning": control_categories,
|
||||
"history": control_categories
|
||||
}
|
||||
|
||||
controls = state_controls.get(previous_state, [])
|
||||
if not controls:
|
||||
control_columns = state_controls.get(previous_state, {})
|
||||
if not control_columns:
|
||||
return
|
||||
|
||||
screen.blit(OVERLAY, (0, 0))
|
||||
|
||||
max_width = config.screen_width - 80
|
||||
wrapped_controls = []
|
||||
current_line = ""
|
||||
for control in controls:
|
||||
test_line = f"{current_line} | {control}" if current_line else control
|
||||
if config.font.size(test_line)[0] <= max_width:
|
||||
current_line = test_line
|
||||
else:
|
||||
wrapped_controls.append(current_line)
|
||||
current_line = control
|
||||
if current_line:
|
||||
wrapped_controls.append(current_line)
|
||||
|
||||
line_height = config.font.get_height() + 10
|
||||
popup_width = max_width + 40
|
||||
popup_height = len(wrapped_controls) * line_height + 60
|
||||
# Organisation en 2x2
|
||||
categories = list(control_columns.keys())
|
||||
col1 = [categories[0], categories[2]] # Navigation, Historique/Téléchargements
|
||||
col2 = [categories[1], categories[3]] # Actions principales, Recherche / Filtre
|
||||
|
||||
# Calculer la largeur nécessaire
|
||||
max_text_width = 0
|
||||
for category, controls in control_columns.items():
|
||||
for control in controls:
|
||||
text_width = config.small_font.size(control)[0]
|
||||
max_text_width = max(max_text_width, text_width)
|
||||
|
||||
col_width = max_text_width + 40
|
||||
popup_width = col_width * 2 + 100 # Plus d'espace entre colonnes
|
||||
popup_height = 320
|
||||
popup_x = (config.screen_width - popup_width) // 2
|
||||
popup_y = (config.screen_height - popup_height) // 2
|
||||
|
||||
# Fond principal
|
||||
pygame.draw.rect(screen, THEME_COLORS["button_idle"], (popup_x, popup_y, popup_width, popup_height), border_radius=12)
|
||||
pygame.draw.rect(screen, THEME_COLORS["border"], (popup_x, popup_y, popup_width, popup_height), 2, border_radius=12)
|
||||
|
||||
for i, line in enumerate(wrapped_controls):
|
||||
text = config.font.render(line, True, THEME_COLORS["text"])
|
||||
text_rect = text.get_rect(center=(config.screen_width // 2, popup_y + 40 + i * line_height))
|
||||
screen.blit(text, text_rect)
|
||||
# Titre
|
||||
title_text = "Aide des contrôles"
|
||||
title_surface = config.title_font.render(title_text, True, THEME_COLORS["text"])
|
||||
title_rect = title_surface.get_rect(center=(config.screen_width // 2, popup_y + 25))
|
||||
screen.blit(title_surface, title_rect)
|
||||
|
||||
# Affichage en colonnes
|
||||
start_y = popup_y + 60
|
||||
|
||||
# Colonne 1
|
||||
current_y = start_y
|
||||
for category in col1:
|
||||
controls = control_columns[category]
|
||||
# Titre
|
||||
cat_surface = config.font.render(category, True, THEME_COLORS["fond_lignes"])
|
||||
cat_rect = cat_surface.get_rect(x=popup_x + 20, y=current_y)
|
||||
screen.blit(cat_surface, cat_rect)
|
||||
current_y += 30 # Plus d'espace après titre
|
||||
# Contrôles
|
||||
for control in controls:
|
||||
ctrl_surface = config.small_font.render(f"• {control}", True, THEME_COLORS["text"])
|
||||
ctrl_rect = ctrl_surface.get_rect(x=popup_x + 30, y=current_y)
|
||||
screen.blit(ctrl_surface, ctrl_rect)
|
||||
current_y += 20
|
||||
current_y += 20 # Plus d'espace entre sections
|
||||
|
||||
# Colonne 2
|
||||
current_y = start_y
|
||||
for category in col2:
|
||||
controls = control_columns[category]
|
||||
# Titre
|
||||
cat_surface = config.font.render(category, True, THEME_COLORS["fond_lignes"])
|
||||
cat_rect = cat_surface.get_rect(x=popup_x + col_width + 40, y=current_y) # Plus d'espace entre colonnes
|
||||
screen.blit(cat_surface, cat_rect)
|
||||
current_y += 30 # Plus d'espace après titre
|
||||
# Contrôles
|
||||
for control in controls:
|
||||
ctrl_surface = config.small_font.render(f"• {control}", True, THEME_COLORS["text"])
|
||||
ctrl_rect = ctrl_surface.get_rect(x=popup_x + col_width + 50, y=current_y) # Plus d'espace entre colonnes
|
||||
screen.blit(ctrl_surface, ctrl_rect)
|
||||
current_y += 20
|
||||
current_y += 20 # Plus d'espace entre sections
|
||||
|
||||
# Menu Quitter Appli
|
||||
def draw_confirm_dialog(screen):
|
||||
|
||||
5403
es_input.cfg
Normal file
5403
es_input.cfg
Normal file
File diff suppressed because it is too large
Load Diff
166
es_input_parser.py
Normal file
166
es_input_parser.py
Normal file
@@ -0,0 +1,166 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
import logging
|
||||
import pygame #type: ignore
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def parse_es_input_config():
|
||||
"""Parse le fichier es_input.cfg d'EmulationStation et retourne la configuration des contrôles"""
|
||||
es_input_path = "/usr/share/emulationstation/es_input.cfg"
|
||||
|
||||
if not os.path.exists(es_input_path):
|
||||
logger.debug(f"Fichier {es_input_path} non trouvé")
|
||||
return None
|
||||
|
||||
try:
|
||||
tree = ET.parse(es_input_path)
|
||||
root = tree.getroot()
|
||||
|
||||
# Mapping des boutons EmulationStation vers les actions RGSX
|
||||
# Priorité: D-pad > Joystick pour la navigation
|
||||
es_to_rgsx_mapping = {
|
||||
"b": "confirm",
|
||||
"a": "cancel",
|
||||
"up": "up",
|
||||
"down": "down",
|
||||
"left": "left",
|
||||
"right": "right",
|
||||
"pageup": "page_up",
|
||||
"pagedown": "page_down",
|
||||
"y": "progress",
|
||||
"x": "history",
|
||||
"select": "filter",
|
||||
"leftshoulder": "delete",
|
||||
"rightshoulder": "space",
|
||||
"start": "start"
|
||||
}
|
||||
|
||||
# Priorité pour les entrées directionnelles (hat > axis)
|
||||
direction_priority = {"up": [], "down": [], "left": [], "right": []}
|
||||
|
||||
controls_config = {}
|
||||
|
||||
# Chercher la première configuration de joystick
|
||||
for inputConfig in root.findall("inputConfig"):
|
||||
if inputConfig.get("type") == "joystick":
|
||||
logger.debug(f"Configuration trouvée pour: {inputConfig.get('deviceName', 'Manette inconnue')}")
|
||||
|
||||
# Première passe: collecter toutes les entrées par action
|
||||
for input_tag in inputConfig.findall("input"):
|
||||
es_name = input_tag.get("name")
|
||||
es_type = input_tag.get("type")
|
||||
es_id = input_tag.get("id")
|
||||
es_value = input_tag.get("value", "1")
|
||||
|
||||
logger.debug(f"Entrée trouvée: {es_name} = {es_type}:{es_id} (value={es_value})")
|
||||
|
||||
if es_name in es_to_rgsx_mapping:
|
||||
rgsx_action = es_to_rgsx_mapping[es_name]
|
||||
|
||||
if es_type == "hat" and rgsx_action in direction_priority:
|
||||
# Priorité maximale pour le D-pad
|
||||
hat_mapping = {
|
||||
"1": (0, 1), # Haut
|
||||
"2": (1, 0), # Droite
|
||||
"4": (0, -1), # Bas
|
||||
"8": (-1, 0) # Gauche
|
||||
}
|
||||
if es_value in hat_mapping:
|
||||
logger.debug(f"D-pad trouvé pour {rgsx_action}: hat {es_id}, value {es_value}")
|
||||
direction_priority[rgsx_action].append(("hat", {
|
||||
"type": "hat",
|
||||
"joy": 0,
|
||||
"hat": int(es_id),
|
||||
"value": hat_mapping[es_value]
|
||||
}))
|
||||
elif es_type == "axis" and rgsx_action in direction_priority:
|
||||
# Priorité secondaire pour les axes
|
||||
direction = 1 if int(es_value) > 0 else -1
|
||||
logger.debug(f"Axe trouvé pour {rgsx_action}: axis {es_id}, direction {direction}")
|
||||
direction_priority[rgsx_action].append(("axis", {
|
||||
"type": "axis",
|
||||
"joy": 0,
|
||||
"axis": int(es_id),
|
||||
"direction": direction
|
||||
}))
|
||||
elif es_type == "button":
|
||||
controls_config[rgsx_action] = {
|
||||
"type": "button",
|
||||
"joy": 0,
|
||||
"button": int(es_id)
|
||||
}
|
||||
elif es_type == "key":
|
||||
controls_config[rgsx_action] = {
|
||||
"type": "key",
|
||||
"key": int(es_id)
|
||||
}
|
||||
|
||||
# Deuxième passe: assigner les directions avec priorité
|
||||
for action, entries in direction_priority.items():
|
||||
if entries:
|
||||
logger.debug(f"Priorité pour {action}: {[(e[0], e[1]['type']) for e in entries]}")
|
||||
# Trier par priorité: hat d'abord, puis axis
|
||||
entries.sort(key=lambda x: 0 if x[0] == "hat" else 1)
|
||||
controls_config[action] = entries[0][1]
|
||||
logger.debug(f"Sélectionné pour {action}: {entries[0][1]['type']}")
|
||||
|
||||
logger.debug(f"Configuration finale: {controls_config}")
|
||||
|
||||
# Forcer l'utilisation du D-pad pour les directions si disponible, sinon clavier
|
||||
if any(controls_config.get(action, {}).get("type") == "axis" for action in ["up", "down", "left", "right"]):
|
||||
# Vérifier si une manette est connectée
|
||||
|
||||
pygame.joystick.init()
|
||||
if pygame.joystick.get_count() > 0:
|
||||
logger.debug("Remplacement des axes par le D-pad pour la navigation")
|
||||
controls_config["up"] = {"type": "hat", "joy": 0, "hat": 0, "value": (0, 1)}
|
||||
controls_config["down"] = {"type": "hat", "joy": 0, "hat": 0, "value": (0, -1)}
|
||||
controls_config["left"] = {"type": "hat", "joy": 0, "hat": 0, "value": (-1, 0)}
|
||||
controls_config["right"] = {"type": "hat", "joy": 0, "hat": 0, "value": (1, 0)}
|
||||
else:
|
||||
logger.debug("Aucune manette détectée, utilisation du clavier pour toutes les actions")
|
||||
controls_config["up"] = {"type": "key", "key": pygame.K_UP}
|
||||
controls_config["down"] = {"type": "key", "key": pygame.K_DOWN}
|
||||
controls_config["left"] = {"type": "key", "key": pygame.K_LEFT}
|
||||
controls_config["right"] = {"type": "key", "key": pygame.K_RIGHT}
|
||||
controls_config["confirm"] = {"type": "key", "key": pygame.K_RETURN}
|
||||
controls_config["cancel"] = {"type": "key", "key": pygame.K_BACKSPACE}
|
||||
controls_config["start"] = {"type": "key", "key": pygame.K_p}
|
||||
controls_config["filter"] = {"type": "key", "key": pygame.K_f}
|
||||
controls_config["history"] = {"type": "key", "key": pygame.K_h}
|
||||
controls_config["progress"] = {"type": "key", "key": pygame.K_x}
|
||||
controls_config["page_up"] = {"type": "key", "key": pygame.K_PAGEUP}
|
||||
controls_config["page_down"] = {"type": "key", "key": pygame.K_PAGEDOWN}
|
||||
|
||||
# Ajouter les actions manquantes avec des valeurs par défaut
|
||||
default_actions = {
|
||||
"confirm": {"type": "key", "key": pygame.K_RETURN},
|
||||
"cancel": {"type": "key", "key": pygame.K_BACKSPACE},
|
||||
"up": {"type": "key", "key": pygame.K_UP},
|
||||
"down": {"type": "key", "key": pygame.K_DOWN},
|
||||
"left": {"type": "key", "key": pygame.K_LEFT},
|
||||
"right": {"type": "key", "key": pygame.K_RIGHT},
|
||||
"page_up": {"type": "key", "key": pygame.K_PAGEUP},
|
||||
"page_down": {"type": "key", "key": pygame.K_PAGEDOWN},
|
||||
"progress": {"type": "key", "key": pygame.K_x},
|
||||
"history": {"type": "key", "key": pygame.K_h},
|
||||
"filter": {"type": "key", "key": pygame.K_f},
|
||||
"delete": {"type": "key", "key": pygame.K_DELETE},
|
||||
"space": {"type": "key", "key": pygame.K_SPACE},
|
||||
"start": {"type": "key", "key": pygame.K_p}
|
||||
}
|
||||
|
||||
for action, default_config in default_actions.items():
|
||||
if action not in controls_config:
|
||||
controls_config[action] = default_config
|
||||
|
||||
logger.info(f"Configuration importée depuis EmulationStation pour {len(controls_config)} actions")
|
||||
return controls_config
|
||||
|
||||
logger.debug("Aucune configuration de joystick trouvée dans es_input.cfg")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors du parsing de es_input.cfg: {str(e)}")
|
||||
return None
|
||||
@@ -39,7 +39,7 @@ def load_history():
|
||||
if not all(key in entry for key in ['platform', 'game_name', 'status']):
|
||||
logger.warning(f"Entrée d'historique invalide : {entry}")
|
||||
return []
|
||||
logger.debug(f"Historique chargé depuis {history_path}, {len(history)} entrées")
|
||||
#logger.debug(f"Historique chargé depuis {history_path}, {len(history)} entrées")
|
||||
return history
|
||||
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||
logger.error(f"Erreur lors de la lecture de {history_path} : {e}")
|
||||
|
||||
@@ -34,7 +34,7 @@ def load_language(lang_code=None):
|
||||
translations = json.load(f)
|
||||
|
||||
current_language = lang_code
|
||||
logger.debug(f"Langue {lang_code} chargée avec succès ({len(translations)} traductions)")
|
||||
#logger.debug(f"Langue {lang_code} chargée avec succès ({len(translations)} traductions)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
@@ -114,7 +114,6 @@ def load_language_preference():
|
||||
data = json.load(f)
|
||||
lang_code = data.get("language", DEFAULT_LANGUAGE)
|
||||
|
||||
logger.debug(f"Préférence de langue chargée: {lang_code}")
|
||||
return lang_code
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("Fichier de préférence de langue corrompu, utilisation du français par défaut")
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
"controls_action_filter": "Filter",
|
||||
"controls_action_delete": "Delete",
|
||||
"controls_action_space": "Space",
|
||||
"controls_action_start": "Menu",
|
||||
"controls_action_start": "Help / Settings",
|
||||
|
||||
"controls_desc_confirm": "Validate (e.g. A, Enter)",
|
||||
"controls_desc_cancel": "Cancel/Back (e.g. B, Backspace)",
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
"controls_action_filter": "Filtrer",
|
||||
"controls_action_delete": "Supprimer",
|
||||
"controls_action_space": "Espace",
|
||||
"controls_action_start": "Menu",
|
||||
"controls_action_start": "Aide / Réglages",
|
||||
|
||||
"controls_desc_confirm": "Valider (ex: A, Entrée)",
|
||||
"controls_desc_cancel": "Annuler/Retour (ex: B, RetourArrière)",
|
||||
|
||||
40
network.py
40
network.py
@@ -189,13 +189,49 @@ async def download_rom(url, platform, game_name, is_zip_non_supported=False, tas
|
||||
dest_path = os.path.join(dest_dir, f"{sanitized_name}")
|
||||
logger.debug(f"Chemin destination: {dest_path}")
|
||||
|
||||
headers = {'User-Agent': 'Mozilla/5.0'}
|
||||
response = requests.get(url, stream=True, headers=headers, timeout=30)
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'en-US,en;q=0.5',
|
||||
'Accept-Encoding': 'gzip, deflate',
|
||||
'DNT': '1',
|
||||
'Connection': 'keep-alive',
|
||||
'Upgrade-Insecure-Requests': '1'
|
||||
}
|
||||
|
||||
# Utiliser une session pour gérer les cookies
|
||||
session = requests.Session()
|
||||
session.headers.update(headers)
|
||||
|
||||
# Première requête HEAD pour obtenir la vraie URL
|
||||
logger.debug(f"Première requête HEAD vers {url}")
|
||||
head_response = session.head(url, timeout=30, allow_redirects=False)
|
||||
logger.debug(f"HEAD Status: {head_response.status_code}, Headers: {dict(head_response.headers)}")
|
||||
|
||||
# Suivre la redirection manuellement si nécessaire
|
||||
final_url = url
|
||||
if head_response.status_code in [301, 302, 303, 307, 308]:
|
||||
final_url = head_response.headers.get('Location', url)
|
||||
logger.debug(f"Redirection détectée vers: {final_url}")
|
||||
|
||||
# Requête GET vers l'URL finale avec en-têtes spécifiques
|
||||
download_headers = headers.copy()
|
||||
download_headers['Accept'] = 'application/octet-stream, */*'
|
||||
download_headers['Referer'] = 'https://myrient.erista.me/'
|
||||
response = session.get(final_url, stream=True, timeout=30, allow_redirects=False, headers=download_headers)
|
||||
logger.debug(f"Status code: {response.status_code}")
|
||||
logger.debug(f"Headers: {dict(response.headers)}")
|
||||
response.raise_for_status()
|
||||
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
logger.debug(f"Taille totale: {total_size} octets")
|
||||
|
||||
if total_size == 0:
|
||||
logger.warning(f"Taille de fichier 0, possible redirection ou erreur. URL finale: {response.url}")
|
||||
# Vérifier si c'est une redirection
|
||||
if response.url != url:
|
||||
logger.debug(f"Redirection détectée: {url} -> {response.url}")
|
||||
|
||||
# Initialiser la progression avec task_id
|
||||
progress_queue.put((task_id, 0, total_size))
|
||||
logger.debug(f"Progression initiale envoyée: 0% pour {game_name}, task_id={task_id}")
|
||||
|
||||
4
utils.py
4
utils.py
@@ -34,7 +34,7 @@ def detect_non_pc():
|
||||
result = subprocess.run(["batocera-es-swissknife", "--arch"], capture_output=True, text=True, timeout=2)
|
||||
if result.returncode == 0:
|
||||
arch = result.stdout.strip()
|
||||
logger.debug(f"Architecture via batocera-es-swissknife: {arch}")
|
||||
#logger.debug(f"Architecture via batocera-es-swissknife: {arch}")
|
||||
except (subprocess.SubprocessError, FileNotFoundError):
|
||||
logger.debug(f"batocera-es-swissknife non disponible, utilisation de platform.machine(): {arch}")
|
||||
|
||||
@@ -130,7 +130,7 @@ def load_sources():
|
||||
def load_games(platform_id):
|
||||
"""Charge les jeux pour une plateforme donnée en utilisant platform_id et teste la première URL."""
|
||||
games_path = os.path.join(config.APP_FOLDER, "games", f"{platform_id}.json")
|
||||
logger.debug(f"Chargement des jeux pour {platform_id} depuis {games_path}")
|
||||
#logger.debug(f"Chargement des jeux pour {platform_id} depuis {games_path}")
|
||||
try:
|
||||
with open(games_path, 'r', encoding='utf-8') as f:
|
||||
games = json.load(f)
|
||||
|
||||
Reference in New Issue
Block a user