3

Following the advice from this thread: distinguish between keyboard's Real and Virtual key presses

I'm trying to create a program, that will send keyboard's key-press events using SendInput() method.

However, the problem is that when I try to simulate a key press event - nothing happens whatsoever. So far that's my code:

    [DllImport("user32.dll")]
    static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);

    [StructLayout(LayoutKind.Sequential)]
    struct KEYBDINPUT
    {
        public short wScan; public int dwFlags;
        public int time; public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct INPUT
    {
        [FieldOffset(0)] public int type;
        [FieldOffset(8)]  public KEYBDINPUT ki; //x64 - 8, x32 - 4
    }

    const int KEYEVENTF_DOWN = 0; //key UP
    const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    const int KEYEVENTF_KEYUP = 0x0002; //key UP
    const int KEYEVENTF_UNICODE = 0x0004;
    const int KEYEVENTF_SCANCODE = 0x0008; // scancode

    public void Send_Key(short Keycode)
    {
        INPUT[] InputData = new INPUT[1];
        InputData[0].type = 1;
        InputData[0].ki.wScan = Keycode;
        InputData[0].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
        InputData[0].ki.time = 0;
        InputData[0].ki.dwExtraInfo = IntPtr.Zero;
        SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
    }

To decipher the scancodes I've downloaded the program that was suggested in this thread:

https://superuser.com/questions/293609/windows-7-tool-to-capture-keyboard-scan-codes

according to this program - "a" key's code for my keyboard is "65"

My program is supposed to trigger a key press event when textbox text is changed, so if we enter "q" - the text should change to "q" plus the result of send_key(), i.e. "qa":

    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        Send_Key(0x0065); // nothing happens (0x65 also fails)
    }

what am I doing wrong? In the future I'll be changing this code so I can specify key-hold time (between DOWN and UP events). but for now, for testing purposes I'm simulating only keyUP event.

EDIT: Hans, according to your advice here is the edit - but it doesn't work, unfortunately.

 public void Send_Key(short Keycode)
        {
            INPUT[] InputData = new INPUT[1];
            InputData[0].type = 1;
            InputData[0].ki.wScan = Keycode;
            InputData[0].ki.dwFlags = KEYEVENTF_DOWN;
            InputData[0].ki.time = 0;
            InputData[0].ki.dwExtraInfo = IntPtr.Zero;

            uint intReturn = SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));

            if (intReturn == 0) //!=1
            {
                throw new Exception("Could not send keyDOWN: " + Keycode);
            }

            INPUT[] InputData2 = new INPUT[1];
            InputData2[0].type = 1;
            InputData2[0].ki.wScan = Keycode;
            InputData2[0].mi.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
            InputData2[0].ki.time = 0;
            InputData2[0].ki.dwExtraInfo = IntPtr.Zero;

            uint intReturn2 = SendInput(1, InputData2, Marshal.SizeOf(typeof(INPUT)));

            if (intReturn2 == 0) //!=1
            {
                throw new Exception("Could not send keyUP: " + Keycode);
            }
        }

no errors.. and no output.

3
  • edit2: after any failed attempt to print a letter, when I close my program - I can't change TABS in Google Chrome!!! Checked this thing several times - my program is the cause! strange.. Commented Apr 29, 2012 at 21:17
  • I'm not 100% but I don't think you can 'append' like that from TextChanged directly - you'd have to spawn a thread for that I think - still might not be all. Anyway, why use that 'for your own app'? You're using win-forms?... Commented Apr 29, 2012 at 23:40
  • yes that's winforms indeed. solved my problem by changing the code completely (found it on some forum) and choosing right scan codes from this page: msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx For example to print "a" I had to enter either "30" or "0x1E".. Commented Apr 30, 2012 at 8:23

1 Answer 1

2

but for now, for testing purposes I'm simulating only keyUP event

Which is okay I guess but that is not going to make Windows do anything. To generate a keystroke, you must first send a KEYDOWN. A "hold-time" doesn't have any useful effect so just put the two SendInput calls in the same method.

You should add error checking, winapi calls don't generate any exceptions. Throw a Win32Exception if the function returns 0. And fix the [DllImport] declaration with SetLastError = true.

You can avoid using that program you found at superuser.com by setting the ki.wVk field instead and omitting the KEYEVENTF_SCANCODE flag. So that you specify virtual keys instead of scan codes. The .NET Keys enumeration type gives you the values you need. Like Keys.A to generate a key press for the A key.

Sign up to request clarification or add additional context in comments.

2 Comments

See edit: keydown event - added, hold time - skipped, SetLastError - added, exception - added. Regarding ScanCodes - I'd like to stick with them if possible..
No reason you have to use virtual keys. It is just simpler with the Keys enumeration.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.