今天需要用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