再談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!

糾正:VK_OFF應爲0xDF

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章