виявити натискання клавіші в python?


104

Я створюю програму типу секундоміра в python, і я хотів би знати, як визначити, чи натискається клавіша (наприклад, p для паузи та s для зупинки), і я не хотів би, щоб це було щось на зразок raw_input, яке чекає введення користувача перед продовженням виконання. Хтось знає, як це зробити за певний цикл?

Крім того, я хотів би зробити цю крос-платформу, але якщо це неможливо, тоді моєю основною метою розвитку є Linux


для OS X stackoverflow.com/a/47197390/5638869 працює в Python 2 і 3
neoDev

Відповіді:


69

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

1
Я не впевнений у Linux, але він працює у Windows для мене.

72
keyboardмабуть, потрібен root в linux: /
Inaimathi

Я спробував це рішення, але при спробі імпортувати модуль після його встановлення з'являється повідомлення "ImportError: Немає модуля з назвою" клавіатура "", тому воно не спрацювало. Я перевірив репо GitHub і виявив пов'язану з цим проблему , але це не вирішує мене. Потім я спробував завантажити репо і виконати деякі з його прикладів, але я отримую та "ImportError: Ви повинні мати root, щоб використовувати цю бібліотеку в Linux", як @Inaimathi коментував раніше. Очевидно, це повний модуль для управління клавіатурою за допомогою Python, але вимога до root є великим недоліком :(
Ivanhercaz,

3
"Щоб уникнути залежності від X, частини Linux зчитують файли необроблених пристроїв (/ dev / input / input *), але це вимагає кореня."
jrouquie

7
Не розумію, чому спроба: osim: була б корисною.
TypicalHog

49

Для тих, хто на вікнах і намагався знайти робочу відповідь, ось мій: 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". Документація до клавіатури тут для більш варіативного використання.

Маркус фон Броді виділив потенційну проблему: Ця відповідь не вимагає, щоб Ви знаходились у поточному вікні, щоб цей сценарій був активований, рішенням для 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 ... і не вимагає root :)
cz

1
З цим рішенням є проблема (не впевнений щодо альтернативних варіантів): клавішу не потрібно натискати всередині вікна консолі, щоб вона набрала чинності. Уявіть, що у вас є скрипт, який виконує якусь роботу, поки не натисне ESC, але потім ви натиснете його в іншій програмі.
Маркус фон

1
@MarkusvonBroady Я думаю, що win32gui було б достатньо для його вирішення, я відредагував свою відповідь таким чином, що потенційно вирішив би її як мінімум для користувачів Windows.
Мітрек,

@Mitrek Я спробував це, але мій код зупиняє подальше виконання і застряг тут. Це працює як input (). У мене є код, що виконується в селені, firefox, але як тільки ця послідовність виявляється, подальших дій немає.
Лакшмі Нараянан,

1
Повинна бути прийнятою відповіддю, бо вона працює як в Linux, так і у Windows
Akash Karnatak

31

Оскільки OP згадує про raw_input - це означає, що він хоче рішення cli. Linux: прокляття - це те, що ви хочете (windows PDCurses). Прокляття - це графічний 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і так далі ...
Х'ю Перкінс,

5
потрібно додати import os, щоб мати можливість вийти, закрийте приклад.
мальте

Якщо ви це зробите win.nodelay(False)замість True, це не призведе до мільйона винятків за секунду.
Йоганнес Хофф,

24

Є більше речей, з якими можна впоратись keyboard модуля.

Ось декілька методів:


Спосіб No1:

Використання функції read_key():

import keyboard

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

Це розірве цикл при pнатисканні клавіші.


Спосіб No2:

Використання функції wait:

import keyboard

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

Він буде чекати, поки ви натиснете pі продовжите код, як він натиснутий.


Спосіб No3:

Використання функції on_press_key:

import keyboard

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

Для цього потрібна функція зворотного виклику. я використав_ оскільки функція клавіатури повертає подію клавіатури до цієї функції.

Після запуску він запустить функцію при натисканні клавіші. Ви можете зупинити всі хуки, запустивши цей рядок:

keyboard.unhook_all()

Спосіб No4:

На цей метод користувач уже відповів користувачем 8167727, але я не погоджуюся з кодом, який вони створили. Він використовуватиме функцію, is_pressedале по-іншому:

import keyboard

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

Це розірве петлю при pнатисканні.


Примітки:

  • keyboard читатиме натискання клавіш з усієї ОС.
  • keyboard вимагає root на linux

11
Найбільшим запереченням використання модуля клавіатури є його вимога, яку ви запускаєте як користувач ROOT. Це робить модуль детальним у моєму коді. Для опитування, чи була натиснута клавіша, не потрібні права root. Я прочитав документ і розумію, чому обмеження виходить в модулі, але подивіться в іншому місці, якщо все, що вам потрібно, це опитування ключа ...
muman

Дуже корисна інформація, сер! Я хотів знати, чи можу я keyboard.wait()зачекати більше 1 клавіші і продовжувати, якщо натиснута будь-яка з них
Прееткаран Сінгх

@PreetkaranSingh wait()не надає цієї функціональності. Вам доведеться використовувати keyboard.read_key()з умовою if, упакованою в цикл while. Дивіться метод №1
Чорний грім

Дякую, сер!, Хотіли б ви пролити світло на використання suppressключового слова keyboard.read_key(), коли, а коли ні ...
Preetkaran Singh

@PreetkaranSingh Я б, але у мене недостатньо інформації про аргумент придушення
Чорний грім

14

Для Windows ви можете використовувати msvcrtнаступне:

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

7
msvcrt - це модуль лише для Windows.
Дунатотатос

1
Я фактично використовую pynput зараз, це може бути кращою відповіддю
Бенджі

Зверніть увагу, що pynput для роботи в OS X (не знаю про Linux) повинен працювати як root, щоб працювати. Для деяких людей це може бути початком.
Gabe Weiss,

Я міг би поклястись, що питання стосувалось "крос-платформенності" або "Linux" ...
Аарон Манн,

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) спеціальні клавіші. Буквено-цифрові клавіші не виявляються, і навпаки, вважаються такими, ніби я пишу код на оболонці. Чи знаєте ви, в чому може бути проблема?
Даріо Деніз

Той самий код працював у мене в оболонці. Будь ласка, перевірте це. Цей пакет клавіатури не потребує.
Маніваннан Муругавел

1
Це шлях у Linux, оскільки для клавіатури потрібен root.
Девід

1
Це рішення виявить усі натискання клавіш; також ті, що відбуваються в іншому вікні терміналу. На жаль, це суттєво обмежує можливі випадки використання.
Серж Строобандт

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

Якщо вам потрібен повний вихідний код порграми, ви можете переглянути його або завантажити звідси:

Гра на секретний ключ (GitHub)

(примітка: секретне натискання клавіші: Ctrl+ F12)

Сподіваюсь, ви можете послужити прикладом та допомогою тим, хто прийде ознайомитися з цією інформацією.



1
key = cv2.waitKey(1)

Це з пакету openCV. Він виявляє натискання клавіші, не чекаючи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.