2 votes

Existe-t-il un moyen de capturer les frappes de touches en Python et de filtrer celles qui sont générées par la répétition des touches ?

J'expérimente quelques méthodes d'entrée en Python, et j'utilise pynput J'ai un simple grabber pour les touches pressées et relâchées, comme dans la documentation :

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

Cependant, on_press est appelé indépendamment du fait que la touche ait été générée par une répétition de touches ou simplement par la touche pressée et, pour autant que je sache, je ne peux pas savoir ce qu'il en est.

Existe-t-il un moyen de le savoir ? Ma plateforme cible est macOS, mais j'espère que cela fonctionnera aussi sous Windows, car il se peut que je veuille porter cette idée un jour.

pynput est bien, mais cela ne me dérange pas de changer de bibliothèque si cela signifie que je peux obtenir ce dont j'ai besoin pour que cela fonctionne.

1voto

Leon Points 20011

En cas de répétition d'une touche (du moins sur mon système Ubuntu), d'autres appuis sur la touche sont générés/simulés sans qu'il y ait de relâchement de la touche :

$ python keypress_vs_repeat.py 
Key.enter release
a'a' pressed
a'a' pressed
a'a' pressed
a'a' pressed
a'a' release

Vous pouvez utiliser ces informations pour distinguer une pression de touche réelle d'une pression de touche simulée :

keypress_vs_repeat.py

from pynput.keyboard import Key, Listener

currently_pressed_key = None

def on_press(key):
    global currently_pressed_key
    if key == currently_pressed_key:
        print('{0} repeated'.format(key))
    else:
        print('{0} pressed'.format(key))
        currently_pressed_key = key

def on_release(key):
    global currently_pressed_key
    print('{0} release'.format(key))
    currently_pressed_key = None
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

Essais (presse a une fois, appuyez et maintenez enfoncée la touche b ) :

$ python keypress_vs_repeat.py
Key.enter release
'a' pressed
a'a' release
'b' pressed
b'b' repeated
b'b' repeated
b'b' repeated
b'b' repeated
b'b' repeated
b'b' release
Key.esc pressed
^[Key.esc release
^[$

0voto

dawg Points 26051

Cela fonctionne sur OS X et Mint. Je n'ai pas de Windows à tester :

class _Getch:
    """Gets a single character from standard input.  Does not echo to the
screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()
    def __call__(self): return self.impl()

class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        return msvcrt.getch()

getch = _Getch()

Test :

c=getch()
i=1
while c!='q':
    c=getch()
    print c, i
    # if key is held, it does not repeat...
    i+=1

Sur la base de cette recette ActiveState

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X