ตรวจจับการกดปุ่มใน python?


113

ฉันกำลังสร้างโปรแกรมประเภทนาฬิกาจับเวลาใน python และฉันต้องการทราบวิธีตรวจสอบว่ามีการกดปุ่มหรือไม่ (เช่น p สำหรับ pause และ s เพื่อหยุด) และฉันไม่ต้องการให้เป็น raw_input ที่รอ อินพุตของผู้ใช้ก่อนดำเนินการต่อ ใครรู้วิธีทำแบบนี้ในขณะวนซ้ำ

นอกจากนี้ฉันต้องการสร้างข้ามแพลตฟอร์มนี้ แต่ถ้าเป็นไปไม่ได้เป้าหมายการพัฒนาหลักของฉันคือ linux


สำหรับ OS X stackoverflow.com/a/47197390/5638869ทำงานใน Python 2 และ 3
neoDev

คำตอบ:


78

Python มีโมดูลแป้นพิมพ์ที่มีคุณสมบัติมากมาย ติดตั้งบางทีอาจใช้คำสั่งนี้:

pip3 install keyboard

จากนั้นใช้ในรหัสเช่น:

import keyboard  # using module keyboard
while True:  # making a loop
    try:  # used try so that if user pressed other than the given key error will not be shown
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            print('You Pressed A Key!')
            break  # finishing the loop
    except:
        break  # if user pressed a key other than the given key the loop will break

3
ฉันไม่แน่ใจสำหรับ linux แต่มันใช้งานได้กับ Windows สำหรับฉัน

84
keyboardเห็นได้ชัดว่าต้องรูทใน linux: /
Inaimathi

ฉันลองวิธีแก้ปัญหานี้แล้ว แต่เมื่อฉันพยายามนำเข้าโมดูลหลังจากติดตั้งแล้วฉันได้รับข้อความ "ImportError: No module named 'keyboard'" จึงใช้งานไม่ได้ ฉันตรวจสอบใน repo GitHub และพบปัญหาที่เกี่ยวข้องแต่ไม่สามารถแก้ปัญหาได้ จากนั้นฉันลองดาวน์โหลด repo และดำเนินการบางตัวอย่าง แต่ฉันได้รับและ "ImportError: คุณต้องรูทเพื่อใช้ไลบรารีนี้บน linux" ตามที่ @Inaimathi แสดงความคิดเห็นไว้ก่อน เห็นได้ชัดว่าโมดูลเต็มรูปแบบสำหรับจัดการแป้นพิมพ์ด้วย Python แต่ความต้องการของรูทนั้นขาดไปอย่างมาก :(
Ivanhercaz

3
"เพื่อหลีกเลี่ยงการขึ้นอยู่กับ X ส่วนของ Linux จะอ่านไฟล์อุปกรณ์ดิบ (/ dev / input / input *) แต่รูทนี้ต้องการ"
jrouquie

8
ฉันไม่เห็นว่าทำไมถึงลอง: ยกเว้น: มีประโยชน์
TypicalHog

52

สำหรับผู้ที่ใช้ windows และกำลังดิ้นรนเพื่อหาคำตอบที่ใช้งานได้นี่คือของฉัน: pynput

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

ฟังก์ชันด้านบนจะพิมพ์คีย์ใดก็ตามที่คุณกำลังกดบวกเริ่มการทำงานเมื่อคุณปล่อยปุ่ม "esc" เอกสารเกี่ยวกับแป้นพิมพ์อยู่ที่นี่สำหรับการใช้งานที่หลากหลายมากขึ้น

Markus von Broadyเน้นปัญหาที่อาจเกิดขึ้นนั่นคือ: คำตอบนี้ไม่ต้องการให้คุณอยู่ในหน้าต่างปัจจุบันเพื่อเปิดใช้งานสคริปต์นี้วิธีแก้ปัญหาสำหรับ windows จะเป็น:

from win32gui import GetWindowText, GetForegroundWindow
current_window = (GetWindowText(GetForegroundWindow()))
desired_window_name = "Stopwatch" #Whatever the name of your window should be

#Infinite loops are dangerous.
while True: #Don't rely on this line of code too much and make sure to adapt this to your project.
    if current_window == desired_window_name:

        with Listener(
            on_press=on_press,
            on_release=on_release) as listener:
            listener.join()

7
@ nimig18 ... และไม่ต้องรูท :)
cz

1
มีปัญหากับวิธีแก้ปัญหานี้ (ไม่แน่ใจเกี่ยวกับทางเลือกอื่น): ไม่ต้องกดปุ่มในหน้าต่างคอนโซลเพื่อให้มีผล ลองนึกภาพว่ามีสคริปต์ที่ทำงานบางอย่างจนกว่า ESC จะถูกกด แต่คุณกดมันในโปรแกรมอื่น
Markus von Broady

1
@MarkusvonBroady ฉันเดาว่า win32gui น่าจะเพียงพอที่จะแก้ปัญหานี้ฉันได้แก้ไขคำตอบของฉันด้วยวิธีที่อาจแก้ปัญหาให้กับผู้ใช้ windows อย่างน้อยที่สุด
Mitrek

@Mitrek ฉันลองแล้ว แต่รหัสของฉันหยุดการดำเนินการเพิ่มเติมและติดอยู่ที่นี่ ทำงานเหมือนอินพุต () ฉันมีรหัสที่เรียกใช้ในซีลีเนียม, Firefox แต่ทันทีที่พบลำดับนี้ไม่มีการดำเนินการใด ๆ เพิ่มเติม
Lakshmi Narayanan

1
ควรเป็นคำตอบที่ได้รับการยอมรับเพราะใช้งานได้ทั้งใน linux และ windows
Akash Karnatak

31

ตามที่ OP พูดถึง raw_input นั่นหมายความว่าเขาต้องการโซลูชัน cli Linux: คำสาปคือสิ่งที่คุณต้องการ (windows PDCurses) Curses เป็น API แบบกราฟิกสำหรับซอฟต์แวร์ cli คุณสามารถทำได้มากกว่าแค่ตรวจจับเหตุการณ์สำคัญ

รหัสนี้จะตรวจจับคีย์จนกว่าจะกดบรรทัดใหม่

import curses
import os

def main(win):
    win.nodelay(True)
    key=""
    win.clear()                
    win.addstr("Detected key:")
    while 1:          
        try:                 
           key = win.getkey()         
           win.clear()                
           win.addstr("Detected key:")
           win.addstr(str(key)) 
           if key == os.linesep:
              break           
        except Exception as e:
           # No input   
           pass         

curses.wrapper(main)

นี่เป็นสิ่งที่ดีจริงๆ ต้องค้นหาตลอดก่อนที่จะเจอ ดูเหมือนจะสะอาดกว่าการแฮ็กไปมาเรื่อย ๆtermios...
Hugh Perkins

5
จำเป็นต้องเพิ่มimport osเพื่อให้สามารถออกจากตัวอย่างได้
malte

หากคุณทำwin.nodelay(False)แทนTrueมันจะไม่สร้างล้านข้อยกเว้นต่อวินาที
Johannes Hoff

29

มีหลายสิ่งที่สามารถทำได้ด้วยkeyboardโมดูล

นี่คือบางส่วนของวิธีการ:


วิธี # 1:

การใช้ฟังก์ชันread_key():

import keyboard

while True:
    if keyboard.read_key() == "p":
        print("You pressed p")
        break

นี่จะทำให้ลูปแตกเมื่อpกดปุ่ม


วิธีที่ 2:

ใช้ฟังก์ชันwait:

import keyboard

keyboard.wait("p")
print("You pressed p")

มันจะรอให้คุณกดpและดำเนินการต่อรหัสตามที่กด


วิธี # 3:

การใช้ฟังก์ชันon_press_key:

import keyboard

keyboard.on_press_key("p", lambda _:print("You pressed p"))

