作者:eaglet
轉(zhuǎn)載請注明出處
在嵌入式應(yīng)用和一些安全軟件中經(jīng)常需要不通過物理鍵盤輸入,雖然微軟提供了也一個軟鍵盤,但這個軟件盤不能定制界面不能自動感應(yīng)當(dāng)前光標(biāo)是否處于輸入狀態(tài),所以有時候我們還是需要自己來實現(xiàn)這個軟鍵盤。本文將講解自己實現(xiàn)軟鍵盤時涉及到的幾個關(guān)鍵技術(shù)。
一、浮動窗體的實現(xiàn)
軟鍵盤的窗體和普通窗體不一樣,這個窗體在成為當(dāng)前窗體時,不會影響其它進(jìn)程的窗體的光標(biāo)焦點。也就是說雖然這個窗體現(xiàn)在為當(dāng)前激活的前臺窗體,但光標(biāo)仍然停在其他進(jìn)程的窗體上。
如上圖所示,雖然軟鍵盤在記事本的前面,但光標(biāo)仍然在記事本上。
要實現(xiàn)這個技術(shù),我們必須要把當(dāng)前窗體設(shè)置為浮動工具條才行。這里我給出 C# Winform 的實現(xiàn)方法:
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; } }
如上代碼就是將 Winform 指定為浮動工具條窗體。只要在winform 的類中重載 CreateParams 函數(shù),并按上述代碼編寫就可以了。
二、如何檢測當(dāng)前處于輸入狀態(tài)
在一些嵌入式設(shè)備中,我們沒有物理鍵盤,所有的輸入都是通過觸摸屏和軟鍵盤輸入。那么這個時候,我們必須要做到只有處于輸入狀態(tài)時才彈出軟鍵盤,否則如果軟鍵盤一直在界面上,既不美觀也妨礙其他程序的正常使用。
要實現(xiàn)這個功能,我們能想到的最直接的方法是 windows 是否會在當(dāng)前處于輸入狀態(tài)下時發(fā)一個什么事件,或者通過什么鉤子程序來實現(xiàn)。但我研究了很久,沒有找到這種方法。如果哪位知道這種方法,不妨在回復(fù)中告訴我。
我目前找到的方法是定時詢問 windows 的當(dāng)前窗體是否處于輸入狀態(tài)。
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 得到當(dāng)前窗體的句柄。然后我們再通過 GetGUIThreadInfo 得到當(dāng)前窗體的一些屬性。這些屬性在 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; }
上面是 GUITHREADINFO 結(jié)構(gòu)。我們可以通過這個信息得到當(dāng)前窗體中當(dāng)前焦點的子窗口句柄,當(dāng)前獲得光標(biāo)的子窗口句柄,當(dāng)前正激活的子窗體句柄等等。這里我們只要用到當(dāng)前獲得光標(biāo)的子窗口句柄,就是 hwndCaret 。如果hwndCaret 不為0,則表示當(dāng)前窗體處于可輸入狀態(tài)。
相關(guān)API函數(shù)的 C# 定義如下:
[DllImport("user32.dll")] [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 提供了一個靜態(tài)函數(shù)來模擬鍵盤輸入
System.Windows.Forms.SendKeys.Send
這個函數(shù)很簡單,而且微軟的幫助也很全面了,我這里就不多說了。
另外我們還可以用更加底層的 API 函數(shù)來模擬鍵盤的輸入
[DllImport("user32.dll")] static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
這個函數(shù)是 keybd_event,關(guān)于這個函數(shù)的使用,微軟的幫助也寫的很清楚,這里也不重述了。

浙公網(wǎng)安備 33010602011771號