Как я могу использовать автоматизацию для щелчка правой кнопкой мыши в Windows 7?

Я потратил некоторое время на то, чтобы моя мышь могла щелкнуть правой кнопкой мыши в Windows XP. Вот код:

public class Mouse
{
    [DllImport("user32.dll", SetLastError = true)]
    internal static extern uint SendInput(uint numberOfInputs, Input[] inputs, int sizeOfInputStructure);

    private const int RightDown = 0x0008;
    private const int RightUp = 0x0010;
    private const int InputMouse = 0;

    public void RightClick<T>(T element) where T: AutomationElementWrapper
    {

        var point = element.Element.GetClickablePoint();
        var processId = element.Element.GetCurrentPropertyValue(AutomationElement.ProcessIdProperty);
        var window = AutomationElement.RootElement.FindFirst(
            TreeScope.Children,
            new PropertyCondition(AutomationElement.ProcessIdProperty,
                                  processId));

        window.SetFocus();

         var x = (int)point.X;
         var y = (int)point.Y;

        System.Windows.Forms.Cursor.Position = new System.Drawing.Point(x, y);

        SendInput(2, new[] {InputFor(RightDown, x, y), InputFor(RightUp, x, y)}, Marshal.SizeOf(typeof (Input)));
    }


    private static Input InputFor(uint mouseButtonAction, int x, int y)
    {
        var input = new Input
                        {
                            Dx = x,
                            Dy = y,
                            MouseData = 0,
                            DwFlags = mouseButtonAction,
                            Time = 0,
                            DwType = InputMouse,
                            MouseExtraInfo = new IntPtr()
                        };
        return input;
    }

    internal struct Input
    {
        public int DwType;
        public int Dx;
        public int Dy;
        public uint MouseData;
        public uint DwFlags;
        public uint Time;
        public IntPtr MouseExtraInfo;
    }
}

Это не работает в Windows 7. Почему и как это исправить?

Для получения дополнительной информации я использую это в инструменте автоматизации, чтобы вызвать контекстное меню.

Изменить: ссылка @GSerg выглядит полезной. Я не уверен, что происходит в поле «тип» ввода после того, как вы добавили объединение — я оставил его пустым, и теперь это вызывает появление моей заставки. Ах, радости Win32. Любая помощь приветствуется.


person Lunivore    schedule 15.01.2012    source источник
comment
А, структура INPUT. Вы делаете это неправильно.   -  person GSerg    schedule 16.01.2012
comment
Хочешь осветить, как будет выглядеть право? Мне потребовалось некоторое время, чтобы собрать это вместе, и я новичок в Win32. Вам 25 баллов, если вы это сделаете...   -  person Lunivore    schedule 16.01.2012
comment
Почему, мне не все равно :) Вот почему в моем комментарии есть ссылка, которая показывает правильное объявление INPUT pinvoke и объясняет, почему. Кроме этого, я не совсем уверен, что проблема вызвана ошибочным объявлением (хотя, если ваша машина с Windows 7 64-разрядная, это, безусловно, может быть), поэтому я сделал комментарий вместо ответа.   -  person GSerg    schedule 16.01.2012
comment
Хм, да, моя машина 64-битная. Ваша ссылка объясняет, почему для людей, которые уже знакомы с Win32. Мне удалось заставить его включить заставку! Спасибо за ссылку в любом случае. Мне действительно нужен кто-то, кто поможет мне заполнить некоторые пробелы, которые все еще остаются на этой странице.   -  person Lunivore    schedule 16.01.2012
comment
См. этот ответ для примера, который использует SendInput, надеюсь, вы можете просто вырезать/вставить соответствующие определения, даже если он делает клавиатуру по сравнению с вводом мыши.   -  person BrendanMcK    schedule 17.01.2012
comment
Спасибо, я сделал это по ссылке @GSerg. Я это сделал! Оно работает! Я очень счастлив сейчас. Если вы напишете ответ с этим, я дам вам очки и все такое.   -  person Lunivore    schedule 18.01.2012


