mendeteksi penekanan tombol dengan python?

106

Saya membuat program jenis stopwatch dengan python dan saya ingin tahu bagaimana mendeteksi jika tombol ditekan (seperti p untuk jeda dan s untuk berhenti), dan saya tidak ingin itu menjadi sesuatu seperti raw_input yang menunggu masukan pengguna sebelum melanjutkan eksekusi. Adakah yang tahu bagaimana melakukan ini dalam loop sementara?

Juga, saya ingin membuat cross-platform ini, tetapi jika itu tidak memungkinkan, maka target pengembangan utama saya adalah linux

lobuo
sumber
untuk OS X stackoverflow.com/a/47197390/5638869 bekerja dengan Python 2 dan 3
neoDev

Jawaban:

71

Python memiliki modul keyboard dengan banyak fitur. Instal, mungkin dengan perintah ini:

pip3 install keyboard

Kemudian gunakan dalam kode seperti:

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
Komunitas
sumber
2
Saya tidak yakin untuk linux tetapi bekerja pada Windows untuk saya.
75
keyboardtampaknya membutuhkan root di linux: /
Inaimathi
Saya mencoba solusi ini tetapi ketika saya mencoba mengimpor modul setelah menginstalnya, saya mendapatkan "ImportError: Tidak ada modul bernama 'keyboard'", jadi tidak berhasil. Saya memeriksa di repo GitHub dan saya menemukan masalah terkait , tetapi itu tidak menyelesaikan masalah saya. Kemudian, saya mencoba mengunduh repo dan menjalankan beberapa contohnya tetapi saya mendapatkan dan "ImportError: Anda harus menjadi root untuk menggunakan perpustakaan ini di linux", seperti yang dikomentari @Inaimathi sebelumnya. Rupanya tampaknya modul penuh untuk mengelola keyboard dengan Python, tetapi persyaratan root sangat kurang :(
Ivanhercaz
3
"Untuk menghindari ketergantungan pada X, bagian Linux membaca file perangkat mentah (/ dev / input / input *) tetapi ini membutuhkan root."
jrouquie
8
Saya tidak mengerti mengapa mencoba: kecuali: berguna.
TypicalHog
50

Bagi mereka yang menggunakan jendela dan berjuang untuk menemukan jawaban yang berfungsi, inilah milik saya: 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()

Fungsi di atas akan mencetak tombol mana saja yang Anda tekan dan memulai tindakan saat Anda melepaskan tombol 'esc'. Dokumentasi keyboard ada di sini untuk penggunaan yang lebih bervariasi.

Markus von Broady menyoroti masalah potensial yaitu: Jawaban ini tidak mengharuskan Anda berada di jendela saat ini untuk mengaktifkan skrip ini, solusi untuk jendela adalah:

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()
Mitrek
sumber
7
@ nimig18 ... dan tidak membutuhkan root :)
cz
1
Ada masalah dengan solusi ini (tidak yakin tentang alternatifnya): tombol tidak harus ditekan di dalam jendela konsol agar dapat berfungsi. Bayangkan memiliki skrip yang melakukan beberapa pekerjaan sampai ESC ditekan, tetapi kemudian Anda menekannya di program lain.
Markus von Broady
1
@MarkusvonBroady Saya kira win32gui akan cukup untuk menyelesaikannya, saya telah mengedit jawaban saya dengan cara yang berpotensi menyelesaikannya setidaknya untuk pengguna windows.
Mitrek
@Mitrek Saya mencoba ini, tetapi kode saya menghentikan eksekusi lebih lanjut dan macet di sini. Ia bekerja seperti input (). Saya memiliki kode yang dijalankan di selenium, firefox, tetapi begitu urutan ini ditemukan, tidak ada tindakan lebih lanjut.
Lakshmi Narayanan
1
Seharusnya jawaban yang diterima, karena berfungsi baik di linux dan windows
Akash Karnatak
31

Seperti yang disebutkan OP tentang raw_input - itu berarti dia menginginkan solusi cli. Linux: kutukan adalah apa yang Anda inginkan (windows PDCurses). Curses, adalah API grafis untuk perangkat lunak cli, Anda dapat mencapai lebih dari sekedar mendeteksi peristiwa penting.

Kode ini akan mendeteksi kunci sampai baris baru ditekan.

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)
Abc Xyz
sumber
Ini sangat bagus. Harus mencari selamanya sebelum menemukannya. Kelihatannya jauh lebih bersih daripada meretas termiosdan sebagainya ...
Hugh Perkins
5
perlu menambahkan import osagar dapat keluar dari contoh.
malte
Jika Anda melakukannya, win.nodelay(False)bukan True, itu tidak akan menghasilkan satu juta pengecualian per detik.
Johannes Hoff
25

Ada lebih banyak hal yang bisa dilakukan dengan keyboardmodul.

Berikut beberapa caranya:


Metode # 1:

Menggunakan fungsi read_key():

import keyboard

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

Ini akan memutus lingkaran saat tombol pditekan.


Metode # 2:

Menggunakan fungsi wait:

import keyboard

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

