自己制作软键盘的几个关键技术解析
来源:互联网 发布:k均值聚类算法 python 编辑:程序博客网 时间:2024/05/16 11:43
在嵌入式应用和一些安全软件中经常需要不通过物理键盘输入,虽然微软提供了也一个软键盘,但这个软件盘不能定制界面不能自动感应当前光标是否处于输入状态,所以有时候我们还是需要自己来实现这个软键盘。本文将讲解自己实现软键盘时涉及到的几个关键技术。
一、浮动窗体的实现
软键盘的窗体和普通窗体不一样,这个窗体在成为当前窗体时,不会影响其它进程的窗体的光标焦点。也就是说虽然这个窗体现在为当前激活的前台窗体,但光标仍然停在其他进程的窗体上。
如上图所示,虽然软键盘在记事本的前面,但光标仍然在记事本上。
要实现这个技术,我们必须要把当前窗体设置为浮动工具条才行。这里我给出 C# Winform 的实现方法:
private const int WS_EX_TOOLWINDOW = 0x00000080;
private const int WS_EX_NOACTIVATE = 0x08000000;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);
cp.Parent = IntPtr.Zero; // Keep this line only if you used UserControl
return cp;
//return base.CreateParams;
}
}
.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
如上代码就是将 Winform 指定为浮动工具条窗体。只要在winform 的类中重载 CreateParams 函数,并按上述代码编写就可以了。
二、如何检测当前处于输入状态
在一些嵌入式设备中,我们没有物理键盘,所有的输入都是通过触摸屏和软键盘输入。那么这个时候,我们必须要做到只有处于输入状态时才弹出软键盘,否则如果软键盘一直在界面上,既不美观也妨碍其他程序的正常使用。
要实现这个功能,我们能想到的最直接的方法是 windows 是否会在当前处于输入状态下时发一个什么事件,或者通过什么钩子程序来实现。但我研究了很久,没有找到这种方法。如果哪位知道这种方法,不妨在回复中告诉我。
我目前找到的方法是定时询问 windows 的当前窗体是否处于输入状态(http://www.my400800.cn)。
IntPtr hWnd = GetForegroundWindow();
uint processId;
uint threadid = GetWindowThreadProcessId(hWnd, out processId);
GUITHREADINFO lpgui = new GUITHREADINFO();
lpgui.cbSize = Marshal.SizeOf(lpgui);
if (GetGUIThreadInfo(threadid, ref lpgui))
{
if (lpgui.hwndCaret != 0)
{
return hWnd;
}
}
如上面代码所示
首先我们通过 GetForegroundWindows API 得到当前窗体的句柄。然后我们再通过 GetGUIThreadInfo 得到当前窗体的一些属性。这些属性在 GUITHREADINFO 中定义
public struct GUITHREADINFO
{
public int cbSize;
public int flags;
public int hwndActive;
public int hwndFocus;
public int hwndCapture;
public int hwndMenuOwner;
public int hwndMoveSize;
public int hwndCaret;
public System.Drawing.Rectangle rcCaret;
}
.csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }上面是 GUITHREADINFO 结构。我们可以通过这个信息得到当前窗体中当前焦点的子窗口句柄,当前获得光标的子窗口句柄,当前正激活的子窗体句柄等等。这里我们只要用到当前获得光标的子窗口句柄,就是 hwndCaret 。如果hwndCaret 不为0,则表示当前窗体处于可输入状态。
相关API函数的 C# 定义如下:
[DllImport("user32.dll")].csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
三、模拟键盘输入
模拟键盘输入比较简单,.Net 提供了一个静态函数来模拟键盘输入
System.Windows.Forms.SendKeys.Send
这个函数很简单,而且微软的帮助也很全面了,我这里就不多说了。
另外我们还可以用更加底层的 API 函数来模拟键盘的输入
[DllImport("user32.dll")].csharpcode pre { margin: 0em; }.csharpcode .rem { color: rgb(0, 128, 0); }.csharpcode .kwrd { color: rgb(0, 0, 255); }.csharpcode .str { color: rgb(0, 96, 128); }.csharpcode .op { color: rgb(0, 0, 192); }.csharpcode .preproc { color: rgb(204, 102, 51); }.csharpcode .asp { background-color: rgb(255, 255, 0); }.csharpcode .html { color: rgb(128, 0, 0); }.csharpcode .attr { color: rgb(255, 0, 0); }.csharpcode .alt { background-color: rgb(244, 244, 244); width: 100%; margin: 0em; }.csharpcode .lnum { color: rgb(96, 96, 96); }
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,
int dwExtraInfo);
这个函数是 keybd_event,关于这个函数的使用,微软的帮助也写的很清楚,这里也不重述了。
- 自己制作软键盘的几个关键技术解析
- C#实现软键盘的几个关键技术介绍
- Qt 软键盘 个人制作的嵌入式软键盘
- Loadrunner的脚本开发几个关键技术
- 精简版系统制作的关键技术
- Linux系统启动盘制作关键技术的探讨
- 学习FLASH制作动画的关键技术点
- Android 软键盘 解析
- 用js制作软键盘
- C#自己编写软键盘
- 软键盘如何加入自己要的按键
- Btrace中的几个关键技术
- 无刷新上传文件的几个关键技术点
- 全面解析Android EditText以及软键盘的设置
- qt creator制作软键盘例子
- 制作自己的控制台
- 制作自己的控制台
- 制作自己的WinRAR
- Javascript全选,反选,全不选 收藏
- code pieces xml parse
- dns rfc 1304 中文
- 网站开发中常用js表单取值方法-很全很好用哦
- (转)深入理解sizeof
- 自己制作软键盘的几个关键技术解析
- 悲催的MSSQL 2 Oracle之旅(一)
- TIFF图像文件格式详解(4)
- Java I/O总结——InputStream
- Java I/O总结——InputStream
- ZOJ1058Currency Exchange
- 嵌入式实时操作系统(RTOS)专题讨论:unlinux,ucOS,VxWorks,ThreadX,Nucleus,eCos,FreeRTOS,uPos...
- Java I/O总结——OutputStream
- 查看sybase字符集和页面大小