简体   繁体   English

如何使 pynput 防止某些击键到达特定应用程序?

[英]How to make pynput prevent certain keystrokes from reaching a particular application?

I want to create a tool which will allow me to use some of the Vim-style commands in an application ( Scrivener ) that does not support it.我想创建一个工具,允许我在不支持它的应用程序( Scrivener )中使用一些 Vim 风格的命令。

For example, if例如,如果

  • the current mode is Command mode and当前模式是Command模式和
  • the user presses the button w ,用户按下按钮w

then, the caret should move one character to the right.然后,插入符号应该向右移动一个字符。 Instead of the w character, Scrivener should receive the "right arrow" signal. Scrivener 应该接收“右箭头”信号,而不是w字符。

To implement this, I wrote the following code (based on these 2 answers: 1 , 2 ):为了实现这一点,我编写了以下代码(基于这两个答案: 12 ):

from pynput.keyboard import Key, Listener, Controller
from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer

def getForegroundWindowTitle() -> Optional[str]:
    hWnd = windll.user32.GetForegroundWindow()
    length = windll.user32.GetWindowTextLengthW(hWnd)
    buf = create_unicode_buffer(length + 1)
    windll.user32.GetWindowTextW(hWnd, buf, length + 1)
    if buf.value:
        return buf.value
    else:
        return None

class State:
    def __init__(self):
        self.mode = "Command"

state = State()
keyboard = Controller()

def on_press(key):
    pass

def on_release(key):
    if key == Key.f12:
        return False
    window_title = getForegroundWindowTitle()
    if not window_title.endswith("Scrivener"):
        return
    print("Mode: " + state.mode)
    print('{0} release'.format(
        key))
    if state.mode == "Command":
        print("1")
        if str(key) == "'w'":
            print("2")
            print("w released in command mode")
            # Press the backspace button to delete the w letter
            keyboard.press(Key.backspace)
            # Press the right arrow button
            keyboard.press(Key.right)
    if key == Key.insert:
        if state.mode == "Command":
            state.mode = "Insert"
        else:
            state.mode = "Command"

# Collect events until released
print("Press F12 to exit")

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

Whenever I press the button w in Scrivener in Command mode, two keystrokes are sent to Scrivener:每当我在命令模式下按下 Scrivener 中的按钮w时,都会向 Scrivener 发送两次击键:

  1. Backspace to delete the already typed w character.退格删除已经输入的w字符。
  2. Right arrow to move the caret.向右箭头移动插入符号。

This kinda works, but you can see the w character being displayed and deleted again (see this video ).这有点工作,但您可以看到w字符再次显示和删除(请参阅此视频)。

How can I make sure that the keystroke with w does not reach Scrivener at all, if the mode is Command and currently focused window is the Scrivener application?如果模式是Command并且当前关注的 window 是 Scrivener 应用程序,我如何确保带有w的击键根本不会到达 Scrivener?

First you need to install pyHook and pywin32 library.首先你需要安装 pyHook 和 pywin32 库。

Then monitor the keyboard information through pyhook.然后通过pyhook监听键盘信息。 If you need to intercept the keyboard information (for example, press w), return False.如果需要截取键盘信息(例如按w),返回False。

Finally, through pythoncom.PumpMessages () to achieve loop monitoring.最后通过pythoncom.PumpMessages()实现循环监控。 Here is the sample:这是示例:

import pyHook
import pythoncom
from pynput.keyboard import Key, Listener, Controller
keyboard = Controller()
def onKeyboardEvent(event):
    if event.Key == "F12":
        exit()
    print("1")
    if event.Key == 'W':
        print("2")
        print("w released in command mode")
        # Press the right arrow button
        keyboard.press(Key.right)
        return False

    print("hook" + event.Key)
    return True

# Collect events until released
print("Press F12 to exit")
hm = pyHook.HookManager()
hm.KeyDown = onKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages() 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM