phát hiện phím bấm trong python?


103

Tôi đang tạo một chương trình loại đồng hồ bấm giờ bằng python và tôi muốn biết cách phát hiện nếu một phím được nhấn (chẳng hạn như p để tạm dừng và s để dừng) và tôi không muốn nó giống như raw_input chờ đầu vào của người dùng trước khi tiếp tục thực thi. Có ai biết cách làm điều này trong vòng lặp while không?

Ngoài ra, tôi muốn tạo ra nền tảng đa nền tảng này, nhưng nếu điều đó là không thể, thì mục tiêu phát triển chính của tôi là linux


cho OS X stackoverflow.com/a/47197390/5638869 hoạt động bằng Python 2 và 3
neoDev

Câu trả lời:


69

Python có một mô-đun bàn phím với nhiều tính năng. Cài đặt nó, có lẽ bằng lệnh này:

pip3 install keyboard

Sau đó, sử dụng nó trong mã như:

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

1
Tôi không chắc đối với Linux nhưng nó hoạt động trên Windows đối với tôi.

71
keyboardrõ ràng đòi hỏi gốc trong linux: /
Inaimathi

Tôi đã thử giải pháp này nhưng khi tôi cố gắng nhập mô-đun sau khi cài đặt, tôi nhận được thông báo "ImportError: No module có tên 'keyboard'", vì vậy nó không hoạt động. Tôi đã kiểm tra trong repo GitHub và tôi tìm thấy một vấn đề liên quan , nhưng nó không giải quyết được vấn đề của tôi. Sau đó, tôi đã thử tải xuống repo và thực hiện một số ví dụ của nó nhưng tôi nhận được và "ImportError: Bạn phải root để sử dụng thư viện này trên linux", như @Inaimathi đã nhận xét trước đó. Rõ ràng nó có vẻ là một mô-đun đầy đủ để quản lý bàn phím với Python, nhưng yêu cầu về quyền root là một thiếu sót lớn :(
Ivanhercaz

3
"Để tránh phụ thuộc vào X, phần Linux đọc các tệp thiết bị thô (/ dev / input / input *) nhưng điều này yêu cầu root."
jrouquie

7
Tôi không hiểu tại sao phải thử: ngoại trừ: hữu ích.
Tiêu biểuHog

49

Đối với những người đang sử dụng windows và đang đấu tranh để tìm câu trả lời phù hợp, đây là của tôi: 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()

Hàm trên sẽ in bất kỳ phím nào bạn đang nhấn cộng với bắt đầu một hành động khi bạn nhả phím 'esc'. Tài liệu bàn phím ở đây để sử dụng đa dạng hơn.

Markus von Broady nêu bật một vấn đề tiềm ẩn đó là: Câu trả lời này không yêu cầu bạn phải ở trong cửa sổ hiện tại để kích hoạt tập lệnh này, một giải pháp cho cửa sổ sẽ là:

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 ... và không yêu cầu root :)
cz

1
Có một vấn đề với giải pháp này (không chắc chắn về các lựa chọn thay thế): phím không phải được nhấn bên trong cửa sổ bảng điều khiển để nó có hiệu lực. Hãy tưởng tượng có một tập lệnh thực hiện một số công việc cho đến khi nhấn ESC, nhưng sau đó bạn nhấn nó trong một chương trình khác.
Markus von Broady

1
@MarkusvonBroady Tôi đoán rằng win32gui sẽ đủ để giải quyết nó, tôi đã chỉnh sửa câu trả lời của mình theo cách có thể giải quyết được nó cho người dùng windows ít nhất.
Mitrek

@Mitrek Tôi đã thử điều này, nhưng mã của tôi ngừng thực thi thêm và bị kẹt ở đây. Nó hoạt động giống như input (). Tôi có mã đang thực thi trong selen, firefox, nhưng ngay khi gặp trình tự này, không có hành động nào khác.
Lakshmi Narayanan

1
Đáng lẽ phải là câu trả lời được chấp nhận, vì nó hoạt động cả trong Linux và windows
Akash Karnatak

31

Khi OP đề cập đến raw_input - điều đó có nghĩa là anh ấy muốn giải pháp cli. Linux: Lời nguyền là những gì bạn muốn (windows PDCurses). Curses, là một API đồ họa cho phần mềm cli, bạn có thể đạt được nhiều điều hơn là chỉ phát hiện các sự kiện chính.

Mã này sẽ phát hiện các phím cho đến khi dòng mới được nhấn.

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)

Điều này thực sự tốt đẹp. Phải tìm kiếm mãi trước khi bắt gặp nó. Có vẻ nhiều bụi hơn hacking xung quanh với termiosvà vân vân ...
Hugh Perkins

5
cần thêm import osđể có thể thoát khỏi ví dụ.
malte

Nếu bạn làm win.nodelay(False)thay vì True, nó sẽ không tạo ra một triệu ngoại lệ mỗi giây.
Johannes Hoff

24

Có nhiều thứ hơn có thể được thực hiện với keyboardmô-đun.

Dưới đây là một số phương pháp:


Phương pháp # 1:

Sử dụng chức năng read_key():

import keyboard

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

