none
Mouse Recognition code, How to create?

    Question

  • In designing a game, I seek to have code recognize the fact that the mouse has not necessarily been moved (MouseMove) but the extent that it has been moved. This detection is essentially not by distance but how erratic the mouse is moved. (back and forth quickly)  I would also like this to work when the mouse is outside the form area.

    Thoughts appreciated....

    Saturday, January 19, 2013 5:23 PM

Answers

  • You should be able to just monitor the mouse position in your game loop's input routine.  The MousePosition property is global so it will work regardless of what application has focus.  Here is an example with a crude monitoring routine.  In this example, a background worker component serves as the game-loop substitue:

    Public Class Form1
        Friend WithEvents BackgroundWorker1 As New System.ComponentModel.BackgroundWorker With {.WorkerReportsProgress = True, .WorkerSupportsCancellation = True}
    
        Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            If BackgroundWorker1.IsBusy Then
                BackgroundWorker1.CancelAsync()
                e.Cancel = True
            End If
        End Sub
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
            Dim shakeCount As Integer = 0
            Dim shakeThreshold As Integer = 5
            Dim timeDelta As Integer = 0
            Dim position As Point = MousePosition
            While Not BackgroundWorker1.CancellationPending
                If (shakeCount Mod 2) = 0 Then
                    If MousePosition.X > position.X Then
                        shakeCount += 1
                        position = MousePosition
                        timeDelta += 10
                    End If
                Else
                    If MousePosition.X < position.X Then
                        shakeCount += 1
                        position = MousePosition
                        timeDelta += 10
                    End If
                End If
                timeDelta -= 1
                If timeDelta < 1 Then
                    timeDelta = 0
                    shakeCount = 0
                    position = MousePosition
                End If
                If shakeCount >= shakeThreshold Then
                    worker.ReportProgress(0)
                    timeDelta = 0
                    shakeCount = 0
                    position = MousePosition
                End If
                System.Threading.Thread.Sleep(10)
            End While
        End Sub
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            MessageBox.Show("Mouse Shake!")
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Me.Close()
        End Sub
    End Class
     


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, January 19, 2013 9:45 PM
    Moderator
  • Determining how erratic a set of points are sounds to me similar to finding the corelation of a group of points.  The points for the corelation calculation would need to be gathered within a global mouse hook code.  Codes for both of these pieces should be available searching the net, but this sounds like an approach, without knowing why you want to know the mouse "erraticness".

    --
    Mike
    Saturday, January 19, 2013 6:44 PM
  • What you want, as far as tracking the mouse outside of the form can actually be done without API, but with timers, so I think a global hook would be better(to consume less cpu). Here is an example of a global mouse hook.

    Here is an example using the WindowsHookLib provided here(3rd party site - VBForums):

    Global hooks

    In order for this example to work, you will need to create a .Net Framework 3.5 project, and you will need to add a reference to WindowsHookLib.Dll(from the site listed above)

    Option Strict On
    Public Class Form1
        'Requires .Net 3.5
        Friend WithEvents MouseHook1 As New WindowsHook.MouseHook
        Private Sub MouseHook1_MouseDown(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseDown
            Me.Text = "mouse down(" & e.Button.ToString & ")"
        End Sub
        Private Sub MouseHook1_MouseUp(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseUp
            Me.Text = "mouse up(" & e.Button.ToString & ")"
        End Sub
        Private Sub MouseHook1_MouseClick1(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MouseHook1.MouseClick
            Me.Text = "click"
        End Sub
        Private Sub MouseHook1_MouseDoubleClick1(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MouseHook1.MouseDoubleClick
            Me.Text = "doubleclick"
        End Sub
        Private Sub MouseHook1_MouseWheel(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseWheel
            Me.Text = e.Delta.ToString
        End Sub
        Private Sub MouseHook1_MouseMove(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseMove
            Me.Text = e.Location.ToString
        End Sub
        Private Sub MouseHook1_StateChanged(ByVal sender As Object, ByVal e As WindowsHook.StateChangedEventArgs) Handles MouseHook1.StateChanged
            Me.Text = "Mouse Hook " & e.State.ToString & "!"
        End Sub
        Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            Me.MouseHook1.RemoveHook()
            MsgBox("mouse hook removed")
        End Sub
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.MouseHook1.InstallHook()
            MsgBox("mouse hook installed")
        End Sub
    End Class


    “If you want something you've never had, you need to do something you've never done.”

    Don't forget to mark helpful posts and answers ! Answer an interesting question? Write a new article about it! My Articles
    *This post does not reflect the opinion of Microsoft, or its employees.


    Saturday, January 19, 2013 6:50 PM
    Moderator
  • In addition to my previous post, I've been giving some thought about (Back and forth quickly)

    I think if you were to set up a discrimination factor, i.e. a Minimum left point, and a minimum right point, and time how long it took a the mouse to be moved to to a discrimination point and back to the other(complete cycle, starting on either side), then you could possibly achieve this.


    “If you want something you've never had, you need to do something you've never done.”

    Don't forget to mark helpful posts and answers ! Answer an interesting question? Write a new article about it! My Articles
    *This post does not reflect the opinion of Microsoft, or its employees.


    Saturday, January 19, 2013 8:28 PM
    Moderator
  • The real problem I believe is how to determine erraticness in ticks since what I believe is extremely erratic may only be very erratic to somebody else.

    For example in the attached code I use a stopwatch to determine ticks at the time the mouse begins incrementing or decrimenting while moving across the screen (I think). I had to use a Label resize event to determine when incrementing stopped and decrimenting started and vice versa in order to realize erraticness of mouse movement.

    This may get you in the ballpark of what you're trying to do. Or it may not resemble at all what you're trying to do since I'm not sure exactly what you mean by detection.

    It works while the mouse is outside the Form area.

    Public Class Form1
    
        Dim MPosit1 As Integer = 0
        Dim MPosit2 As Integer = 0
        Dim Timing As New Stopwatch
        Dim MouseSpeed As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Timing.Start()
            Timer1.Interval = 1
            Timer2.Interval = 5
            Timer3.Interval = 10
            Timer1.Start()
            Timer2.Start()
            Timer3.Start()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            MPosit1 = MousePosition.X
        End Sub
    
        Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
            MPosit2 = MousePosition.X
            If MPosit1 > MPosit2 Then
                Label1.Text = ""
                Label2.Text = "Decrimenting"
            ElseIf MPosit1 < MPosit2 Then
                Label1.Text = "Incrementing"
                Label2.Text = ""
            End If
        End Sub
    
        Private Sub Timer3_Tick(sender As Object, e As EventArgs) Handles Timer3.Tick
            If MouseSpeed > 100000 And MouseSpeed < 200000 Then
                Label3.Text = "Mouse extremely erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 200000 And MouseSpeed < 300000 Then
                Label3.Text = "Mouse very erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 300000 And MouseSpeed < 400000 Then
                Label3.Text = "Mouse mostly erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 400000 And MouseSpeed < 500000 Then
                Label3.Text = "Mouse somewhat erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 500000 And MouseSpeed < 600000 Then
                Label3.Text = "Mouse erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 600000 Then
                Label3.Text = "Mouse rather slow" & "..." & CStr(MouseSpeed)
            End If
        End Sub
    
        Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
    
        End Sub
    
        Private Sub Label2_Click(sender As Object, e As EventArgs) Handles Label2.Click
    
        End Sub
    
        Private Sub Label1_Resize(sender As Object, e As EventArgs) Handles Label1.Resize
            If Label1.Text = "" Then
                MouseSpeed = Timing.ElapsedTicks
                Timing.Restart()
            End If
        End Sub
    
        Private Sub Label2_Resize(sender As Object, e As EventArgs) Handles Label2.Resize
            If Label2.Text = "" Then
                MouseSpeed = Timing.ElapsedTicks
                Timing.Restart()
            End If
        End Sub
    
        Private Sub Label3_Click(sender As Object, e As EventArgs) Handles Label3.Click
    
        End Sub
    
    End Class


    You've taught me everything I know but not everything you know.

    Saturday, January 19, 2013 9:21 PM

All replies

  • Determining how erratic a set of points are sounds to me similar to finding the corelation of a group of points.  The points for the corelation calculation would need to be gathered within a global mouse hook code.  Codes for both of these pieces should be available searching the net, but this sounds like an approach, without knowing why you want to know the mouse "erraticness".

    --
    Mike
    Saturday, January 19, 2013 6:44 PM
  • What you want, as far as tracking the mouse outside of the form can actually be done without API, but with timers, so I think a global hook would be better(to consume less cpu). Here is an example of a global mouse hook.

    Here is an example using the WindowsHookLib provided here(3rd party site - VBForums):

    Global hooks

    In order for this example to work, you will need to create a .Net Framework 3.5 project, and you will need to add a reference to WindowsHookLib.Dll(from the site listed above)

    Option Strict On
    Public Class Form1
        'Requires .Net 3.5
        Friend WithEvents MouseHook1 As New WindowsHook.MouseHook
        Private Sub MouseHook1_MouseDown(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseDown
            Me.Text = "mouse down(" & e.Button.ToString & ")"
        End Sub
        Private Sub MouseHook1_MouseUp(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseUp
            Me.Text = "mouse up(" & e.Button.ToString & ")"
        End Sub
        Private Sub MouseHook1_MouseClick1(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MouseHook1.MouseClick
            Me.Text = "click"
        End Sub
        Private Sub MouseHook1_MouseDoubleClick1(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MouseHook1.MouseDoubleClick
            Me.Text = "doubleclick"
        End Sub
        Private Sub MouseHook1_MouseWheel(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseWheel
            Me.Text = e.Delta.ToString
        End Sub
        Private Sub MouseHook1_MouseMove(ByVal sender As Object, ByVal e As WindowsHook.MouseEventArgs) Handles MouseHook1.MouseMove
            Me.Text = e.Location.ToString
        End Sub
        Private Sub MouseHook1_StateChanged(ByVal sender As Object, ByVal e As WindowsHook.StateChangedEventArgs) Handles MouseHook1.StateChanged
            Me.Text = "Mouse Hook " & e.State.ToString & "!"
        End Sub
        Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            Me.MouseHook1.RemoveHook()
            MsgBox("mouse hook removed")
        End Sub
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.MouseHook1.InstallHook()
            MsgBox("mouse hook installed")
        End Sub
    End Class


    “If you want something you've never had, you need to do something you've never done.”

    Don't forget to mark helpful posts and answers ! Answer an interesting question? Write a new article about it! My Articles
    *This post does not reflect the opinion of Microsoft, or its employees.


    Saturday, January 19, 2013 6:50 PM
    Moderator
  • In addition to my previous post, I've been giving some thought about (Back and forth quickly)

    I think if you were to set up a discrimination factor, i.e. a Minimum left point, and a minimum right point, and time how long it took a the mouse to be moved to to a discrimination point and back to the other(complete cycle, starting on either side), then you could possibly achieve this.


    “If you want something you've never had, you need to do something you've never done.”

    Don't forget to mark helpful posts and answers ! Answer an interesting question? Write a new article about it! My Articles
    *This post does not reflect the opinion of Microsoft, or its employees.


    Saturday, January 19, 2013 8:28 PM
    Moderator
  • The real problem I believe is how to determine erraticness in ticks since what I believe is extremely erratic may only be very erratic to somebody else.

    For example in the attached code I use a stopwatch to determine ticks at the time the mouse begins incrementing or decrimenting while moving across the screen (I think). I had to use a Label resize event to determine when incrementing stopped and decrimenting started and vice versa in order to realize erraticness of mouse movement.

    This may get you in the ballpark of what you're trying to do. Or it may not resemble at all what you're trying to do since I'm not sure exactly what you mean by detection.

    It works while the mouse is outside the Form area.

    Public Class Form1
    
        Dim MPosit1 As Integer = 0
        Dim MPosit2 As Integer = 0
        Dim Timing As New Stopwatch
        Dim MouseSpeed As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Timing.Start()
            Timer1.Interval = 1
            Timer2.Interval = 5
            Timer3.Interval = 10
            Timer1.Start()
            Timer2.Start()
            Timer3.Start()
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            MPosit1 = MousePosition.X
        End Sub
    
        Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
            MPosit2 = MousePosition.X
            If MPosit1 > MPosit2 Then
                Label1.Text = ""
                Label2.Text = "Decrimenting"
            ElseIf MPosit1 < MPosit2 Then
                Label1.Text = "Incrementing"
                Label2.Text = ""
            End If
        End Sub
    
        Private Sub Timer3_Tick(sender As Object, e As EventArgs) Handles Timer3.Tick
            If MouseSpeed > 100000 And MouseSpeed < 200000 Then
                Label3.Text = "Mouse extremely erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 200000 And MouseSpeed < 300000 Then
                Label3.Text = "Mouse very erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 300000 And MouseSpeed < 400000 Then
                Label3.Text = "Mouse mostly erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 400000 And MouseSpeed < 500000 Then
                Label3.Text = "Mouse somewhat erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 500000 And MouseSpeed < 600000 Then
                Label3.Text = "Mouse erratic" & "..." & CStr(MouseSpeed)
            ElseIf MouseSpeed > 600000 Then
                Label3.Text = "Mouse rather slow" & "..." & CStr(MouseSpeed)
            End If
        End Sub
    
        Private Sub Label1_Click(sender As Object, e As EventArgs) Handles Label1.Click
    
        End Sub
    
        Private Sub Label2_Click(sender As Object, e As EventArgs) Handles Label2.Click
    
        End Sub
    
        Private Sub Label1_Resize(sender As Object, e As EventArgs) Handles Label1.Resize
            If Label1.Text = "" Then
                MouseSpeed = Timing.ElapsedTicks
                Timing.Restart()
            End If
        End Sub
    
        Private Sub Label2_Resize(sender As Object, e As EventArgs) Handles Label2.Resize
            If Label2.Text = "" Then
                MouseSpeed = Timing.ElapsedTicks
                Timing.Restart()
            End If
        End Sub
    
        Private Sub Label3_Click(sender As Object, e As EventArgs) Handles Label3.Click
    
        End Sub
    
    End Class


    You've taught me everything I know but not everything you know.

    Saturday, January 19, 2013 9:21 PM
  • You should be able to just monitor the mouse position in your game loop's input routine.  The MousePosition property is global so it will work regardless of what application has focus.  Here is an example with a crude monitoring routine.  In this example, a background worker component serves as the game-loop substitue:

    Public Class Form1
        Friend WithEvents BackgroundWorker1 As New System.ComponentModel.BackgroundWorker With {.WorkerReportsProgress = True, .WorkerSupportsCancellation = True}
    
        Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            If BackgroundWorker1.IsBusy Then
                BackgroundWorker1.CancelAsync()
                e.Cancel = True
            End If
        End Sub
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            BackgroundWorker1.RunWorkerAsync()
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
            Dim shakeCount As Integer = 0
            Dim shakeThreshold As Integer = 5
            Dim timeDelta As Integer = 0
            Dim position As Point = MousePosition
            While Not BackgroundWorker1.CancellationPending
                If (shakeCount Mod 2) = 0 Then
                    If MousePosition.X > position.X Then
                        shakeCount += 1
                        position = MousePosition
                        timeDelta += 10
                    End If
                Else
                    If MousePosition.X < position.X Then
                        shakeCount += 1
                        position = MousePosition
                        timeDelta += 10
                    End If
                End If
                timeDelta -= 1
                If timeDelta < 1 Then
                    timeDelta = 0
                    shakeCount = 0
                    position = MousePosition
                End If
                If shakeCount >= shakeThreshold Then
                    worker.ReportProgress(0)
                    timeDelta = 0
                    shakeCount = 0
                    position = MousePosition
                End If
                System.Threading.Thread.Sleep(10)
            End While
        End Sub
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            MessageBox.Show("Mouse Shake!")
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Me.Close()
        End Sub
    End Class
     


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, January 19, 2013 9:45 PM
    Moderator