ฉันจะทำให้หลามรอให้กดคีย์ได้อย่างไร


571

ฉันต้องการให้สคริปต์ของฉันรอจนกว่าผู้ใช้กดปุ่มใด ๆ

ฉันจะทำอย่างไร

คำตอบ:


543

ในPython 3 ให้ใช้input():

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

ในPython 2 ให้ใช้raw_input():

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

สิ่งนี้จะรอให้ผู้ใช้กด Enter เท่านั้น

หนึ่งอาจต้องการใช้msvcrt ((Windows / DOS เท่านั้น) โมดูลmsvcrtให้คุณเข้าถึงฟังก์ชันต่างๆในไลบรารีรันไทม์ Microsoft Visual C / C ++ Runtime (MSVCRT):

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

สิ่งนี้ควรรอการกดปุ่ม

ข้อมูลเพิ่มเติม:

ใน Python 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 ใช้อินพุต () ควรทำงานกับแพลตฟอร์มอื่นเช่นกัน มันไร้สาระที่จะเทียบคะแนนสำหรับการจัดหาโซลูชัน Windows ทางเลือกเท่านั้นเมื่อโซลูชันแรกเป็นหลายแพลตฟอร์ม
Cory Buckley

7
@ Solarsaturn9 อ่านคำถามและคำตอบอีกครั้ง: inputไม่ดำเนินการต่อหากมีการกดปุ่มใด ๆ เฉพาะเมื่อกด Enter
ctrl-alt-delor

13
@ JonTirsen นั่นเป็นเพราะ Python 2.7 มีฟังก์ชั่นที่เรียกว่าอินพุตซึ่งประเมินสตริงที่คุณป้อน ในการแก้ไขให้ใช้ raw_input
Samy Bencherif

316

วิธีหนึ่งในการทำเช่นนี้ใน Python 2 คือการใช้raw_input():

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

ใน python3 เป็นเพียงแค่ input()


17
จะเกิดอะไรขึ้นเมื่อมันเป็นหนึ่งในกุญแจจำนวนหนึ่งได้? ไม่ใช่แค่enter?
noio

33
กับงูหลาม 3+input()นี้มีการเปลี่ยนแปลงเพียง
palswim

ใช้หกสำหรับโค้ดที่เข้ากันได้กับ Py2 & Py3:from six.moves import input; input("Press Enter to continue...")
rcoup

56

บนกล่อง linux ของฉันฉันใช้รหัสต่อไปนี้ นี่คล้ายกับรหัสที่ฉันเคยเห็นที่อื่น (ในคำถามที่พบบ่อยของงูหลามเก่า) แต่โค้ดนั้นหมุนวนเป็นวงแคบโดยที่รหัสนี้ไม่ได้และมีมุมกรณีแปลก ๆ มากมายที่รหัสไม่ได้เกี่ยวข้องกับสิ่งนี้ รหัสทำ

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)

ในขณะที่นี่คือคำตอบที่ฉันชอบที่นี่เหมือนคนอื่น ๆ ไม่จับสิ่งต่าง ๆ เช่นกะควบคุม ฯลฯ
Mala

1
@ Mala ที่สวยมากเป็นไปไม่ได้ใน Python บริสุทธิ์; บางทีคุณควรเขียนโมดูล C
แมว

ฉันได้รับ "\ x03" จากการขัดจังหวะโดยแป้นพิมพ์ (Ctrl-C) ในระบบของฉัน
GDR

1
ctrl-c เป็น ascii 3 ดังนั้นคาดว่าจะเป็น หากคุณต้องการเพิ่มสัญญาณใน ctrl-c ทางออกที่ง่ายคือใส่ if if (return_value) == 3: os.kill (os.getpid (), signal.SIGINT) แต่คุณสามารถปิดการประมวลผลสัญญาณได้ โดย attrs [0] | = termios.BRKINT, attrs [3]! = termios.ISIG และกำจัดยกเว้นการประมวลผล KeyboardInterrupt หมายเหตุ - ฉันเปลี่ยนค่าตอบแทนสำหรับ KeyboardInterrupt เป็น '\ x03' เพื่อเป็นเกียรติแก่การสืบค้นของคุณ (และเนื่องจากทำให้รหัสนี้ส่งคืนสตริงเสมอ )
mheyman

