2013-12-12 4 views
0

사용자가 아무 것도 클릭하지 않거나 화면과 상호 작용하지 않고 60 초 후에 특정 작업을 수행 할 Visual Basic 응용 프로그램이 있습니다.마우스가 윈도우의 어느 곳 으로든 이동하면 타이머 재설정

기본적으로 사용자가 키보드를 움직이거나 클릭하거나 키를 누르면 타이머를 재설정하고 싶습니다.

내 양식의 특정 컨트롤을 사용하여이를 수행하는 방법을 알고 있지만 내 응용 프로그램 외부에 포커스가 있어도 등록하고 싶습니다. 어떤 아이디어?

이 문제에 도움을 주시면 매우 감사하겠습니다.

+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 

그것은 C 번호의 here

참조하지만 난 당신을 도움이되기를 바랍니다.

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