Метод Python для чтения нажатия клавиш?

Я новичок в Python, и я только что сделал игру и меню на Python. Вопрос в том, что использование (raw_)input() требует, чтобы я нажимал ввод после каждого нажатия клавиши, я хотел бы сделать так, чтобы нажатие стрелки вниз мгновенно выбирало следующий пункт меню или перемещалось вниз в игре. На данный момент мне нужно набрать «вниз», а затем нажать «Ввод». Я также провел довольно много исследований, но я бы предпочел не загружать огромные модули (например, pygame) только для достижения одного метода keyDown(). Так есть ли более простые способы, которых я просто не смог найти?

Изменить: только что узнал, что msvcrt.getch() поможет. Это не keyDown(), но работает. Тем не менее, я тоже не уверен, как его использовать, это кажется довольно странным, любая помощь здесь? Вот что я получил на данный момент:

from msvcrt import getch
while True:
    key = getch()
    print(key)

Тем не менее, он продолжает выдавать мне все эти бессмысленные байты, например, стрелка вниз:

b'\xe0'
b'P'

И я понятия не имею, как их использовать, я пытался сравнить с chr() и даже использовать ord(), но не могу сделать никаких сравнений. То, что я пытаюсь сделать, в основном это:

from msvcrt import getch
while True:
    key = getch()
    if key == escape:
        break
    elif key == downarrow:
        movedown()
    elif key == 'a':
        ...

И так далее... Любая помощь?


person Community    schedule 29.08.2012    source источник
comment
Не дубликат этого. Речь идет о событиях нажатия клавиш, а не о вводе одного символа.   -  person Deestan    schedule 29.08.2012
comment
Я могу найти кросс-платформенное решение ?? msvcrt недоступен в дистрибутивах Python для Mac/Linux.   -  person cat    schedule 11.01.2016


Ответы (6)


Выяснил это, протестировав все на себе. Тем не менее, я не смог найти ни одной темы по этому поводу, поэтому я просто оставлю решение здесь. Возможно, это не единственное и даже не лучшее решение, но оно работает для моих целей (в пределах ограничений getch) и лучше, чем ничего.

Примечание: правильный keyDown(), который будет распознавать все клавиши и фактические нажатия клавиш, по-прежнему ценится.

Решение: использование ord()-функции для первого преобразования getch() в целое число (я думаю, это виртуальные коды клавиш, но не совсем уверен) работает нормально, а затем сравнение результата с фактическим числом, представляющим хотел ключ. Кроме того, если бы мне было нужно, я мог бы добавить дополнительные chr() вокруг возвращаемого числа, чтобы оно преобразовало его в символ. Однако я использую в основном стрелку вниз, esc и т. д., поэтому преобразовывать их в символ было бы глупо. Вот окончательный код:

from msvcrt import getch
while True:
    key = ord(getch())
    if key == 27: #ESC
        break
    elif key == 13: #Enter
        select()
    elif key == 224: #Special keys (arrows, f keys, ins, del, etc.)
        key = ord(getch())
        if key == 80: #Down arrow
            moveDown()
        elif key == 72: #Up arrow
            moveUp()

Также, если кому-то нужно, вы можете легко узнать коды клавиш из google или с помощью python и просто нажав клавишу:

from msvcrt import getch
while True:
    print(ord(getch()))
person Community    schedule 29.08.2012
comment
Я использую приведенный выше код, но мой код просто блокируется в getch(), и тогда ничего не происходит. любая помощь ? - person Anum Sheraz; 09.05.2016
comment
@AnumSheraz Вышеупомянутый метод работает только при запуске кода из командной строки. - person Moondra; 27.05.2017
comment
если вы сначала преобразуете char в байты, вы можете напрямую сравнить с нажатием клавиши 'keypressed == bytes('q', 'utf-8')' проверяет, была ли нажата q. Это будет работать для специальных клавиш, таких как ввод или esc, но вам нужно знать коды для них (например, esc - это '\ x1b') - person Xitcod13; 24.05.2018

См. документы MSDN getch. Конкретно:

Функции _getch и_getwch считывают один символ с консоли, не повторяя его. Ни одна из этих функций не может быть использована для чтения CTRL+C. При чтении функциональной клавиши или клавиши со стрелкой каждая функция должна вызываться дважды; первый вызов возвращает 0 или 0xE0, а второй вызов возвращает фактический код клавиши.

Функция Python возвращает символ. вы можете использовать ord() для получения целочисленного значения, которое вы можете проверить, например keycode = ord(msvcrt.getch()).

