Jak symulujesz kliknięcie myszą w C #?

128

Jak symulujesz kliknięcia myszą w aplikacjach C # winForms?

Nowicjusz
źródło
5
Możesz podać więcej informacji, aby uzyskać przydatną odpowiedź.
Andy
36
Wskazówka: jeśli tytuł jest taki sam jak pytanie, oznacza to, że jest on o wiele za długi lub pytanie jest zbyt krótkie. W tym przypadku jest to drugie, musisz podać dużo więcej kontekstu, aby ktokolwiek miał rozsądną szansę na udzielenie użytecznej odpowiedzi.
Guffa

Odpowiedzi:

145

Połączyłem kilka źródeł, aby utworzyć poniższy kod, którego obecnie używam. Usunąłem również odwołania do Windows.Forms, dzięki czemu mogę go używać z aplikacji konsoli i WPF bez dodatkowych odniesień.

using System;
using System.Runtime.InteropServices;

public class MouseOperations
{
    [Flags]
    public enum MouseEventFlags
    {
        LeftDown = 0x00000002,
        LeftUp = 0x00000004,
        MiddleDown = 0x00000020,
        MiddleUp = 0x00000040,
        Move = 0x00000001,
        Absolute = 0x00008000,
        RightDown = 0x00000008,
        RightUp = 0x00000010
    }

    [DllImport("user32.dll", EntryPoint = "SetCursorPos")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetCursorPos(int x, int y);      

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetCursorPos(out MousePoint lpMousePoint);

    [DllImport("user32.dll")]
    private static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);

    public static void SetCursorPosition(int x, int y) 
    {
        SetCursorPos(x, y);
    }

    public static void SetCursorPosition(MousePoint point)
    {
        SetCursorPos(point.X, point.Y);
    }

    public static MousePoint GetCursorPosition()
    {
        MousePoint currentMousePoint;
        var gotPoint = GetCursorPos(out currentMousePoint);
        if (!gotPoint) { currentMousePoint = new MousePoint(0, 0); }
        return currentMousePoint;
    }

