0

I'm trying to use a combination of attaching thread input to another thread and setting key states to send a shift+a combination (A) to Notepad. The problem is, the code below prints a instead of A.

I have tried debugging the code and holding down the shift while stepping through breakpoints and it works great when holding down shift. So I know that the thread attachment is working.

So it seems like the SetKeyboardState(...) command isn't working, though. What am I doing wrong?

Here is the code:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetKeyboardState(byte[] lpKeyState);

    [DllImport("user32.dll")]
    static extern bool SetKeyboardState(byte[] lpKeyState);

    public static void simKeyPressWithModifier(IntPtr winHandle)
    {
        uint threadId = User32.GetWindowThreadProcessId(winHandle, IntPtr.Zero);
        byte[] keys = new byte[256];

        if (!GetKeyboardState(keys))
        {
            int err = Marshal.GetLastWin32Error();
            throw new Win32Exception(err);
        }
        User32.AttachThreadInput((uint)AppDomain.GetCurrentThreadId(), threadId, true);

        int sKey = (int)VK.VK_LSHIFT;
        keys[sKey] = 0xFF;


        if (!SetKeyboardState(keys))
        {
            int err = Marshal.GetLastWin32Error();
            throw new Win32Exception(err);
        }

        User32.PostMessage(winHandle, WM.WM_KEYDOWN, (IntPtr)Keys.A, IntPtr.Zero);

        keys[sKey] = 0;
        if (!SetKeyboardState(keys))
        {
            int err = Marshal.GetLastWin32Error();
            throw new Win32Exception(err);
        }
        User32.AttachThreadInput((uint)AppDomain.GetCurrentThreadId(), threadId, false);
    }

Update

Posting as four commands:

    public static void simKeyPressWithModifier(IntPtr winHandle)
    {

        User32.PostMessage(winHandle, WM.WM_KEYDOWN, (IntPtr)VK.VK_LSHIFT, IntPtr.Zero);
        User32.PostMessage(winHandle, WM.WM_KEYDOWN, (IntPtr)Keys.A, IntPtr.Zero);
        User32.PostMessage(winHandle, WM.WM_KEYUP, (IntPtr)Keys.A, IntPtr.Zero);
        User32.PostMessage(winHandle, WM.WM_KEYUP, (IntPtr)VK.VK_LSHIFT, IntPtr.Zero);
    }

Results in two lowercase as.

If I do SendMessage instead of PostMessage, nothing appears at all:

    public static void simKeyPressWithModifier(IntPtr winHandle)
    {

        User32.SendMessage(winHandle, WM.WM_KEYDOWN, (IntPtr)VK.VK_LSHIFT, IntPtr.Zero);
        User32.SendMessage(winHandle, WM.WM_KEYDOWN, (IntPtr)Keys.A, IntPtr.Zero);
        User32.SendMessage(winHandle, WM.WM_KEYUP, (IntPtr)Keys.A, IntPtr.Zero);
        User32.SendMessage(winHandle, WM.WM_KEYUP, (IntPtr)VK.VK_LSHIFT, IntPtr.Zero);

    }

Using .NET Framework 4 on Windows 8.1 in C#.


How I'm getting the context handle:

Process p = Process.Start("notepad");
IntPtr windowHandle = p.MainWindowHandle;
RECT bounds = new RECT();
User32.GetWindowRect(windowHandle, out bounds);

POINT currentContextLocation = new POINT();
currentContextLocation.x = bounds.left + 100;
currentContextLocation.y = bounds.top + 100;
IntPtr contextHandle = User32.WindowFromPoint(currentContextLocation);

simKeyPressWithModifier(contextHandle);
Jason
  • 13,563
  • 15
  • 74
  • 125
  • Why not just post Shift-Down A-Down A-Up Shift-Up? Or for that matter, why not just post WM_CHAR with 'A'? – MicroVirus May 17 '14 at 22:06
  • I tried that too, but it prints two lowercase `a`s. I want to be able to extend it to do ctrl commands too. – Jason May 17 '14 at 22:10
  • You get two `a`'s if you send a `WM_KEYDOWN / WM_KEYUP` pair? – MicroVirus May 17 '14 at 22:12
  • 2
    Call GetKeyboardState() *after* AttachThreadInput(). Set the key value to 0x80. You have to set the state of all the modifier keys, not just Shift. PostMessage() must use an appropriate LParam. You must restore the key state, not just assign 0. – Hans Passant May 17 '14 at 23:37
  • @HansPassant, what do you mean "all the modifier keys"? If I want shift+a is `shift` the only one I need to set? (or not?) What is the right LParam for WM_KEYDOWN? all the docs I see show 0. – Jason May 18 '14 at 17:18
  • What do you expect to happen when the Ctrl or Alt key is already down? – Hans Passant May 18 '14 at 18:02
  • Be warned that [AttachThreadInput is dangerous](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/19/10426841.aspx). – Harry Johnston May 19 '14 at 00:43
  • Tell me again why SendInput isn't doing what you want? Because calling AttachThreadInput on somebody else's process is almost guaranteed to deadlock at some point. – Eric Brown May 20 '14 at 06:31

0 Answers0