2025-07-09 01:13:55 +02:00
import shutil
import pygame # type: ignore
2025-07-06 19:47:21 +02:00
import config
2025-07-06 20:54:16 +02:00
from config import CONTROLS_CONFIG_PATH
2025-07-06 19:47:21 +02:00
import asyncio
import math
2025-07-07 02:48:05 +02:00
import json
2025-07-09 01:13:55 +02:00
import os
2025-07-06 19:47:21 +02:00
from display import draw_validation_transition
2025-07-09 01:13:55 +02:00
from network import download_rom , check_extension_before_download , download_from_1fichier , is_1fichier_url , is_extension_supported , load_extensions_json , sanitize_filename
2025-07-06 19:47:21 +02:00
from controls_mapper import get_readable_input_name
2025-07-07 02:48:05 +02:00
from utils import load_games
from history import load_history , clear_history
2025-07-06 19:47:21 +02:00
import logging
logger = logging . getLogger ( __name__ )
# Constantes pour la répétition automatique
REPEAT_DELAY = 300 # Délai initial avant répétition (ms)
REPEAT_INTERVAL = 100 # Intervalle entre répétitions (ms)
JOYHAT_DEBOUNCE = 200 # Délai anti-rebond pour JOYHATMOTION (ms)
JOYAXIS_DEBOUNCE = 50 # Délai anti-rebond pour JOYAXISMOTION (ms)
REPEAT_ACTION_DEBOUNCE = 50 # Délai anti-rebond pour répétitions up/down/left/right (ms)
2025-07-07 02:48:05 +02:00
# Liste des états valides (mise à jour)
VALID_STATES = [
" platform " , " game " , " download_progress " , " download_result " , " confirm_exit " ,
2025-07-09 16:56:37 +02:00
" extension_warning " , " pause_menu " , " controls_help " , " history " , " controls_mapping " ,
2025-07-09 01:13:55 +02:00
" redownload_game_cache " , " restart_popup " , " error " , " loading " , " confirm_clear_history "
2025-07-07 02:48:05 +02:00
]
def validate_menu_state ( state ) :
2025-07-09 16:56:37 +02:00
valid_states = [ " platform " , " game " , " download_progress " , " download_result " , " confirm_exit " , " extension_warning " , " pause_menu " , " controls_help " , " controls_mapping " , " redownload_game_cache " , " restart_popup " , " confirm_clear_history " ]
if state not in VALID_STATES :
logger . debug ( f " État invalide { state } , retour à platform " )
return " platform "
if state == " history " : # Éviter de revenir à history
logger . debug ( f " État history non autorisé comme previous_menu_state, retour à platform " )
return " platform "
return state
2025-07-07 02:48:05 +02:00
2025-07-06 20:54:16 +02:00
def load_controls_config ( path = CONTROLS_CONFIG_PATH ) :
""" Charge la configuration des contrôles depuis un fichier JSON. """
try :
with open ( path , " r " ) as f :
2025-07-07 02:48:05 +02:00
config_data = json . load ( f )
# Vérifier les actions nécessaires
required_actions = [ " confirm " , " cancel " , " left " , " right " ]
for action in required_actions :
if action not in config_data :
logger . warning ( f " Action { action } manquante dans { path } , utilisation de la valeur par défaut " )
config_data [ action ] = {
" type " : " key " ,
" value " : {
" confirm " : pygame . K_RETURN ,
" cancel " : pygame . K_ESCAPE ,
" left " : pygame . K_LEFT ,
" right " : pygame . K_RIGHT
} [ action ]
}
return config_data
2025-07-06 20:54:16 +02:00
except ( FileNotFoundError , json . JSONDecodeError ) as e :
2025-07-07 02:48:05 +02:00
logger . error ( f " Erreur lors de la lecture de { path } : { e } , utilisation de la configuration par défaut " )
return {
" confirm " : { " type " : " key " , " value " : pygame . K_RETURN } ,
" cancel " : { " type " : " key " , " value " : pygame . K_ESCAPE } ,
" left " : { " type " : " key " , " value " : pygame . K_LEFT } ,
" right " : { " type " : " key " , " value " : pygame . K_RIGHT } ,
" up " : { " type " : " key " , " value " : pygame . K_UP } ,
" down " : { " type " : " key " , " value " : pygame . K_DOWN } ,
" start " : { " type " : " key " , " value " : pygame . K_p } ,
2025-07-09 01:13:55 +02:00
" progress " : { " type " : " key " , " value " : pygame . K_x } ,
" history " : { " type " : " key " , " value " : pygame . K_h } ,
2025-07-07 02:48:05 +02:00
" page_up " : { " type " : " key " , " value " : pygame . K_PAGEUP } ,
" page_down " : { " type " : " key " , " value " : pygame . K_PAGEDOWN } ,
" filter " : { " type " : " key " , " value " : pygame . K_f } ,
" delete " : { " type " : " key " , " value " : pygame . K_BACKSPACE } ,
" space " : { " type " : " key " , " value " : pygame . K_SPACE }
}
2025-07-06 19:47:21 +02:00
def is_input_matched ( event , action_name ) :
""" Vérifie si l ' événement correspond à l ' action configurée. """
if not config . controls_config . get ( action_name ) :
return False
mapping = config . controls_config [ action_name ]
input_type = mapping [ " type " ]
input_value = mapping [ " value " ]
event_type = event [ " type " ] if isinstance ( event , dict ) else event . type
event_key = event . get ( " key " ) if isinstance ( event , dict ) else getattr ( event , " key " , None )
event_button = event . get ( " button " ) if isinstance ( event , dict ) else getattr ( event , " button " , None )
event_axis = event . get ( " axis " ) if isinstance ( event , dict ) else getattr ( event , " axis " , None )
event_value = event . get ( " value " ) if isinstance ( event , dict ) else getattr ( event , " value " , None )
if input_type == " key " and event_type in ( pygame . KEYDOWN , pygame . KEYUP ) :
2025-07-09 01:13:55 +02:00
#logger.debug(f"Vérification key: event_key={event_key}, input_value={input_value}")
2025-07-06 19:47:21 +02:00
return event_key == input_value
elif input_type == " button " and event_type in ( pygame . JOYBUTTONDOWN , pygame . JOYBUTTONUP ) :
2025-07-09 01:13:55 +02:00
#logger.debug(f"Vérification button: event_button={event_button}, input_value={input_value}")
2025-07-06 19:47:21 +02:00
return event_button == input_value
elif input_type == " axis " and event_type == pygame . JOYAXISMOTION :
axis , direction = input_value
result = event_axis == axis and abs ( event_value ) > 0.5 and ( 1 if event_value > 0 else - 1 ) == direction
2025-07-09 01:13:55 +02:00
#logger.debug(f"Vérification axis: event_axis={event_axis}, event_value={event_value}, input_value={input_value}, result={result}")
2025-07-06 19:47:21 +02:00
return result
elif input_type == " hat " and event_type == pygame . JOYHATMOTION :
input_value_tuple = tuple ( input_value ) if isinstance ( input_value , list ) else input_value
2025-07-09 01:13:55 +02:00
#logger.debug(f"Vérification hat: event_value={event_value}, input_value={input_value_tuple}")
2025-07-06 19:47:21 +02:00
return event_value == input_value_tuple
elif input_type == " mouse " and event_type == pygame . MOUSEBUTTONDOWN :
2025-07-09 01:13:55 +02:00
#logger.debug(f"Vérification mouse: event_button={event_button}, input_value={input_value}")
2025-07-06 19:47:21 +02:00
return event_button == input_value
return False
def handle_controls ( event , sources , joystick , screen ) :
""" Gère un événement clavier/joystick/souris et la répétition automatique.
2025-07-07 02:48:05 +02:00
Retourne ' quit ' , ' download ' , ' redownload ' , ou None .
2025-07-06 19:47:21 +02:00
"""
action = None
current_time = pygame . time . get_ticks ( )
2025-07-07 02:48:05 +02:00
# Valider previous_menu_state avant tout traitement
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-09 01:13:55 +02:00
#logger.debug(f"Validation initiale: previous_menu_state={config.previous_menu_state}")
2025-07-07 02:48:05 +02:00
2025-07-06 19:47:21 +02:00
# Debounce général
if current_time - config . last_state_change_time < config . debounce_delay :
return action
# Log des événements reçus
2025-07-09 01:13:55 +02:00
#logger.debug(f"Événement reçu: type={event.type}, value={getattr(event, 'value', None)}")
2025-07-06 19:47:21 +02:00
# --- CLAVIER, MANETTE, SOURIS ---
if event . type in ( pygame . KEYDOWN , pygame . JOYBUTTONDOWN , pygame . JOYAXISMOTION , pygame . JOYHATMOTION , pygame . MOUSEBUTTONDOWN ) :
# Débouncer les événements JOYHATMOTION
if event . type == pygame . JOYHATMOTION :
logger . debug ( f " JOYHATMOTION détecté: hat= { event . hat } , value= { event . value } " )
if event . value == ( 0 , 0 ) : # Ignorer les relâchements
return action
if current_time - config . repeat_last_action < JOYHAT_DEBOUNCE :
return action
# Débouncer les événements JOYAXISMOTION
if event . type == pygame . JOYAXISMOTION and current_time - config . repeat_last_action < JOYAXIS_DEBOUNCE :
return action
# Quitter l'appli
if event . type == pygame . QUIT :
logger . debug ( " Événement pygame.QUIT détecté " )
return " quit "
# Vérification des actions mappées
2025-07-09 01:13:55 +02:00
#for action_name in ["up", "down", "left", "right"]:
#if is_input_matched(event, action_name):
#logger.debug(f"Action mappée détectée: {action_name}, input={get_readable_input_name(event)}")
2025-07-06 19:47:21 +02:00
2025-07-07 02:48:05 +02:00
# Menu pause
2025-07-09 16:56:37 +02:00
if is_input_matched ( event , " start " ) and config . menu_state not in ( " pause_menu " , " controls_help " , " controls_mapping " , " redownload_game_cache " ) :
2025-07-07 02:48:05 +02:00
config . previous_menu_state = config . menu_state
config . menu_state = " pause_menu "
config . selected_option = 0
config . needs_redraw = True
logger . debug ( f " Passage à pause_menu depuis { config . previous_menu_state } " )
return action
2025-07-06 19:47:21 +02:00
# Erreur
if config . menu_state == " error " :
if is_input_matched ( event , " confirm " ) :
2025-07-09 01:13:55 +02:00
config . menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-07 02:48:05 +02:00
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
logger . debug ( " Sortie du menu erreur avec Confirm " )
2025-07-06 19:47:21 +02:00
# Plateformes
elif config . menu_state == " platform " :
max_index = min ( 9 , len ( config . platforms ) - config . current_page * 9 ) - 1
current_grid_index = config . selected_platform - config . current_page * 9
row = current_grid_index / / 3
if is_input_matched ( event , " down " ) :
if current_grid_index + 3 < = max_index :
config . selected_platform + = 3
config . repeat_action = " down "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " up " ) :
if current_grid_index - 3 > = 0 :
config . selected_platform - = 3
config . repeat_action = " up "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " left " ) :
if current_grid_index % 3 != 0 :
config . selected_platform - = 1
config . repeat_action = " left "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif config . current_page > 0 :
config . current_page - = 1
config . selected_platform = config . current_page * 9 + row * 3 + 2
if config . selected_platform > = len ( config . platforms ) :
config . selected_platform = len ( config . platforms ) - 1
config . repeat_action = " left "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " right " ) :
if current_grid_index % 3 != 2 and current_grid_index < max_index :
config . selected_platform + = 1
config . repeat_action = " right "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif ( config . current_page + 1 ) * 9 < len ( config . platforms ) :
config . current_page + = 1
config . selected_platform = config . current_page * 9 + row * 3
if config . selected_platform > = len ( config . platforms ) :
config . selected_platform = len ( config . platforms ) - 1
config . repeat_action = " right "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " page_down " ) :
2025-07-07 02:48:05 +02:00
if ( config . current_page + 1 ) * 9 < len ( config . platforms ) :
config . current_page + = 1
config . selected_platform = config . current_page * 9 + row * 3
if config . selected_platform > = len ( config . platforms ) :
config . selected_platform = len ( config . platforms ) - 1
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
config . repeat_last_action = current_time
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug("Page suivante, répétition réinitialisée")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " page_up " ) :
if config . current_page > 0 :
config . current_page - = 1
config . selected_platform = config . current_page * 9 + row * 3
if config . selected_platform > = len ( config . platforms ) :
config . selected_platform = len ( config . platforms ) - 1
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
config . repeat_last_action = current_time
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug("Page précédente, répétition réinitialisée")
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " progress " ) :
if config . download_tasks :
config . menu_state = " download_progress "
config . needs_redraw = True
logger . debug ( " Retour à download_progress depuis platform " )
2025-07-09 01:13:55 +02:00
elif is_input_matched ( event , " history " ) :
config . menu_state = " history "
config . needs_redraw = True
logger . debug ( " Ouverture history depuis platform " )
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " confirm " ) :
if config . platforms :
config . current_platform = config . selected_platform
2025-07-07 02:48:05 +02:00
config . games = load_games ( config . platforms [ config . current_platform ] )
2025-07-06 19:47:21 +02:00
config . filtered_games = config . games
config . filter_active = False
config . current_game = 0
config . scroll_offset = 0
2025-07-07 02:48:05 +02:00
draw_validation_transition ( screen , config . current_platform )
2025-07-06 19:47:21 +02:00
config . menu_state = " game "
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Plateforme sélectionnée: {config.platforms[config.current_platform]}, {len(config.games)} jeux chargés")
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " cancel " ) :
config . menu_state = " confirm_exit "
config . confirm_selection = 0
2025-07-07 02:48:05 +02:00
config . needs_redraw = True
2025-07-06 19:47:21 +02:00
# Jeux
elif config . menu_state == " game " :
2025-07-07 02:48:05 +02:00
games = config . filtered_games if config . filter_active or config . search_mode else config . games
if config . search_mode and config . is_non_pc :
keyboard_layout = [
[ ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' ] ,
[ ' A ' , ' Z ' , ' E ' , ' R ' , ' T ' , ' Y ' , ' U ' , ' I ' , ' O ' , ' P ' ] ,
[ ' Q ' , ' S ' , ' D ' , ' F ' , ' G ' , ' H ' , ' J ' , ' K ' , ' L ' , ' M ' ] ,
[ ' W ' , ' X ' , ' C ' , ' V ' , ' B ' , ' N ' ]
]
row , col = config . selected_key
max_row = len ( keyboard_layout ) - 1
max_col = len ( keyboard_layout [ row ] ) - 1
if is_input_matched ( event , " up " ) :
if row > 0 :
config . selected_key = ( row - 1 , min ( col , len ( keyboard_layout [ row - 1 ] ) - 1 ) )
config . repeat_action = " up "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " down " ) :
if row < max_row :
config . selected_key = ( row + 1 , min ( col , len ( keyboard_layout [ row + 1 ] ) - 1 ) )
config . repeat_action = " down "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " left " ) :
if col > 0 :
config . selected_key = ( row , col - 1 )
config . repeat_action = " left "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " right " ) :
if col < max_col :
config . selected_key = ( row , col + 1 )
config . repeat_action = " right "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " confirm " ) :
config . search_query + = keyboard_layout [ row ] [ col ]
config . filtered_games = [ game for game in config . games if config . search_query . lower ( ) in game [ 0 ] . lower ( ) ]
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
logger . debug ( f " Recherche mise à jour: query= { config . search_query } , jeux filtrés= { len ( config . filtered_games ) } " )
elif is_input_matched ( event , " delete " ) :
if config . search_query :
config . search_query = config . search_query [ : - 1 ]
config . filtered_games = [ game for game in config . games if config . search_query . lower ( ) in game [ 0 ] . lower ( ) ]
2025-07-06 19:47:21 +02:00
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Suppression caractère: query={config.search_query}, jeux filtrés={len(config.filtered_games)}")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " space " ) :
config . search_query + = " "
config . filtered_games = [ game for game in config . games if config . search_query . lower ( ) in game [ 0 ] . lower ( ) ]
config . current_game = 0
config . scroll_offset = 0
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Espace ajouté: query={config.search_query}, jeux filtrés={len(config.filtered_games)}")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " cancel " ) :
config . search_mode = False
config . search_query = " "
config . selected_key = ( 0 , 0 )
config . filtered_games = config . games
config . current_game = 0
config . scroll_offset = 0
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( " Sortie du mode recherche " )
2025-07-09 16:56:37 +02:00
elif is_input_matched ( event , " filter " ) :
config . search_mode = False
config . filter_active = bool ( config . search_query )
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
elif config . search_mode and not config . is_non_pc :
# Gestion de la recherche sur PC
if event . type == pygame . KEYDOWN :
# Saisie de texte alphanumérique
if event . unicode . isalnum ( ) or event . unicode == ' ' :
config . search_query + = event . unicode
config . filtered_games = [ game for game in config . games if config . search_query . lower ( ) in game [ 0 ] . lower ( ) ]
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
logger . debug ( f " Recherche mise à jour: query= { config . search_query } , jeux filtrés= { len ( config . filtered_games ) } " )
# Gestion de la suppression
elif is_input_matched ( event , " delete " ) :
if config . search_query :
config . search_query = config . search_query [ : - 1 ]
config . filtered_games = [ game for game in config . games if config . search_query . lower ( ) in game [ 0 ] . lower ( ) ]
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
logger . debug ( f " Suppression caractère: query= { config . search_query } , jeux filtrés= { len ( config . filtered_games ) } " )
# Gestion de la validation
2025-07-09 16:56:37 +02:00
elif is_input_matched ( event , " select " ) :
2025-07-09 01:13:55 +02:00
config . search_mode = False
config . filter_active = True # Conserver le filtre actif
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
logger . debug ( f " Validation de la recherche: query= { config . search_query } , jeux filtrés= { len ( config . filtered_games ) } " )
# Gestion de l'annulation
elif is_input_matched ( event , " cancel " ) :
config . search_mode = False
config . search_query = " "
config . filtered_games = config . games
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
2025-07-09 16:56:37 +02:00
logger . debug ( " Sortie du mode recherche " )
2025-07-07 02:48:05 +02:00
else :
2025-07-09 01:13:55 +02:00
2025-07-07 02:48:05 +02:00
if is_input_matched ( event , " up " ) :
if config . current_game > 0 :
config . current_game - = 1
config . repeat_action = " up "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " down " ) :
if config . current_game < len ( games ) - 1 :
config . current_game + = 1
config . repeat_action = " down "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " page_up " ) :
2025-07-07 02:48:05 +02:00
config . current_game = max ( 0 , config . current_game - config . visible_games )
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
2025-07-06 19:47:21 +02:00
config . repeat_last_action = current_time
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug("Page précédente dans la liste des jeux")
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " page_down " ) :
2025-07-07 02:48:05 +02:00
config . current_game = min ( len ( games ) - 1 , config . current_game + config . visible_games )
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
2025-07-06 19:47:21 +02:00
config . repeat_last_action = current_time
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug("Page suivante dans la liste des jeux")
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " filter " ) :
config . search_mode = True
config . search_query = " "
config . filtered_games = config . games
config . current_game = 0
config . scroll_offset = 0
2025-07-07 02:48:05 +02:00
config . selected_key = ( 0 , 0 )
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( " Entrée en mode recherche " )
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " progress " ) :
if config . download_tasks :
2025-07-09 01:13:55 +02:00
config . previous_menu_state = config . menu_state
2025-07-06 19:47:21 +02:00
config . menu_state = " download_progress "
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
logger . debug ( f " Retour à download_progress depuis { config . previous_menu_state } " )
elif is_input_matched ( event , " history " ) :
config . menu_state = " history "
config . needs_redraw = True
logger . debug ( " Ouverture history depuis game " )
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " confirm " ) :
if games :
2025-07-09 01:13:55 +02:00
config . pending_download = check_extension_before_download (
games [ config . current_game ] [ 0 ] ,
config . platforms [ config . current_platform ] ,
games [ config . current_game ] [ 1 ]
)
2025-07-07 02:48:05 +02:00
if config . pending_download :
url , platform , game_name , is_zip_non_supported = config . pending_download
2025-07-09 01:13:55 +02:00
is_supported = is_extension_supported (
sanitize_filename ( game_name ) ,
platform ,
load_extensions_json ( )
)
if not is_supported :
config . previous_menu_state = config . menu_state # Ajouter cette ligne
2025-07-07 02:48:05 +02:00
config . menu_state = " extension_warning "
config . extension_confirm_selection = 0
config . needs_redraw = True
logger . debug ( f " Extension non supportée, passage à extension_warning pour { game_name } " )
else :
2025-07-09 01:13:55 +02:00
if is_1fichier_url ( url ) :
if not config . API_KEY_1FICHIER :
config . previous_menu_state = config . menu_state # Ajouter cette ligne
config . menu_state = " error "
config . error_message = (
" Attention il faut renseigner sa clé API (premium only) dans le fichier /userdata/saves/ports/rgsx/1fichier.api à ouvrir dans un editeur de texte et coller la clé API "
)
config . needs_redraw = True
logger . error ( " Clé API 1fichier absente, téléchargement impossible. " )
config . pending_download = None
return action
loop = asyncio . get_running_loop ( )
task = loop . run_in_executor ( None , download_from_1fichier , url , platform , game_name , is_zip_non_supported )
else :
task = asyncio . create_task ( download_rom ( url , platform , game_name , is_zip_non_supported ) )
config . download_tasks [ task ] = ( task , url , game_name , platform )
config . previous_menu_state = config . menu_state # Ajouter cette ligne
2025-07-07 02:48:05 +02:00
config . menu_state = " download_progress "
config . needs_redraw = True
logger . debug ( f " Début du téléchargement: { game_name } pour { platform } depuis { url } " )
2025-07-09 01:13:55 +02:00
config . pending_download = None
2025-07-07 02:48:05 +02:00
action = " download "
else :
config . menu_state = " error "
config . error_message = " Extension non supportée ou erreur de téléchargement "
config . pending_download = None
config . needs_redraw = True
logger . error ( f " config.pending_download est None pour { games [ config . current_game ] [ 0 ] } " )
elif is_input_matched ( event , " cancel " ) :
config . menu_state = " platform "
config . current_game = 0
config . scroll_offset = 0
config . needs_redraw = True
logger . debug ( " Retour à platform " )
2025-07-09 01:13:55 +02:00
elif is_input_matched ( event , " redownload_game_cache " ) :
config . previous_menu_state = config . menu_state
config . menu_state = " redownload_game_cache "
config . needs_redraw = True
logger . debug ( " Passage à redownload_game_cache depuis game " )
2025-07-09 16:56:37 +02:00
#Historique
2025-07-07 02:48:05 +02:00
elif config . menu_state == " history " :
history = config . history
if is_input_matched ( event , " up " ) :
if config . current_history_item > 0 :
config . current_history_item - = 1
config . repeat_action = " up "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " down " ) :
if config . current_history_item < len ( history ) - 1 :
config . current_history_item + = 1
config . repeat_action = " down "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
elif is_input_matched ( event , " page_up " ) :
config . current_history_item = max ( 0 , config . current_history_item - config . visible_history_items )
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
config . repeat_last_action = current_time
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug("Page précédente dans l'historique")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " page_down " ) :
config . current_history_item = min ( len ( history ) - 1 , config . current_history_item + config . visible_history_items )
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
config . repeat_last_action = current_time
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug("Page suivante dans l'historique")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " progress " ) :
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
config . menu_state = " confirm_clear_history "
config . confirm_clear_selection = 0 # 0 pour "Non", 1 pour "Oui"
config . needs_redraw = True
logger . debug ( " Passage à confirm_clear_history depuis history " )
elif is_input_matched ( event , " confirm " ) :
if history :
entry = history [ config . current_history_item ]
platform = entry [ " platform " ]
game_name = entry [ " game_name " ]
for game in config . games :
if game [ 0 ] == game_name and config . platforms [ config . current_platform ] == platform :
config . pending_download = check_extension_before_download ( game_name , platform , game [ 1 ] )
if config . pending_download :
url , platform , game_name , is_zip_non_supported = config . pending_download
if is_zip_non_supported :
2025-07-09 01:13:55 +02:00
config . previous_menu_state = config . menu_state # Remplacer cette ligne
2025-07-07 02:48:05 +02:00
config . menu_state = " extension_warning "
config . extension_confirm_selection = 0
config . needs_redraw = True
logger . debug ( f " Extension non supportée pour retéléchargement, passage à extension_warning pour { game_name } " )
else :
task = asyncio . create_task ( download_rom ( url , platform , game_name , is_zip_non_supported ) )
config . download_tasks [ task ] = ( task , url , game_name , platform )
2025-07-09 01:13:55 +02:00
config . previous_menu_state = config . menu_state # Remplacer cette ligne
2025-07-07 02:48:05 +02:00
config . menu_state = " download_progress "
config . needs_redraw = True
logger . debug ( f " Retéléchargement: { game_name } pour { platform } depuis { url } " )
config . pending_download = None
action = " redownload "
else :
config . menu_state = " error "
config . error_message = " Extension non supportée ou erreur de retéléchargement "
config . pending_download = None
config . needs_redraw = True
logger . error ( f " config.pending_download est None pour { game_name } " )
break
elif is_input_matched ( event , " cancel " ) :
config . menu_state = validate_menu_state ( config . previous_menu_state )
config . current_history_item = 0
config . history_scroll_offset = 0
config . needs_redraw = True
logger . debug ( f " Retour à { config . menu_state } depuis history " )
2025-07-09 01:13:55 +02:00
2025-07-09 16:56:37 +02:00
# Confirmation vider l'historique"
2025-07-07 02:48:05 +02:00
elif config . menu_state == " confirm_clear_history " :
logger . debug ( f " État confirm_clear_history, confirm_clear_selection= { config . confirm_clear_selection } , événement= { event . type } , valeur= { getattr ( event , ' value ' , None ) } " )
if is_input_matched ( event , " confirm " ) :
logger . debug ( f " Action confirm détectée dans confirm_clear_history " )
if config . confirm_clear_selection == 1 : # Oui
clear_history ( )
config . history = [ ]
config . current_history_item = 0
config . history_scroll_offset = 0
config . menu_state = " history "
config . needs_redraw = True
logger . info ( " Historique vidé après confirmation " )
else : # Non
config . menu_state = " history "
config . needs_redraw = True
logger . debug ( " Annulation du vidage de l ' historique, retour à history " )
elif is_input_matched ( event , " left " ) :
2025-07-09 01:13:55 +02:00
#logger.debug(f"Action left détectée dans confirm_clear_history")
2025-07-07 02:48:05 +02:00
config . confirm_clear_selection = 1 # Sélectionner "Non"
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Changement sélection confirm_clear_history: {config.confirm_clear_selection}")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " right " ) :
2025-07-09 01:13:55 +02:00
#logger.debug(f"Action right détectée dans confirm_clear_history")
2025-07-07 02:48:05 +02:00
config . confirm_clear_selection = 0 # Sélectionner "Oui"
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Changement sélection confirm_clear_history: {config.confirm_clear_selection}")
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " cancel " ) :
2025-07-09 01:13:55 +02:00
#logger.debug(f"Action cancel détectée dans confirm_clear_history")
2025-07-07 02:48:05 +02:00
config . menu_state = " history "
config . needs_redraw = True
logger . debug ( " Annulation du vidage de l ' historique, retour à history " )
2025-07-09 01:13:55 +02:00
2025-07-09 16:56:37 +02:00
# Progression téléchargement
2025-07-06 19:47:21 +02:00
elif config . menu_state == " download_progress " :
if is_input_matched ( event , " cancel " ) :
2025-07-07 02:48:05 +02:00
for task in config . download_tasks :
task . cancel ( )
config . download_tasks . clear ( )
config . download_progress . clear ( )
config . pending_download = None
config . menu_state = validate_menu_state ( config . previous_menu_state )
config . needs_redraw = True
logger . debug ( f " Téléchargement annulé, retour à { config . menu_state } " )
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " progress " ) :
2025-07-07 02:48:05 +02:00
config . menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Retour à { config . menu_state } depuis download_progress " )
2025-07-06 19:47:21 +02:00
2025-07-07 02:48:05 +02:00
# Résultat téléchargement
elif config . menu_state == " download_result " :
if is_input_matched ( event , " confirm " ) :
config . menu_state = validate_menu_state ( config . previous_menu_state )
config . popup_timer = 0
config . pending_download = None
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Retour à { config . menu_state } depuis download_result " )
# Confirmation quitter
elif config . menu_state == " confirm_exit " :
if is_input_matched ( event , " confirm " ) :
2025-07-06 19:47:21 +02:00
if config . confirm_selection == 1 :
return " quit "
else :
2025-07-07 02:48:05 +02:00
config . menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Retour à { config . menu_state } depuis confirm_exit " )
elif is_input_matched ( event , " left " ) or is_input_matched ( event , " right " ) :
config . confirm_selection = 1 - config . confirm_selection
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Changement sélection confirm_exit: {config.confirm_selection}")
2025-07-07 02:48:05 +02:00
# Avertissement extension
2025-07-06 19:47:21 +02:00
elif config . menu_state == " extension_warning " :
2025-07-07 02:48:05 +02:00
if is_input_matched ( event , " confirm " ) :
2025-07-06 19:47:21 +02:00
if config . extension_confirm_selection == 1 :
2025-07-07 02:48:05 +02:00
if config . pending_download and len ( config . pending_download ) == 4 :
2025-07-06 19:47:21 +02:00
url , platform , game_name , is_zip_non_supported = config . pending_download
2025-07-07 02:48:05 +02:00
task = asyncio . create_task ( download_rom ( url , platform , game_name , is_zip_non_supported ) )
2025-07-06 19:47:21 +02:00
config . download_tasks [ task ] = ( task , url , game_name , platform )
2025-07-07 02:48:05 +02:00
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-06 19:47:21 +02:00
config . menu_state = " download_progress "
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Téléchargement confirmé après avertissement: { game_name } pour { platform } depuis { url } " )
config . pending_download = None
action = " download "
2025-07-06 19:47:21 +02:00
else :
2025-07-07 02:48:05 +02:00
config . menu_state = " error "
config . error_message = " Données de téléchargement invalides "
config . pending_download = None
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . error ( " config.pending_download invalide " )
2025-07-06 19:47:21 +02:00
else :
config . pending_download = None
2025-07-07 02:48:05 +02:00
config . menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Retour à { config . menu_state } depuis extension_warning " )
elif is_input_matched ( event , " left " ) or is_input_matched ( event , " right " ) :
config . extension_confirm_selection = 1 - config . extension_confirm_selection
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
#logger.debug(f"Changement sélection extension_warning: {config.extension_confirm_selection}")
2025-07-06 19:47:21 +02:00
elif is_input_matched ( event , " cancel " ) :
config . pending_download = None
2025-07-07 02:48:05 +02:00
config . menu_state = validate_menu_state ( config . previous_menu_state )
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Retour à { config . menu_state } depuis extension_warning " )
2025-07-06 19:47:21 +02:00
2025-07-09 16:56:37 +02:00
# Menu pause
2025-07-07 02:48:05 +02:00
elif config . menu_state == " pause_menu " :
2025-07-09 01:13:55 +02:00
logger . debug ( f " État pause_menu, selected_option= { config . selected_option } , événement= { event . type } , valeur= { getattr ( event , ' value ' , None ) } " )
2025-07-07 02:48:05 +02:00
if is_input_matched ( event , " up " ) :
config . selected_option = max ( 0 , config . selected_option - 1 )
config . repeat_action = " up "
config . repeat_start_time = current_time + REPEAT_DELAY
config . repeat_last_action = current_time
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
logger . debug ( f " Navigation vers le haut: selected_option= { config . selected_option } " )
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " down " ) :
2025-07-09 01:13:55 +02:00
config . selected_option = min ( 4 , config . selected_option + 1 )
2025-07-07 02:48:05 +02:00
config . repeat_action = " down "
config . repeat_start_time = current_time + REPEAT_DELAY
2025-07-06 19:47:21 +02:00
config . repeat_last_action = current_time
2025-07-07 02:48:05 +02:00
config . repeat_key = event . key if event . type == pygame . KEYDOWN else event . button if event . type == pygame . JOYBUTTONDOWN else ( event . axis , 1 if event . value > 0 else - 1 ) if event . type == pygame . JOYAXISMOTION else event . value
config . needs_redraw = True
2025-07-09 01:13:55 +02:00
logger . debug ( f " Navigation vers le bas: selected_option= { config . selected_option } " )
2025-07-07 02:48:05 +02:00
elif is_input_matched ( event , " confirm " ) :
2025-07-09 01:13:55 +02:00
logger . debug ( f " Confirmation dans pause_menu avec selected_option= { config . selected_option } " )
2025-07-07 02:48:05 +02:00
if config . selected_option == 0 : # Controls
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
config . menu_state = " controls_help "
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
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 )
2025-07-09 16:56:37 +02:00
logger . debug ( f " Previous menu state avant controls_mapping: { config . previous_menu_state } " )
config . menu_state = " controls_mapping "
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-09 16:56:37 +02:00
logger . debug ( f " Passage à controls_mapping depuis pause_menu " )
2025-07-07 02:48:05 +02:00
elif config . selected_option == 2 : # History
config . history = load_history ( )
config . current_history_item = 0
config . history_scroll_offset = 0
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
config . menu_state = " history "
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Passage à history depuis pause_menu " )
2025-07-09 01:13:55 +02:00
elif config . selected_option == 3 : # Redownload game cache
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
config . menu_state = " redownload_game_cache "
config . redownload_confirm_selection = 0
config . needs_redraw = True
logger . debug ( f " Passage à redownload_game_cache depuis pause_menu " )
elif config . selected_option == 4 : # Quit
2025-07-07 02:48:05 +02:00
config . previous_menu_state = validate_menu_state ( config . previous_menu_state )
config . menu_state = " confirm_exit "
config . confirm_selection = 0
2025-07-06 19:47:21 +02:00
config . needs_redraw = True
2025-07-07 02:48:05 +02:00
logger . debug ( f " Passage à confirm_exit depuis pause_menu " )
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 pause_menu " )
2025-07-06 19:47:21 +02:00
2025-07-07 02:48:05 +02:00
# 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 . needs_redraw = True
logger . debug ( f " Retour à { config . menu_state } depuis controls_help " )
# Remap controls
2025-07-09 16:56:37 +02:00
elif config . menu_state == " controls_mapping " :
2025-07-07 02:48:05 +02:00
if is_input_matched ( event , " cancel " ) :
config . menu_state = " pause_menu "
config . needs_redraw = True
2025-07-09 16:56:37 +02:00
logger . debug ( " Retour à pause_menu depuis controls_mapping " )
2025-07-09 01:13:55 +02:00
2025-07-09 16:56:37 +02:00
# Redownload game cache
2025-07-09 01:13:55 +02:00
elif config . menu_state == " redownload_game_cache " :
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 } " )
elif is_input_matched ( event , " confirm " ) :
logger . debug ( f " Action confirm dans redownload_game_cache, 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 ( )
config . download_progress . clear ( )
config . pending_download = None
if os . path . exists ( " /userdata/roms/ports/RGSX/sources.json " ) :
try :
os . remove ( " /userdata/roms/ports/RGSX/sources.json " )
logger . debug ( " Fichier sources.json supprimé avec succès " )
if os . path . exists ( " /userdata/roms/ports/RGSX/games " ) :
shutil . rmtree ( " /userdata/roms/ports/RGSX/games " )
logger . debug ( " Dossier games supprimé avec succès " )
if os . path . exists ( " /userdata/roms/ports/RGSX/images " ) :
shutil . rmtree ( " /userdata/roms/ports/RGSX/images " )
logger . debug ( " Dossier images supprimé avec succès " )
config . menu_state = " restart_popup "
config . popup_message = " Redownload des jeux effectué. \n Veuillez redémarrer l ' application pour voir les changements. "
config . popup_timer = 5000 # 5 secondes
config . needs_redraw = True
logger . debug ( " Passage à restart_popup " )
except Exception as e :
logger . error ( f " Erreur lors de la suppression du fichier sources.json ou dossiers: { e } " )
config . menu_state = " error "
config . error_message = " Erreur lors de la suppression du fichier sources.json ou dossiers "
config . needs_redraw = True
return action
else :
logger . debug ( " Fichier sources.json non trouvé, passage à restart_popup " )
config . menu_state = " restart_popup "
config . popup_message = " Aucun cache trouvé. \n Veuillez redémarrer l ' application pour charger les jeux. "
config . popup_timer = 5000 # 5 secondes
config . needs_redraw = True
logger . debug ( " Passage à restart_popup " )
else : # Non
config . menu_state = validate_menu_state ( config . previous_menu_state )
config . needs_redraw = True
logger . debug ( f " Annulation du redownload, retour à { config . menu_state } " )
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 " )
# Popup de redémarrage
elif config . menu_state == " restart_popup " :
if is_input_matched ( event , " confirm " ) or is_input_matched ( event , " cancel " ) :
config . menu_state = validate_menu_state ( config . previous_menu_state )
config . popup_message = " "
config . popup_timer = 0
config . needs_redraw = True
logger . debug ( f " Retour manuel à { config . menu_state } depuis restart_popup " )
2025-07-07 02:48:05 +02:00
# Gestion de la répétition automatique (relâchement)
if event . type in ( pygame . KEYUP , pygame . JOYBUTTONUP , pygame . JOYAXISMOTION , pygame . JOYHATMOTION ) :
if event . type == pygame . JOYAXISMOTION and abs ( event . value ) > 0.5 :
return action
if event . type == pygame . JOYHATMOTION and event . value != ( 0 , 0 ) :
return action
config . repeat_action = None
config . repeat_key = None
config . repeat_start_time = 0
2025-07-09 01:13:55 +02:00
#logger.debug("Répétition arrêtée")
2025-07-07 02:48:05 +02:00
return action
2025-07-09 16:56:37 +02:00
#Gestion de la répétition automatique des actions
2025-07-07 02:48:05 +02:00
async def handle_repeat_actions ( ) :
""" Gère la répétition automatique des actions. """
current_time = pygame . time . get_ticks ( )
if config . repeat_action and config . repeat_key and current_time > config . repeat_start_time :
if current_time - config . repeat_last_action > REPEAT_ACTION_DEBOUNCE :
logger . debug ( f " Répétition action: { config . repeat_action } " )
event_dict = {
" type " : pygame . KEYDOWN if isinstance ( config . repeat_key , int ) and config . repeat_key < 1000 else pygame . JOYBUTTONDOWN if isinstance ( config . repeat_key , int ) else pygame . JOYAXISMOTION if isinstance ( config . repeat_key , tuple ) and len ( config . repeat_key ) == 2 else pygame . JOYHATMOTION ,
" key " : config . repeat_key if isinstance ( config . repeat_key , int ) and config . repeat_key < 1000 else None ,
" button " : config . repeat_key if isinstance ( config . repeat_key , int ) and config . repeat_key > = 1000 else None ,
" axis " : config . repeat_key [ 0 ] if isinstance ( config . repeat_key , tuple ) and len ( config . repeat_key ) == 2 else None ,
" value " : config . repeat_key [ 1 ] if isinstance ( config . repeat_key , tuple ) and len ( config . repeat_key ) == 2 else config . repeat_key if isinstance ( config . repeat_key , tuple ) else None
}
handle_controls ( event_dict , None , None , None )
config . repeat_last_action = current_time
config . repeat_start_time = current_time + REPEAT_INTERVAL