鼠标移动到窗口中的任何位置时重置计时器

时间:2013-12-12 19:38:13

标签: vb.net timer keydown mousemove onmouseclick

我有一个Visual Basic应用程序,我想让它在60秒后执行某些任务,而无需用户点击任何内容或与屏幕交互。

所以基本上我想在用户移动,点击或按下键盘上的键时重置计时器。

我知道如何使用我的表单上的特定控件来执行此操作,但即使焦点超出了我的应用程序,我也希望它能够注册。有什么想法吗?

对此的任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:3)

这是一个使用IMessageFilter的快速示例,正如我之前在评论中提到的那样。 IMessageFilter在这里特别受欢迎,因为它适用于所有形式的应用程序,而不仅仅是主要的应用程序:

Public Class Form1

    Private WithEvents IdleDetector As IdleTimeout

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        IdleDetector = New IdleTimeout(New TimeSpan(0, 1, 0)) ' one minute timeout duration
        Application.AddMessageFilter(IdleDetector)
        IdleDetector.Reset()
    End Sub

    Private Sub IdleDetector_UserIsIdle() Handles IdleDetector.UserIsIdle

        ' ... do something in here ...
        MessageBox.Show("Inactivity detected...locking some feature!")
        Button1.Enabled = False

        ' restart the timeout period?
        ' IdleDetector.Reset()
    End Sub

End Class

Public Class IdleTimeout
    Implements IMessageFilter

    Public Event UserIsIdle()

    Private Const WM_MOUSEMOVE As Integer = &H200
    Private Const WM_LBUTTONDOWN As Integer = &H201
    Private Const WM_LBUTTONUP As Integer = &H202
    Private Const WM_LBUTTONDBLCLK As Integer = &H203
    Private Const WM_RBUTTONDOWN As Integer = &H204
    Private Const WM_RBUTTONUP As Integer = &H205
    Private Const WM_RBUTTONDBLCLK As Integer = &H206
    Private Const WM_MBUTTONDOWN As Integer = &H207
    Private Const WM_MBUTTONUP As Integer = &H208
    Private Const WM_MBUTTONDBLCLK As Integer = &H209
    Private Const WM_MOUSEWHEEL As Integer = &H20A
    Private Const WM_KEYDOWN As Integer = &H100
    Private Const WM_KEYUP As Integer = &H101
    Private Const WM_SYSKEYDOWN As Integer = &H104
    Private Const WM_SYSKEYUP As Integer = &H105

    Private IdleTimeoutDuration As TimeSpan
    Private WithEvents tmr As System.Timers.Timer
    Private TargetDateTime As DateTime
    Private SC As WindowsFormsSynchronizationContext

    Public Sub New(ByVal TimeoutDuration As TimeSpan)
        SC = System.Windows.Forms.WindowsFormsSynchronizationContext.Current
        Me.IdleTimeoutDuration = TimeoutDuration
        tmr = New System.Timers.Timer
        tmr.Interval = 1000
        Me.Reset()
    End Sub

    Public Sub Reset()
        TargetDateTime = DateTime.Now.Add(IdleTimeoutDuration)
        tmr.Start()
    End Sub

    Public Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
        Select Case m.Msg
            Case WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, _
                    WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, _
                    WM_RBUTTONDOWN, WM_RBUTTONUP, WM_RBUTTONDBLCLK, _
                    WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MBUTTONDBLCLK

                TargetDateTime = DateTime.Now.Add(IdleTimeoutDuration)
        End Select

        Return False
    End Function

    Private Sub tmr_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmr.Elapsed
        If TargetDateTime.Subtract(DateTime.Now).TotalMilliseconds < 0 Then
            tmr.Stop()

            If Not IsNothing(SC) Then
                SC.Post(New System.Threading.SendOrPostCallback(AddressOf RaiseIdleEvent), Nothing)
            End If
        Else
            ' This is a one second timer so you could raise a "time out duration left" type event if you wanted to ...
        End If
    End Sub

    Private Sub RaiseIdleEvent(ByVal x As Object)
        ' ... do not call directly ...
        ' Called via SC.Post() which puts this in the main UI thread!
        RaiseEvent UserIsIdle()
    End Sub

End Class

答案 1 :(得分:3)

你必须使用它来获取系统的空闲时间(这是lastinputinfo时间)

<DllImport("user32.dll")> _
Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
End Function

参考here

这是C#,但我希望它可以帮助你。

答案 2 :(得分:1)

我从LastInputInfo获得空闲时间 我使用计时器检索它并每隔500毫秒测试一次,代码看起来像这样(它已经生产了几年了):

Private ATimer As DispatcherTimer

Public Sub New()
        ....

    ATimer = New DispatcherTimer
    AddHandler ATimer.Tick, AddressOf Me.ATimer_Tick
    ATimer.Interval = TimeSpan.FromMilliseconds(500)  'Checks for idle every 500ms
    ATimer.Start()
End Sub


Public Structure LASTINPUTINFO
    Public cbSize As Integer
    Public dwTime As Integer
End Structure

Public Declare Function GetLastInputInfo Lib "User32.dll" _
                              (ByRef lii As LASTINPUTINFO) As Boolean

Private Sub ATimer_Tick(ByVal sender As Object, ByVal e As EventArgs)

    MyLastInputInfo = New LASTINPUTINFO
    MyLastInputInfo.cbSize = Runtime.InteropServices.Marshal.SizeOf(MyLastInputInfo)

   ' get last input info from Windows
    If GetLastInputInfo(MyLastInputInfo) Then     ' if we have an input info     
       ' compute idle time
       Dim sysIdleTime_ms As Integer = (GetTickCount() - MyLastInputInfo.dwTime)

       ' ... Now you have the idle time in ms, do whatever you want with it :=)
 End Sub