再谈Windows Mobile上的模拟按键操作

   

再谈Windows Mobile上的模拟按键操作

摘要:本文总结了如何在Windows Mobile上实现模拟按键的操作,并阐述了通过模拟按键我们可以实现的种种有意义的应用。
Keywords
Windows Mobile, keybd_event, .Net Compact Framework, keystroke

Windows CE /Windows Mobile的键盘消息处理方式和桌面版本的Windows大体相同。当一个键被按下的时候,OS会发送一系列的消息给焦点窗体。通常首先是一个WM_KEYDOWN消息,如果按下的键代表的是一个字符或者数字,Windows会接着发送一个WM_CHAR的消息。当键被释放(松开)的时候,Windows会发送一个WM_KEYUP的消息。如果一个键被一直按着到足够长的时间(足以被OS认定为自动重复模式),则会在释放前重复发送WM_KEYDOWN和WM_CHAR的消息。

Tips一些功能键和鼠标键是不代表任何字符和数字的,这时需要在按键时由程序截获WM_KEYDOWN消息来获知按键信息。当然,目前对于Windows Mobile的大部分设备,并没有鼠标键和诸多功能键的实现。此外,当Alt键被按住的时候,如果有其他键被按下,则前面提到的消息分别会是:WM_SYSKEYDOWN, WM_SYSCHAR和WM_SYSKEYUP。

之前的一些随笔中曾用到过在Windows Mobile如何实现模拟按键的方法,比如:

http://www.cnblogs.com/fox23/archive/2008/02/19/1069059.html

http://www.cnblogs.com/fox23/archive/2008/04/27/windowsmobile-compactframework-speaker-csharp.html

现在可以来总结一下在Windows Mobile上面模拟按键是一件多么有趣的事情了。

在前面的两篇文章里面都提到了keybd_event这个函数,在Windows CE SDK中我们可以找到它,从文档中可以看到这个函数能产生WM_KEYUP 或 WM_KEYDOWN的消息。也就是说你可以将按键的信息广播至整个系统。

该函数定义如下:

VOID keybd_event (BYTE bVk, //VK键值

BYTE bScan, 
//WinCE下通常设为0

DWORD dwFlags, 
//按键状态标示

DWORD dwExtraInfo
//WinCE下通常设为0

);

参数的含义文档上已经做了说明,这里不再赘述。在前面文章用过的例子中可以看到,要模拟一次按键行为,需要调用keybd_event两次(如果是组合按键的话将会是2n次)。第一次是按下键,只需传递一个键值和一个非KEYEVENTF_KEYUP的状态(一般是KEYEVENTF_KEYDOWN)。第二次是传递该键值和KEYEVENTF_KEYUP标志,表示松开按键。这里还有一个常用的状态标志是使用KEYEVENTF_SILENT0x4)标志,表示模拟击键而不产生常规按键时敲击的“嘟”声音。

 

Tips 关于Windows Mobile/Windows CE常见的VK键值表可以参考:

http://www.cnblogs.com/fox23/archive/2008/02/01/1061906.html

http://msdn.microsoft.com/en-us/library/ms927178.aspx

http://msdn.microsoft.com/en-us/library/bb431750.aspx

以下是使用模拟按键的一些有趣示例:

1.     将应用程序放置到后台

在 SmartPhone上面有时候我们也想实现在PPC上面一样的最小化功能,可惜SmartPhone的Form上没有那个“X”可以点击。所以,你想把程序挪到后台的话就得按下回退键(通常是红色的)。我们可以通过在程序中模拟按键的方式来实现。你需要做的只是把VK_ESC 键(0x1B)送给 keybd_event。

2.     在程序中调用今日屏幕(Today Screen)

实际上就是模拟按下”Home”键。对应的键是VK_F4,对应的键值是0x73。

3.     锁定键盘

如果你想锁定你的设备,就像它待机一定时间之后做的一样,你同样可以通过模拟按键的方式来实现。在Smartphone上面你需要使用VK_APP6 键(0xC6)。在Pocket PC上面需要用VK_F22或者VK_KEYLOCK键(键值均为0x85)。

