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

时间:2010-07-03 09:38:10

标签: python windows windows-7 soft-keyboard

有时晚上,我喜欢在床上看电影,或在网上看电视。这很方便,因为我的电脑就在我的桌子旁边,所以我只是旋转我的一个显示器,禁用我的另一个屏幕并将鼠标拉过来。如果没有重新布线,当我第二天搬回办公桌时,我的键盘无法正常工作。有时我正在看电影的时候,我的朋友们试着和我说话,我希望能够在没有跳起来的情况下进行对话,旋转显示器,将鼠标移回原位并再次坐在椅子上。

我想做的是让屏幕键盘与鼠标一起使用 - 但是采用T9手机键盘样式(希望)最大限度地减少点击次数和移动鼠标的数量,目标。我想用Python做这个,因为我已经熟悉这门语言,但我不知道从哪里开始。

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

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

非常感谢帮助,如果这种事情已经存在(用任何语言),那么指向我也会非常感激。

我肯定会开源并在此处发布项目链接,如果我开发它,那么其他任何人都会发现这类事情很有用:)

1 个答案:

答案 0 :(得分:3)

大约12年前,我写了一个Windows程序,它坐在托盘中,当他们获得焦点时会向某些窗口发送击键。我不再拥有代码,而且我已经忘记了所有细节。

尽管如此,这个过程仍然有效。

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

如果是我,我会推迟GUI编程并使用PythonWin。使用其GUI工具(源代码中的大量示例)创建一个简单的对话框(也是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上找到了这篇文章。