【问题标题】:How can I send a right-click event to an AutomationElement using WPF's UI automation?如何使用 WPF 的 UI 自动化向 AutomationElement 发送右键单击事件?
【发布时间】:2018-12-31 17:24:19
【问题描述】:

使用 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,
    }
}

【问题讨论】:

  • 就我而言,我使用了automationElement (automationElement.Current.BoundingRectangle) 的“BoundingRectangle”属性来获取移动光标所需的x、y 坐标。然后我移动光标,并使用 MouseEvent 发送右键单击。此外,听起来移动光标是行不通的;以下内容过去对我有用: [DllImport("user32.dll", EntryPoint = "SetCursorPos")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SetCursorPos(int X, int Y);

标签: c# .net wpf testing ui-automation


【解决方案1】:

据我了解,您对 SendInput 模拟 UIA 元素上的右键单击是正确的。

至于如何在右键单击之前强制光标移动到您的元素上,您可以尝试在您的 dwFlags 中添加 MOUSEEVENTF_MOVE 标志。

如果这仍然不起作用,也许尝试调用 SendInput 两次 - 一次移动鼠标(使用“dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE”),第二次按照您现在的方式执行右键单击。

另外,你看过这个项目吗?

http://inputsimulator.codeplex.com/

目前不确定它的鼠标输入支持有多完善,但它可能有用。

另外,这个问题也可能有用:

using mouse with sendInput in C

【讨论】:

    【解决方案2】:

    MSDN 说:

    如果指定了 MOUSEEVENTF_ABSOLUTE 值,则 dx 和 dy 包含 0 到 65,535 之间的标准化绝对坐标。事件过程将这些坐标映射到显示表面上。坐标(0,0)映射到显示表面的左上角;坐标 (65535,65535) 映射到右下角。在多显示器系统中,坐标映射到主显示器。

    这意味着你不能只使用 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 标志对其进行或运算。

    【讨论】:

      【解决方案3】:

      如果您从控件派生,则可以使用以下内容:

      var e = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Right);
      e.RoutedEvent = Mouse.MouseDownEvent;
      this.OnMouseDown(e);
      

      【讨论】:

        【解决方案4】:

        我检查了所有答案并编译了最终的工作解决方案。

        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,
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2019-04-27
          • 2016-04-24
          • 2012-06-17
          • 2019-01-09
          • 2018-04-19
          • 2010-09-24
          • 2019-09-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多