代码之家  ›  专栏  ›  技术社区  ›  Carson Myers

如何为Windows制作T9风格的屏幕键盘?

  •  3
  • Carson Myers  · 技术社区  · 15 年前

    有时候晚上,我喜欢在床上看电影,或者在网上看电视节目。这很方便,因为我的电脑就在我的办公桌旁边,所以我只需旋转一个显示器,禁用另一个屏幕,然后把鼠标拉过来。如果不重新布线的话,我的键盘就够不着了,第二天我搬回办公桌时,这种方式就不起作用了。有时我在看电影的时候,我的朋友试着和我说话,我希望能够顶嘴而不跳起来,不旋转显示器,不向后移动鼠标,不坐在椅子上。

    我想做的是做一个屏幕上的键盘与鼠标一起使用,但在T9手机键盘风格(希望)尽量减少点击次数和移动鼠标的数量,丢失目标。我想用Python来做这件事,因为我已经熟悉Python语言了,但是我不知道从哪里开始。

    有一件事我不确定,那就是如何点击屏幕上的键盘而不从聊天窗口窃取焦点。这能做到吗?或者应用程序能否记住最后一个聚焦窗口中的最后一个聚焦控件并向其发送击键?

    另外,我是否需要一个外部库来进行窗口管理和按键发送?

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

    1 回复  |  直到 15 年前
        1
  •  3
  •   Community Mohan Dere    8 年前

    大约12年前,我为托盘中的Windows编写了一个程序,当某些Windows获得焦点时,它会向它们发送击键。我已经没有密码了,我忘记了所有的细节。

    不过,这个过程还是会像这样运作的。

    Window )执行事件处理。

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

    • 当你的窗口获得焦点时(有一个事件你可以捕捉,比如 WM_FOCUS ),您可以查询具有焦点的最后一个窗口,也可以 keep tabs on which windows have 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技术效果不太好(我根本无法让它为我工作)。

    我在网上也发现了这篇文章 identifying the last active window .