C# - 全局控制台应用程序鼠标和键盘控制?

时间:2015-09-15 18:38:14

标签: c# keyboard console-application mouse

任何人都知道如何操作全局控制台应用程序控制器?
(通过控制器,我的意思是可以读取当前键盘/鼠标并模拟键盘/鼠标)

P.S。:如果您发现任何重复,我认为其中大部分用于winforms和/或不是全球性的,我看了!

1 个答案:

答案 0 :(得分:2)

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上找到更完整的枚举列表。

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坐标的所有坐标,因此应始终根据屏幕上应用程序的大小和位置来读取这些坐标。

可以在此处找到Hooking 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钩子。