简体   繁体   中英

C# - Global console application mouse and keyboard control?

Anyone has an idea how to do global and console apllication controller?
(By controller I mean something that can read current keyboard/mouse and simulate keyboard/mouse)

PS: If you find any duplicates I think that most of them is used for winforms and/or not global, I've looked!

Windows Hooks !

The concept behind a windows hook is that your program inserts itself into the message chain of the OS and can read/intercept those messages. You can also send inputs using windows hooks.

The windows hooks api is a C++ API so you will have to use some DLLImports to get these native methods in your project. Like below. These are the imports for the functions you will need to receive the messages. You'll also need to import the SendInput function.

    //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);

You'll also need some constants and structs.

These first constants will be used to tell the SetWindowsHookEx functions that you want a mouse hook or keyboard hook respectively

    /// <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;

These constants will be used to identify what the mouse is doing (clicking, moving, etc.)

    /// <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;

This enum will allow you to identify keyboard input. There are also native methods to do this conversion for you. I may be missing some of the keys but you can find a more complete enum list on 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
    }

You will also need some structs to be able to communicate between the C++ API and your code.

        //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;
    }

From there you use the SetWindowsHookEx to set a windows hook of either mouse or keyboard. (you can have more than one hook at a time) You will pass in a delegate that is your HookProcedure. This procedure will be called whenever a windows message is fired. To make the hook a Global hook you will pass IntPtr.Zero as the last parameter to SetWindowsHookEx . This function returns a hook handle. You'll need to save this and use it later to unhook.

To stop the hook you will call UnhookWindowsHookEx and pass in the hook handle.

Now that we've covered hearing messages from the keyboard and mouse I'll talk about sending messages.

For this you will use the SendInput method from the same API. However, you will again need some structs to help you communicate.

        [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;
    }

You will fill these structs with the information you need to send. Combine them in a InputUnion then put them in an INPUT struct to be sent to the system. More or less you will use the same constants as above to tell the keyboard or mouse what and where to send certain signals. However, unfortunately this is all x and y coordinate based so these coordinates should always be read in relation to the size and position of the application on the screen.

The Hooking API reference can be found here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632589(v=vs.85).aspx

An overview of how to use hooks can be found here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644960(v=vs.85).aspx

Sending input reference can be found here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx

I hope this helps! Feel free to message me if you have questions about my answer. I've worked with windows hooks a lot.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM