python'da tuş basımını algıla?


113

Python'da bir kronometre tipi program yapıyorum ve bir tuşa basılıp basılmadığını nasıl tespit edeceğimi bilmek istiyorum (duraklatmak için p ve durdurmak için s gibi) ve bunun için bekleyen raw_input gibi bir şey olmasını istemiyorum yürütmeye devam etmeden önce kullanıcının girdisi. Bunu bir süre içinde nasıl yapacağını bilen var mı?

Ayrıca, bu çapraz platform yapmak istiyorum, ancak bu mümkün değilse, o zaman ana geliştirme hedefim linux


OS X stackoverflow.com/a/47197390/5638869 için Python 2 ve 3'te çalışır
neoDev

Yanıtlar:


78

Python, birçok özelliğe sahip bir klavye modülüne sahiptir. Belki de şu komutla kurun:

pip3 install keyboard

Ardından, aşağıdaki gibi bir kodda kullanın:

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'tan emin değilim ama benim için Windows'ta çalışıyor.

84
keyboardgörünüşe göre
linux'ta

Bu çözümü denedim, ancak modülü yükledikten sonra içe aktarmaya çalıştığımda, "ImportError: 'keyboard' adlı modül yok" mesajı alıyorum, bu yüzden çalışmadı. GitHub deposunu kontrol ettim ve ilgili bir sorun buldum , ancak sorunu çözmedi . Ardından repo'yu indirmeyi ve bazı örneklerini çalıştırmayı denedim ama @Inaimathi'nin daha önce yorumladığı gibi "ImportError: Bu kütüphaneyi linux üzerinde kullanmak için root olmanız gerekir" mesajı alıyorum. Görünüşe göre klavyeyi Python ile yönetmek için tam bir modül gibi görünüyor, ancak kök gereksinimi büyük bir eksiklik :(
Ivanhercaz

3
"X'e bağlı olmaktan kaçınmak için, Linux parçaları ham aygıt dosyalarını (/ dev / input / input *) okur, ancak bu kök gerektirir."
jrouquie

8
Neden deneyeceğini anlamıyorum: dışında: yararlı.
TypicalHog

52

Pencerelerde olan ve işe yarayan bir cevap bulmakta zorlananlar için işte benimki: 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()

Yukarıdaki işlev, bastığınız her tuşu yazdırır ve 'esc' tuşunu bıraktığınızda bir eylem başlatır. Klavye belgeleri daha çeşitli bir kullanım için burada .

Markus von Broady olası bir sorunu vurguladı: Bu yanıt, bu komut dosyasının etkinleştirilmesi için mevcut pencerede olmanızı gerektirmez, pencerelere bir çözüm olabilir:

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 ... ve kök gerektirmez :)
cz

1
Bu çözümle ilgili bir sorun var (alternatiflerden emin değilim): Anahtarın etkili olması için bir konsol penceresinin içinde basılmasına gerek yoktur. ESC'ye basılıncaya kadar bazı işler yapan bir betiğe sahip olduğunuzu ama sonra başka bir programda bastığınızı hayal edin.
Markus von Broady

1
@MarkusvonBroady Win32gui'nin bunu çözmek için yeterli olacağını tahmin ediyorum, cevabımı en azından Windows kullanıcılarına çözebilecek şekilde düzenledim.
Mitrek

@Mitrek Bunu denedim, ancak kodum daha fazla yürütmeyi durdurdu ve burada sıkıştı. İnput () gibi çalışır. Selenyum, firefox'ta çalıştırılan kodum var, ancak bu sıra ile karşılaşıldığında, başka bir işlem yok.
Lakshmi Narayanan

1
Kabul edilen cevap olmalıydı, çünkü hem linux hem de pencerelerde çalışıyor
Akash Karnatak

31

OP'nin raw_input'tan bahsettiği gibi - bu onun cli çözümü istediği anlamına gelir. Linux: curses , istediğiniz şeydir (Windows PDCurses). Curses, cli yazılımı için bir grafik API'sidir, yalnızca önemli olayları algılamaktan daha fazlasını başarabilirsiniz.

Bu kod, yeni satıra basılana kadar tuşları algılayacaktır.

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)

Bu gerçekten güzel. Karşılaşmadan önce sonsuza kadar aramak zorunda kaldı. Etrafta dolaşmaktan çok daha temiz görünüyor termios...
Hugh Perkins

5
import osörnekten çıkabilmek için eklenmesi gerekiyor .
malte

win.nodelay(False)Bunun yerine yaparsanız True, saniyede bir milyon istisna oluşturmaz.
Johannes Hoff

29

keyboardModül ile yapılabilecek daha çok şey var .

İşte yöntemlerden bazıları:


Yöntem 1:

İşlevi kullanma read_key():