Поэтому, если вы читаете 0x00 или 0xE0, прочитайте его еще раз, чтобы получить код клавиши для стрелки или функциональной клавиши. Экспериментально 0x00 предшествует F1-F10 (0x3B-0x44), а 0xE0 предшествует клавишам со стрелками и Ins/Del/Home/End/PageUp/PageDown.

person Mark Tolonen    schedule 29.08.2012
comment
Ну, я уже понял это, но не могу опубликовать окончательное решение. Но это + ord() + char() - person ; 29.08.2012

Я действительно не хотел публиковать это как комментарий, потому что мне нужно было бы прокомментировать все ответы и исходный вопрос.

Все ответы, похоже, основаны на MSVCRT Microsoft Visual C Runtime. Если вы хотите избежать этой зависимости:

Если вам нужна кроссплатформенная поддержка, используйте библиотеку здесь:

https://pypi.org/project/getkey/#files

https://github.com/kcsaff/getkey

Может позволить более элегантное решение.

Пример кода:

from getkey import getkey, keys
key = getkey()
if key == keys.UP:
  ...  # Handle the UP key
elif key == keys.DOWN:
  ...  # Handle the DOWN key
elif key == 'a':
  ...  # Handle the `a` key
elif key == 'Y':
  ...  # Handle `shift-y`
else:
  # Handle other text characters
  buffer += key
  print(buffer)
person Ken    schedule 17.08.2019
comment
Установка специальной библиотеки ('getkey') - очень неэффективное решение, когда уже встроенный модуль (msvcrt) работает просто отлично! - person Apostolos; 31.08.2020
comment
@Apostolos, как он сказал в своем решении, msvcrt доступен только в Windows, а getkey является кроссплатформенным. - person InxaneNinja; 03.09.2020
comment
Я понимаю что ты имеешь ввиду. Но подумайте: поскольку каждая платформа имеет свой собственный встроенный модуль getkey (как 'msvcrt' в Windows), установка дополнительного модуля getkey всегда будет бесполезна! :) (Простая логика) - person Apostolos; 05.09.2020

Уже очень поздно, но я сделал быстрый скрипт, который работает для Windows, Mac и Linux, просто используя каждую командную строку:

import os, platform

def close():
    if platform.system() == "Windows":
        print("Press any key to exit . . .")
        os.system("pause>nul")
        exit()
    
    elif platform.system() == "Linux":
        os.system("read -n1 -r -p \"Press any key to exit . . .\" key")
        exit()
    
    elif platform.system() == "Darwin":
        print("Press any key to exit . . .")
        os.system("read -n 1 -s -p \"\"")
        exit()
    
    else:
        exit()

Он использует только встроенные функции и должен работать для всех трех (хотя я тестировал только Windows и Linux...).

person Amos Lobel    schedule 27.01.2021
comment
Это ужасное решение. Это даже не использование встроенных функций. Вы открываете подпроцесс оболочки и запускаете команды Linux только для обнаружения нажатия клавиши - person Joel G Mathew; 18.07.2021

Я тоже пытался этого добиться. Из приведенных выше кодов я понял, что вы можете вызывать функцию getch() несколько раз, чтобы получить оба байта из функции. Таким образом, функция ord() не нужна, если вы просто хотите использовать ее с байтовыми объектами.

while True :
    if m.kbhit() :
        k = m.getch()
        if b'\r' == k :
            break
        elif k == b'\x08'or k == b'\x1b':
            # b'\x08' => BACKSPACE
            # b'\x1b' => ESC
            pass
        elif k == b'\xe0' or k == b'\x00':
            k = m.getch()
            if k in [b'H',b'M',b'K',b'P',b'S',b'\x08']:
                # b'H' => UP ARROW
                # b'M' => RIGHT ARROW
                # b'K' => LEFT ARROW
                # b'P' => DOWN ARROW
                # b'S' => DELETE
                pass
            else:
                print(k.decode(),end='')
        else:
            print(k.decode(),end='')

Этот код будет работать для печати любой клавиши до тех пор, пока не будет нажата клавиша ввода в CMD или IDE (я использовал VS CODE). При необходимости вы можете настроить внутри if для определенных клавиш.

person JIGOD UNIVERSAL    schedule 02.05.2020

person    schedule
comment
Пожалуйста, добавьте некоторые пояснения к вашему ответу, чтобы объяснить ваш код. - person AJ123; 03.11.2017
comment
Почему вам нужно сделать еще одну клавишу = ord (getch ()), когда вы нажимаете клавиши со стрелками? В первый раз вы получаете 224, но он сразу получает правильный код для этого ключа. Как? - person luturol; 05.02.2020