Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Record mouse Middle button and wheel scroll

I've made a Class to record the mouse actions, for example to record a task with the mouse (move mouse here and click left button there and... that.)

After recording the mouse actions/task, I can reproduce it from the Class with a thread I made.

What I need is to implement the Middle button of the mouse and the Wheel scrolls too, but I don't have idea how to do that, was a little hard for me to use and understand "GetAsyncKeyState" and I can't found information about "GetAsyncKeyState middle button state" or the wheel scroll (to scroll down/up).

#Region " Record Mouse Class "

' [ Record Mouse Functions ]
'
' // By Elektro H@cker
'
' Examples :
' Record_Mouse.Start_Record()
' Record_Mouse.Stop_Record()
' Record_Mouse.Play() : While Not Record_Mouse.Play_Is_Completed : Application.DoEvents() : End While
' Record_Mouse.Mouse_Speed = 50

Public Class Record_Mouse

''' <summary>
''' Sets the speed of recording/playing the mouse actions.
''' Default value is 25.
''' </summary>
Public Shared Mouse_Speed As Int64 = 25

''' <summary>
''' Gets the status pf the current mouse play.
''' False = mouse task is still playing.
''' True = Mouse task play is done.
''' </summary>
Public Shared Play_Is_Completed As Boolean = False

' Where the mouse coordenates will be stored:
Private Shared Coordenates_List As New List(Of Point)
' Where the mouse clicks will be stored:
Private Shared Clicks_Dictionary As New Dictionary(Of Int64, MouseButton)
' Timer to record the mouse:
Private Shared WithEvents Record_Timer As New Timer
' Button click count to rec/play clicks:
Private Shared Click_Count As Int32 = 0
' Thread to reproduce the mouse actions:
Private Shared Thread_MousePlay_Var As System.Threading.Thread = New Threading.Thread(AddressOf Thread_MousePlay)
' API to record the current mouse button state:
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
' API to reproduce a mouse button click:
Private Declare Sub Mouse_Event Lib "User32" Alias "mouse_event" (ByVal dwFlags As MouseButton, ByVal dx As Integer, ByVal dy As Integer, ByVal dwData As Integer, ByVal dwExtraInfo As Integer)
' GetAsyncKeyState buttons status
Private Shared Last_ClickState_Left As Int64 = -1
Private Shared Last_ClickState_Right As Int64 = -1

Enum MouseButton

    Left_Down = &H2    ' Left button (hold)
    Left_Up = &H4      ' Left button (release)

    Right_Down = &H8   ' Right button (hold)
    Right_Up = &H10    ' Right button (release)

    Middle_Down = &H20 ' Middle button (hold)
    Middle_Up = &H40   ' Middle button (release)

    Left               ' Left   button (press)
    Right              ' Right  button (press)
    Middle             ' Middle button (press)

End Enum

''' <summary>
''' Starts recording the mouse actions over the screen.
''' It records the position of the mouse and left/right button clicks.
''' </summary>
Public Shared Sub Start_Record()
    Play_Is_Completed = False
    Record_Timer.Interval = Mouse_Speed
    Coordenates_List.Clear() : Clicks_Dictionary.Clear() : Click_Count = 0
    Record_Timer.Start()
End Sub

''' <summary>
''' Stop recording the mouse actions.
''' </summary>
Public Shared Sub Stop_Record()
    Record_Timer.Stop()
End Sub

''' <summary>
''' Reproduce the mouse actions.
''' </summary>
Public Shared Sub Play()
    Thread_MousePlay_Var = New Threading.Thread(AddressOf Thread_MousePlay)
    Thread_MousePlay_Var.IsBackground = True
    Thread_MousePlay_Var.Start()
End Sub

' Procedure used to store the mouse actions
Private Shared Sub Record_Timer_Tick(sender As Object, e As EventArgs) Handles Record_Timer.Tick

    Coordenates_List.Add(Control.MousePosition)

    If Not Last_ClickState_Left = GetAsyncKeyState(1) Then
        Last_ClickState_Left = GetAsyncKeyState(1)
        If GetAsyncKeyState(1) = 32768 Then
            Click_Count += 1
            Coordenates_List.Add(Nothing)
            Clicks_Dictionary.Add(Click_Count, MouseButton.Left_Down)
        ElseIf GetAsyncKeyState(1) = 0 Then
            Click_Count += 1
            Coordenates_List.Add(Nothing)
            Clicks_Dictionary.Add(Click_Count, MouseButton.Left_Up)
        End If
    End If

    If Not Last_ClickState_Right = GetAsyncKeyState(2) Then
        Last_ClickState_Right = GetAsyncKeyState(2)
        If GetAsyncKeyState(2) = 32768 Then
            Click_Count += 1
            Coordenates_List.Add(Nothing)
            Clicks_Dictionary.Add(Click_Count, MouseButton.Right_Down)
        ElseIf GetAsyncKeyState(2) = 0 Then
            Click_Count += 1
            Coordenates_List.Add(Nothing)
            Clicks_Dictionary.Add(Click_Count, MouseButton.Right_Up)
        End If
    End If

End Sub

' Procedure to play a mouse button (click)
Private Shared Sub Mouse_Click(ByVal MouseButton As MouseButton)
    Select Case MouseButton
        Case MouseButton.Left : Mouse_Event(MouseButton.Left_Down, 0, 0, 0, 0) : Mouse_Event(MouseButton.Left_Up, 0, 0, 0, 0)
        Case MouseButton.Right : Mouse_Event(MouseButton.Right_Down, 0, 0, 0, 0) : Mouse_Event(MouseButton.Right_Up, 0, 0, 0, 0)
        Case MouseButton.Middle : Mouse_Event(MouseButton.Middle_Down, 0, 0, 0, 0) : Mouse_Event(MouseButton.Middle_Up, 0, 0, 0, 0)
        Case Else : Mouse_Event(MouseButton, 0, 0, 0, 0)
    End Select
End Sub

' Thread used for reproduce the mouse actions
Private Shared Sub Thread_MousePlay()

    Click_Count = 0

    For Each Coordenate In Coordenates_List

        Threading.Thread.Sleep(Mouse_Speed)

        If Coordenate = Nothing Then
            Click_Count += 1
            If Click_Count > 1 Then Mouse_Click(Clicks_Dictionary.Item(Click_Count))
        Else
            Cursor.Position = Coordenate
        End If

        Application.DoEvents()

    Next

    Play_Is_Completed = True

End Sub

End Class

#End Region
like image 378
ElektroStudios Avatar asked Mar 23 '23 19:03

ElektroStudios


1 Answers

You can get the middle-mouse button with GetAsyncKeyState(4). But you'll never get mouse scroll messages with this approach, there isn't any way to ask for the scroll button position. You must rely on the Window message that tells you that the mouse was scrolled, WM_MOUSEWHEEL.

The requirement that a recording is made even if your own window doesn't have the focus requires a fundamentally different approach, you need to use a low-level hook. A hook set by SetWindowsHookEx(), it will call a method in your program when a mouse event occurs.

No point in posting the code for that, there are lots of samples available for that on the Internet. The proper Google query for it is "vb.net setwindowshookex wh_mouse_ll". The first hit is already very good, the Microsoft KB article has almost everything you need. The way it uses SetWindowsHookEx() does however need tweaking, as shown it will only record mouse events for your own program. Instead, use LoadLibrary("user32.dll") and pass the return value as the 3rd argument, 0 for the 4th argument to get it to record every mouse event.

like image 172
Hans Passant Avatar answered Apr 01 '23 04:04

Hans Passant