web-dev-qa-db-fra.com

Quelle est la façon la plus simple de détecter les pressions de touches dans python 3 sur une machine Linux)?

En ce moment j'essaye de faire un petit code avec un Raspberry Pi et un makey makey. Le makey makey est une petite carte qui agit comme un clavier USB lorsque certains contacts sont alimentés. Ma question est de savoir quel est le moyen le plus simple de détecter ces pressions de touches dans un script python. Je comprends que l'utilisation des broches GPIO serait plus facile, mais en ce moment je le cherche. J'ai vu des exemples comme l'utilisation de getch () de msvcrt (qui, d'après ce que je comprends, ne concerne que Windows), l'utilisation de pygame.key et l'utilisation de getKey. Laquelle de ces thèses est la plus facile à utiliser? Y a-t-il quelqu'un qui peut détecter une touche enfoncée et une touche étant libéré?

Code pseudocode (... est-ce ainsi qu'on l'appelle?)

import whatever needs importing    

if the "W" key is pressed:
   print ("You pressed W")

Elif the "S" is pressed:
    print ("You pressed S")

etc. Merci.

11
montainz09

Il s'agit d'une simple boucle qui mettra stdin en mode brut (désactivation de la mise en mémoire tampon afin que vous n'ayez pas à appuyer sur Entrée) pour obtenir des caractères uniques. Vous devriez faire quelque chose de plus intelligent (comme une instruction with pour le désactiver) mais vous avez l'idée ici:

import tty
import sys
import termios

orig_settings = termios.tcgetattr(sys.stdin)

tty.setcbreak(sys.stdin)
x = 0
while x != chr(27): # ESC
    x=sys.stdin.read(1)[0]
    print("You pressed", x)

termios.tcsetattr(sys.stdin, termios.TCSADRAIN, orig_settings)    

Je pense qu'il faudrait boucler pour détecter les versions clés de Python.

ETA quelques explications supplémentaires:

Sous Linux, l'entrée dans votre programme sera mise en mémoire tampon de ligne . Cela signifie que le système d'exploitation mettra en mémoire tampon l'entrée jusqu'à ce qu'il ait une ligne entière, de sorte que votre programme ne verra même rien de ce que l'utilisateur a tapé jusqu'à ce que l'utilisateur frappe également "Entrée". En d'autres termes, si votre programme s'attend à ce que l'utilisateur tape "w" et que l'utilisateur le fasse, "w" restera dans le tampon du système d'exploitation jusqu'à ce que l'utilisateur frappe "enter". À ce stade, la ligne entière est envoyée à votre programme, vous obtiendrez donc la chaîne "w\n" comme entrée de l'utilisateur.

Vous pouvez désactiver cela en mettant le tty en mode brut . Pour ce faire, utilisez la fonction Python tty.setcbreak qui appellera le pilote tty sous linux pour lui dire d'arrêter la mise en mémoire tampon. Je l'ai passé le sys.stdin argument pour lui dire pour quel flux je voulais désactiver la mise en mémoire tampon1. Donc, après le tty.setcbreak appel, la boucle ci-dessus vous donnera une sortie pour chaque touche appuyée par l'utilisateur.

Une complication, cependant, est qu'une fois votre programme terminé, le tty est toujours en mode brut. Vous trouverez généralement cela insatisfaisant car vous n'obtenez pas la puissance offerte par les paramètres de terminal modernes (comme lorsque vous utilisez des séquences de contrôle ou d'échappement). Par exemple, notez que vous pourriez avoir du mal à quitter le programme avec ctrl-C. Par conséquent, vous devez remettre le terminal en mode cuit une fois que vous avez fini de lire les caractères saisis. Le termios.tcsetattr call dit simplement "remettre le terminal comme je l'ai trouvé". Il sait comment procéder en appelant d'abord termios.tcgetattr au début du programme qui dit "dites-moi tous les paramètres actuels du terminal".

Une fois que vous avez compris tout cela, vous devriez pouvoir facilement encapsuler la fonctionnalité dans une fonction qui convient à votre programme.

1stdin est le flux que l'entrée vous vient de l'utilisateur. Wikipedia peut vous en dire plus sur flux standard .

16
Turn

En utilisant un bon module léger curtsies vous pourriez faire quelque chose comme ça (tiré de leurs exemples/répertoire):

from curtsies import Input

def main():
    with Input(keynames='curses') as input_generator:
        for e in input_generator:
            print(repr(e))

if __name__ == '__main__':
    main()

Donc, appuyer sur les touches de votre clavier vous donne quelque chose comme ceci:

'a'
's'
'KEY_F(1)'
'KEY_F(2)'
'KEY_F(3)'
'KEY_F(4)'
'KEY_F(5)'
'KEY_LEFT'
'KEY_DOWN'
'KEY_UP'
'KEY_RIGHT'
'KEY_NPAGE'
'\n'

curtsies est utilisé par bpython comme une abstraction de bas niveau de choses liées aux terminaux.

Le problème de base du décodage de l'entrée est que dans différents terminaux et programmes d'émulation de terminal comme xterm ou gnome-terminals physiquement, les mêmes clés produisent des séquences de codes clés différentes. C'est pourquoi il faut savoir quels paramètres de terminal doivent être utilisés pour décoder l'entrée. Un tel module aide à faire abstraction de ces détails sanglants.

11
user3159253