python中的关键监听器?

Posted

技术标签:

【中文标题】python中的关键监听器?【英文标题】:Key Listeners in python? 【发布时间】:2012-08-08 18:41:43 【问题描述】:

有没有办法在没有像pygame这样的巨大臃肿模块的情况下在python中做关键监听器?

一个例子是,当我按下 a 键时,它会打印到控制台

按下了 a 键!

它还应该监听箭头键/空格键/shift键。

【问题讨论】:

不幸的是,您通常无法检测终端中是否按住了 shift 键。只有当你得到一个受 shift 键影响的角色时才能获得该信息,然后你必须猜测是否按住 shift 来制作该角色。 方向键呢?我知道这在其他一些编程语言中是可能的(即使使用 shift 键!),sigh 哦,好吧 @icktoofay:在Linux上,您可以监控/dev/input/*并直接提取按键。 @Blender:除非你通过 SSH 运行它... @njk828:箭头键是可能的,但很棘手,因为它们是转义序列(通常)。 【参考方案1】:

我正在寻找一个没有窗口焦点的简单解决方案。 Jayk 的回答 pynput 非常适合我。这是我如何使用它的示例。

from pynput import keyboard

def on_press(key):
    if key == keyboard.Key.esc:
        return False  # stop listener
    try:
        k = key.char  # single-char keys
    except:
        k = key.name  # other keys
    if k in ['1', '2', 'left', 'right']:  # keys of interest
        # self.keys.append(k)  # store it in global-like variable
        print('Key pressed: ' + k)
        return False  # stop listener; remove this if want more keys

listener = keyboard.Listener(on_press=on_press)
listener.start()  # start to listen on a separate thread
listener.join()  # remove if main thread is polling self.keys

【讨论】:

pynput 的一个显着限制是它依赖于图形环境,所以在 Linux 上这将是 X。因此它不能在例如远程 VPS 上工作 对于那些想知道的人,您可以在运行循环或 gui 时运行它。尝试在此处的代码末尾添加while True: pass【参考方案2】:

不幸的是,要做到这一点并不容易。如果您正在尝试制作某种文本用户界面,您可能需要查看curses。如果您想像通常在终端中一样显示内容,但又想要这样的输入,那么您将不得不使用termios,不幸的是,它在 Python 中的文档似乎很差。不幸的是,这些选项都不是那么简单。此外,它们不能在 Windows 下工作;如果您需要它们在 Windows 下工作,则必须使用 PDCurses 代替 curses 或 pywin32 而不是 termios


我能够正常工作。它打印出您键入的键的十六进制表示。正如我在您的问题中所说的那样,箭头很棘手;我想你会同意的。

#!/usr/bin/env python
import sys
import termios
import contextlib


@contextlib.contextmanager
def raw_mode(file):
    old_attrs = termios.tcgetattr(file.fileno())
    new_attrs = old_attrs[:]
    new_attrs[3] = new_attrs[3] & ~(termios.ECHO | termios.ICANON)
    try:
        termios.tcsetattr(file.fileno(), termios.TCSADRAIN, new_attrs)
        yield
    finally:
        termios.tcsetattr(file.fileno(), termios.TCSADRAIN, old_attrs)


def main():
    print 'exit with ^C or ^D'
    with raw_mode(sys.stdin):
        try:
            while True:
                ch = sys.stdin.read(1)
                if not ch or ch == chr(4):
                    break
                print '%02x' % ord(ch),
        except (KeyboardInterrupt, EOFError):
            pass


if __name__ == '__main__':
    main()

【讨论】:

你能举一个例子来说明你会做什么来听箭头键吗?这方面的 Python Doc 不是很清楚 @njk828:是的,正如我所说,文档有点稀缺。我发布了一些可以将终端置于正确模式并可以读取原始字符的代码。从那里,您可以尝试找出箭头键的表示方式。 @icktoofay 我认为这仅在您处于终端 rt 上下文中时才有效?否则,如果按键发生在外面......它不会被写入stdin rt? @Prakash047:没错,它只有在你专注于终端窗口时才会起作用。如果您想在其他地方监听按键,则必须研究特定于窗口系统的方法,例如 Linux 上的 X11 或 Wayland。 谢谢,这也适用于 Mac OS。只是对一些不可打印的字符有点麻烦:Esc 读为 0x1B,而另一些也读为 0x1B,后面跟着额外的字符,例如 F1 产生 0x1B 0x4F 0x50,Arrow Up 0x1B 0x5B 0x41,Del (Fn -Mac 键盘上的退格键)0x1B 0x5B 0x33 0x7E。【参考方案3】:

有一种方法可以在 python 中执行关键侦听器。此功能可通过pynput 获得。

命令行:

$ pip install pynput

Python 代码:

from pynput import keyboard
# your code here

【讨论】:

优秀的推荐,因为它是一个非常易于使用和 pythonic 包,但你可以提供一个更清晰的例子。对于任何想了解如何使用它的人,请查看文档:pypi.python.org/pypi/pynput【参考方案4】:

下面是如何在 Windows 上做到这一点:

"""

    Display series of numbers in infinite loop
    Listen to key "s" to stop
    Only works on Windows because listening to keys
    is platform dependent

"""

# msvcrt is a windows specific native module
import msvcrt
import time

# asks whether a key has been acquired
def kbfunc():
    #this is boolean for whether the keyboard has bene hit
    x = msvcrt.kbhit()
    if x:
        #getch acquires the character encoded in binary ASCII
        ret = msvcrt.getch()
    else:
        ret = False
    return ret

#begin the counter
number = 1

#infinite loop
while True:

    #acquire the keyboard hit if exists
    x = kbfunc() 

    #if we got a keyboard hit
    if x != False and x.decode() == 's':
        #we got the key!
        #because x is a binary, we need to decode to string
        #use the decode() which is part of the binary object
        #by default, decodes via utf8
        #concatenation auto adds a space in between
        print ("STOPPING, KEY:", x.decode())
        #break loop
        break
    else:
        #prints the number
        print (number)
        #increment, there's no ++ in python
        number += 1
        #wait half a second
        time.sleep(0.5)

【讨论】:

我写的循环有点不同。 while True:换行x = kbfunc()换行if x != False:换行print("keypress:", x.decode())。这对我来说很有效。我想知道您是否知道如何让终端监视未聚焦时发生的按键操作。【参考方案5】:

键盘

sudo pip install keyboard https://github.com/boppreh/keyboard

使用这个小型 Python 库完全控制您的键盘。挂钩全局事件、注册热键、模拟按键等等。

所有键盘上的全局事件挂钩(无论焦点如何都捕获键)。 监听并发送键盘事件。 适用于 Windows 和 Linux(需要 sudo),具有实验性 OS X 支持(感谢@glitchassassin!)。 纯 Python,无需编译 C 模块。 零依赖。安装和部署很简单,只需复制文件即可。 Python 2 和 3。 具有可控超时的复杂热键支持(例如 Ctrl+Shift+M、Ctrl+Space)。 包括高级 API(例如录制和播放、add_abbreviation)。 映射键实际上在您的布局中,具有完整的国际化支持(例如 Ctrl+ç)。 在单独的线程中自动捕获事件,不会阻塞主程序。 测试并记录在案。 不会破坏带重音的死键(我在看着你,pyHook)。 通过项目鼠标(pip install mouse)提供鼠标支持。

来自README.md:

import keyboard

keyboard.press_and_release('shift+s, space')

keyboard.write('The quick brown fox jumps over the lazy dog.')

# Press PAGE UP then PAGE DOWN to type "foobar".
keyboard.add_hotkey('page up, page down', lambda: keyboard.write('foobar'))

# Blocks until you press esc.
keyboard.wait('esc')

# Record events until 'esc' is pressed.
recorded = keyboard.record(until='esc')
# Then replay back at three times the speed.
keyboard.play(recorded, speed_factor=3)

# Type @@ then press space to replace with abbreviation.
keyboard.add_abbreviation('@@', 'my.long.email@example.com')
# Block forever.
keyboard.wait()

【讨论】:

“为避免依赖 X,Linux 部分读取原始设备文件 (/dev/input/input*),但这需要 root。”遗憾的是,这不适用于许多日常工具……【参考方案6】:

虽然我喜欢使用键盘模块来捕获键盘事件,但我不喜欢它的record() 函数,因为它返回一个类似[KeyboardEvent("A"), KeyboardEvent("~")] 的数组,我觉得它有点难以阅读。所以,为了记录键盘事件,我喜欢同时使用键盘模块和线程模块,像这样:

import keyboard
import string
from threading import *


# I can't find a complete list of keyboard keys, so this will have to do:
keys = list(string.ascii_lowercase)
"""
Optional code(extra keys):

keys.append("space_bar")
keys.append("backspace")
keys.append("shift")
keys.append("esc")
"""
def listen(key):
    while True:
        keyboard.wait(key)
        print("[+] Pressed",key)
threads = [Thread(target=listen, kwargs="key":key) for key in keys]
for thread in threads:
    thread.start()

【讨论】:

以上是关于python中的关键监听器?的主要内容,如果未能解决你的问题,请参考以下文章

如何实现关键监听器?

如何在java的后台运行这个关键监听器

关键监听器工作不正常

Java中的事件监听器没有应用程序有焦点? (全局按键检测)

Python 键盘监听器

Vue 组件中的关键事件不会触发