Just experimenting with some WinAPI stuff. I have a C# console app that uses SendInput to simulate a keydown and keyup events of some keyboard key. It's not working though, maybe I'm doing something stupid, the key isn't being sent, not sure what am I missing - (trying to send a "W", sleep for 5 secs, open up some text editor to see the letter magically there):

static void Main(string[] args)
{

        INPUT input = new INPUT();
        input.type = (int)InputType.INPUT_KEYBOARD;
        input.U.ki.wScan = 0;
        input.U.ki.time = 0;
        input.U.ki.dwExtraInfo = UIntPtr.Zero;
        input.U.ki.wVk = VirtualKeyShort.KEY_W;

        System.Threading.Thread.Sleep(5000);

        input.U.ki.dwFlags = KEYEVENTF.KEYDOWN;
        NativeCalls.SendInput(1, new INPUT[] { input }, INPUT.Size);

        input.U.ki.dwFlags = KEYEVENTF.KEYUP;
        NativeCalls.SendInput(1, new INPUT[] { input }, INPUT.Size);

        return;
}

Definitions:

public static class NativeCalls
{
    [DllImport("user32.dll")]
    public static extern uint SendInput(
    uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
}

[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
    internal uint type;
    internal InputUnion U;
    internal static int Size
    {
        get { return Marshal.SizeOf(typeof(INPUT)); }
    }
}

[StructLayout(LayoutKind.Explicit)]
internal struct InputUnion
{
    [FieldOffset(0)]
    internal KEYBDINPUT ki;
}

[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
    internal VirtualKeyShort wVk;
    internal ScanCodeShort wScan;
    internal KEYEVENTF dwFlags;
    internal int time;
    internal UIntPtr dwExtraInfo;
}

[Flags]
internal enum KEYEVENTF : uint
{
    KEYDOWN = 0x0000,
    EXTENDEDKEY = 0x0001,
    KEYUP = 0x0002,
    SCANCODE = 0x0008,
    UNICODE = 0x0004
}

internal enum InputType { INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2 }

internal enum VirtualKeyShort : short
{
    // keys
    KEY_W = 0x57,
    // more keys
}

What am I doing wrong? why is the key not being sent?

Thanks :)

有帮助吗?

解决方案

Your union declaration is incomplete. Because of that, Marshal.SizeOf(typeof(INPUT)) returns an incorrect value. You do at least need to define the MOUSEINPUT part of the INPUT union since that has the largest size. The pinvoke.net declaration should suffice.

I expect that SendInput would have told you of the problem had you checked the return value. I expect that SendInput returns false, and then a call to GetLastError should yield ERROR_INVALID_PARAMETER. Of course, you should not call GetLastError directly. Use SetLastError = true, and Marshal.GetLastWin32Error(). You simply have to perform accurate error checking when you call Win32 API functions.

[DllImport("user32.dll", SetLastError=true)]
...

This part of the declaration is wrong at pinvoke.net where they omit SetLastError.

You are using SendInput in a clumsy way. The SendInput function exists so that you can place multiple input messages in the queue without having them interleaved by others. The documentation makes this clear when it discusses SendInput in relation to the now deprecated keybd_event and mouse_event functions. Call SendInput once passing an array of length 2.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top