Ответы (1)


Вот моя попытка решения: эта тестовая программа сочетает в себе код из вводного вопроса, страницы SendInput pinvoke.net и старый новый способ выравнивания 64-битной структуры, на который ссылается GSerg.

При этом у меня работает щелчок правой кнопкой мыши на Win7 x64:

using System;
using System.Runtime.InteropServices;
using System.Windows.Automation;
using WiPFlash;
using WiPFlash.Components;
using WiPFlash.Framework;
using WiPFlash.Util;
using WiPFlash.Exceptions;

using NUnit.Framework;

namespace MouseRightClick
{
    class Program
    {
        static void Main(string[] args)
        {
            Application application = new ApplicationLauncher(TimeSpan.Parse("00:00:20"))
                .LaunchOrRecycle("foo", @"C:\\hg\\wipflash\\Example.PetShop\\bin\\Debug\\Example.PetShop.exe", Assert.Fail);

            var window = application.FindWindow("petShopWindow");
            var totalLabel = window.Find<Label>("copyPetContextTarget");
            Mouse mouse = new Mouse();
            mouse.RightClick(totalLabel);
        }
    }

    public class Mouse
    {
        [DllImport("user32.dll", SetLastError = true)]
        static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);

        private const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
        private const int MOUSEEVENTF_RIGHTUP = 0x0010;
        private const int INPUT_MOUSE = 0;
        private const int INPUT_KEYBOARD = 1;
        private const int INPUT_HARDWARE = 2;

        public void RightClick<T>(T element) where T : AutomationElementWrapper
        {
            var point = element.Element.GetClickablePoint();
            var processId = element.Element.GetCurrentPropertyValue(AutomationElement.ProcessIdProperty);
            var window = AutomationElement.RootElement.FindFirst(
                TreeScope.Children,
                new PropertyCondition(AutomationElement.ProcessIdProperty,
                                      processId));

            window.SetFocus();

            var x = (int)point.X;
            var y = (int)point.Y;

            System.Windows.Forms.Cursor.Position = new System.Drawing.Point(x, y);

            SendInput(2, new[] {
                InputFor(MOUSEEVENTF_RIGHTDOWN, x, y),
                InputFor(MOUSEEVENTF_RIGHTUP, x, y) },
                Marshal.SizeOf(typeof(INPUT)));
        }


        private static INPUT InputFor(uint mouseButtonAction, int x, int y)
        {
            var input = new INPUT();
            input.type = INPUT_MOUSE;
            input.u.mi.dwFlags = mouseButtonAction;
            input.u.mi.time = 0;
            input.u.mi.dwExtraInfo = IntPtr.Zero;            
            return input;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct MOUSEINPUT
        {
            public int dx;
            public int dy;
            public uint mouseData;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct KEYBDINPUT
        {
            public ushort wVk;
            public ushort wScan;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct HARDWAREINPUT
        {
            public uint uMsg;
            public ushort wParamL;
            public ushort wParamH;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct INPUT_UNION
        {
            [FieldOffset(0)]
            public MOUSEINPUT mi;
            [FieldOffset(0)]
            public KEYBDINPUT ki;
            [FieldOffset(0)]
            public HARDWAREINPUT hi;
        };

        [StructLayout(LayoutKind.Sequential)]
        internal struct INPUT
        {
            public int type;
            public INPUT_UNION u;
        }
    }

}
person Bill Agee    schedule 19.01.2012
comment
О, вау... и вы на самом деле используете WiPFlash для этого! Я решил проблему именно таким образом, так что, надеюсь, это поможет всем, у кого есть такая же проблема. Спасибо, что написали! Следующая версия WiPFlash теперь будет поддерживать контекстные меню и в 64-разрядных версиях! - person Lunivore; 19.01.2012