จำเป็นต้องมีฟังก์ชันการโทรกลับ ฉันใช้_เพราะฟังก์ชันแป้นพิมพ์ส่งคืนเหตุการณ์แป้นพิมพ์ไปยังฟังก์ชันนั้น

เมื่อดำเนินการแล้วจะเรียกใช้ฟังก์ชันเมื่อกดปุ่ม คุณสามารถหยุดเบ็ดทั้งหมดได้โดยเรียกใช้บรรทัดนี้:

keyboard.unhook_all()

วิธีที่ # 4:

วิธีนี้ได้รับคำตอบแล้วโดยuser8167727แต่ฉันไม่เห็นด้วยกับรหัสที่พวกเขาสร้างขึ้น มันจะใช้ฟังก์ชันis_pressedแต่ในอีกทางหนึ่ง:

import keyboard

while True:
    if keyboard.is_pressed("p"):
        print("You pressed p")
        break

มันจะทำลายลูปเมื่อpกด


หมายเหตุ:

  • keyboard จะอ่านการกดแป้นพิมพ์จากระบบปฏิบัติการทั้งหมด
  • keyboard ต้องการรูทบน linux

11
ข้อเสียที่ใหญ่ที่สุดของการใช้โมดูลแป้นพิมพ์คือข้อกำหนดที่คุณเรียกใช้ในฐานะผู้ใช้ ROOT สิ่งนี้ทำให้โมดูล verboten ในโค้ดของฉัน เพียงเพื่อสำรวจความคิดเห็นว่ามีการกดคีย์ไม่จำเป็นต้องใช้สิทธิ์ root ฉันได้อ่านเอกสารและเข้าใจว่าเหตุใดข้อ จำกัด จึงออกในโมดูล แต่ดูที่อื่นหากสิ่งที่คุณต้องการคือการสำรวจกุญแจ ...
muman

แบ่งปันข้อมูลที่เป็นประโยชน์มากครับท่าน! ฉันต้องการทราบว่าฉันสามารถใช้keyboard.wait()เพื่อรอมากกว่า 1 คีย์ได้หรือไม่และดำเนินการต่อหากกดปุ่มใดปุ่มหนึ่ง
Preetkaran Singh

@PreetkaranSingh wait()ไม่ได้ให้ฟังก์ชันนี้ คุณจะต้องใช้keyboard.read_key()กับ if condition ที่บรรจุใน while loop ดูวิธีการ # 1
Black Thunder

ขอบคุณเซอร์ !, คุณต้องการที่จะหลั่งน้ำตาแสงบางประการเกี่ยวกับsuppressการใช้คำหลักในkeyboard.read_key()เมื่อจะใช้และเมื่อไม่ได้ ....
Preetkaran ซิงห์

@PreetkaranSingh ฉันต้องการ แต่ฉันไม่มีข้อมูลเพียงพอเกี่ยวกับการระงับข้อโต้แย้ง
Black Thunder

15

สำหรับWindowsคุณสามารถใช้msvcrtสิ่งนี้:

   import msvcrt
   while True:
       if msvcrt.kbhit():
           key = msvcrt.getch()
           print(key)   # just to show the result

8
msvcrt เป็นโมดูลสำหรับ Windows เท่านั้น
Dunatotatos

1
ตอนนี้ฉันใช้ pynput แล้วนั่นอาจเป็นคำตอบที่ดีกว่า
Benjie

โปรดทราบว่า pynput เพื่อทำงานบน OS X (ไม่ทราบเกี่ยวกับ Linux) ต้องรันในฐานะรูทเพื่อให้ทำงานได้ นั่นอาจไม่ใช่การเริ่มต้นสำหรับบางคน
Gabe Weiss

ฉันสามารถสาบานได้ว่าคำถามคือ 'cross-platform' หรือ 'linux' ...
Aaron Mann

10

ใช้รหัสนี้เพื่อค้นหาคีย์ที่กด

from pynput import keyboard

def on_press(key):
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))

def on_release(key):
    print('{0} released'.format(
        key))
    if key == keyboard.Key.esc:
        # Stop listener
        return False

# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

