首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 使用全域鉤子實作螢幕鍵盤(五):模擬鍵盤輸入與按鈕整合

     編輯:關於C語言

前言

前四篇已完成全域鍵盤鉤子的安裝、攔截與卸載。本文將示範如何透過 SendInput API 模擬鍵盤輸入,並整合自訂 KeyboardButton 控制項,完成一個功能完整的螢幕鍵盤。

模擬鍵盤按下與釋放

private void SendKeyDown(short vkCode)
{
    var input = new Input[1];
    input[0].type = INPUT.KEYBOARD;
    input[0].ki.wVk = vkCode;
    input[0].ki.time = NativeMethods.GetTickCount();

    if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
        throw new Win32Exception(Marshal.GetLastWin32Error());
}

private void SendKeyUp(short vkCode)
{
    var input = new Input[1];
    input[0].type = INPUT.KEYBOARD;
    input[0].ki.wVk = vkCode;
    input[0].ki.dwFlags = KeyboardConstaint.KEYEVENTF_KEYUP;
    input[0].ki.time = NativeMethods.GetTickCount();

    if (NativeMethods.SendInput((uint)input.Length, input, Marshal.SizeOf(input[0])) < input.Length)
        throw new Win32Exception(Marshal.GetLastWin32Error());
}

按鈕點擊事件處理

private void ButtonOnClick(object sender, EventArgs e)
{
    var btn = sender as KeyboardButton;
    if (btn == null) return;
    SendKeyCommand(btn);
}

private void SendKeyCommand(KeyboardButton btn)
{
    short vk = btn.VKCode;
    // 修飾鍵(Shift, Ctrl, Alt)需切換狀態
    if (combinationVKButtonsMap.ContainsKey(vk))
    {
        if (btn.Checked) SendKeyUp(vk);
        else SendKeyDown(vk);
    }
    else
    {
        // 一般鍵:按下後立即釋放
        SendKeyDown(vk);
        SendKeyUp(vk);
    }
}

關鍵結構體定義(NativeMethods.cs)

[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT { public int dx, dy, mouseData, dwFlags, time; public IntPtr dwExtraInfo; }

[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT { public short wVk, wScan; public int dwFlags, time; public IntPtr dwExtraInfo; }

[StructLayout(LayoutKind.Explicit)]
internal struct Input
{
    [FieldOffset(0)] public int type;
    [FieldOffset(4)] public MOUSEINPUT mi;
    [FieldOffset(4)] public KEYBDINPUT ki;
    [FieldOffset(4)] public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT { public int uMsg; public short wParamL, wParamH; }

internal static class INPUT { public const int MOUSE = 0, KEYBOARD = 1, HARDWARE = 2; }

internal static class NativeMethods
{
    [DllImport("User32.dll", EntryPoint = "SendInput", CharSet = CharSet.Auto)]
    internal static extern UInt32 SendInput(UInt32 nInputs, Input[] pInputs, Int32 cbSize);

    [DllImport("Kernel32.dll", EntryPoint = "GetTickCount", CharSet = CharSet.Auto)]
    internal static extern int GetTickCount();
    // ... 其他 API 宣告
}

UI 設計建議

  • 使用 Visual Studio 或 SharpDevelop 設計鍵盤佈局(QWERTY、數字鍵盤等)。
  • 自訂 KeyboardButton 繼承 Button,增加 VKCode、Checked 屬性。
  • 修飾鍵按鈕設定 Appearance 視覺回饋(按下狀態)。
  • 所有按鈕共用同一 Click 事件處理器 ButtonOnClick。

注意事項

  • SendInput 需正確填寫 cbSize(單一 Input 結構大小),否則呼叫失敗。
  • 虛擬鍵碼 VKCode 需對應 Keys 列舉值(如 Keys.A = 0x41)。
  • 全域鉤子會影響系統效能,僅在必要時啟用,用畢立即卸載(見第 4 篇)。
  • 部分安全軟體可能攔截 SendInput,需測試相容性。

結語

結合低層鉤子攔截與 SendInput 模擬輸入,即可打造功能完整的螢幕鍵盤。本系列涵蓋從理論到實作的完整路徑,可作為無障礙輸入、自動化測試等專案的基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved