3

有时晚上,我喜欢在床上看电影,或者上网看电视节目。这很方便,因为我的电脑就在我的桌子旁边,所以我只需旋转我的一个显示器,禁用我的另一个屏幕并将鼠标拉到上面。如果不重新布置电缆,我的键盘就不能完全够到,这种方式在我第二天搬回办公桌时不起作用。有时我在看电影时,我的朋友试图跟我说话,而我希望能够在不跳起来、旋转显示器、将鼠标移回并重新坐在椅子上的情况下回话。

我想做的是制作一个与鼠标一起使用的屏幕键盘——但采用 T9 电话键盘样式,以(希望)最大限度地减少点击次数和移动鼠标的数量,从而丢失目标。我想在 Python 中执行此操作,因为我已经熟悉该语言,但我不确定从哪里开始。

我不确定的一件事是如何在不从聊天窗口中窃取焦点的情况下单击屏幕键盘。这可以实现吗?或者应用程序可以记住最后一个焦点窗口中的最后一个焦点控件并将击键发送给它吗?

另外,我需要一个外部库来执行任何窗口管理和击键发送吗?

非常感谢您的帮助,如果这样的事情已经存在(以任何语言),将我指向它也将不胜感激。

如果我开发它,我肯定会开源它并在此处发布该项目的链接,以防其他人会发现这种东西很有用:)

4

1 回答 1

3

大约 12 年前,我为 Windows 编写了一个程序,该程序位于托盘中,当它们获得焦点时会向某些窗口发送击键。我不再有代码,我忘记了所有细节。

尽管如此,这个过程还是会像这样工作。

对于您的 GUI,如果使用 Python,您可能希望使用 PyQT 或 wxPython。这两个库都使编写 GUI 应用程序变得容易(尽管您可以直接使用 Windows API)。

不过,如果是我,我会推迟 GUI 编程并使用 PythonWin。使用它的 GUI 工具(源代码中有很多示例)创建一个简单的对话框(也是一个Window)来进行事件处理。

您的应用程序可能有几种方法可以选择target窗口。虚拟键盘窗口可能必须窃取焦点(以接收鼠标事件),但它需要知道将击键发送到哪个窗口。

  • 您可以在对话框中有一个下拉控件,允许您选择目标窗口(您可以轻松获取每个窗口的标题以进行目标选择),或者
  • 当您的窗口获得焦点时(您可以捕获一个事件,例如WM_FOCUS),您可以查询最后一个具有焦点的窗口,也可以密切关注哪些窗口具有焦点并使用您注意到的最后一个。

在任何一种情况下,一旦您有了目标窗口的句柄,您就可以使用SendMessage将击键发送到目标窗口。我建议一开始只转发常规击键,然后再担心捕获鼠标点击。

编辑我能够将它拼凑在一起以将击键发送到另一个窗口。

import win32ui
import win32con
import time
from ctypes import *

PUL = POINTER(c_ulong)
class KeyBdInput(Structure):
    _fields_ = [("wVk", c_ushort),
                ("wScan", c_ushort),
                ("dwFlags", c_ulong),
                ("time", c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(Structure):
    _fields_ = [("uMsg", c_ulong),
                ("wParamL", c_short),
                ("wParamH", c_ushort)]

class MouseInput(Structure):
    _fields_ = [("dx", c_long),
                ("dy", c_long),
                ("mouseData", c_ulong),
                ("dwFlags", c_ulong),
                ("time",c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(Structure):
    _fields_ = [("type", c_ulong),
                ("ii", Input_I)]

def send_char(char):
    FInputs = Input * 1
    extra = c_ulong(0)
    ii_ = Input_I()
    KEYEVENTF_UNICODE = 0x4
    ii_.ki = KeyBdInput( 0, ord(char), KEYEVENTF_UNICODE, 0, pointer(extra) )
    x = FInputs( ( 1, ii_ ) )
    windll.user32.SendInput(1, pointer(x), sizeof(x[0]))

if __name__ == '__main__':
    wnd = win32ui.FindWindow(None, '* Untitled - Notepad2 (Administrator)')
    type_this = 'jaraco'
    wnd.SetFocus()
    wnd.SetForegroundWindow()
    for char in type_this:
        send_char(char)

我发现 PostMessage 技术并不能很好地工作(我根本无法让它为我工作)。

我还发现了这篇关于识别最后一个活动窗口的文章。

于 2010-07-03T14:35:30.303 回答