Bagaimana cara membuat python menunggu tombol yang ditekan?

571

Saya ingin skrip saya menunggu sampai pengguna menekan tombol apa saja.

Bagaimana aku melakukan itu?

Janusz
sumber

Jawaban:

543

Dalam Python 3 gunakan input():

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

Dalam Python 2 gunakan raw_input():

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

Ini hanya menunggu pengguna menekan enter.

Seseorang mungkin ingin menggunakan msvcrt ((hanya Windows / DOS) Modul msvcrt memberi Anda akses ke sejumlah fungsi di Microsoft Visual C / C ++ Runtime Library (MSVCRT)):

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

Ini harus menunggu penekanan tombol.

Informasi tambahan:

dalam Python 3 raw_input()tidak ada

Dalam Python 2 input(prompt)setara denganeval(raw_input(prompt))

riza
sumber
54
Saya mendapatkan kesalahan ini ketika saya mencoba melakukan ini dengan Python 2.7: "Sintaksisnya: EOF yang tak terduga saat parsing"
Jon Tirsen
8
@ Solarsaturn9 dan jumlah yang meningkat dan besar tidak. Jadi jawaban ini tidak berhasil untuk saya, dan banyak lagi yang datang ke sini.
ctrl-alt-delor
5
@richard menggunakan input () juga bisa digunakan pada platform lain. Sangat konyol untuk merapat poin untuk menyediakan solusi alternatif Windows saja ketika solusi pertama adalah multi-platform.
Cory Buckley
7
@ Solarsaturn9 membaca pertanyaan dan menjawab lagi: inputtidak melanjutkan jika ada tombol yang ditekan, hanya jika enter ditekan.
ctrl-alt-delor
13
@ JonTirsen itu karena Python 2.7 memiliki fungsi yang disebut input yang mengevaluasi string yang Anda input. Untuk memperbaikinya, gunakan raw_input
Samy Bencherif
316

Salah satu cara untuk melakukan ini dalam Python 2, adalah dengan menggunakan raw_input():

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

Dalam python3 hanya saja input()

Greg Hewgill
sumber
17
Bagaimana kalau itu bisa menjadi salah satu dari sejumlah kunci? Bukan hanya enter?
noio
33
Dengan Python 3+ , ini telah berubah menjadi adil input().
palswim
Menggunakan enam untuk kode yang kompatibel dengan Py2 & Py3:from six.moves import input; input("Press Enter to continue...")
rcoup
56

Di kotak linux saya, saya menggunakan kode berikut. Ini mirip dengan kode yang pernah saya lihat di tempat lain (dalam python lama FAQs misalnya) tetapi kode itu berputar dalam loop ketat di mana kode ini tidak dan ada banyak kasus sudut aneh bahwa kode tidak menjelaskan bahwa ini kode tidak.

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
sumber
Meskipun ini adalah favorit saya dari jawaban di sini, seperti yang lain tidak menangkap hal-hal seperti shift, kontrol, dll.
Mala
1
@ Mal yang tidak mungkin hanya menggunakan Python murni; mungkin Anda harus menulis modul C?
kucing
Saya mendapatkan "\ x03" di keyboard interrupt (Ctrl-C) di sistem saya.
GDR
1
ctrl-c adalah ascii 3 sehingga diharapkan. Jika Anda ingin menaikkan sinyal pada ctrl-c, solusi mudahnya adalah dengan meletakkan jika ord (return_value) == 3: os.kill (os.getpid (), signal.SIGINT) tetapi Anda juga dapat mematikan pemrosesan sinyal oleh attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG, dan singkirkan proses kecuali KeyboardInterrupt. Catatan - Saya mengubah nilai kembali untuk KeyboardInterrupt menjadi '\ x03' untuk menghormati permintaan Anda (dan karena itu membuat kode ini selalu mengembalikan string).
mheyman
Bagaimana kode di atas dapat disesuaikan sehingga mengembalikan tuple untuk penekanan tombol yang kompleks seperti "Page Up" atau "Left Arrow"?
Derek
33

Jika Anda setuju dengan tergantung pada perintah sistem Anda dapat menggunakan yang berikut:

Linux:

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

Windows:

import os
os.system("pause")
CrouZ
sumber
Jika Anda ingin tetap berjalan sampai sinyal dinaikkan (seperti SIGINT), Anda juga dapat memeriksa nilai balik dari systemdan kemudian menelepon sys.exit(0).
James Taylor
29

Cukup menggunakan

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

akan menyebabkan SyntaxError: EOF yang diharapkan saat parsing.

Penggunaan perbaikan sederhana:

try:
    input("Press enter to continue")
except SyntaxError:
    pass
