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

C# 實現螢幕鍵盤 ScreenKeyboard(一)——鉤子原理、類型與 NativeMethods API 封裝

     編輯:關於C語言

為何需要全域鉤子

螢幕鍵盤需監聽所有鍵盤事件,無論視窗是否啟用。唯有系統級 (全域) 鉤子能攔截所有執行緒訊息。

鉤子 (Hook) 定義

Windows 訊息處理機制:在訊息到達目標視窗前,鉤子函數先捕獲,可修改/攔截/傳遞訊息。注意:影響系統效能,用畢即卸。

鉤子範圍分類

  • 局部:僅本進程事件
  • 遠端:其他進程事件
    • 執行緒鉤子:特定執行緒
    • 系統鉤子:所有進程所有事件 (螢幕鍵盤需求)

Windows 14 種鉤子類型

本專案使用兩種低階鉤子 (LL = Low Level):

  • WH_KEYBOARD_LL (13):監聽執行緒訊息佇列鍵盤訊息
  • WH_MOUSE_LL (14):監聽執行緒訊息佇列滑鼠訊息

NativeMethods 完整 API 封裝


// NativeMethods.cs
using System;
using System.Runtime.InteropServices;
using System.Drawing;

namespace CnBlogs.Youzai.ScreenKeyboard
{
    [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;
        public const int KEYBOARD = 1;
        public const int HARDWARE = 2;
    }

    internal static class NativeMethods
    {
        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        internal static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        internal static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [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();

        [DllImport("User32.dll", EntryPoint = "GetKeyState", CharSet = CharSet.Auto)]
        internal static extern short GetKeyState(int nVirtKey);

        [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
        internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
    }
}

結構設計亮點

  • Input 結構:LayoutKind.Explicit + FieldOffset(4) 實現聯集,同一記憶體區塊切換鍵盤/滑鼠/硬體輸入
  • SendInput:現代輸入模擬 API,取代舊 keybd_event/mouse_event
  • GetTickCount:提供單調遞增時間戳,系統用於輸入排序
  • SetLastError=false:GetWindowLong/SetWindowLong 不需錯誤碼
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved