Есть ли способ чтения одного символа из пользовательского ввода? Например, они нажимают одну клавишу в терминале, и она возвращается (вроде как getch()
). Я знаю, что в Windows есть функция для этого, но я бы хотел что-то кроссплатформенное.
262
msvcrt.getch
сmsvcrt.getwch
, как это было предложено здесь.Ответы:
Вот ссылка на сайт, на котором написано, как можно прочитать один символ в Windows, Linux и OSX: http://code.activestate.com/recipes/134892/
источник
ImportError
исключение используется как некое выражение if; почему бы не вызвать platform.system () для проверки ОС?будет в основном читать 1 байт из STDIN.
Если вы должны использовать метод, который не ожидает,
\n
вы можете использовать этот код, как предложено в предыдущем ответе:( взято с http://code.activestate.com/recipes/134892/ )
источник
Дословный рецепт ActiveState, цитируемый дословно в двух ответах, чрезмерно спроектирован. Это можно свести к следующему:
источник
0
.Также стоит попробовать библиотеку readchar , которая частично основана на рецепте ActiveState, упомянутом в других ответах.
Монтаж:
Использование:
Протестировано на Windows и Linux с Python 2.7.
В Windows, только ключи, отображающие для букв или управляющих кодов ASCII поддерживаются ( Backspace, Enter, Esc, Tab, Ctrl+ письмо ). На GNU / Linux ( в зависимости от точного терминала, возможно?) , Вы также можете получить Insert, Delete, Pg Up, Pg Dn, Home, Endи ключи ... но потом, есть вопросы , разделяющие эти специальные ключи от .F nEsc
Оговорка: Как и большинство (?) Все ответы здесь, сигнальными клавишами , как Ctrl+ C, Ctrl+ Dи Ctrl+ Zпойманы и возвращены (как
'\x03'
,'\x04'
и ,'\x1a'
соответственно); Ваша программа может быть трудно прервать.источник
Альтернативный метод:
Из этого сообщения в блоге .
источник
| os.O_NONBLOCK
. В противном случае вы можете поместить его в цикл (хорошая идея, чтобы немного поспать в цикле, чтобы избежать вращения).while True
тогдаwhile 1
.Этот код, основанный здесь , будет правильно вызывать KeyboardInterrupt и EOFError, если нажаты Ctrl+ Cили Ctrl+ D.
Должно работать на Windows и Linux. Версия для OS X доступна из оригинального источника.
источник
Ответ (в настоящее время) с самым высоким рейтингом (с кодом ActiveState) слишком сложен. Я не вижу смысла использовать классы, когда достаточно простой функции. Ниже приведены две реализации, которые выполняют то же самое, но с более читаемым кодом.
Обе эти реализации:
Версия 1: удобочитаемая и простая
Версия 2: избегайте повторного импорта и обработки исключений:
[EDIT] Я пропустил одно преимущество кода ActiveState. Если вы планируете читать символы несколько раз, этот код позволяет избежать (незначительной) стоимости повторения импорта Windows и обработки исключений ImportError в Unix-подобных системах. В то время как вы, вероятно, должны быть более обеспокоены читабельностью кода, чем этой незначительной оптимизацией, вот альтернатива (она похожа на ответ Луи, но getChar () является автономной), которая функционирует так же, как код ActiveState, и более читабельна:
Пример кода, который использует любую из версий getChar () выше:
источник
Это может быть случай использования для менеджера контекста. Оставляя в стороне допуски для ОС Windows, вот мое предложение:
источник
self
в__enter__
и естьread
метод , который возвращаетsys.stdin.read(1)
, то вы можете прочитать несколько символов в одном контексте.Попробуйте использовать это: http://home.wlu.edu/~levys/software/kbhit.py Это неблокирует (это означает, что вы можете иметь цикл while и обнаружить нажатие клавиши, не останавливая его) и кроссплатформенный.
Пример использования этого:
Или вы можете использовать модуль getch из PyPi . Но это заблокирует цикл
источник
Это НЕ БЛОКИРОВКА, читает ключ и сохраняет его в keypress.key.
в вашей программе
источник
Ответы здесь были информативными, однако я также хотел получить способ асинхронного нажатия клавиш и срабатывания нажатий клавиш в отдельных событиях, все в поточно-ориентированном, кроссплатформенном виде. PyGame тоже была слишком раздутой для меня. Поэтому я сделал следующее (в Python 2.7, но я подозреваю, что он легко переносим), и я решил поделиться с ним здесь, если это будет полезно для кого-то еще. Я сохранил это в файле с именем keyPress.py.
Идея состоит в том, что вы можете просто позвонить
keyPress.getKey()
, чтобы прочитать ключ с клавиатуры, а затем вернуть его.Если вы хотите чего-то большего, я сделал
KeyCapture
объект. Вы можете создать один через что-то вродеkeys = keyPress.KeyCapture()
.Тогда есть три вещи, которые вы можете сделать:
addEvent(functionName)
принимает любую функцию, которая принимает один параметр. Затем при каждом нажатии клавиши эта функция будет вызываться со строкой этой клавиши при вводе. Они запускаются в отдельном потоке, поэтому вы можете заблокировать в них все, что захотите, и это не испортит функциональность KeyCapturer и не задержит другие события.get()
возвращает ключ тем же способом блокировки, что и раньше. Теперь это необходимо здесь, потому что ключи теперь захватываются с помощьюKeyCapture
объекта, поэтомуkeyPress.getKey()
может конфликтовать с этим поведением, и оба они будут пропускать некоторые ключи, поскольку за один раз может быть захвачен только один ключ. Также, скажем, пользователь нажимает «a», затем «b», вы звонитеget()
, пользователь нажимает «c». Этотget()
вызов немедленно возвратит «a», затем, если вы вызовете его снова, он вернет «b», затем «c». Если вы позвоните ему снова, он заблокируется, пока не будет нажата другая клавиша. Это гарантирует, что вы не пропустите ни одной клавиши, если хотите, блокирующим способом. Таким образом, это немного отличаетсяkeyPress.getKey()
от предыдущегоЕсли вы хотите, чтобы поведение
getKey()
back былоget(lossy=True)
аналогичнымget()
, за исключением того, что оно возвращает только те клавиши, которые были нажаты после вызоваget()
. Таким образом, в приведенном выше примереget()
блок будет блокироваться до тех пор, пока пользователь не нажмет «c», а затем, если вы вызовете его снова, он будет блокироваться до тех пор, пока не будет нажата другая клавиша.getAsync()
немного отличается Он предназначен для чего-то, что делает большую обработку, затем иногда возвращается и проверяет, какие клавиши были нажаты. Таким образом,getAsync()
возвращает список всех нажатых клавиш с момента последнего вызоваgetAsync()
в порядке от самой старой нажатой клавиши до самой последней нажатой клавиши. Он также не блокируется, что означает, что если с момента последнего вызова не было нажато ни одной клавишиgetAsync()
,[]
будет возвращена пустая строка.Чтобы фактически начать захват ключей, вам нужно позвонить
keys.startCapture()
сkeys
указанным выше объектом.startCapture
является неблокирующим и просто запускает один поток, который просто записывает нажатия клавиш, а другой поток обрабатывает эти нажатия клавиш. Есть два потока, которые гарантируют, что поток, который записывает нажатия клавиш, не пропускает никаких клавиш.Если вы хотите прекратить захват ключей, вы можете позвонить,
keys.stopCapture()
и он прекратит захват ключей. Однако, поскольку захват ключа является блокирующей операцией, ключи захвата потока могут захватить еще один ключ после вызоваstopCapture()
.Чтобы предотвратить это, вы можете передать необязательный параметр (и) в
startCapture(functionName, args)
функцию, которая просто выполняет что-то вроде проверки, равен ли ключ «c», и затем завершается. Важно, чтобы эта функция работала очень мало, например, если сон здесь заставит нас пропустить клавиши.Однако, если
stopCapture()
в этой функции вызывается, захват клавиш будет немедленно прекращен, без попыток перехвата, и что всеget()
вызовы будут возвращены немедленно, с None, если еще не было нажато ни одной клавиши.Также, поскольку
get()
иgetAsync()
сохранены все предыдущие нажатые клавиши (до тех пор, пока вы их не восстановите), вы можете позвонитьclearGetList()
иclearAsyncList()
забыть ранее нажатые клавиши.Следует отметить , что
get()
,getAsync()
и события независимы, поэтому , если нажата клавиша: 1. Один вызовget()
, ожидающий, с потерями от того , будет возвращать этот ключ. Другие ожидающие вызовы (если таковые имеются) будут продолжать ждать. 2. Эта клавиша будет сохранена в очереди ключей get, так чтоget()
при отключенной функции возврата будет возвращена самая старая нажатая клавиша, которая еще не была возвращенаget()
. 3. Все события будут запускаться с этой клавишей в качестве входных данных. 4. Эта клавиша будет сохранена в спискеgetAsync()
ключей, где этот список будет возвращен и установлен в пустой список при следующем вызове.getAsync()
Если всего этого слишком много, вот пример использования:
Это работает хорошо для меня из простого теста, который я сделал, но я с радостью приму и другие отзывы, если я что-то пропустил.
Я также разместил это здесь .
источник
Комментарий в одном из других ответов упоминал режим cbreak, который важен для реализаций Unix, потому что вы обычно не хотите, чтобы ^ C (
KeyboardError
) использовался getchar (как это будет, когда вы устанавливаете терминал в сырой режим, как это делает большинство других ответов).Еще одна важная деталь: если вы хотите прочитать один символ, а не один байт , вы должны прочитать 4 байта из входного потока, так как это максимальное количество байтов, из которых состоит один символ в UTF-8 (Python 3+ ). Чтение только одного байта приведет к неожиданным результатам для многобайтовых символов, таких как стрелки клавиатуры.
Вот моя измененная реализация для Unix:
источник
Попробуйте это с Pygame:
источник
pygame.error: video system not initialized
Рецепт ActiveState, кажется, содержит небольшую ошибку для «posix» систем, которая препятствует
Ctrl-C
прерыванию (я использую Mac). Если я добавлю следующий код в мой скрипт:Я никогда не смогу завершить сценарий
Ctrl-C
, и мне нужно убить свой терминал, чтобы убежать.Я считаю, что следующая строка является причиной, и она также слишком жестока:
Кроме того, пакет на
tty
самом деле не нужен,termios
достаточно справиться с этим.Ниже приведен улучшенный код, который работает для меня (
Ctrl-C
будет прерывать), с дополнительнойgetche
функцией, которая отображает символ при вводе:Ссылки:
источник
curses
Пакет в Python можно использовать для ввода «сырой» режим для ввода символов с терминала несколько заявлений. Основное использование Curses - захват экрана для вывода, что может быть не тем, что вы хотите. Этот фрагмент кода используетprint()
вместо этого операторы, которые можно использовать, но вы должны знать, как curses изменяет окончания строк, присоединенные к выводу.источник
Если я делаю что-то сложное, я использую проклятия для чтения ключей. Но часто я просто хочу простой скрипт на Python 3, который использует стандартную библиотеку и может читать клавиши со стрелками, поэтому я делаю это:
источник
Мое решение для python3, не зависящее от каких-либо пип пакетов.
источник
Я считаю, что это одно из самых элегантных решений.
а затем использовать его в коде:
источник
Принятый ответ мне не удался (я держал клавишу, ничего не происходило, потом нажимал другую клавишу, и она работала).
Узнав о модуле curses , он действительно кажется правильным. И теперь он доступен для Windows через Windows-курсоры (доступны через pip), так что вы можете программировать независимо от платформы. Вот пример, вдохновленный этим хорошим руководством на YouTube:
Сохраните его с
.py
расширением или запуститеcurses.wrapper(getkey)
в интерактивном режиме.источник
Ответили здесь: raw_input в python без нажатия Enter
Используйте этот код
Ссылка: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
источник
Если вы хотите зарегистрировать только одну нажатие клавиши, даже если пользователь нажимал ее более одного раза или продолжал нажимать клавишу дольше. Чтобы избежать получения нескольких нажатых входов, используйте цикл while и пропустите его.
источник
если вы просто хотите держать экран, чтобы увидеть результат на терминале, просто напишите
в конце кода и он будет держать экран
источник
Встроенный raw_input должен помочь.
источник