Ini akan menunggu Anda untuk menekan pdan melanjutkan kode saat ditekan.


Metode # 3:

Menggunakan fungsi on_press_key:

import keyboard

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

Ini membutuhkan fungsi panggilan balik. Saya dulu_ karena fungsi keyboard mengembalikan acara keyboard ke fungsi itu.

Setelah dijalankan, ini akan menjalankan fungsi saat tombol ditekan. Anda dapat menghentikan semua pengait dengan menjalankan baris ini:

keyboard.unhook_all()

Metode # 4:

Metode ini semacam sudah dijawab oleh user8167727 tetapi saya tidak setuju dengan kode yang mereka buat. Ini akan menggunakan fungsi tersebut is_pressedtetapi dengan cara lain:

import keyboard

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

Ini akan memutus loop saat pditekan.


Catatan:

  • keyboard akan membaca penekanan tombol dari seluruh OS.
  • keyboard membutuhkan root di linux
Petir hitam
sumber
11
NEGATIF ​​terbesar dalam menggunakan modul keyboard adalah persyaratannya Anda menjalankan sebagai pengguna ROOT. Ini membuat modul menjadi verboten dalam kode saya. Hanya untuk memeriksa apakah sebuah tombol telah ditekan tidak membutuhkan hak akses root. Saya telah membaca dokumen dan memahami mengapa batasan keluar dalam modul, tetapi lihat di tempat lain jika yang Anda butuhkan hanyalah polling kunci ...
muman
Info yang sangat membantu dibagikan, Pak! Saya ingin tahu apakah saya dapat menggunakan keyboard.wait()untuk menunggu lebih dari 1 tombol, dan melanjutkan jika salah satu tombol ditekan
Preetkaran Singh
@PreetkaranSingh wait()tidak memberikan fungsi ini. Anda harus menggunakan keyboard.read_key()kondisi if yang dikemas dalam loop sementara. Lihat metode # 1
Guntur Hitam
Terima kasih Pak !, apakah Anda ingin menjelaskan suppresspenggunaan kata kunci dalam keyboard.read_key(), kapan menggunakannya dan kapan tidak ....
Preetkaran Singh
@PreetkaranSingh Saya akan tetapi saya tidak memiliki cukup informasi tentang argumen penindasan
Guntur Hitam
14

Untuk Windows Anda bisa menggunakan msvcrtseperti ini:

   import msvcrt
   while True:
       if msvcrt.kbhit():
           key = msvcrt.getch()
           print(key)   # just to show the result
Benjie
sumber
7
msvcrt adalah modul khusus Windows.
Dunatotatos
1
Saya sebenarnya menggunakan pynput sekarang, itu mungkin jawaban yang lebih baik
Benjie
Perhatikan bahwa pynput untuk bekerja di OS X (tidak tahu tentang Linux) harus dijalankan sebagai root agar dapat berfungsi. Itu mungkin bukan permulaan bagi sebagian orang.
Gabe Weiss
Saya berani bersumpah pertanyaan itu untuk 'cross-platform' atau 'linux' ...
Aaron Mann
10

Gunakan kode ini untuk menemukan tombol mana yang ditekan

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()
Manivannan Murugavel
sumber
Begini masalahnya, saya menggunakan macOS dan menginstal pynput dan keyboard secara terpisah, dan program berjalan tanpa kesalahan apa pun tetapi hanya dapat mendeteksi (pada shell python) tombol khusus. Kunci alfanumerik tidak terdeteksi dan sebaliknya dianggap seolah-olah saya sedang menulis kode pada shell. Tahukah Anda apa masalahnya?
Dario Deniz Ergün
Kode yang sama bekerja untuk saya di shell. Tolong diperiksa. Paket keyboard tidak membutuhkan kode ini.
Manivannan Murugavel
1
Ini adalah cara untuk masuk ke linux, karena keyboard lib membutuhkan root.
David
1
Solusi ini akan mendeteksi semua penekanan tombol; juga yang terjadi di jendela terminal yang berbeda. Sayangnya, hal ini sangat membatasi kemungkinan kasus penggunaannya.
Serge Stroobandt
6

Gunakan PyGame untuk memiliki jendela dan kemudian Anda bisa mendapatkan peristiwa penting.

Untuk suratnya 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()
AJ Uppal
sumber
2

Jadi saya membuat .. jenis game .. berdasarkan posting ini (menggunakan pustaka D3D dan Python 3.7).

Berikut ini adalah "fungsi utama" dari game tersebut, yaitu mendeteksi tombol yang ditekan:

# 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

Jika Anda menginginkan kode sumber porgram secara lengkap, Anda dapat melihatnya atau mengunduhnya dari sini:

Permainan Kunci Rahasia (GitHub)

(catatan: tombol rahasia ditekan adalah: Ctrl+ F12)

Saya harap Anda dapat menjadi contoh dan bantuan bagi mereka yang datang untuk berkonsultasi informasi ini.

Ferd
sumber
1
key = cv2.waitKey(1)

Ini dari paket openCV. Ini mendeteksi penekanan tombol tanpa menunggu.

eyllanesc
sumber