Location>code7788 >text

C# simulates keyboard input, key status and listens to keyboard messages

Popularity:941 ℃/2024-08-18 00:59:01

Analog keyboard input

The ability to simulate keyboard input relies on a Windows function, which is theSendInput, which is a function specifically designed to simulate input from devices such as keyboards and mice.

Also related to keyboard input are the SendKeys functions, which are. SendKeys, can only be used in WinFrom projects, and all its functions can be implemented by SendInput.

The other one iskeybd_eventfunction, which is still useful, but it is now officially recommended to use SendInput instead.

Definition of SendInput
[DllImport("")]
static extern uint SendInput(int nInputs,INPUT[] pInputs,int cbSize);

The INPUT object holds the input content. nInputs and cbSize represent the length of pInputs and the size of the INPUT structure, which help SendInput parse the INPUT object correctly. A return value of 0 indicates failure, and a non-zero value indicates correct execution.

 

Definition of INPUT
[StructLayout()]
struct KEYBDINPUT {
    public ushort wVk;
    public ushort wScan;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}
[StructLayout()]
struct HARDWAREINPUT {
    public uint uMsg;
    public ushort wParamL;
    public ushort wParamH;
}
[StructLayout()]
struct MOUSEINPUT {
    public int dx;
    public int dy;
    public uint mouseData;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}
[StructLayout()]
struct MOUSEKEYBDHARDWAREINPUT {
    [FieldOffset(0)]
    public HARDWAREINPUT hi;
    [FieldOffset(0)]
    public KEYBDINPUT ki;
    [FieldOffset(0)]
    public MOUSEINPUT mi;
}
[StructLayout()]
struct INPUT {
    public uint type;
    public MOUSEKEYBDHARDWAREINPUT mkhi;
}

INPUT structure in the type of the message type, the value of 1 indicates that the keyboard message. mkhi indicates that the specific message content, it can simulate three types of messages, including keyboard messages using KEYBDINPUT said that the structure of other message types are not introduced here (although you can not use the structure of the MOUSEINPUT and so on, but their definitions can not be omitted, or else) SendInput can not correctly parse the specific content of the INPUT).

⩥FieldOffset(0) puts the start of all three structures at position 0, so only one of the contents can be used, since an INPUT can also represent only one message, and this design saves space.

The wVK in the KEYBDINPUT structure represents the virtual key code, and the first bit of dwFlags defaults to 0 for a key press event and 1 for a key release event.

virtual keycodeis a technique that enables Windows to handle the keyboard in a device-independent way, which can be simply understood as follows: each key on the keyboard is represented by a number.

 

Analog A key
INPUT[] inputs = new INPUT[2];
inputs[0]=new INPUT {
    type=1,
    mkhi=new MOUSEKEYBDHARDWAREINPUT {
        ki=new KEYBDINPUT {
            wVk=0x41
        }
    }
};
inputs[1]=new INPUT {
    type=1,
    mkhi=new MOUSEKEYBDHARDWAREINPUT {
        ki=new KEYBDINPUT {
            wVk=0x41,
            dwFlags=2
        }
    }
};
SendInput(,inputs,(inputs[0]));

The virtual keycode for key A is 0x41. type=1 means this is a keyboard message and dwFlags=2 means a keyboard release event.

Here the INPUT array simulates the use of the physical keyboard A key. inputs[0] simulates the A key being pressed and inputs[1] simulates the A key being released.

 

Analog Ctrl+A
INPUT[] inputs = new INPUT[4];
inputs[0]=new INPUT {
    type=1,
    mkhi=new MOUSEKEYBDHARDWAREINPUT {
        ki=new KEYBDINPUT {
            wVk=0x11
        }
    }
};
inputs[1]=new INPUT {
    type=1,
    mkhi=new MOUSEKEYBDHARDWAREINPUT {
        ki=new KEYBDINPUT {
            wVk=0x41
        }
    }
};
inputs[2]=new INPUT {
    type=1,
    mkhi=new MOUSEKEYBDHARDWAREINPUT {
        ki=new KEYBDINPUT {
            wVk=0x41,
            dwFlags=2
        }
    }
};
inputs[3]=new INPUT {
    type=1,
    mkhi=new MOUSEKEYBDHARDWAREINPUT {
        ki=new KEYBDINPUT {
            wVk=0x11,
            dwFlags=2,
        }
    }
};
SendInput(,inputs,(inputs[0]));