รหัสด้านบนสามารถปรับได้อย่างไรเพื่อให้มันส่งคืน tuple สำหรับการกดปุ่มที่ซับซ้อนเช่น "Page Up" หรือ "Left Arrow"
Derek

33

หากคุณเห็นด้วยกับคำสั่งของระบบคุณสามารถใช้สิ่งต่อไปนี้:

ลินุกซ์:

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

ของ windows:

import os
os.system("pause")

ถ้าคุณต้องการที่จะทำงานต่อไปจนกว่าจะมีสัญญาณที่จะเพิ่มขึ้น (เช่น SIGINT) นอกจากนี้คุณยังสามารถตรวจสอบค่าที่ส่งกลับจากนั้นโทรsystem sys.exit(0)
James Taylor

29

เพียงแค่ใช้

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

จะทำให้เกิด SyntaxError: EOF ที่คาดไว้ขณะแยกวิเคราะห์

ใช้การแก้ไขอย่างง่าย:

try:
    input("Press enter to continue")
except SyntaxError:
    pass

5
อย่าใช้inputในหลาม 2 - raw_inputฟังก์ชั่นที่ถูกต้องคือ ในหลาม 2 เทียบเท่ากับinput eval(raw_input())
Blorgbeard ออกเมื่อ

2
สิ่งนี้จะเพิกเฉยต่อปุ่มทั้งหมดที่ผู้ใช้กดจนกว่าพวกเขาจะกดปุ่มซึ่งแตกต่างจากที่ปุ่ม OP ถาม
Jonathan Hartley

1
นอกจากนี้หากคุณกำลังจะใช้ 'อินพุต' การจับ SyntaxError ไม่เหมาะสม ไม่ว่าผู้ใช้ประเภทใดจะได้รับการประเมินดังนั้นถ้าเช่นพวกเขาพิมพ์ "1/0" แล้ว ZeroDivisionError จะถูกยกขึ้นแทน SyntaxError และโปรแกรมของคุณจะออก
Jonathan Hartley

ตามที่ @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
เป็นวิธีปฏิบัติที่ดีในการคัดลอกสิ่งที่คุณเชื่อมโยงไปเพื่อให้ความรู้ยังคงอยู่แม้ว่าลิงก์นั้นจะตาย (และพวกเขาก็ทำ!)
Richard

1
ฉันจะทำงานนี้ใน Python 3.x ได้อย่างไร ใน 3.x หลังจากเปลี่ยนคำสั่งการพิมพ์เพื่อให้เข้ากันได้นี่จะวนซ้ำไปเรื่อย ๆ และไม่รออินพุต มันใช้งานได้ดีใน Python 2
แมว

ลิงค์ได้รับการปรับปรุงเพื่อเปลี่ยนเส้นทางไปยังหน้าอื่น ลิงค์ใหม่อยู่ที่นี่
Matthias

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 / ไม่ใช่การปิดกั้นเพราะมันให้IOErrorและฉันไม่ต้องการมัน ฉันใช้รหัสนี้โดยเฉพาะเพราะฉันต้องการให้บล็อก ;)

ภาคผนวก:

ฉันนำสิ่งนี้ไปใช้ในแพ็คเกจบน PyPI กับสินค้าอีกมากมายที่เรียกว่าคอนโซล :

>>> from console.utils import wait_key

>>> wait_key()
'h'

1
ฉันได้รับข้อผิดพลาด: ioctl ที่ไม่เหมาะสมสำหรับอุปกรณ์ '
เบอนัวต์

@Benoit ระบบปฏิบัติการใด?
Gringo Suave

Linux - Ubuntu 20.04
เบอนัวต์

14

ฉันไม่ทราบวิธีที่เป็นอิสระของแพลตฟอร์ม แต่ใน Windows หากคุณใช้โมดูล msvcrt คุณสามารถใช้ฟังก์ชัน getch ได้:

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

