【问题标题】:How to detect combination of key presses on keyboard in linux with python pynput and opencv?如何使用python pynput和opencv检测linux中键盘上的按键组合?
【发布时间】:2020-02-11 13:16:09
【问题描述】:

我正在做一个关于在 Linux 平台上创建自主驱动程序的项目。我需要在特定时间捕捉键盘上按下的键,尤其是同时按下它们时。我写了这段代码,它在 Windows 中非常好用,但在 linux 中却不太好:

import time
import cv2
import mss
import numpy as np
from pynput.keyboard import Key, Listener

def up():
    print("Go up")


def down():
    print("Go down")


def left():
    print("Go left")


def right():
    print("Go right")


def up_left():
    print("Go up_left")


def up_right():
    print("Go up_right")


def down_left():
    print("Go down_left")


def down_right():
    print("Go down_right")


def do_nothing():
    print("Do Nothing")


# Create a mapping of keys to function (use frozenset as sets are not hashable - so they can't be used as keys)



# The keys combinatons to check

combination_to_function = {
    frozenset([Key.up]): up,
    frozenset([Key.down, ]): down,
    frozenset([Key.left, ]): left,
    frozenset([Key.right, ]): right,
    frozenset([Key.up, Key.left]): up_left,
    frozenset([Key.up, Key.right]): up_right,
    frozenset([Key.down, Key.left]): down_left,
    frozenset([Key.down, Key.right]): down_right,
}

# Currently pressed keys
current_keys = set()

def on_press(key):
    # When a key is pressed, add it to the set we are keeping track of and check if this set is in the dictionary
    current_keys.add(key)
    if frozenset(current_keys) in combination_to_function:
        # If the current set of keys are in the mapping, execute the function
        combination_to_function[frozenset(current_keys)]()


def on_release(key):
    # When a key is released, remove it from the set of keys we are keeping track of
    if key in current_keys:
        current_keys.remove(key)


def process_img(original_img):
    processed_img = cv2.cvtColor(original_img, cv2.COLOR_BGR2GRAY)
    processed_img = cv2.Canny(processed_img, threshold1=200, threshold2=300)
    return processed_img


with mss.mss() as sct:
    # Part of the screen to capture
    monitor = {"top": 0, "left": 70, "width": 640, "height": 480}

    while True:
        listener = Listener(on_press=on_press, on_release=on_release)
        listener.start()
        last_time = time.time()
        # key_catcher = MockButton()
        # Get raw pixels from the screen, save it to a Numpy array
        screen = np.array(sct.grab(monitor))
        new_screen = process_img(original_img=screen)

        # Display the picture
        cv2.imshow("Window", new_screen)

        # print("Loop took {} seconds".format(time.time() - last_time))
        # Press "q" to quit

        k = cv2.waitKey(10)

        if k & 0xFF == ord("q"):
            cv2.destroyAllWindows()
            break

        listener.stop()

go_up, go_down, ... 函数只是象征性的,我想编写其他代码来将按下的键转换为机器学习过程的向量。

例如,如果我在键盘上按w,我希望得到这样的向量:

 w   s   a   d   wa  wd  sa  sd  nk
[1   0   0   0   0   0   0   0   0 ]

当我同时按下wa 时,我希望这样:

 w   s   a   d   wa  wd  sa  sd  nk
[0   0   0   0   1   0   0   0   0 ]

无论如何,代码在 linux 中运行得不够好。该程序在运行一段时间时遇到了一些问题。程序运行一段时间后,终端停止输出。有人可以帮我让这段代码在 linux 中更高效吗?

【问题讨论】:

  • 如果有cv2.waitKey(),为什么还要使用key_check
  • 顺便说一句:keyList = ["\b"] + list("ABCDEFGHIJKLMNOPQRSTUVWXYZ 123456789,.'£$/\\") 但您不必将字符串转换为列表即可在for key on keyList 中使用它。它应该可以工作for key in "\bABCDEFGHIJKLMNOPQRSTUVWXYZ 123456789,.'£$/\\":
  • 顺便说一句:你不必使用with ... as listener: listener.join()。您可以在循环之前运行listener.start(),在循环之后运行listener.stop()
  • 是否可以检测与cv2.waitKey()同时按下的键?例如,按下w 我希望某个函数运行,而wA 我希望另一个函数运行。所以抓住正确的钥匙很重要。
  • cv2.waitKey() 按下w 后,您将不得不等待几毫秒(几个循环),如果您在下一个循环中获得A,则运行第二个函数。如果你没有得到A,那么你运行第一个函数。但是您无法检查是否同时没有释放w。使用listener,您可能必须这样做 - 您必须等待几个循环才能检查您是否没有按A,但您可以轻松检查您是否没有释放w

标签: python linux opencv keypress pynput


【解决方案1】:

我不知道您尝试使用 key_check() 做什么,但我希望您可以使用 cv2.waitKey() 做同样的事情


如果你想使用pynput 那么你可以这样做

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

     # your loop

     listener.stop()
     listener.join()

listener = pynput.Listener(on_press=on_press, on_release=on_release)
listener.start()

# your loop

listener.stop()
listener.join()

【讨论】:

  • 感谢您的提示。我更新了问题。我需要在循环到达key_check 函数时按下按键。你有什么想法吗?
  • on_press 中使用keyList.append(key),在on_release 中使用if key in keyList: keyList.remove(key),您将一直按下所有按键。你只需要对它们进行排序。或者使用带键的字典,在on_press 中设置keys["a"] = True,在on_release 中设置keys["a"] = False
猜你喜欢
  • 2020-02-17
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 2021-04-06
相关资源
最近更新 更多