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 a
s.
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);