0x11 is the virtual keycode of Ctrl, here we simulate the process of pressing Ctrl, pressing A, releasing A, releasing Ctrl, and realizing the key combination effect of Ctrl+A.

 

SendInput can simulate keystroke messages as well as character messages in text input.

The wScan of the KEYBDINPUT structure indicates the character content. Setting the second bit of dwFlags to 1 indicates that the wScan attribute is used instead of wVK.

text input
string ntext = "How are you?";
INPUT[] inputs = new INPUT[*2];
for(int i = 0;i<;i++) {
    ushort ch = ntext[i];
    inputs[i*2]=new INPUT {
        type=1,
        mkhi=new MOUSEKEYBDHARDWAREINPUT {
            ki=new KEYBDINPUT {
                wScan=ch,
                dwFlags=4
            }
        }
    };
    inputs[i*2+1]=new INPUT {
        type=1,
        mkhi=new MOUSEKEYBDHARDWAREINPUT {
            ki=new KEYBDINPUT {
                wScan=ch,
                dwFlags=4|2
            }
        }
    };
}
SendInput(,inputs,(inputs[0]));

 

key status

Sometimes you need to know the current state of the keyboard keys, you can use theGetKeyStatefunction.

Definition of GetKeyState
[DllImport("")]
static extern short GetKeyState(int VKey);

The parameter is the virtual code of the key. For the on/off keys (Caps Look, Num Lock, and Scroll Lock), a return value of 1 indicates the on state. For the other keys, a negative number is returned to indicate the pressed state.

CapsLock key status
short iState = GetKeyState(0x14);

 

Listening for Keyboard Messages

For WinForm and WPF programs, to listen to the keyboard messages entered into the program directly use the KeyDown and KeyUp events of the window.

For other keyboard messages (i.e., for keyboard messages outside of this program), you need to use thehooks(hook)。

A hook is a node in the Windows system message handling mechanism that can be installed to listen for Windows messages on the system.

Windows messages are divided into many kinds, for a specific type of message you need to use the corresponding specific type of hooks, here only introduces the keyboard message hooks.

Hook installation requires a call to the systemSetWindowsHookExMethods.

 

Definition of SetWindowsHookEx
[DllImport("")]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hmod, int threadID);

idHook equals 13 for the global keyboard message hook, lpfn for the keyboard message handler, and a return of non indicates a successful installation.

 

Installation Hooks
delegate int HookProc(int code,IntPtr wParam,IntPtr lParam);
static HookProc KeyboardProc;
static void InstallKeyboardHook() {
    KeyboardProc=KeyboardHookCallback;
    pKeyboardHook=SetWindowsHookEx(13,keyboardProc,,0);
}

KeyboardHookCallback is the customized method that specifically handles keyboard messages.

 

message processing
[DllImport("")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
static int KeyboardHookCallback(int code,IntPtr wParam,IntPtr lParam) {
    if(code<0)
        return CallNextHookEx(,code,wParam,lParam);
    int vkCode = Marshal.ReadInt32(lParam);
    (vkCode+" ");
    long downup = (long)wParam;
    switch(downup) {
        case 256:
            ("down");
            break;
        case 257:
            ("up");
            break;
        case 260:
            ("sys_down");
            break;
        case 261:
            ("sys_up");
            break;
     }
     return CallNextHookEx(,code,wParam,lParam);
}

The virtual code of the key is read from lParam (lParam is actually a pointer to a KEYBDINPUT structure similar to the one mentioned earlier), and wParam indicates the type of the keystroke event. callNextHookEx passes the message on to the next message-handling node.

⩥ Simulating keyboard input using the previously mentioned SendInput method can also be listened to by the hook.

⩥ Time-consuming operations during message processing should be avoided.

 

Unloading hooks requires the use of theUnhookWindowsHookEx

Definition of UnhookWindowsHookEx
[DllImport("")]
static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);

Just pass in the return value of SetWindowsHookEx. If it returns true, the uninstallation is successful.