mscvcrt ยังมีฟังก์ชั่นที่ไม่ปิดกั้น kbhit () เพื่อดูว่ามีการกดคีย์โดยไม่ต้องรอหรือไม่ (ไม่แน่ใจว่ามีฟังก์ชั่นคำสาปที่สอดคล้องกันหรือไม่) ภายใต้ UNIX มีแพ็คเกจ curses แต่ไม่แน่ใจว่าคุณสามารถใช้งานได้หรือไม่โดยไม่ใช้มันสำหรับการแสดงผลหน้าจอทั้งหมด รหัสนี้ทำงานภายใต้ UNIX:

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

โปรดทราบว่า curses.getch () ส่งคืนลำดับของคีย์ที่กดดังนั้นเพื่อให้มีเอาต์พุตเหมือนกันฉันต้องใช้มัน


การใช้คำสาปนั้นดีกว่าตัวอย่างที่ซับซ้อนมากกว่าที่อธิบายไว้ในคู่มือแม้ว่าจะเกี่ยวข้องกับการพึ่งพาอาศัยกันมากก็ตาม +1
เดเมียน

4

หากคุณต้องการรอการป้อน (ดังนั้นผู้ใช้ที่เคาะแป้นพิมพ์จะไม่ทำให้เกิดสิ่งที่ไม่ตั้งใจเกิดขึ้น) ใช้

sys.stdin.readline()

2
จุดรวมสำหรับผู้ใช้ไม่จำเป็นต้องกดเฉพาะปุ่ม Enter ตัวอย่างเช่นสามารถกด Spacebar ได้ หากคุณต้องการ Enter เพื่อหลีกเลี่ยงสิ่งที่ไม่ได้ตั้งใจเกิดขึ้นนั่นคือการออกแบบที่ไม่ดี
Synetech

3

ฉันยังใหม่กับงูหลามและฉันคิดอยู่แล้วว่าฉันโง่เกินไปที่จะทำซ้ำคำแนะนำที่ง่ายที่สุดที่นี่ ปรากฎว่ามีข้อผิดพลาดที่ควรรู้:

เมื่อ python-script ถูกเรียกใช้จาก IDLE คำสั่ง IO-ดูเหมือนว่าจะทำงานแตกต่างไปจากเดิมอย่างสิ้นเชิง (เนื่องจากไม่มีหน้าต่างเทอร์มินัล)

เช่น. msvcrt.getch ไม่ถูกบล็อกและส่งคืน $ ff ทุกครั้ง สิ่งนี้ได้รับการรายงานมานานแล้ว (ดูเช่นhttps://bugs.python.org/issue9290 ) - และมันถูกทำเครื่องหมายว่าได้รับการแก้ไขแล้วแต่ปัญหาดูเหมือนว่าจะยังคงอยู่ใน python / IDLE เวอร์ชันปัจจุบัน

ดังนั้นถ้าใด ๆ ของรหัสที่โพสต์บนไม่ได้ผลสำหรับคุณลองใช้สคริปต์ด้วยตนเองและไม่ได้มาจาก IDLE


0

หากคุณต้องการดูว่าพวกเขากดแป้นที่ถูกต้องหรือไม่ (เช่นพูดว่า 'b') ทำสิ่งนี้:

while True:
    choice = raw_input("> ")

    if choice == 'b' :
        print "You win"
        input("yay")
        break

8
สิ่งนี้ต้องการให้ผู้ใช้พิมพ์ 'b' (หรืออย่างอื่น) จากนั้นกด Enter ซึ่งค่อนข้างแตกต่างจากสิ่งที่ OP ขอ
Jonathan Hartley

0

ดูเหมือนว่า os.system จะเรียกใช้ sh เสมอซึ่งไม่รู้จักตัวเลือก s และ n สำหรับการอ่าน อย่างไรก็ตามคำสั่ง read สามารถส่งผ่านไปยัง bash:

 os.system("""bash -c 'read -s -n 1 -p "Press any key to continue..."'""")

2
เอกสารการอ่านทำให้ฉันคิดว่ามันจะไม่หมดเวลาเว้นแต่คุณจะระบุตัวเลือก -t
James King
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.