Entwickler-Ecke

Sonstiges (.NET) - Frage zu MouseHooks MouseMove, MouseUp und MouseDown


markusmayer123 - Fr 23.02.18 00:15
Titel: Frage zu MouseHooks MouseMove, MouseUp und MouseDown
Hallo,

ich bin neu in dem Forum und entschuldige mich vorab, wenn ich in einer falschen Sektion poste:D


Ich beschäftige mich aktuell mit folgender Bibliothek: https://archive.codeplex.com/?p=keyboardmousehooks

Hierbei stehe ich vor folgendem Problem:

Ich würde gerne eine Schleife programmieren, welche solange ich die linke Maustaste gedrückt halte,
eine einfache Konsolenausgabe ausgibt.

Die folgende While-Schleife funktioniert natürlich nicht:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
private void MouseHook_LeftButtonUp(RamGecTools.MouseHook.MSLLHOOKSTRUCT mouseStruct)
{
     gedrückt = false;
}

private void MouseHook_LeftButtonDown(RamGecTools.MouseHook.MSLLHOOKSTRUCT mouseStruct)
{
    gedrückt = true;
}

public void MouseMoved(object sender, MouseEventArgs e)
{
    while(gedrückt == true)
    {
        Console.Writeline("abc");
    }
}


Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Moderiert von user profile iconTh69: Topic aus C# - Die Sprache verschoben am Fr 23.02.2018 um 09:10


Delete - Fr 23.02.18 00:56

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Fr 23.02.18 01:07

Hi, vielen Dank für deine Antwort.

Ja, du meinst vermutlich das hier:

C#-Quelltext
1:
2:
3:
mouseHook.LeftButtonDown += new RamGecTools.MouseHook.MouseHookCallback(MouseHook_LeftButtonDown);
mouseHook.LeftButtonUp += new RamGecTools.MouseHook.MouseHookCallback(MouseHook_LeftButtonUp);
mouseHook.Install();

Das habe ich in Form1_Load geschrieben.

Ich könnte also mit GetAsyncKeyState() einfach direkt abfragen, ob die Taste aktuell gedrückt wird und sobald sie losgelassen wird, aus der Schleife springen?

LG

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Moderiert von user profile iconTh69: Vollzitat entfernt


Delete - Fr 23.02.18 01:25

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Fr 23.02.18 12:37

Also die Ausgabe an sich funktioniert ja wunderbar.

Ich würde nur gerne ausgeben, während die linke Maustaste gedrückt ist. Sobald die nicht mehr gedrückt wird, wird ein Wert auf False gesetzt und die Ausgabe wird gestoppt.

Leider hat das mit While-Schleife nicht wirklich funktioniert.

Moderiert von user profile iconTh69: Vollzitat entfernt.


Delete - Fr 23.02.18 13:25

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Fr 23.02.18 13:40

Verzeihung, ich habe mich nicht klar ausgedrückt.

Das hier zum Beispiel funktioniert mit der Konsolenausgabe wunderbar. Allerdings nur einmalig bei einem Linksklick.
Jetzt will ich es irgendwie schaffen im MouseMoved Block eine Schleife zu schreiben, die solange eine Konsolenausgabe wie z.B. Console.WriteLine("taste wird gedrückt"); ausgibt, solange die linke Maustaste gedrückt gehalten wird.

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
private void MouseHook_LeftButtonUp(RamGecTools.MouseHook.MSLLHOOKSTRUCT mouseStruct)
{
    gedrückt = false;
}

private void MouseHook_LeftButtonDown(RamGecTools.MouseHook.MSLLHOOKSTRUCT mouseStruct)
{
    gedrückt = true;
}
     
public void MouseMoved(object sender, MouseEventArgs e)
{
    if (gedrückt == true)
    {
        Console.WriteLine("taste wird gedrückt");
    }
}


Moderiert von user profile iconTh69: Vollzitat entfernt.
Moderiert von user profile iconTh69: C#-Tags hinzugefügt


Delete - Fr 23.02.18 13:58

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Fr 23.02.18 14:22

-Ich habe mir überlegt im MouseMoved Block eine While-Schleife einzubauen, um zu überprüfen, ob die Linke Maustaste noch immer gedrückt ist und wenn ja, dass eine Konsolenausgabe erfolgt, solange der Wert true ist. Dafür habe ich den Wert "gedrückt" als boolean deklariert und setzte sie mit mouseup/mousedown auf false/true.