semua benar
sumber
5
Jangan gunakan inputdi python 2 - fungsi yang benar adalah raw_input. Dalam python 2, inputsama dengan eval(raw_input()).
Blorgbeard keluar
2
Ini mengabaikan semua kunci yang ditekan pengguna, sampai mereka menekan enter, yang sangat berbeda dari apa yang diminta OP.
Jonathan Hartley
1
Juga, jika Anda akan menggunakan 'input', menangkap SyntaxError tidak tepat. Apa pun tipe pengguna yang akan dievaluasi, jadi jika, misalnya, mereka mengetik "1/0" maka ZeroDivisionError dinaikkan alih-alih SyntaxError, dan program Anda akan keluar.
Jonathan Hartley
Seperti @Blorgbeard sebutkan, cukup menggunakan raw_input ("Tekan Enter untuk melanjutkan ...") sudah cukup. Saya sering menggunakannya saat debugging.
alltrue
15

Manual python menyediakan yang berikut:

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)

yang dapat digulung ke dalam use case Anda.

Jaap Versteegh
sumber
12
Ini adalah praktik yang baik untuk menyalin hal yang Anda tautkan sehingga pengetahuan tetap ada, bahkan jika tautan tersebut mati (dan itu benar!).
Richard
1
Bagaimana saya bisa membuat ini bekerja di Python 3.x? Dalam 3.x, setelah mengubah pernyataan cetak agar kompatibel, ini hanya loop tak terhingga dan tidak menunggu input. Ini berfungsi dengan baik di Python 2.
kucing
Tautan telah diperbarui untuk mengarahkan ke halaman lain. Tautan baru ada di sini.
Matthias
15

Cross Platform, kode 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

Saya menghapus hal-hal fctl / non-blocking karena memberi IOError dan saya tidak membutuhkannya. Saya menggunakan kode ini secara khusus karena saya ingin memblokirnya. ;)

Tambahan:

Saya menerapkan ini dalam sebuah paket di PyPI dengan banyak barang lain yang disebut konsol :

>>> from console.utils import wait_key

>>> wait_key()
'h'
Gringo Suave
sumber
1
Saya mendapat kesalahan: ioctl tidak sesuai untuk perangkat '
Benoit
@ Beneno OS yang mana?
Gringo Suave
Linux - Ubuntu 20.04
Benoit
14

Saya tidak tahu cara platform independen untuk melakukannya, tetapi di bawah Windows, jika Anda menggunakan modul msvcrt, Anda dapat menggunakan fungsi getch-nya:

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

mscvcrt juga menyertakan fungsi kbhit () non-blocking untuk melihat apakah suatu tombol ditekan tanpa menunggu (tidak yakin apakah ada fungsi kutukan yang sesuai). Di bawah UNIX, ada paket kutukan, tetapi tidak yakin apakah Anda dapat menggunakannya tanpa menggunakannya untuk semua output layar. Kode ini berfungsi di bawah UNIX:

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

Perhatikan bahwa curses.getch () mengembalikan ordinal tombol yang ditekan sehingga untuk membuatnya memiliki output yang sama saya harus melemparkannya.

John Gaines Jr.
sumber
Menggunakan kutukan jauh lebih baik daripada contoh-contoh yang agak berbelit-belit yang dijelaskan oleh manual, bahkan jika itu melibatkan ketergantungan yang sangat besar. +1
Damian
4

Jika Anda ingin menunggu untuk masuk (sehingga pengguna mengetuk keyboard tidak menyebabkan sesuatu yang tidak diinginkan terjadi) gunakan

sys.stdin.readline()
andrew pate
sumber
2
Intinya adalah agar pengguna tidak perlu hanya menekan tombol Enter, untuk misalnya hanya bisa menampar bilah spasi. Jika Anda memerlukan Enter untuk menghindari sesuatu yang tidak diinginkan terjadi, maka itu desain yang buruk.
Synetech
3

Saya baru mengenal python dan saya sudah berpikir saya terlalu bodoh untuk mereproduksi saran sederhana yang dibuat di sini. Ternyata, ada jebakan yang harus diketahui:

Ketika skrip python dijalankan dari IDLE, beberapa perintah-IO tampaknya berperilaku sangat berbeda (karena sebenarnya tidak ada jendela terminal).

Misalnya. msvcrt.getch adalah non-blocking dan selalu mengembalikan $ ff. Ini sudah dilaporkan sejak lama (lihat mis. Https://bugs.python.org/issue9290 ) - dan ditandai sebagai diperbaiki, entah bagaimana masalahnya tetap ada di versi python / IDLE saat ini.

Jadi jika salah satu kode yang diposting di atas tidak berfungsi untuk Anda, coba jalankan skrip secara manual, dan BUKAN dari IDLE .

ralfiii
sumber
0

Jika Anda ingin melihat apakah mereka menekan tombol yang tepat (seperti katakan 'b') Lakukan ini:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break
E40
sumber
8
Ini mengharuskan pengguna untuk mengetikkan 'b' (atau yang lainnya) lalu tekan enter, yang sangat berbeda dari yang diminta OP.
Jonathan Hartley
0

os.sistem tampaknya selalu memanggil sh, yang tidak mengenali opsi s dan n untuk dibaca. Namun perintah baca dapat diteruskan ke bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")
James King
sumber
2
Dokumentasi baca membuat saya berpikir itu tidak akan habis kecuali Anda menentukan opsi -t.
James King