Как заставить Python ждать нажатой клавиши?

571

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

Как я могу это сделать?

Януш
источник

Ответы:

543

В Python 3 используйте input():

input("Press Enter to continue...")

В Python 2 используйте raw_input():

raw_input("Press Enter to continue...")

Это только ждет, пока пользователь нажмет ввод.

Кто-то может захотеть использовать msvcrt ((только для Windows / DOS) Модуль msvcrt предоставляет вам доступ к ряду функций в библиотеке времени выполнения Microsoft Visual C / C ++ (MSVCRT)):

import msvcrt as m
def wait():
    m.getch()

Это должно ждать нажатия клавиши.

Дополнительная информация:

в питоне 3 raw_input()не существует

В Python 2 input(prompt)эквивалентноeval(raw_input(prompt))

риза
источник
54
Я получаю эту ошибку, когда пытаюсь сделать это в Python 2.7: «SyntaxError: неожиданный EOF при синтаксическом анализе»
Jon Tirsen
8
@ Solarsaturn9 и все большее и большее количество не делают. Таким образом, этот ответ не работал для меня и многих других, которые приходят сюда.
Ctrl-Alt-Delor
5
@richard с использованием input () должен работать и на других платформах. Смешно ставить точки за предоставление альтернативного решения только для Windows, когда первое решение является мультиплатформенным.
Кори Бакли
7
@ Solarsaturn9 прочитайте вопрос и ответьте снова: inputне продолжается, если нажата какая-либо клавиша, только если нажата кнопка ввода.
Ctrl-Alt-Delor
13
@JonTirsen потому что в Python 2.7 есть функция input, которая оценивает введенную вами строку. Чтобы исправить, используйте raw_input
Samy Bencherif
316

Один из способов сделать это в Python 2, это использовать raw_input():

raw_input("Press Enter to continue...")

В python3 это просто input()

Грег Хьюгилл
источник
17
Как насчет того, когда это может быть один из нескольких ключей? Не просто enter?
noio
33
С Python 3+ это изменилось на просто input().
Palswim
Используя шесть для Py2 & Py3-совместимого кода:from six.moves import input; input("Press Enter to continue...")
rcoup
56

На моем компьютере с Linux я использую следующий код. Это похоже на код, который я видел в другом месте (например, в старых FAQ по Python), но этот код вращается в узком цикле, где этого кода нет, и существует множество странных угловых случаев, которые код не учитывает код делает.

def read_single_keypress():
    """Waits for a single keypress on stdin.

    This is a silly function to call if you need to do it a lot because it has
    to store stdin's current setup, setup stdin for reading single keystrokes
    then read the single keystroke then revert stdin back after reading the
    keystroke.

    Returns a tuple of characters of the key that was pressed - on Linux, 
    pressing keys like up arrow results in a sequence of characters. Returns 
    ('\x03',) on KeyboardInterrupt which can happen when a signal gets
    handled.

    """
    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    ret = []
    try:
        ret.append(sys.stdin.read(1)) # returns a single character
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save | os.O_NONBLOCK)
        c = sys.stdin.read(1) # returns a single character
        while len(c) > 0:
            ret.append(c)
            c = sys.stdin.read(1)
    except KeyboardInterrupt:
        ret.append('\x03')
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return tuple(ret)
mheyman
источник
Хотя это мой любимый из ответов здесь, как и другие не ловят такие вещи, как сдвиг, контроль и т. Д.
Мала
1
@ Мала, что почти невозможно в чистом Python; возможно, вам стоит написать модуль C?
кошка
Я получаю "\ x03" при прерывании клавиатуры (Ctrl-C) в моей системе.
ГДР
1
Ctrl-C является ASCII 3, так что это ожидается. Если вы хотите поднять сигнал с помощью ctrl-c, простое решение состоит в том, чтобы поместить if ord (return_value) == 3: os.kill (os.getpid (), signal.SIGINT), но вы также можете отключить обработку сигналов. от attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG и избавьтесь от обработки, кроме KeyboardInterrupt. Примечание. Я изменил возвращаемое значение KeyboardInterrupt на '\ x03' в честь вашего запроса (и потому что этот код всегда возвращает строку).
Мейман
Как можно изменить приведенный выше код так, чтобы он возвращал кортеж для сложного нажатия клавиш, например «Page Up» или «Стрелка влево»?
Дерек
33

Если у вас все в порядке в зависимости от системных команд, вы можете использовать следующее:

Linux:

import os
os.system('read -sn 1 -p "Press any key to continue..."')
print

Окна:

import os
os.system("pause")
CrouZ
источник
Если вы хотите продолжать работать до тех пор, пока не будет подан сигнал (например, SIGINT), вы также можете проверить возвращаемое значение из, systemа затем вызвать sys.exit(0).
Джеймс Тейлор
29

Просто используя

input("Press Enter to continue...")

вызовет синтаксическую ошибку: ожидаемый EOF при разборе.

Простое исправление использования:

try:
    input("Press enter to continue")
except SyntaxError:
    pass