-Das Ereignis MouseMoved soll später dafür verwendet werden, um den Cursor zu einem bestimmten Punkt zu bewegen, während die Linke Maustaste gedrückt wird.
Zum Beispiel soll das Ereignis das hier ausführen:
Allerdings nicht die ganze Zeit, sondern wirklich nur während die Maustaste gedrückt wird.

C#-Quelltext
1:
2:
3:
4:
5:
while(gedrückt == true)
{
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 15);
    System.Threading.Thread.Sleep(25);
}


-Ich benötige die MouseHook-Klasse, damit ich außerhalb der Form prüfen kann, ob eine Maustaste gedrückt wird.

-Das Konsolenfenster habe ich nur als Testmittel genutzt. Ich wollte dadurch schauen, ob ich solange ich die linke Maustaste gedrückt halte eine Konsolenausgabe machen kann.


Ich hoffe ich konnte deine Fragen einigermaßen beantworten.

Vielen Dank für deine Hilfe!


LG

Moderiert von user profile iconTh69: Vollzitat entfernt.


Ralf Jansen - Fr 23.02.18 14:33

Zitat:
Ich benötige die MouseHook-Klasse, damit ich außerhalb der Form prüfen kann, ob eine Maustaste gedrückt wird.


Dir ist aber bewußt das der MouseMove Event den du scheinbar benutzt nur dann feuert wenn das Control an dem du den Event verdrahtet hast auch das Control ist über dem sich der Mouse Cursor gerade befindet?


markusmayer123 - Fr 23.02.18 14:54

Hi, erstmal Danke für deine Antwort.

Sorry hätte vielleicht noch hinzufügen sollen, dass MouseMoved ebenfalls von einer MouseHook-Klasse verwendet wird.
Hier wird die Methode MouseMoved registriert in der Main()

C#-Quelltext
1:
actHook.OnMouseActivity += new MouseEventHandler(MouseMoved);                    


Moderiert von user profile iconTh69: Vollzitat entfernt.


Th69 - Fr 23.02.18 14:56

Für wiederholende Aufgaben benutze einen Timer (ansonsten blockierst du mit der Schleife alle weiteren UI- bzw. MouseHook-Aktivitäten).

PS: Bitte keine ganzen Beiträge zitieren.


Ralf Jansen - Fr 23.02.18 16:41

Zitat:
Sorry hätte vielleicht noch hinzufügen sollen, dass MouseMoved ebenfalls von einer MouseHook-Klasse verwendet wird.


Meine Nase sagt mir das da was stinkt ;)
Ich bezweifle das der Move Event eine winformstypische Sender,EventArgs-Signatur hat die anderen Events der Klasse aber mit einem eigenen struct arbeiten.
Das klingt total sinnfrei da die interna bei den Hooks die gleichen sind. Da macht mann die Eventsignaturen nicht einfach so unterschiedlich.


markusmayer123 - Fr 23.02.18 16:55

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Für wiederholende Aufgaben benutze einen Timer (ansonsten blockierst du mit der Schleife alle weiteren UI- bzw. MouseHook-Aktivitäten).

Hi, vielen Dank für deine Antwort.

Ich werde es mal versuchen.

user profile iconRalf Jansen hat folgendes geschrieben Zum zitierten Posting springen:
Ich bezweifle das der Move Event eine winformstypische Sender,EventArgs-Signatur hat die anderen Events der Klasse aber mit einem eigenen struct arbeiten.
Das klingt total sinnfrei da die interna bei den Hooks die gleichen sind. Da macht mann die Eventsignaturen nicht einfach so unterschiedlich.

Ich hatte 2 verschiedene Klassen, da ich zuerst einmal eine andere benutzt habe und dann dort festgestellt habe, dass die kein MouseUp/MouseDown implementiert hatten. Daraufhin benutzte ich für MouseDown/MouseUp eine neue Klasse und behielt die alte Klasse für MouseMove.

Hab das jetzt mal geändert, damit es nicht für Verwirrung sorgt.

C#-Quelltext
1:
mouseHook.MouseMove += new RamGecTools.MouseHook.MouseHookCallback(mouseHook_MouseMove);                    


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
void mouseHook_MouseMove(RamGecTools.MouseHook.MSLLHOOKSTRUCT mouseStruct)
{
    if (gedrückt == true)
    {
        Console.WriteLine("taste wird gedrückt");
    }
}


Delete - Fr 23.02.18 21:21

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Fr 23.02.18 22:40

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Es funktioniert schon, wie es soll:


Vielen Dank!
Hast du eine Idee, wie ich das hier umsetzen könnte?

