Как я могу отправить событие правой кнопки мыши на AutomationElement с помощью автоматизации пользовательского интерфейса WPF? - PullRequest
5 голосов
/ 02 июля 2011

Используя встроенную в WPF автоматизацию пользовательского интерфейса, легко (хотя и довольно многословно) отправить событие левого щелчка в AutomationElement (например, Button):

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

Ответы [ 4 ]

1 голос
/ 28 января 2016

MSDN говорит:

Если указано значение MOUSEEVENTF_ABSOLUTE, dx и dy содержат нормализованные абсолютные координаты между 0 и 65 535 .Процедура события отображает эти координаты на поверхности дисплея.Координаты (0,0) отображаются в верхнем левом углу поверхности дисплея;координата (65535,65535) отображается в правом нижнем углу.В системе с несколькими мониторами координаты отображаются на основной монитор.

Это означает, что вы не можете просто использовать pX и pY. Вам необходимо нормализовать его, например, следующим образом:

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.

1 голос
/ 06 июля 2011

Насколько я понимаю, вы правы в том, что SendInput необходим для имитации щелчка правой кнопкой мыши по элементу UIA.

Что касается того, как заставить курсор перемещаться к вашему элементу до щелчка правой кнопкой мыши, вы можете попробовать добавить флаг MOUSEEVENTF_MOVE к вашим dwFlags.

Если это по-прежнему не работает, возможно, попробуйте вызвать SendInput дважды - один раз, чтобы переместить мышь (с помощью "dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE"), и второй раз, чтобы выполнить щелчок правой кнопкой мыши, как вы делаете это сейчас.

Кроме того, вы видели этот проект?

http://inputsimulator.codeplex.com/

Не уверен, насколько полно в данный момент поддержка ввода мышью, но это может быть полезно.

Кроме того, этот вопрос также может быть полезен:

с помощью мыши с sendInput в C

0 голосов
/ 08 декабря 2018

Я проверил все ответы и составил окончательное рабочее решение.

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,
    }
}
0 голосов
/ 28 декабря 2011

Если вы наследуете от элемента управления, вы можете использовать следующее:

var e = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Right);
e.RoutedEvent = Mouse.MouseDownEvent;
this.OnMouseDown(e);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...