alltrue
источник
5
Не используйте inputв Python 2 - правильная функция raw_input. В Python 2 inputэквивалентно eval(raw_input()).
Blorgbeard выходит
2
Это игнорирует все клавиши, которые нажимает пользователь, до тех пор, пока они не нажмут клавишу ввода, что весьма отличается от того, что запрашивает OP.
Джонатан Хартли
1
Кроме того, если вы собираетесь использовать 'input', перехват SyntaxError не подходит. Независимо от того, какие типы пользователей оцениваются, поэтому, например, если они набирают «1/0», то вместо SyntaxError возникает ZeroDivisionError, и ваша программа завершает работу.
Джонатан Хартли
Как упомянул @Blorgbeard, достаточно просто использовать raw_input («Нажмите Enter, чтобы продолжить ...»). Я использую это часто сейчас при отладке.
Alltrue
15

Питон руководство содержит следующее:

import termios, fcntl, sys, os
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 1:
        try:
            c = sys.stdin.read(1)
            print "Got character", repr(c)
        except IOError: pass
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

который может быть свернут в ваш случай использования.

Яап Верстег
источник
12
Хорошей практикой является копирование того, на что вы ссылаетесь, чтобы знания оставались, даже если ссылка умирает (а они делают!).
Ричард
1
Как я могу заставить это работать в Python 3.x? В 3.x после изменения оператора печати на совместимость он просто зацикливается и не ждет ввода. Это прекрасно работает в Python 2, хотя.
кот
Ссылка была обновлена ​​для перенаправления на другую страницу. Новая ссылка здесь.
Матиас
15

Кроссплатформенность, код Python 2/3:

# import sys, os

def wait_key():
    ''' Wait for a key press on the console and return it. '''
    result = None
    if os.name == 'nt':
        import msvcrt
        result = msvcrt.getch()
    else:
        import termios
        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)

        try:
            result = sys.stdin.read(1)
        except IOError:
            pass
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)

    return result

Я удалил fctl / неблокирующий материал, потому что он давал IOErrors, и мне это не нужно. Я использую этот код специально, потому что я хочу его заблокировать. ;)

Приложение:

Я реализовал это в пакете на PyPI с множеством других вкусностей, называемых консолью :

>>> from console.utils import wait_key

>>> wait_key()
'h'
Гринго Суаве
источник
1
Я получил ошибку: неуместно ioctl для устройства »
Бенуа
@Benoit, какая ОС?
Гринго Суаве
Linux - Ubuntu 20.04
Бенуа
14

Я не знаю, как это сделать независимо от платформы, но в Windows, если вы используете модуль msvcrt, вы можете использовать его функцию getch:

import msvcrt
c = msvcrt.getch()
print 'you entered', c

mscvcrt также включает неблокирующую функцию kbhit (), чтобы увидеть, была ли нажата клавиша без ожидания (не уверен, что есть соответствующая функция curses). Под UNIX есть пакет curses, но не уверен, что вы можете использовать его, не используя его для всего вывода на экран. Этот код работает под UNIX:

import curses
stdscr = curses.initscr()
c = stdscr.getch()
print 'you entered', chr(c)
curses.endwin()

Обратите внимание, что curses.getch () возвращает порядковый номер нажатой клавиши, чтобы у нее был тот же вывод, что и для приведения.

Джон Гейнс младший
источник
Использование curses намного приятнее, чем довольно запутанные примеры, описанные в руководстве, даже если это связано с огромной зависимостью. +1
Дамиан
4

Если вы хотите подождать ввода (чтобы пользователь, стучавший по клавиатуре, не вызывал непредвиденных ситуаций), используйте

sys.stdin.readline()
Эндрю Пэйт
источник
2
Все дело в том, чтобы пользователю не нужно было нажимать только клавишу Enter, чтобы, например, можно было просто щелкнуть пробел. Если вам требуется Enter, чтобы избежать непредвиденных ситуаций, это плохой дизайн.
Synetech
3

Я новичок в Python, и я уже думал, что я слишком глуп, чтобы воспроизвести самые простые предложения, сделанные здесь. Оказывается, есть ловушка, которую нужно знать:

Когда Python-скрипт выполняется из IDLE, некоторые IO-команды ведут себя совершенно иначе (поскольку на самом деле нет оконечного окна).

Например. msvcrt.getch не блокирует и всегда возвращает $ ff. Об этом уже сообщалось давно (см., Например, https://bugs.python.org/issue9290 ) - и оно помечено как исправленное, как-то проблема, похоже, сохраняется в текущих версиях python / IDLE.

Поэтому, если какой-либо из приведенных выше кодов не работает для вас, попробуйте запустить скрипт вручную, а НЕ из IDLE .

ralfiii
источник
0

Если вы хотите увидеть, нажали ли они точную клавишу (например, скажем 'b'), сделайте следующее:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break
E40
источник
8
Это требует, чтобы пользователь набрал 'b' (или что-то еще), а затем нажал клавишу ввода, что сильно отличается от того, что запрашивает OP.
Джонатан Хартли
0

os.system, кажется, всегда вызывает sh, который не распознает параметры s и n для чтения. Однако команду чтения можно передать bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")
Джеймс Кинг
источник
2
Прочитанная документация заставляет меня думать, что время не истечет, если вы не укажете опцию -t.
Джеймс Кинг