如何使用WPF';将右键单击事件发送到AutomationElement;用户界面自动化
本文关键字:AutomationElement 自动化 用户界面 事件 右键 WPF 何使用 单击 | 更新日期: 2023-09-27 18:01:11
使用WPF内置的UI自动化,可以很容易地(尽管相当冗长(将左键单击事件发送到AutomationElement(如按钮(:
InvokePattern invokePattern = (InvokePattern) element.GetCurrentPattern(InvokePattern.Pattern);
invokePattern.Invoke();
然而,似乎没有内置的方法来向同一个元素发送右键单击。我已经接受了使用P/Invoke来调用SendInput,但我无法让它工作。使用下面的代码,当我调用RightClick((时,一个上下文菜单会在光标所在的位置弹出,而不是在我希望右键单击的元素处。所以它似乎忽略了我输入的坐标,只使用当前的光标位置。
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,
}
}
据我所知,SendInput是模拟右键单击UIA元素所必需的,这是正确的。
至于如何在右键单击之前强制光标移动到元素,您可以尝试将MOUSEEVENTF_move标志添加到dwFlags中。
如果仍然不起作用,可以尝试调用SendInput两次——一次是移动鼠标(使用"dwFlags=MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_move"(,第二次是以现在的方式右键单击。
另外,你看过这个项目吗?
http://inputsimulator.codeplex.com/
目前还不确定它对鼠标输入的支持有多完整,但它可能很有用。
此外,这个问题可能也很有用:
在C 中使用带有sendInput的鼠标
如果指定了MOUSEEVENTF_ABSOLUTE值,则dx和dy包含介于0和65535之间的归一化绝对坐标。事件过程将这些坐标映射到显示表面上。坐标(0,0(映射到显示表面的左上角;坐标(6553565535(映射到右下角。在多监视器系统中,坐标映射到主监视器。
这意味着你不能只使用p.X和p.Y。你需要像这样规范它,例如:
var virtualScreen = System.Windows.Forms.SystemInformation.VirtualScreen;
Int32 x = Convert.ToInt32((p.X - virtualScreen.Left) * 65536 / virtualScreen.Width);
Int32 y = Convert.ToInt32((p.Y - virtualScreen.Top) * 65536 / virtualScreen.Height);
并且您还需要将其与MOUSEEVENTF_VIRTUALDESK
标志进行OR运算。
如果从控件派生,则可以使用以下内容:
var e = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Right);
e.RoutedEvent = Mouse.MouseDownEvent;
this.OnMouseDown(e);
我检查了所有答案并编译了最终的工作解决方案。
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 = 0,
dy = 0,
mouseData = 0,
dwFlags = NativeEnums.MouseEventFlags.Absolute | NativeEnums.MouseEventFlags.RightDown | NativeEnums.MouseEventFlags.Move,
time = 0,
dwExtraInfo = IntPtr.Zero,
},
};
var primaryScreen = Screen.PrimaryScreen;
input.mouseInput.dx = Convert.ToInt32((p.X - primaryScreen.Bounds.Left) * 65536 / primaryScreen.Bounds.Width);
input.mouseInput.dy = Convert.ToInt32((p.Y - primaryScreen.Bounds.Top) * 65536 / primaryScreen.Bounds.Height);
NativeMethods.SendInput(1, ref input, Marshal.SizeOf(input));
input.mouseInput.dwFlags = NativeEnums.MouseEventFlags.Absolute | NativeEnums.MouseEventFlags.RightUp | NativeEnums.MouseEventFlags.Move;
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,
}
}