前几天碰到一个问题,需要使用Winform实现屏幕小键盘,研究了一下,有一个自认为比较完美的解决方案。
屏幕小键盘的实现方式很简单,无非就是在窗体上加上几个按钮,然后在鼠标的点击事件里使用SendKeys.Send函数将按钮代表的字符输入到当前激活的窗口里面。
因此如何保证小键盘窗口永远不会获取鼠标焦点,是实现屏幕小键盘的关键。一般的窗口如果有鼠标在它上面操作的话,那么这个窗口默认就处于激活(Activated)状态,所有的键盘鼠标输入都是被操作系统重定向到桌面上激活(Activated)状态的窗体上。这样就会产生类似下面描述的矛盾:
1. 打开一个Windows程序,比如说notepad.exe。
2. 启动屏幕小键盘程序keyboard.exe。
3. 在keyboard.exe上面点击按钮,这时keyboard.exe处于激活状态—因为它获取到了鼠标焦点。
4. SendKeys.Send函数没有办法把对应的字符输入到notepad.exe里面,因为notepad.exe不能获取鼠标焦点—它不是桌面上处于激活状态的窗口。
为了解决上面的矛盾,Win32 API里面,CreateWindowEx的第一个参数dwExStyle如果设置为WS_EX_NOACTIVATE,那么创建的窗口则不会被操作系统设置为激活状态。因此如果我们能够在创建keyboard.exe的时候,通知Winform函数库将其创建成一个WS_EX_NOACTIVATE就可以了,这就是为什么Winform函数库里面有一个Form.CreateParams这个属性,在从Form类继承下来的窗体中重载这个属性,就可以在Winform创建窗口之前,修改创建参数了。
下面是keyboard.exe小键盘窗口的源代码, 当然在创建这个窗口的时候,最好将窗口的Topmost属性设置为true。
public partial class Form2 : Form { protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= (int)0x08000000L; return cp; } }
public Form2() { InitializeComponent(); }
// 屏幕小键盘上的一个按钮“A” private void button1_Click(object sender, EventArgs e) { SendKeys.Send("A"); } } |