4

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
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • Looks to me you're making it more complicated than it needs to be. Everything you're trying to record is exposed as events in .net already. All the buttons, single click , double click, wheel. The MouseEventArgs exposes all the properties needed – tinstaafl May 28 '13 at 19:33
  • @tinstaafl thanks for your comment, but the MouseEventArgs are only for events inside the form and not outside, I'm right? correct me if not please, anyways I can't imagine how to do this using the mouseventargs, maybe if you can answer with a example of a better way to do this... thanks anyways. – ElektroStudios May 28 '13 at 19:42
  • Ok. I didn't see anything in your OP, to say you were trying to do this system wide. Here's an [article](http://msdn.microsoft.com/en-us/library/ms644990.aspx) that might help you – tinstaafl May 29 '13 at 06:10
  • That seems really hard for me and any code example in that MSDN :( – ElektroStudios May 31 '13 at 11:43
  • Here is my new question if somebody will help: stackoverflow.com/questions/16857370/setwindowshookex-for-wm-mousewheel – ElektroStudios May 31 '13 at 17:11

1 Answers1

7

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks, Really I can't do that low-level hook without taking an VB example and if that example is for WM-MOUSEWHEEL while all examples I find are for c# with things I can't translate using translators or by myself and using C# pointers, I think I will make other question about the hooks if you can't post a code, thanks again. – ElektroStudios May 31 '13 at 12:20
  • The Microsoft KB article is for VB.NET, just copy/paste the code. I don't want to reproduce it here and keep it updated when the KB article changes, there's just no point to that. Not even sure if that's legal. If that sounds like an insurmountable problem then just keep it on the shelf until you learn more. – Hans Passant May 31 '13 at 12:32
  • Maybe is a problem of my country search criteria but when I search "vb.net setwindowshookex wm_mouse_ll" in google.com and google.es there is not any KB article in the first three pages of results, can you post the link please? I see a MSDN article (wich is not in VB) but any Microsoft KB article. – ElektroStudios May 31 '13 at 12:38
  • I fumbled a letter :( Post updated with link to the KB article included. – Hans Passant May 31 '13 at 12:41
  • 1
    Here is my new question if somebody will help: stackoverflow.com/questions/16857370/setwindowshookex-for-wm-mousewheel – ElektroStudios May 31 '13 at 17:12