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.

Community
  • 1
  • 1
Alex
  • 4,607
  • 9
  • 61
  • 99
  • 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.. – Alex Apr 29 '12 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?... – NSGaga-mostly-inactive Apr 29 '12 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: http://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx For example to print "a" I had to enter either "30" or "0x1E".. – Alex Apr 30 '12 at 08:23

1 Answers1

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • See edit: keydown event - added, hold time - skipped, SetLastError - added, exception - added. Regarding ScanCodes - I'd like to stick with them if possible.. – Alex Apr 29 '12 at 20:17
  • No reason you *have* to use virtual keys. It is just simpler with the Keys enumeration. – Hans Passant Apr 29 '12 at 20:23