Điều này sẽ phá vỡ vòng lặp khi phím pđược nhấn.


Phương pháp # 2:

Sử dụng chức năng wait:

import keyboard

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

Nó sẽ đợi bạn nhấn pvà tiếp tục mã khi nó được nhấn.


Phương pháp # 3:

Sử dụng chức năng on_press_key:

import keyboard

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

Nó cần một chức năng gọi lại. Tôi đã sử dụng _vì hàm bàn phím trả về sự kiện bàn phím cho hàm đó.

Sau khi thực thi, nó sẽ chạy chức năng khi nhấn phím. Bạn có thể dừng tất cả các hook bằng cách chạy dòng này:

keyboard.unhook_all()

Phương pháp # 4:

Phương pháp này đã được user8167727 trả lời nhưng tôi không đồng ý với mã mà họ thực hiện. Nó sẽ sử dụng chức năng is_pressednhưng theo một cách khác:

import keyboard

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

Nó sẽ phá vỡ vòng lặp khi pđược nhấn.


Ghi chú:

  • keyboard sẽ đọc các lần nhấn phím từ toàn bộ hệ điều hành.
  • keyboard yêu cầu root trên linux

11
TIÊU CỰC lớn nhất của việc sử dụng mô-đun bàn phím là yêu cầu bạn chạy với tư cách người dùng ROOT. Điều này làm cho mô-đun trở nên dài dòng trong mã của tôi. Chỉ để thăm dò xem một phím đã được nhấn hay chưa mà không yêu cầu quyền root. Tôi có đọc doc và hiểu tại sao các lối ra hạn chế trong mô-đun, nhưng tìm nơi khác nếu tất cả các bạn cần là để thăm dò ý kiến một chìa khóa ...
muman

Thông tin rất hữu ích được chia sẻ, thưa ông! Tôi muốn biết liệu tôi có thể sử dụng keyboard.wait()để đợi nhiều hơn 1 phím hay không và tiếp tục nếu một trong hai phím được nhấn
Preetkaran Singh

@PreetkaranSingh wait()không cung cấp chức năng này. Bạn sẽ phải sử dụng keyboard.read_key()với điều kiện if được đóng gói trong vòng lặp while. Xem phương pháp # 1
Black Thunder,

Cảm ơn Sir !, bạn muốn làm sáng tỏ về sự suppresssử dụng từ khóa trong keyboard.read_key(), khi sử dụng nó và khi không ....
Preetkaran Singh

@PreetkaranSingh Tôi muốn nhưng tôi không có đủ thông tin về lập luận đàn áp
Black Thunder

13

Đối với Windows, bạn có thể sử dụng msvcrtnhư sau:

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

7
msvcrt là một mô-đun chỉ dành cho Windows.
Dunatotatos

1
Tôi thực sự sử dụng pynput bây giờ, đó có thể là một câu trả lời tốt hơn
Benjie

Lưu ý rằng pynput để hoạt động trên OS X (không biết về Linux) phải chạy dưới dạng root để hoạt động. Điều đó có thể không phải là khởi đầu cho một số người.
Gabe Weiss

Tôi có thể thề rằng câu hỏi dành cho 'đa nền tảng' hoặc 'linux' ...
Aaron Mann

10

Sử dụng mã này để tìm phím được nhấn

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()

Tuy nhiên, đây là điều, tôi đang sử dụng macOS và đã cài đặt riêng cả pynput và bàn phím, và chương trình chạy mà không có bất kỳ lỗi nào nhưng chỉ có thể phát hiện các phím đặc biệt (trên python shell). Các phím chữ và số không được phát hiện và ngược lại, được coi như thể tôi đang viết mã trên shell. Bạn có biết vấn đề có thể là gì không?
Dario Deniz Ergün

Cùng một mã đã làm việc cho tôi trong shell. Xin vui lòng kiểm tra xem nó. Gói bàn phím không cần mã này.
Manivannan Murugavel

1
Đây là cách để thực hiện trong Linux, vì lib bàn phím cần root.
David

1
Giải pháp này sẽ phát hiện tất cả các lần gõ phím; cũng có thể xảy ra trong một cửa sổ đầu cuối khác. Thật không may, điều này hạn chế nghiêm trọng các trường hợp sử dụng có thể có của nó.
Serge Stroobandt

6

Sử dụng PyGame để có một cửa sổ và sau đó bạn có thể nhận các sự kiện quan trọng.

Đối với bức thư 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

Vì vậy, tôi đã thực hiện điều này ..kind of game .. dựa trên bài đăng này (sử dụng thư viện msvcr và Python 3.7).

Sau đây là "chức năng chính" của trò chơi, đó là phát hiện các phím được nhấn:

# 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

Nếu bạn muốn có mã nguồn đầy đủ của porgram, bạn có thể xem hoặc tải xuống từ đây:

Trò chơi chìa khóa bí mật (GitHub)

(lưu ý: phím bí mật là: Ctrl+ F12)

Tôi hy vọng bạn có thể làm ví dụ và giúp đỡ cho những người đến tham khảo thông tin này.



1
key = cv2.waitKey(1)

Đây là từ gói openCV. Nó phát hiện một lần nhấn phím mà không cần chờ đợi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.