2013-12-12 82 views
0

我有一個Visual Basic應用程序,我希望在60秒後沒有用戶單擊任何內容或與屏幕交互時執行某些任務。當鼠標移動到窗口中的任何位置時重置計時器

所以基本上我想在用戶移動,點擊或按下鍵盤上的某個按鍵時重置計時器。

我知道如何用我的表單上的特定控件來做到這一點,但即使焦點位於我的應用程序之外,我也希望它能夠註冊。有任何想法嗎?

任何幫助,這將不勝感激。

+0

後,我們得到了一個鼠標點擊 - 我們應該激活主窗口,然後調用彈出窗口中的控件的.Focus()按預期工作。 – user2526236

+0

看看這個:http://stackoverflow.com/a/20434431/897326它回答你的問題嗎? – Neolisk

+0

在自定義類中實現IMessageFilter,並在其WndProc()中捕獲所有需要的「操作」。如果在您的時間限制內未檢測到任何活動,請讓該班級舉辦自定義活動。 –

回答

2

下面是使用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 
+0

「即使焦點位於我的應用程序之外」 –

+0

無論應用程序關注什麼,它都可以工作。 ......但我把這個問題解釋爲一個空閒的探測器**,僅僅是爲了他的應用程序**,但我可以看到它是如何被解釋爲系統範圍的。如果是這種情況,那麼你可以使用SomeNickName的方法,或者實現低級別的鼠標/鍵盤鉤子。 –

3

你有這個工作得到了系統的空閒時間(這是lastinputinfo時間)

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

參考here

這是C#,但我希望它可以幫助你。

1

我從LastInputInfo獲得空閒時間。
我用一個定時器來檢索並測試它每500ms,代碼如下所示(它已經在生產了好幾年):

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 
相關問題