【问题标题】:How to make pynput prevent certain keystrokes from reaching a particular application?如何使 pynput 防止某些击键到达特定应用程序?
【发布时间】:2020-07-11 20:37:22
【问题描述】:

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

例如,如果

  • 当前模式为Command模式和
  • 用户按下按钮w

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

为了实现这一点,我编写了以下代码(基于这两个答案: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()

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

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

这有点工作,但您可以看到w 字符再次显示和删除(请参阅this video)。

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

【问题讨论】:

  • 一个(低级)键盘钩子可以过滤掉输入,并防止它被传递到前台线程。即使您使用 pynput 解决了这个问题,您仍然必须处理此解决方案的 基本 缺陷(例如,确保内部状态实际上与目标应用程序的模式匹配,或正确处理键盘输入如 Ctrl+Insert 或 Shift+w)。
  • @IInspectable Re内部状态实际上与目标应用程序的模式匹配:目标应用程序没有模式。该模式仅存在于我的 Python 应用程序中

标签: python winapi pynput


【解决方案1】:

首先你需要安装 pyHook 和 pywin32 库。

然后通过pyhook监听键盘信息。如果需要截取键盘信息(比如按w),返回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() 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 2020-09-23
    • 2019-12-07
    • 1970-01-01
    • 2015-05-14
    • 2019-06-20
    • 1970-01-01
    相关资源
    最近更新 更多