Automating Key Presses with SendInput

2020-02-16 04:08发布

When I attempt to use SendInput to send single key presses, and combined keypresses, I can't get my program to hold the keyboard button until commanded to be released. With the code below I am ables to send the character 'a', and 'A', by hitting shift first. However, I cannot get it to hold the 'a' button in perpetuity.

public static void KeyDown()
{
    SwitchWindow(Process.GetProcessesByName("notepad").FirstOrDefault().MainWindowHandle);
    INPUT[] inputs = new INPUT[1];
    KEYBDINPUT kb = new KEYBDINPUT();

    //Set up generic keyboard event
    inputs[0].type = INPUT_KEYBOARD;
    kb.wScan = 0; // hardware scan code for key
    kb.time = 0;
    kb.dwExtraInfo = IntPtr.Zero;

    kb.dwFlags = 0; // 0 for key press

    //Press shift
    kb.wVk = (ushort)KeyCode.SHIFT;
    inputs[0].ki = kb;
    SendInput(1, inputs, Marshal.SizeOf(inputs[0]));

    //Press 'a' key
    kb.wVk = (ushort)0x41; // virtual-key code for the "a" key
    inputs[0].ki = kb;
    SendInput(1, inputs, Marshal.SizeOf(inputs[0]));

    //Release 'a' key
    kb.dwFlags = KEYEVENTF_KEYUP;
    kb.wVk = (ushort)0x41; // virtual-key code for the "a" key
    inputs[0].ki = kb;
    SendInput(1, inputs, Marshal.SizeOf(inputs[0]));

    //Release 'shift' key
    kb.dwFlags = KEYEVENTF_KEYUP;
    kb.wVk = (ushort)KeyCode.SHIFT; // virtual-key code for the "a" key
    inputs[0].ki = kb;
    SendInput(1, inputs, Marshal.SizeOf(inputs[0]));
}

Any idea why, if I remove the last two SendInputs, it doesn't just hold 'A' down?

1条回答
够拽才男人
2楼-- · 2020-02-16 04:59

For the benefit of others that are searching for how to use SendInput() in C#, please see the below description.

1) There are two ways to send the key stroke with SendInput(), either using a Scancode or a virtual-key code

2) If you intend to send keystrokes to a game or another application that takes input from Direct 3D (or another DirectInput environment), you need to send the key strokes as scancodes, and therefor you specify the wScan field, and leave wVk blank. See info here: KEYBDINPUT

3) Remember to switch the window in focus to the application you want to send keystrokes to, before sending the keystroke. Example:

MemoryHandler.SwitchWindow(Process.GetProcessesByName("notepad").FirstOrDefault().MainWindowHandle);

4) Final code:

    public static void PressKey(char ch, bool press)
    {
        byte vk = MemoryApi.VkKeyScan(ch);
        PressKey((MemoryApi.KeyCode)vk, press);
    }

    public static void PressKey(MemoryApi.KeyCode vk, bool press)
    {
        ushort scanCode = (ushort)MemoryApi.MapVirtualKey((ushort)vk, 0);

        //Console.WriteLine("SendInput:: VK: " + (ushort)vk + " (" + vk + ") <-> SC: " + (ushort)(scanCode & 0xff));

        if (press)
            KeyDown(scanCode);
        else
            KeyUp(scanCode);
    }

    public static void KeyDown(ushort scanCode)
    {
        //Console.WriteLine("Key Down (SC): " + (ushort)(scanCode & 0xff));
        MemoryApi.INPUT[] inputs = new MemoryApi.INPUT[1];

        inputs[0].type = MemoryApi.INPUT_KEYBOARD;
        inputs[0].ki.wScan = (ushort)(scanCode & 0xff);
        inputs[0].ki.dwFlags = MemoryApi.KEYEVENTF_SCANCODE;
        inputs[0].ki.time = 0;
        inputs[0].ki.dwExtraInfo = IntPtr.Zero;

        uint intReturn = MemoryApi.SendInput(1, inputs, Marshal.SizeOf(inputs[0]));
        if (intReturn != 1)
        {
            throw new Exception("Could not send key: " + scanCode);
        }
    }

    public static void KeyUp(ushort scanCode)
    {
        //Console.WriteLine("Key Up (SC): " + scanCode);
        MemoryApi.INPUT[] inputs = new MemoryApi.INPUT[1];

        inputs[0].type = MemoryApi.INPUT_KEYBOARD;
        inputs[0].ki.wScan = (ushort)(scanCode & 0xff);
        inputs[0].ki.dwFlags = MemoryApi.KEYEVENTF_SCANCODE | MemoryApi.KEYEVENTF_KEYUP;
        inputs[0].ki.time = 0;
        inputs[0].ki.dwExtraInfo = IntPtr.Zero;

        uint intReturn = MemoryApi.SendInput(1, inputs, Marshal.SizeOf(inputs[0]));
        if (intReturn != 1)
        {
            throw new Exception("Could not send key: " + scanCode);
        }
}
查看更多
登录 后发表回答