    public static void MouseEvent(MouseEventFlags value)
    {
        MousePoint position = GetCursorPosition();

        mouse_event
            ((int)value,
             position.X,
             position.Y,
             0,
             0)
            ;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MousePoint
    {
        public int X;
        public int Y;

        public MousePoint(int x, int y)
        {
            X = x;
            Y = y;
        }
    }
}
Keith
źródło
2
Nie widzę żadnej przewagi tego długiego kodu źródłowego nad tym, co opublikował Marcos Placona 17 miesięcy temu.
Al Kepp
46
Biorąc pod uwagę niejasność pytania, pomyślałem, że ludzie mogą skorzystać na przykładzie, który pozwala im zrobić coś więcej niż tylko lewe kliknięcie zasysanie prawego lub środkowego kliknięcia lub zezwolenie na kliknięcie i przeciągnięcie.
Keith
2
Działa świetnie. Przyszedłem tutaj, szukając czegoś takiego
CSharpie
To jest to, czego szukam, ale jak kliknąć w dół, przesunąć mysz w inne miejsce, a następnie zwolnić?
ninjaxelite
1
@ninjaxelite Zgaduję, że wyślesz 1. SetCursorPos, 2. MouseEvent(LeftButtonDown), 3. SetCursorPos, 4. MouseEvent(LeftButtonUp). Potencjalnie owinąć to metodą pomocniczą
Michał Ciechan
137

Przykład, który znalazłem gdzieś tutaj w przeszłości. Może być pomocna:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class Form1 : Form
{
   [DllImport("user32.dll",CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
   public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
   //Mouse actions
   private const int MOUSEEVENTF_LEFTDOWN = 0x02;
   private const int MOUSEEVENTF_LEFTUP = 0x04;
   private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
   private const int MOUSEEVENTF_RIGHTUP = 0x10;

   public Form1()
   {
   }

   public void DoMouseClick()
   {
      //Call the imported function with the cursor's current position
      uint X = (uint)Cursor.Position.X;
      uint Y = (uint)Cursor.Position.Y;
      mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
   }

   //...other code needed for the application
}
Marcos Placona
źródło
12
Może gdzieś tu jest ?
mpen
3
Dobrze rozegrane. Dodano odniesienie do oryginalnej odpowiedzi
Marcos Placona
2
Otrzymuję błąd z tym kodem: Wywołanie funkcji PInvoke „MyForm! MyForm.Form1 :: mouse_event” spowodowało wyważenie stosu. Jest to prawdopodobne, ponieważ zarządzany podpis PInvoke nie pasuje do niezarządzanego podpisu docelowego. Sprawdź, czy konwencja wywoływania i parametry podpisu PInvoke są zgodne z docelowym niezarządzanym podpisem. Jakieś pomysły?
Abdulla
12
Musisz rzucić X i Y do uintów.
Dibesjr,
1
Działa idealnie, wymaga pewnych zmian pozycji kursora zgodnie z wymaganiami ...
Anurag Rabadia
14

Niektóre kontrolki, takie jak Button w System.Windows.Forms, mają do tego celu metodę „PerformClick”.

Denis
źródło
Jeśli formant nie ma metody PerformClick, możesz ją rozszerzyć / dodać, wystarczy wywołać OnMouseClick z odpowiednim argumentem MouseEventArgs.
Tony Hopkinson
8
Mouse.Click();

Microsoft.VisualStudio.TestTools.UITesting

zardzewiały gwóźdź
źródło
1
To trochę dziwne, że zostało to odizolowane w przestrzeni nazw testowych interfejsu użytkownika programu Visual Studio, ale przejmę to przez PInvoke każdego dnia, kiedy nie muszę filtrować zdarzeń według urządzenia.
kayleeFrye_onDeck
2
Wygląda na to, że wersja Visual Studio Community nie jest dostarczana z tą biblioteką DLL.
CM,
2
Właśnie spędziłem godzinę próbując to uruchomić, kopiując biblioteki DLL z projektu „zakodowanego testu interfejsu użytkownika” do innego i jeśli nie używasz typu projektu „kodowany test interfejsu użytkownika”, moja rada brzmi: nie przejmuj się. Nawet gdy skopiowałem wszystkie niezbędne biblioteki DLL, wyrzucił plik InvalidUITestExtensionPackageException, więc niestety wydaje się być bardzo wybredny, jeśli chodzi o uruchamianie w określonym typie projektu.
Jez
@Jez - Dobrze wiedzieć, dzięki. Sam jeszcze nie widziałem żadnych problemów, ale teraz przynajmniej wiem, że niektóre istnieją; 0)
Rusty Nail
5

Wypróbowałem kod, który opublikował Marcos i nie zadziałał. Cokolwiek podano współrzędnej Y, kursor nie poruszał się po osi Y. Poniższy kod zadziała, jeśli chcesz ustawić kursor względem lewego górnego rogu pulpitu, a nie względem aplikacji.

    [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
    private const int MOUSEEVENTF_LEFTDOWN = 0x02;
    private const int MOUSEEVENTF_LEFTUP = 0x04;
    private const int MOUSEEVENTF_MOVE = 0x0001;

    public void DoMouseClick()
    {
        X = Cursor.Position.X;
        Y = Cursor.Position.Y;

        //move to coordinates
        pt = (Point)pc.ConvertFromString(X + "," + Y);
        Cursor.Position = pt;       

        //perform click            
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    }

Używam tylko funkcji mouse_event, aby faktycznie wykonać kliknięcie. Możesz podać X i Y jakie współrzędne chcesz, użyłem wartości z pola tekstowego:

            X = Convert.ToInt32(tbX.Text);
            Y = Convert.ToInt32(tbY.Text);
AlinaM
źródło
to jest dla mnie właściwe, w zasadzie Cursor.Positionwystarcza do umieszczenia kursora myszy w dowolnym miejscu, a następnie użyj WIN32API, aby wykonać faktyczne kliknięcie.
Ge Rong
0

są to potrzeby, których nie mogę spełnić, aby zrobić coś takiego jak Keith czy Marcos Placona, zamiast po prostu je realizować

using System;
using System.Windows.Forms;

namespace WFsimulateMouseClick
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button1_Click(button1, new MouseEventArgs(System.Windows.Forms.MouseButtons.Left, 1, 1, 1, 1));

            //by the way
            //button1.PerformClick();
            // and
            //button1_Click(button1, new EventArgs());
            // are the same
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("clicked");
        }
    }
}
WiiMaxx
źródło
1
Możesz także zrobić button1_Click (null, null), jeśli nie potrzebujesz żadnego z tych parametrów.
sab669
@ sab669 oczywiście, ale nadal zależy to od jego potrzeb :-)
WiiMaxx
nie powinieneś używać nullw drugim parametrze, wyrzuci on NullReferenceException, zamiast tego użyjEventArgs.Empty
Etor Madiv
1
@EtorMadiv, jak powiedziałem wcześniej, zależy to od tego, co próbujesz zrobić do NullReferenceException
zrobienia