今天需要用winform实现小键盘,因为车载电脑没有键盘,所以自己就做一个. 这里参考了这两篇文章,并小记一下.

http://www.cnblogs.com/killmyday/archive/2009/09/11/1564673.html

http://www.pin5i.com/showtopic-27071.html

非常感谢以上两位,这里作下整理.

 

首先引用一段话:

屏幕小键盘的实现方式很简单,无非就是在窗体上加上几个按钮,然后在鼠标的点击事件里使用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");

}

}

但是发现这个时候并不能用,我们需要的是像输入法那种没有焦点的窗体.

这个时候点击button1焦点又回到了新的窗体上.

(后来将Form1的FormBorderStyle设置为 System.Windows.Forms.FormBorderStyle.FixedToolWindow后证实了这一点。焦点的确移到Form1 上)
后来想想,在启动Form1后,强制将焦点切回来后能不能好一点呢,于是,降打开窗体的代码改为.

Form1.Show()
this.Activate()

焦点回来了,当作为第二个页面打开的时候,第一个页面还是保留有焦点,但是当打开第二个页面,再点一次,焦点还是被当前窗体获取到了.

所以需要继续.将当前窗体获取焦点事件取消掉.

添加了一段修改Form的WndProc代码,拦截WM_MOUSEACTIVATE消息,改为MA_NOACTIVATE

完整代码如下:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
//download by http://www.codefans.net
namespace TouchKey
{
public partial class Form1 : Form
{
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATE = 0x0003;

protected override CreateParams CreateParams
{
get
{
CreateParams cp
= base.CreateParams;
cp.ExStyle
|= WS_EX_NOACTIVATE;
return cp;
}

}

protected override void WndProc(ref Message m)
{
//If we're being activated because the mouse clicked on us...
if (m.Msg == WM_MOUSEACTIVATE)
{
//Then refuse to be activated, but allow the click event to pass through (don't use MA_NOACTIVATEEAT)
m.Result = (IntPtr)MA_NOACTIVATE;
}
else
{
base.WndProc(ref m);
}
}

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
lbl_0.Click
+= new EventHandler(lbl_Click);
lbl_1.Click
+= new EventHandler(lbl_Click);
lbl_2.Click
+= new EventHandler(lbl_Click);
lbl_3.Click
+= new EventHandler(lbl_Click);
lbl_4.Click
+= new EventHandler(lbl_Click);
lbl_5.Click
+= new EventHandler(lbl_Click);
lbl_6.Click
+= new EventHandler(lbl_Click);
lbl_7.Click
+= new EventHandler(lbl_Click);
lbl_8.Click
+= new EventHandler(lbl_Click);
lbl_9.Click
+= new EventHandler(lbl_Click);
lbl_Q.Click
+= new EventHandler(lbl_Click);
lbl_W.Click
+= new EventHandler(lbl_Click);
lbl_R.Click
+= new EventHandler(lbl_Click);
lbl_E.Click
+= new EventHandler(lbl_Click);
lbl_T.Click
+= new EventHandler(lbl_Click);
lbl_Y.Click
+= new EventHandler(lbl_Click);
lbl_U.Click
+= new EventHandler(lbl_Click);
lbl_I.Click
+= new EventHandler(lbl_Click);
lbl_O.Click
+= new EventHandler(lbl_Click);
lbl_P.Click
+= new EventHandler(lbl_Click);
lbl_A.Click
+= new EventHandler(lbl_Click);
lbl_S.Click
+= new EventHandler(lbl_Click);
lbl_D.Click
+= new EventHandler(lbl_Click);
lbl_F.Click
+= new EventHandler(lbl_Click);
lbl_G.Click
+= new EventHandler(lbl_Click);
lbl_H.Click
+= new EventHandler(lbl_Click);
lbl_J.Click
+= new EventHandler(lbl_Click);
lbl_K.Click
+= new EventHandler(lbl_Click);
lbl_L.Click
+= new EventHandler(lbl_Click);
lbl_Z.Click
+= new EventHandler(lbl_Click);
lbl_X.Click
+= new EventHandler(lbl_Click);
lbl_C.Click
+= new EventHandler(lbl_Click);
lbl_V.Click
+= new EventHandler(lbl_Click);
lbl_B.Click
+= new EventHandler(lbl_Click);
lbl_N.Click
+= new EventHandler(lbl_Click);
lbl_M.Click
+= new EventHandler(lbl_Click);
lbl_BACKSPACE.Click
+=new EventHandler(lbl_Click);
}



void lbl_Click(object sender, EventArgs e)
{
Label l
= (Label)sender;
string strkey = l.Name.Substring(4);
if (label9.Text == "大写")
{
strkey
= strkey.ToUpper();
}
else
{
strkey
= strkey.ToLower();
}
SendKeys.Send(
"{" + strkey + "}");
}

private void label1_Click(object sender, EventArgs e)
{
Close();
}

private void label9_Click(object sender, EventArgs e)
{
if (label9.Text =="大写")
{
label9.Text
= "小写";
}
else
{
label9.Text
= "大写";
}
}
}
}

 

 

调用代码如下:

private void btnKeybord_Click(object sender, EventArgs e)
{
Form1 f
= new Form1();
tbcontent.Focus();
f.Show();
this.Activate();
}

 

再做了若干测试,发现上面的代码效果,如果要成功,还必不可少的是Form上没有能接受焦点的控件(Button,TextBox等),而且还不能有标题栏。解决的办法,就是去掉Form的标题栏,不使用能接受焦点的控件(或者是改写控件的WndProc过程,拦截接受焦点的消息,使之不能接受焦点)。虽然Form不能接受焦点,但是经过测试,控件还是能接受其他的事件(例如:Click,DoubleClick,MouseHover,MouseLeave 等事件),合理运用的话,还是能产生不错的效果。

概括一下就是 去掉标题栏 this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

             this.TopMost = true;

 

感谢上述两位的奉献.提供源码下载:https://files.cnblogs.com/cyrix/TouchKey.rar

posted on 2010-11-24 19:34  sn_wolf  阅读(1871)  评论(1编辑  收藏  举报