Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Tkinter] Bind plusieurs touches

blocage incompréhensible

Sujet résolu
    20 octobre 2016 à 20:21:51

    Salutation communauté du Zér0,

    Récemment, j'ai remarqué qu'on était facilement bloqué avec Tkinter lorsqu'on voulait faire un jeu qui nécessite l'appui simultané sur différentes touches du clavier.

    Je me suis donc mis dans l'optique de créer un widget qui faciliterait l'accès à l'utilisateur de TOUTES les touches appuyées.

    L'idée est simple:

    • on a un set qui contient les touches
    • à chaque appui, on ajoute la touche au set
    • à chaque relâchement, on la retire
    • Si l'utilisateur veut connaitre les touches, on lui renvoie le set

    J'en suis arrivé au code suivant:

    # -*- encoding:utf-8 -*-
    # using Python 3.4.4
    
    import tkinter as tk
    
    class Tk_Multikey(tk.Frame):
        """Allow the user to get all actived keys"""
        
        def __init__(self, master, **kwargs):
            super().__init__(master, **kwargs)
            
            self.keysym = set()
            self.keycode = set()
            self.keysym_num = set()
            master.bind('<KeyPress>', self.add_a_key, add='+')
            master.bind('<KeyRelease>', self.discard_a_key, add='+')
        
        def add_a_key(self, event):
            """When a key is pressed, add its keysym, keycode and keysym_num to the 
            corresponding set"""
            
            self.keysym.add(event.keysym.upper()) # the upper method prevents a 
            # bug when the user is using the Shift/Caplock key and a letter key
            self.keycode.add(event.keycode)
            self.keysym_num.add(event.keysym_num)
            
            
        def discard_a_key(self, event):
            """When a key is released, discard its keysym, keycode and keysym_num to 
            the corresponding set"""
            
            self.keysym.discard(event.keysym.upper()) 
            self.keycode.discard(event.keycode)
            self.keysym_num.discard(event.keysym_num)
            
        
        def __delattr__(self, nameattr):
            """The user is not allowed to delete a set"""
            raise AttributeError("Unable to delete")
        
        def get_keys(self):
            return((self.keysym, self.keycode, self.keysym_num))
        
    
    if __name__ == "__main__":
        
        def update(event=None):
            print("updating")
            strvar_keysym.set(mtk.keysym)
            strvar_keycode.set(mtk.keycode)
            strvar_keysym_num.set(mtk.keysym_num)
        
        root = tk.Tk()
        
        mtk = Tk_Multikey(root)
        mtk.pack()
        
        root.bind('<KeyPress>', update, add='+')
        root.bind('<KeyRelease>', update, add='+')
        
        strvar_keysym = tk.StringVar()
        strvar_keycode = tk.StringVar()
        strvar_keysym_num = tk.StringVar()
        update()
        
        tk.Label(root, textvariable=strvar_keysym).pack()    
        tk.Label(root, textvariable=strvar_keycode).pack()    
        tk.Label(root, textvariable=strvar_keysym_num).pack()
        
        root.mainloop()

    Ce code semble entièrement fonctionnel, cependant je suis déconcerté face au problème suivant:

    Lorsqu'on appuie sur A, puis Z, puis E, puis R; ca affiche les 4. Mais si on rajoute le T, ca ne marche plus.
    Pourtant, si on retire le R, et qu'on rééssaie le T, ca marche.

    J'ai tiré la conclusion (trop hâtive) que le nombre maximal ne pouvait excéder 4 touches, ce qui me semblait absurde.

    J'ai ensuite testé avec d'autre touches du clavier, et certaines passent, d'autre non.

    On a le même problème avec W, X, C (le C ne passe pas..)

    Seriez-vous m'indiquer d'où provient ce bug? (ou alors si n'arrive qu'avec mon Pc; j'ai pas testé sur une autre machine)
    Si oui, auriez-vous une solution à me proposer?

    Merci d'avance,
    et bonne soirée à tous. 

    • Partager sur Facebook
    • Partager sur Twitter
    Si je suis tête en l'air, c'est par habitude de viser le sommet
      20 octobre 2016 à 21:02:43

      Quand tu restes appuyé sur une touche, en fait il y a une succession de keypress et keyrelease qui sont exécutés (rajoute un print dans chaque méthode pour t'en rendre compte). Ce comportement s'appelle le bouncing (trad: le rebond) et c'est peut-être ce qui créé des problèmes dans ton programme.

      Il y a un code sur github qui permet de retirer le rebond (debouncing), regarde si ça peut t'aider (j'avoue ne pas mettre plonger dans son code donc je ne sais comment il s'y prend ni même si ça pourra t'aider)

      • Partager sur Facebook
      • Partager sur Twitter
      Précepte: Le mieux est l'ennemi du bien
        20 octobre 2016 à 21:38:10

        Merci pour ta réponse, je n'y avais jamais fait attention en fait (pourtant j'avais un print("updating") qui l'illustrait bien).

        ça a peut-être un rapport effectivement.

        J'y a jeté un coup d’œil, mais je m'y mettrais sérieusement demain, là je rentre de l'hôpital, je suis un peu fatigué ^^

        Merci pour la piste en tout cas :)

        EDIT: Au passage, si tu vois des choses qu'on peut améliorer dans mon code, hésites pas à me le dire; il n'est sans doute pas parfait ^^

        -
        Edité par WexyR 20 octobre 2016 à 21:40:50

        • Partager sur Facebook
        • Partager sur Twitter
        Si je suis tête en l'air, c'est par habitude de viser le sommet
          20 octobre 2016 à 22:13:16

          J'ai testé ton code, et pour moi le max est de 6 touches simultanément. Je me demande si ce n'est pas une restriction de l'os (et non de tkinter). Peut-être existe-il une commande (avec le module os) pour outrepasser cette restriction. J'ai un peu cherché sur SO, mais je n'ai rien trouvé (peut-être que poser cette question sur SO pourrait être intéressant).
          • Partager sur Facebook
          • Partager sur Twitter
          Précepte: Le mieux est l'ennemi du bien
            21 octobre 2016 à 11:39:06

            D'accord, je vais poster un topic là-bas. Merci :)

            EDIT: J'ai testé le code de github mais je comprend pas vraiment ce qu'il apporte en rapport avec le debouncing.. Le code laisse quand même tous les evenements passer et donc ne ralentit pas la charge...

            Sinon j'ai réussi à  monter à 8-9 touches avec mon code en testant différentes combinaisons.

            -
            Edité par WexyR 21 octobre 2016 à 15:26:30

            • Partager sur Facebook
            • Partager sur Twitter
            Si je suis tête en l'air, c'est par habitude de viser le sommet
              22 octobre 2016 à 12:28:47

              J'ai eu une réponse sur SO, voici le lien:

              http://stackoverflow.com/questions/40173909/bind-many-keys-at-the-same-time

              C'est simplement dû à une restriction mécanique du clavier.

              Problème résolu ^^ Merci @Olygrim de t'être penché sur le sujet :p

              • Partager sur Facebook
              • Partager sur Twitter
              Si je suis tête en l'air, c'est par habitude de viser le sommet
                22 octobre 2016 à 15:08:22

                Merci pour le lien ^^. Cette limitation est intéressante à savoir lorsqu'on veut faire un jeu multijoueur sur un même clavier.
                • Partager sur Facebook
                • Partager sur Twitter
                Précepte: Le mieux est l'ennemi du bien
                  22 octobre 2016 à 19:58:38

                  C'est parce que j'avais prévu de le faire que je me suis retrouvé fasse à ce problème ^^ C'était néanmoins intéressant de tomber sur ce problème dont je m'attendais pas du tout :) Maintenant les gens pourront utiliser mon programme pour tester si leur clavier est de bonne qualité ou pas haha..

                  J'avoue que j'ai été plutôt surpris quand il m'a parlé d'une limitation mécanique.. J'ai été déçu de mon ordi :p

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Si je suis tête en l'air, c'est par habitude de viser le sommet

                  [Tkinter] Bind plusieurs touches

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown