全局控制台应用程序的鼠标和键盘控制

本文关键字:键盘 控制 鼠标 控制台 应用程序 全局 | 更新日期: 2023-09-27 18:12:47

有人知道如何做全局控制台应用程序控制器吗?
(这里的控制器是指可以读取当前键盘/鼠标并模拟键盘/鼠标的东西)

注:如果你发现任何重复,我认为他们中的大多数是用于winforms和/或不是全局的,我已经看过了!

全局控制台应用程序的鼠标和键盘控制

Windows Hooks!

windows钩子背后的概念是你的程序将自己插入到操作系统的消息链中,并且可以读取/拦截这些消息。您还可以使用windows钩子发送输入。

windows hooks api是一个c++ api,所以你必须使用一些DLLImports才能在你的项目中获得这些本地方法。像下面。这些是接收消息所需的函数的导入。您还需要导入SendInput函数。

    //Imports for Windows Hooks operations
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern bool UnhookWindowsHookEx(int idHook);
    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);

你还需要一些常量和结构体。

第一个常量将用来告诉SetWindowsHookEx函数你想要一个鼠标钩子或者键盘钩子

    /// <summary>
    /// A lower level mouse hook
    /// </summary>
    public const int WH_MOUSE_LL = 14;
    /// <summary>
    /// A lower level keyboard hook
    /// </summary>
    public const int WH_KEYBOARD_LL = 13;

这些常量将用于识别鼠标正在做什么(点击,移动等)

    /// <summary>
    /// Indicates left mouse button down
    /// </summary>
    public const int WM_LBUTTONDOWN = 0x0201;
    /// <summary>
    /// Indicates left mouse button up
    /// </summary>
    public const int WM_LBUTTONUP = 0x0202;
    /// <summary>
    /// Indicates right mouse button down
    /// </summary>
    public const int WM_RBUTTONDOWN = 0x0204;
    /// <summary>
    /// Indicates the mouse is moving
    /// </summary>
    public const int WM_MOUSEMOVE = 0x0200;

此枚举将允许您识别键盘输入。还有一些本机方法可以为您完成此转换。我可能遗漏了一些关键字,但你可以在MSDN上找到更完整的enum列表。

public enum SystemHotKeys
    {
        [Description("ENTER key")]
        ENTER = 0x0D,
        [Description("SPACEBAR")]
        SPACE = 0x20,
        [Description("DOWN ARROW key")]
        DOWN = 0x28,
        [Description("Numeric keypad 0 key")]
        NUMPAD_ZERO = 0x60,
        [Description("Numeric keypad 1 key")]
        NUMPAD_ONE = 0x61,
        [Description("Numeric keypad 2 key")]
        NUMPAD_TWO = 0x62,
        [Description("Numeric keypad 3 key")]
        NUMPAD_THREE = 0x63,
        [Description("Numeric keypad 4 key")]
        NUMPAD_FOUR = 0x64,
        [Description("Numeric keypad 5 key")]
        NUMPAD_FIVE = 0x65,
        [Description("Numeric keypad 6 key")]
        NUMPAD_SIX = 0x66,
        [Description("Numeric keypad 7 key")]
        NUMPAD_SEVEN = 0x67,
        [Description("Numeric keypad 8 key")]
        NUMPAD_EIGHT = 0x68,
        [Description("Numeric keypad 9 key")]
        NUMPAD_NINE = 0x69,
        [Description("F4 key")]
        F4 = 0x73,
        [Description("F6 key")]
        F6 = 0x75
    }
    public enum WindowsVirtualKey
    {
        [Description("BACKSPACE key")]
        BACKSPACE = 0x08,
        [Description("TAB key")]
        TAB = 0x09,
        [Description("ENTER key")]
        ENTER = 0x0D,
        [Description("SPACEBAR")]
        SPACE = 0x20,
        [Description("LEFT ARROW key")]
        LEFT = 0x25,
        [Description("UP ARROW key")]
        UP = 0x26,
        [Description("RIGHT ARROW key")]
        RIGHT = 0x27,
        [Description("DOWN ARROW key")]
        DOWN = 0x28,
        [Description("0 key")]
        ZERO = 0x30,
        [Description("1 key")]
        ONE = 0x31,
        [Description("2 key")]
        TWO = 0x32,
        [Description("3 key")]
        THREE = 0x33,
        [Description("4 key")]
        FOUR = 0x34,
        [Description("5 key")]
        FIVE = 0x35,
        [Description("6 key")]
        SIX = 0x36,
        [Description("7 key")]
        SEVEN = 0x37,
        [Description("8 key")]
        EIGHT = 0x38,
        [Description("9 key")]
        NINE = 0x39,
        [Description("A key")]
        A = 0x41,
        [Description("B key")]
        B = 0x42,
        [Description("C key")]
        C = 0x43,
        [Description("D key")]
        D = 0x44,
        [Description("E key")]
        E = 0x45,
        [Description("F key")]
        F = 0x46,
        [Description("G key")]
        G = 0x47,
        [Description("H key")]
        H = 0x48,
        [Description("I key")]
        I = 0x49,
        [Description("J key")]
        J = 0x4A,
        [Description("K key")]
        K = 0x4B,
        [Description("L key")]
        L = 0x4C,
        [Description("M key")]
        M = 0x4D,
        [Description("N key")]
        N = 0x4E,
        [Description("O key")]
        O = 0x4F,
        [Description("P key")]
        P = 0x50,
        [Description("Q key")]
        Q = 0x51,
        [Description("R key")]
        R = 0x52,
        [Description("S key")]
        S = 0x53,
        [Description("T key")]
        T = 0x54,
        [Description("U key")]
        U = 0x55,
        [Description("V key")]
        V = 0x56,
        [Description("W key")]
        W = 0x57,
        [Description("X key")]
        X = 0x58,
        [Description("Y key")]
        Y = 0x59,
        [Description("Z key")]
        Z = 0x5A,
        [Description("Numeric keypad 0 key")]
        NUMPAD_ZERO = 0x60,
        [Description("Numeric keypad 1 key")]
        NUMPAD_ONE = 0x61,
        [Description("Numeric keypad 2 key")]
        NUMPAD_TWO = 0x62,
        [Description("Numeric keypad 3 key")]
        NUMPAD_THREE = 0x63,
        [Description("Numeric keypad 4 key")]
        NUMPAD_FOUR = 0x64,
        [Description("Numeric keypad 5 key")]
        NUMPAD_FIVE = 0x65,
        [Description("Numeric keypad 6 key")]
        NUMPAD_SIX = 0x66,
        [Description("Numeric keypad 7 key")]
        NUMPAD_SEVEN = 0x67,
        [Description("Numeric keypad 8 key")]
        NUMPAD_EIGHT = 0x68,
        [Description("Numeric keypad 9 key")]
        NUMPAD_NINE = 0x69,
        [Description("F1 key")]
        F1 = 0x70,
        [Description("F2 key")]
        F2 = 0x71,
        [Description("F3 key")]
        F3 = 0x72,
        [Description("F4 key")]
        F4 = 0x73,
        [Description("F5 key")]
        F5 = 0x74,
        [Description("F6 key")]
        F6 = 0x75,
        [Description("F7 key")]
        F7 = 0x76,
        [Description("F8 key")]
        F8 = 0x77,
        [Description("F9 key")]
        F9 = 0x78,
        [Description("F10 key")]
        F10 = 0x79,
        [Description("F11 key")]
        F11 = 0x7A,
        [Description("F12 key")]
        F12 = 0x7B
    }

你还需要一些结构体来在c++ API和你的代码之间进行通信。

        //Declare the wrapper managed POINT class.
    [StructLayout(LayoutKind.Sequential)]
    public class POINT
    {
        public int x;
        public int y;
    }
    //Declare the wrapper managed MouseHookStruct class.
    [StructLayout(LayoutKind.Sequential)]
    public class MouseHookStruct
    {
        public POINT pt;
        public int hwnd;
        public int wHitTestCode;
        public int dwExtraInfo;
    }

从那里你使用SetWindowsHookEx设置鼠标或键盘的窗口钩子。(你可以一次有多个钩子)你将传入一个委托,它是你的HookProcedure。每当触发windows消息时,将调用此过程。为了使钩子成为一个全局钩子,你将把IntPtr.Zero作为最后一个参数传递给SetWindowsHookEx。这个函数返回一个钩子句柄。你需要保存它,以后用它来解钩。

要停止钩子,您将调用UnhookWindowsHookEx并传入钩子句柄。

既然我们已经讨论了从键盘和鼠标中听到消息,我将讨论发送消息。

您将使用来自相同API的SendInput方法。但是,您将再次需要一些结构体来帮助您进行通信。

        [StructLayout(LayoutKind.Sequential)]
    public struct MOUSEINPUT
    {
        public int dx;
        public int dy;
        public uint mouseData;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBOARDINPUT
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct HARDWAREINPUT
    {
        public uint uMsg;
        public ushort wParamL;
        public ushort wParamH;
    }
    [StructLayout(LayoutKind.Explicit)]
    public struct InputUnion
    {
        [FieldOffset(0)]
        public MOUSEINPUT mi;
        [FieldOffset(0)]
        public KEYBDINPUT ki;
        [FieldOffset(0)]
        public HARDWAREINPUT hi;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct INPUT
    {
        public int type;
        public InputUnion union;
    }

您将用需要发送的信息填充这些结构体。将它们组合在一个InputUnion中,然后将它们放入一个INPUT结构体中发送给系统。或多或少,您将使用与上述相同的常量来告诉键盘或鼠标发送某些信号的内容和位置。然而,不幸的是,这些都是基于x和y坐标的,所以这些坐标应该总是根据应用程序在屏幕上的大小和位置来读取。

钩子API参考可以在这里找到:https://msdn.microsoft.com/en-us/library/windows/desktop/ms632589(v=vs.85).aspx

如何使用钩子的概述可以在这里找到:https://msdn.microsoft.com/en-us/library/windows/desktop/ms644960(v=vs.85).aspx

发送输入引用可以在这里找到:https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx

我希望这对你有帮助!如果你对我的回答有疑问,请随时给我发信息。我用过很多windows钩子。