Using WPF's built-in UI automation, it's easy (though pretty verbose) to send a left-click event to an AutomationElement (such as a Button):
InvokePattern invokePattern = (InvokePattern) element.GetCurrentPattern(InvokePattern.Pattern);
invokePattern.Invoke();
However, there seems to be no built-in way to send right-clicks to the same element. I've resigned myself to using P/Invoke to call SendInput, but I can't get it to work. With the code below, when I call RightClick(), a context menu pops up right where the cursor is, rather than at the element I expect to be right-clicked. So it seems like it's ignoring the coordinates I hand in and just using the current cursor location.
public static void RightClick(this AutomationElement element)
{
Point p = element.GetClickablePoint();
NativeStructs.Input input = new NativeStructs.Input
{
type = NativeEnums.SendInputEventType.Mouse,
mouseInput = new NativeStructs.MouseInput
{
dx = (int) p.X,
dy = (int) p.Y,
mouseData = 0,
dwFlags = NativeEnums.MouseEventFlags.Absolute | NativeEnums.MouseEventFlags.RightDown,
time = 0,
dwExtraInfo = IntPtr.Zero,
},
};
NativeMethods.SendInput(1, ref input, Marshal.SizeOf(input));
input.mouseInput.dwFlags = NativeEnums.MouseEventFlags.Absolute | NativeEnums.MouseEventFlags.RightUp;
NativeMethods.SendInput(1, ref input, Marshal.SizeOf(input));
}
internal static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint SendInput(uint nInputs, ref NativeStructs.Input pInputs, int cbSize);
}
internal static class NativeStructs
{
[StructLayout(LayoutKind.Sequential)]
internal struct Input
{
public NativeEnums.SendInputEventType type;
public MouseInput mouseInput;
}
[StructLayout(LayoutKind.Sequential)]
internal struct MouseInput
{
public int dx;
public int dy;
public uint mouseData;
public NativeEnums.MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
}
internal static class NativeEnums
{
internal enum SendInputEventType : int
{
Mouse = 0,
Keyboard = 1,
Hardware = 2,
}
[Flags]
internal enum MouseEventFlags : uint
{
Move = 0x0001,
LeftDown = 0x0002,
LeftUp = 0x0004,
RightDown = 0x0008,
RightUp = 0x0010,
MiddleDown = 0x0020,
MiddleUp = 0x0040,
XDown = 0x0080,
XUp = 0x0100,
Wheel = 0x0800,
Absolute = 0x8000,
}
}
From what I understand, you're correct about SendInput being necessary to simulate a right click on a UIA element.
As for how to force the cursor to move to your element before the right click, you might try adding the MOUSEEVENTF_MOVE flag to your dwFlags.
If that still doesn't work, perhaps try calling SendInput twice - once to move the mouse (with "dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE") and a second time to perform the right click the way you're doing it now.
Also, have you seen this project?
http://inputsimulator.codeplex.com/
Not sure how complete its mouse input support is at the moment, but it might be useful.
Also, this question might be useful too:
using mouse with sendInput in C
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With