Python кросс-платформенное прослушивание нажатий клавиш?

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

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

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


изменить

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

Ответы

Ответ 1

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

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

Объединив рецепт keypress из часто задаваемых вопросов Python и модуля 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)

Ответ 2

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

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

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

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

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

Ответ 3

Здесь вы можете сделать это в 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 no ++ in python
        number += 1
        #wait half a second
        time.sleep(0.5)