ユーザーが何もクリックしたり画面を操作したりせずに 60 秒が経過した後に、特定のタスクを実行させたい Visual Basic アプリケーションがあります。
したがって、基本的には、ユーザーがキーボードのキーを移動、クリック、または押すたびにタイマーをリセットしたいと考えています。
フォームの特定のコントロールでこれを行う方法は知っていますが、フォーカスがアプリケーションの外にある場合でも登録したいと思います。何か案は?
これについての助けをいただければ幸いです。
ユーザーが何もクリックしたり画面を操作したりせずに 60 秒が経過した後に、特定のタスクを実行させたい Visual Basic アプリケーションがあります。
したがって、基本的には、ユーザーがキーボードのキーを移動、クリック、または押すたびにタイマーをリセットしたいと考えています。
フォームの特定のコントロールでこれを行う方法は知っていますが、フォーカスがアプリケーションの外にある場合でも登録したいと思います。何か案は?
これについての助けをいただければ幸いです。
システムのアイドル時間 (lastinputinfo 時間) を取得するには、これを使用する必要があります。
<DllImport("user32.dll")> _
Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
End Function
ここを参照
C#ですが参考になれば幸いです。
前にコメントで述べたように、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
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