在Windows Mobile 6.0及其以后的设备上要方便一些,直接可以使用API 函数SHDeviceLockAndPrompt来实现锁和解锁的状态切换。

Tips VK_APP系列键并没有在Windows Embedded CE中定义,是Windows Mobile特有的。VK_APP键只有在被VK_LWIN键“包装”后才能正常使用,其用法如下:

keybd_event(VK_LWIN, 0, KEYEVENTF_SILENT, 0);
GenKeyEvent(VK_APP6);
keybd_event(VK_LWIN, 
0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);

4.     防止设备进入休眠或者锁住的状态

当你在浏览网页或者看电子书的时候,尤其是如果你的显示屏比较大,当你正看得欢的时候突然屏幕被锁住了,这的确是一件令人郁闷的事。好在你可以通过模拟按键来避免这种情况发生,有按键的行为发生相当于告知了你的设备你你还在忙,你还需要它工作。不过我们应该模拟按下哪个键呢?按下哪个键可以不影响用户的使用,不影响用户的输入呢?显然,模拟数字,字符或者常见键盘操作键都似不可取的。如果你认为可以是shift或者caps-lock之类的,那就更不对了。因为一旦你模拟的按键是它们的话很可能你在程序中的输入会变成“lIkE tHiS”大小写不一。好在我们可以在VK表中找到这样一个键: VK_NONAME (0xFC)。他是一个不做任何实质性操作的保留键,也就是我们想要的。

5.     关闭设备

恩,没想到阿没想到,还可以模拟按键来关闭设备。只需要模拟按下VK_OFF (0xDF)就可以在SmartPhone上面实现软启动,在Pocket PC上面实现关闭屏幕。

(关于编程重启Windows Mobile设备可以参考老马的文章:http://blog.csdn.net/aawolf/archive/2008/02/07/2086199.aspx)

6.打开扬声器

    这是我之前的文章中用到的,你只需要发送VK_F16 键(0x7F)的按键消息即可。

7.     组合按键

组合按键无非是先按下一些键,再松开一些键,下面的例子演示了如何按下shift+2组合键:

//按下键

keybd_event(VK_SHIFT, 
0xAA,  00);

keybd_event(
20x830 ,0);

//松开键

keybd_event(VK_SHIFT,
0xAA , KeyUp,  0);

keybd_event(
20x83, KeyUp , 0);

好了,纸上谈兵了一会儿,最后我们来看看代码吧。

 

下面这个很简单的类封装了keybd_event,并提供了一个Sendkey的函数供调用,可以完成上述的所有功能,该类仅仅用到了p/invoke兼容.Net Compact Frame work 1.0到现在的所有版本:

using System.Runtime.InteropServices;



public class SystemCalls

{

//更多按键请参考 http://msdn2.microsoft.com/en-us/library/ms927178.aspx

    
public const byte VK_NONAME = 0xFC// 什么也不做

    
public const byte VK_ESC     = 0x1B// Smartphone的回退键

    
public const byte VK_F4      = 0x73// Home Screen

    
public const byte VK_APP6    = 0xC6// Smartphone上锁定键盘

    
public const byte VK_F22     = 0x85// PocketPC上锁定键盘 (VK_KEYLOCK)

    
public const byte VK_F16     = 0x7F// 出发扬声器

public const byte VK_OFF     = 0x7F//电源键

    
/// <summary>

    
/// 将按键送至全局键盘缓冲区

    
/// </summary>

    
/// <param name="key"></param>


    
public static void SendKey(byte key)

{

  
//const byte KEYEVENTF_SILENT = 0x0004;

        
const int KEYEVENTF_KEYUP = 0x02;

        
const int KEYEVENTF_KEYDOWN = 0x00;

        keybd_event(key, 
0, KEYEVENTF_KEYDOWN, 0);

        keybd_event(key, 
0, KEYEVENTF_KEYUP, 0);

    }


    [DllImport(
"coredll", SetLastError = true)]

    
private static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

}

使用方法:

 

SystemCalls.SendKey(SystemCalls.VK_F22);

Enjoy it!

黄季冬<fox23>

纠正:VK_OFF应为0xDF

 

posted on 2008-06-04 16:12  J.D Huang  阅读(8098)  评论(9编辑  收藏