นี่คือสิ่งที่ฉันใช้ macOS และติดตั้งทั้ง pynput และคีย์บอร์ดแยกกันและโปรแกรมทำงานโดยไม่มีข้อผิดพลาดใด ๆ แต่สามารถตรวจจับได้เฉพาะคีย์พิเศษ (บน python shell) เท่านั้น ไม่พบคีย์ตัวอักษรและตัวเลขและในทางกลับกันถือว่าฉันกำลังเขียนโค้ดบนเชลล์ คุณรู้หรือไม่ว่ามีปัญหาอะไร
Dario Deniz Ergün

รหัสเดียวกันทำงานให้ฉันในเชลล์ โปรดตรวจสอบ แพ็กเกจแป้นพิมพ์ไม่ต้องการรหัสนี้
Manivannan Murugavel

1
นี่เป็นวิธีที่จะไปใน linux เนื่องจาก lib แป้นพิมพ์ต้องการรูท
เดวิด

1
โซลูชันนี้จะตรวจจับการกดแป้นพิมพ์ทั้งหมด สิ่งที่เกิดขึ้นในหน้าต่างเทอร์มินัลอื่น น่าเสียดายที่สิ่งนี้ จำกัด กรณีการใช้งานที่เป็นไปได้อย่างรุนแรง
Serge Stroobandt

6

ใช้ PyGame เพื่อมีหน้าต่างจากนั้นคุณจะได้รับเหตุการณ์สำคัญ

สำหรับจดหมายp:

import pygame, sys
import pygame.locals

pygame.init()
BLACK = (0,0,0)
WIDTH = 1280
HEIGHT = 1024
windowSurface = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)

windowSurface.fill(BLACK)

while True:
    for event in pygame.event.get():
        if event.key == pygame.K_p: # replace the 'p' to whatever key you wanted to be pressed
             pass #Do what you want to here
        if event.type == pygame.locals.QUIT:
             pygame.quit()
             sys.exit()

2

ผมจึงสร้าง .. ชนิดของเกมขึ้นมาจากโพสต์นี้ (โดยใช้ไลบรารี msvcr และ Python 3.7)

ต่อไปนี้เป็น "ฟังก์ชันหลัก" ของเกมนั่นคือการตรวจจับปุ่มที่กด:

# Requiered libraries - - - -
import msvcrt
# - - - - - - - - - - - - - -


def _secret_key(self):
    # Get the key pressed by the user and check if he/she wins.

    bk = chr(10) + "-"*25 + chr(10)

    while True:

        print(bk + "Press any key(s)" + bk)
        #asks the user to type any key(s)

        kp = str(msvcrt.getch()).replace("b'", "").replace("'", "")
        # Store key's value.

        if r'\xe0' in kp:
            kp += str(msvcrt.getch()).replace("b'", "").replace("'", "")
            # Refactor the variable in case of multi press.

        if kp == r'\xe0\x8a':
            # If user pressed the secret key, the game ends.
            # \x8a is CTRL+F12, that's the secret key.

            print(bk + "CONGRATULATIONS YOU PRESSED THE SECRET KEYS!\a" + bk)
            print("Press any key to exit the game")
            msvcrt.getch()
            break
        else:
            print("    You pressed:'", kp + "', that's not the secret key(s)\n")
            if self.select_continue() == "n":
                if self.secondary_options():
                    self._main_menu()
                break

หากคุณต้องการซอร์สโค้ดแบบเต็มของ porgram คุณสามารถดูหรือดาวน์โหลดได้จากที่นี่:

เกมคีย์ลับ (GitHub)

(หมายเหตุ: การกดแป้นพิมพ์ลับคือ: Ctrl+F12 )

ฉันหวังว่าคุณจะสามารถใช้เป็นตัวอย่างและช่วยให้ผู้ที่มาปรึกษาข้อมูลนี้



1
key = cv2.waitKey(1)

นี่มาจากแพ็คเกจ openCV ตรวจจับการกดแป้นพิมพ์โดยไม่ต้องรอ

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