import keyboard

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

Bu, tuşa pbasıldıkça döngüyü bozacaktır.


Yöntem 2:

Fonksiyonu kullanma wait:

import keyboard

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

Basıldıkça, basıp pkoda devam etmenizi bekleyecektir .


Yöntem 3:

İşlevi kullanma on_press_key:

import keyboard

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

Geri arama işlevine ihtiyacı var. Kullandığım _klavye işlevi o fonksiyona klavye olayı döndürdüğü için.

Çalıştırıldıktan sonra, tuşuna basıldığında işlevi çalıştıracaktır. Bu satırı çalıştırarak tüm kancaları durdurabilirsiniz:

keyboard.unhook_all()

Yöntem 4:

Bu yöntem, user8167727 tarafından zaten yanıtlanmış gibi, ancak yaptıkları koda katılmıyorum. İşlevi kullanacak, is_pressedancak başka bir şekilde:

import keyboard

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

pBasıldığı gibi döngüyü kıracaktır.


Notlar:

  • keyboard tüm işletim sistemindeki tuş vuruşlarını okuyacaktır.
  • keyboard linux üzerinde root gerektirir

11
Klavye modülünü kullanmanın en büyük NEGATİFİ, ROOT kullanıcısı olarak çalıştırmanızın gerekliliğidir. Bu, modülü kodumda verboten yapar. Sadece bir tuşa basılıp basılmadığını sorgulamak için kök ayrıcalıkları gerekmez.
Belgeyi okudum

Çok faydalı bilgiler paylaşıldı, efendim! keyboard.wait()1
tuştan

@PreetkaranSingh wait()bu işlevi vermez. keyboard.read_key()Bir while döngüsü içinde paketlenmiş if koşuluyla kullanmanız gerekecek . Yöntem # 1
Black Thunder

Teşekkürler Efendim !, suppressanahtar kelime kullanımına keyboard.read_key(), ne zaman kullanılacağına ve ne zaman kullanılmayacağına ışık tutmak ister misiniz ....
Preetkaran Singh

@PreetkaranSingh isterdim ama bastırma argümanı hakkında yeterli bilgiye sahip değilim
Black Thunder

15

For Windows'un Kullanabileceğin msvcrtböyle:

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

8
msvcrt, yalnızca Windows'a yönelik bir modüldür.
Dunatotatos

1
Aslında şimdi pynput kullanıyorum, bu daha iyi bir cevap olabilir
Benjie

OS X üzerinde çalışmak için pynput'un (Linux hakkında bilmiyorum) çalışması için root olarak çalıştırılması gerektiğini unutmayın. Bu, bazı insanlar için başlangıç ​​olmayabilir.
Gabe Weiss

Sorunun 'çapraz platform' ya da 'linux' için olduğuna yemin edebilirdim ...
Aaron Mann

10

Hangi tuşa basıldığını bulmak için bu kodu kullanı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()

Yine de olay şu ki, macOS kullanıyorum ve hem pynput hem de klavyeyi ayrı ayrı kuruyorum ve program hatasız çalışıyor ancak yalnızca (python kabuğunda) özel tuşları algılayabiliyor. Alfasayısal anahtarlar algılanmıyor ve tam tersine kabuk üzerine kod yazıyormuşum gibi kabul ediliyor. Sorunun ne olabileceğini biliyor musunuz?
Dario Deniz Ergün

Aynı kod kabukta benim için çalıştı. Lütfen kontrol et. Klavye paketinin bu koda ihtiyacı yoktur.
Manivannan Murugavel

1
Klavye kütüphanesinin root'a ihtiyacı olduğu için linux'a girmenin yolu budur.
David

1
Bu çözüm tüm tuş vuruşlarını algılayacaktır ; ayrıca farklı bir terminal penceresinde olanlar. Maalesef bu, olası kullanım durumlarını ciddi şekilde sınırlamaktadır.
Serge Stroobandt

6

Bir pencereye sahip olmak için PyGame'i kullanın ve ardından önemli olayları alabilirsiniz.

Mektup için 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

Ben de bu .. türden bir oyun yaptım .. bu yazıya dayanarak (msvcr kütüphanesi ve Python 3.7 kullanarak).

Aşağıdakiler oyunun "ana işlevi" yani basılan tuşları algılamaktır:

# 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

Programın tam kaynak kodunu istiyorsanız, onu görebilir veya buradan indirebilirsiniz:

Gizli Anahtar Oyunu (GitHub)

(not: gizli tuşa basma: Ctrl+ F12)

Umarım bu bilgilere danışmak için gelenlere örnek olur ve yardımcı olursunuz.



1
key = cv2.waitKey(1)

Bu openCV paketindendir. Beklemeden bir tuşa basmayı algılar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.