Utilitaires

Répétition simultanée de plusieurs touches clavier

De base, lorsque l’utilisateur appuie sur plusieurs touches clavier à la fois, pygame ne prend en compte que la première touche enfoncée. Dans cette section, nous développons un utilitaire nous permettant de gérer plusieurs touches enfoncées simultanément.

Pygame fournit la méthode pygame.key.get_pressed() qui renvoie l’état de toutes les touches du clavier sous forme d’une liste de booléens. L’indice d’une touche dans cette liste est la « constante de touche » correspondante (définie par pygame, par exemple pygame.K_e), et la valeur correspondante est 1 si la touche est enfoncée.

De là, il est assez simple « d’injecter », pour chaque touche enfoncée, un nouvel évènement pygame.KEYPRESSED dans la file d’évènements que votre code lit (pygame.event.get()) pour traiter les entrées de utilisateur.

Le code ci-dessous permet de créer une nouvelleGestionClavier, d’enregister un délai initial et une période de répétition pour les touches qui vous intéressent (repeteTouche). La méthode scan doit être appelée AVANT de lire la file d’évènements de pygame.

Notez bien que l’utilisation de la méthode pygame.key.set_repeat dans votre programme peut interférer avec le bon fonctionnement de notre utilitaire, et cette méthode ne devrait donc pas être utilisée avec l’utilitaire.

import pygame

#définition d'un nouvel évènement pour représenter une touche qui reste enfoncée
pygame.KEYPRESSED = pygame.USEREVENT

BLEU_CIEL = (135, 206, 250)

FENETRE_LARGEUR = 800
FENETRE_HAUTEUR = 600

FLAPPY_LARGEUR = 60
FLAPPY_HAUTEUR = 51

pygame.init()

# Gestionnaire de répétition automatique de plusieurs touches
# !!! NE PAS UTILISER pygame.key.set_repeat() dans votre programme !!!
# ===== début GestionClavier ===== 
def _nouveauEtatTouche():
    return {
        'actif': False,
        'delai': 0,
        'periode': 0,
        'suivant': 0
    }

def nouvelleGestionClavier():
    return {}

# gc: gestionnaire de clavier (créé par nouvelleGestion Clavier())
# touche: numéro de la touche (ex: pygame.K_e)
# delai: attente (en ms) avant la première répétition
# periode: temps (en ms) entre deux répétitions

def repeteTouche(gc, touche, delai, periode):
    pygame.key.set_repeat()
    
    if touche in gc:
        entree = gc[touche]
    else:
        entree = _nouveauEtatTouche()

    entree['delai'] = delai
    entree['periode'] = periode
    gc[touche] = entree


def scan(gc):
    maintenant = pygame.time.get_ticks()
    keys = pygame.key.get_pressed()
    for touche in gc:
        if keys[touche] == 1:
            if gc[touche]['actif']:
                if maintenant >= gc[touche]['suivant']:
                    gc[touche]['suivant'] = gc[touche]['periode'] + maintenant
                    pygame.event.post(pygame.event.Event(pygame.KEYPRESSED, {'key':touche}))
            else:
                gc[touche]['actif'] = True
                gc[touche]['suivant'] = gc[touche]['delai'] + maintenant
        else:
            gc[touche]['actif'] = False
            gc[touche]['suivant'] = 0

        
# ===== fin GestionClavier =====

    
fenetre_taille = (FENETRE_LARGEUR, FENETRE_HAUTEUR)
fenetre = pygame.display.set_mode(fenetre_taille)
pygame.display.set_caption('Test keyboard')

fini = False
temps = pygame.time.Clock()

fenetre.fill(BLEU_CIEL)
pygame.display.flip()

# répétition de plusieurs touches
gc = nouvelleGestionClavier()
repeteTouche(gc, pygame.K_e, 100, 25)
repeteTouche(gc, pygame.K_j, 100, 25)

while not fini:
    now = pygame.time.get_ticks()
    # --- Traiter entrées joueur
    scan(gc) # DOIT être appelée avant pygame.event.get()
    events = pygame.event.get()
    #print("Events: " + str(len(events)))
    for evenement in events:
        #print(str(evenement))
        if evenement.type == pygame.QUIT:
            fini = True
        if evenement.type == pygame.KEYDOWN:
            print("KEYDOWN: " + str(evenement.key) + " " + str(now))
        elif evenement.type == pygame.KEYPRESSED:
            print("KEYPRESSED:" + str(evenement.key) + " " + str(now))

    #print("keys: " + str(tk))



    temps.tick(50)

pygame.display.quit()
pygame.quit()
exit()