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

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

我想创建一个工具,允许我在不支持它的应用程序 (Scrivener) 中使用一些 Vim 风格的命令。

例如,如果

那么,插入符号应该向右移动一个字符。 Scrivener 应该收到“右箭头”信号,而不是 w 字符。

为了实现这一点,我编写了以下代码(基于这 2 个答案:1, 2):

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()

每当我在命令模式下按下 Scrivener 中的按钮 w 时,都会向 Scrivener 发送两次击键:

  1. 退格键删除已输入的 w 个字符。
  2. 向右箭头移动插入符号。

这有点管用,但您可以看到 w 字符再次显示并被删除(参见 this video)。

如果模式是 Command 并且当前聚焦 window 是 Scrivener 应用程序,我如何确保使用 w 的击键根本不会到达 Scrivener?

首先需要安装pyHook和pywin32库

然后通过pyhook监听键盘信息。如果需要截取键盘信息(比如按w),return False.

最后通过pythoncom.PumpMessages()实现循环监控。 这是示例:

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()