Wenn _pressed = true und ich eben keine Mausbewegung mache? Also die MouseMoved Funktion ganz weglasse?


C#-Quelltext
1:
2:
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 15);
    System.Threading.Thread.Sleep(25);


Das soll immer wieder aufgerufen werden, solange die linke Maustaste gedrückt gehalten wird.



LG


Delete - Fr 23.02.18 23:35

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Sa 24.02.18 13:23

Cool, vielen Dank! Es funktioniert wunderbar mit dem Timer :)

Eine kleine Frage noch:
Wenn ich jetzt beispielsweise im Timer Block den Befehl

C#-Quelltext
1:
Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 15);                    

mit verschiedenen Y Koordinaten also zum Beispiel


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
private void timer1_Tick(object sender, EventArgs e)
{
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 15);
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 21);
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 22);
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 22);
    Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 24);
}


Das hier ausführen will, aber nicht direkt nacheinander, sondern mit einer Art Thread.Sleep dazwischen, wie kann ich das elegant lösen in dem Fall?
Es sollen später ca. 30 solcher Befehle nacheinander folgen.

LG

Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Moderiert von user profile iconTh69: Zitat entfernt.


Delete - Sa 24.02.18 15:00

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Sa 24.02.18 16:38

Hi, danke.
Aber ist es möglich, dass die Anweisungen nicht direkt nacheinander aufgerufen werden? Also ein Sleep dazwischen einzubauen?
Gibt es da möglicherweiße eine Funktion die man über den Timer aufrufen kann?

Sorry bin noch ganz neu in C# :D


LG

Moderiert von user profile iconNarses: Komplettzitat des letzten Beitrags entfernt.


Delete - Sa 24.02.18 18:32

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Sa 24.02.18 18:51

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Weiss nicht, was du meinst. :gruebel: Aufrufe erfolgen nunmal nacheinander.
Wenn du Thread.Sleep() ständig aufrufst, dann blockst du in dieser Zeit den Haupt-Thread, also deine Anwendung per se. D.h. du kannst in dieser Zeit das Fenster der Anwendung nicht bedienen.
Mit dem Timer kannst du nebenbei, während er arbeitet, die Hauptanwendung bedienen. Wie regelmäßig der Timer etwas ausführt, hängt von seiner gesetzten .Intervall-Eigenschaft (in Millisekundnen) ab.


Ja genau, die erfolgen genau nacheinander und dazwischen suche ich was, um einen kurzen delay zwischen den Aufrufen zu haben:D
Schau mal, ich versuche mit C# ein AutoHotKey Ablauf nachzubilden, dieser sieht wie folgt aus:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
if GetKeyState(key_pressed)
{

if s
{
loop
{
DllCall("mouse_event", uint, 2, int, 0, int, 0, uint, 0, int, 0)
sleep 92
if !GetKeyState(key_pressed)
{
DllCall("mouse_event", uint, 4, int, 0, int, 0, uint, 0, int, 0)
break
}
DllCall("mouse_event", "UInt", 0x01, "UInt", 0*modifier, "UInt", 25*modifier)
sleep 92
if !GetKeyState(key_pressed)
{
DllCall("mouse_event", uint, 4, int, 0, int, 0, uint, 0, int, 0)
break
}
DllCall("mouse_event", "UInt", 0x01, "UInt", 0*modifier, "UInt", 25*modifier)
sleep 92
if !GetKeyState(key_pressed)
{
DllCall("mouse_event", uint, 4, int, 0, int, 0, uint, 0, int, 0)
break
}
DllCall("mouse_event", "UInt", 0x01, "UInt", 0*modifier, "UInt", 25*modifier)
sleep 92
if !GetKeyState(key_pressed)
{
DllCall("mouse_event", uint, 4, int, 0, int, 0, uint, 0, int, 0)
break
}
DllCall("mouse_event", "UInt", 0x01, "UInt", 0*modifier, "UInt", 22*modifier)
sleep 92


Hier ist im AutoHotKey Script auch eine Art Sleep drinne.
Das versuche ich auch in C# umzusetzen.
Ist das überhaupt möglich?

Moderiert von user profile iconTh69: Code-Tags hinzugefügt


Delete - Sa 24.02.18 19:07

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - Sa 24.02.18 19:26

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Ja, das ist möglich, und hier muss auch sleep() aufgerufen werden, damit die Befehle die nötige Zeit haben, ausgeführt werden zu können. Wo ist nun das Problem?


Okay, ja mit Thread.Sleep(92); hängt ja das ganze Programm:D


Th69 - Sa 24.02.18 19:46

Dann schau dir mal die asynchrone Programmierung [https://msdn.microsoft.com/de-de/library/hh191443(v=vs.120).aspx] an. Stichworte: async, await, Task.Delay, ...

Ich denke aber, daß du als Anfänger nicht gleich so komplexe Anwendungen entwickeln solltest (also Fernsteuerung eines anderen Programms). Warum bleibst du nicht bei AutoHotKey?


markusmayer123 - Sa 24.02.18 19:54

Dankeschön, ich schau es mir an:)

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Warum bleibst du nicht bei AutoHotKey?

Da ich sehr eingeschränkte Möglichekeiten mit AHK habe. Leider.

LG


markusmayer123 - So 25.02.18 01:11

Guten Abend zusammen!

Ich habe mal folgendes ausprobiert mit einem Async Timer:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
 private async void timer2_TickAsync(object sender, EventArgs e)
        {


            if (_pressed == true)
            {

                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 21);
                await Task.Delay(92);
            }
            
            if (_pressed == true)
            {
                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 21);
                await Task.Delay(92);
            }
           

            if (_pressed == true)
            {
                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 21);
                await Task.Delay(92);
            }
            
            if (_pressed == true)
            {
                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 21);
                await Task.Delay(92);

            }

           
            if (_pressed == true)
            {

                Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + 18);
                await Task.Delay(92);

            }
            
            if (_pressed == true)
            {
                Cursor.Position = new Point(Cursor.Position.X -11, Cursor.Position.Y + 16);
                await Task.Delay(92);


            }
            
            if (_pressed == true)
            {


                Cursor.Position = new Point(Cursor.Position.X - 11, Cursor.Position.Y + 19);
                await Task.Delay(92);
            }
}


Das funktioniert soweit auch, allerdings geht der Cursor nur Y nach unten und ignoriert die X Werte:D

Hat jemand eine Idee, woran das liegen könnte? Habe jetzt sämtliches erfolglos ausprobiert.


LG


Delete - So 25.02.18 20:01

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - So 25.02.18 20:50

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:

key_pressed ist kein bool'scher Wert, sondern entspricht einer (virtuellen) Taste, siehe Virtual Key Code [https://msdn.microsoft.com/de-de/library/windows/desktop/dd375731(v=vs.85).aspx].
Welchen Wert modifier hat oder annehmen soll, ist aus dem Skript nicht zu entnehmen.


Weiteres nachzulesen unter:
- GetKeyState() [https://msdn.microsoft.com/de-de/library/windows/desktop/ms646301%28v=vs.85%29.aspx]
- mouse_event() [https://msdn.microsoft.com/en-us/library/windows/desktop/ms646260(v=vs.85).aspx]


Guten Abend!

Erstmal vielen herzlichen Dank für deine Hilfe! :)

Ich bin deinen geposteten Code durchgegangen und habe mir die Links die du gepostet hast, angeschaut.

Mir ist leider nicht ganz klar, wie der Code jetzt ausführbar ist:D

Wenn ich jetzt annehmen würde, der Modifier hätte den Wert 1 und ich würde die Linke Maustaste drücken wollen, müsste ich doch dann in Form1_Load das hier schreiben, um den Code ausführen zu können:


C#-Quelltext
1:
DoAutoHotKey(0x011);                    


PS: Tut mir leid für die dummen Fragen:P

Edit2:

C#-Quelltext
1:
DoAutoHotKey(0x011);                    
Das hier kommt glaub ich in einen Timer und
Timer1.Enabled = true;
in form1_load
LG


Delete - So 25.02.18 22:33

- Nachträglich durch die Entwickler-Ecke gelöscht -


markusmayer123 - So 25.02.18 23:04

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Gute Frage. Wo wird es denn im AutoHotKey ausgeführt? Ich hätte es wohl in einem MouseDown oder KeyDown Ereignis ausgeführt.
Solltest du es im Timer ausführen, dann muss aber die while-Schleife verschwinden, ansonsten hängt sich die Anwendung noch auf.


Das wird auch innerhalb einer Loop ausgeführt.
Okay, ich teste ein wenig herum.

Vielen Dank nochmal!

Edit: Also ohne Timer schaffe ich es garnicht, DoAutoHotkey(); auszuführen.

LG

Markus


Delete - So 25.02.18 23:23

- Nachträglich durch die Entwickler-Ecke gelöscht -