Кросс-платформенный Python прослушивает нажатия клавиш? [дубликат]


На этот вопрос уже есть ответ здесь:

Мне нужно прослушать определенные нажатия клавиш в терминальной программе python, не останавливая выполнение с помощью raw_input. Я видел, как люди используют несколько специфичных для windows способов прослушивания нажатий клавиш, и я видел, как люди используют большие модули, такие как tkinter и pygame, которой я хочу избежать.

Есть ли легкий модуль, который делает эту кросс-платформу (по крайней мере ubuntu, windows, mac)? или есть способ использовать только систему событий от tkinter, pygame и т. д...?

Если нет, то как я должен подойти к решению этой проблемы? Моя первая мысль-перенаправить stdin на другой процесс и продолжать проверять, содержит ли он один из моих ключей событий.


Править

Спасибо @unutbu за то, что нашли время отметить этот вопрос, что является 3-летним и успешно ответил как дубликат другого вопроса, ответы которого не относятся к этому вопросу, потому что я специально спросил о неблокирующем решении.

3 16

3 ответа:

Я не знаю ни одного кросс-платформенного легкого модуля, который слушает нажатия клавиш. Но вот предложение на случай, если вы хотите реализовать что-то простое:

Проверьте этот вопрос наполучение одного нажатия клавиши одновременно в Python FAQ. Вы можете немного поэкспериментировать с блокировкой чтения из sys.stdin и threading. Но это может работать только на Unix. В Windows вы можете использовать msvcrt.kbhit.

Комбинируя рецепт нажатия клавиш из Python FAQ и модуль msvcrt, результирующая функция kbhit будет выглядеть следующим образом:

try:
    from msvcrt import kbhit
except ImportError:
    import termios, fcntl, sys, os
    def kbhit():
        fd = sys.stdin.fileno()
        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)
        oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
        try:
            while True:
                try:
                    c = sys.stdin.read(1)
                    return True
                except IOError:
                    return False
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
            fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

Короткий ответ: нет Нажатия клавиш зависят от системы. Они управляются прерываниями. Они одна из основных вещей, встроенных в большинство современных ОС. У них разные философии, которые не могут быть объединены общим способом без потери функциональности.

Вы можете попробовать- termios = unix, файловый дескриптор в стиле posix

Curses = портальная терминальная обработка (которая является специфической консольной парадигмой, а не универсальной)

Python обертывает определенные классы ввод, который может исходить с клавиатуры: например, sys.stdin для консоли inupt.

Но попытка получить универсальный ввод с клавиатуры - это очень общая проблема, которая по своей сути зависит от платформы.

Вот как это можно сделать в Windows:

"""

    Display series of numbers in infinite loop
    Listen to key "s" to stop
    Only works on Windows because listening to keys
    is platform dependent

"""

# msvcrt is a windows specific native module
import msvcrt
import time

# asks whether a key has been acquired
def kbfunc():
    #this is boolean for whether the keyboard has bene hit
    x = msvcrt.kbhit()
    if x:
        #getch acquires the character encoded in binary ASCII
        ret = msvcrt.getch()
    else:
        ret = False
    return ret

#begin the counter
number = 1

#infinite loop
while True:

    #acquire the keyboard hit if exists
    x = kbfunc() 

    #if we got a keyboard hit
    if x != False and x.decode() == 's':
        #we got the key!
        #because x is a binary, we need to decode to string
        #use the decode() which is part of the binary object
        #by default, decodes via utf8
        #concatenation auto adds a space in between
        print ("STOPPING, KEY:", x.decode())
        #break loop
        break
    else:
        #prints the number
        print (number)
        #increment, there's no ++ in python
        number += 1
        #wait half a second
        time.sleep(0.5)