VBA code to check inactivity on a sheet and display an alert

kelly mort

Well-known Member
Joined
Apr 10, 2017
Messages
2,169
Office Version
  1. 2016
Platform
  1. Windows
I have been doing some digging for a while now and I have come across cool stuffs concerning what I want to achieve.

The only setback is that they are scattered all over in bits.

So I came across this code from @Tom Urtis which tacks the movement of the mouse.

Code:
Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Public Type POINTAPI
x As Long
y As Long
End Type
 
Sub PositionXY()
Dim lngCurPos As POINTAPI
Do
GetCursorPos lngCurPos
Range("A1").Value = "X: " & lngCurPos.x & " Y: " & lngCurPos.y
DoEvents
Loop
End Sub

I want to display an alert when there is inactivity in the system for a given duration.

**I will use this to prompt user to login.
**If the alert is on already, I don’t want to pop it again(as that might cause some form of conflict)

Each time there is mouse movement, I want to reset the timer.

When I leave the active workbook to any other window, I want to show the alert (in this case an input box to accept user password) immediately.

I have also come across amazing workarounds from @Jaafar Tribak and the likes:

But I am finding it tougher to rightfully connect the dots.

I will be more than happy if someone can help me out for it.

Thanks in advance
Kelly Mort
 

Excel Facts

Which lookup functions find a value equal or greater than the lookup value?
MATCH uses -1 to find larger value (lookup table must be sorted ZA). XLOOKUP uses 1 to find values greater and does not need to be sorted.
Please find the sample file below. Maybe it can be achieved with a less complex procedure but this is the best I can do. In this example, it checks for 10 sec. inactivity. I add a comment in Module1 where you should change the duration per your need. Have a good day!
 
Upvote 0
Please find the sample file below. Maybe it can be achieved with a less complex procedure but this is the best I can do. In this example, it checks for 10 sec. inactivity. I add a comment in Module1 where you should change the duration per your need. Have a good day!
I have tested the code.
It keeps popping the message “move mouse” even when I am still interacting with the sheet or workbook.

And sometimes the message keeps popping continuously.
 
Upvote 0
After thinking a bit, any effort will be useless.
When you click inside a cell to enter a value, any macro will be stopped. This is the nature of Excel. You can't change it.
Any user can enter into a cell and can wait for hours without doing nothing.
 
Upvote 0
After thinking a bit, any effort will be useless.
When you click inside a cell to enter a value, any macro will be stopped. This is the nature of Excel. You can't change it.
Any user can enter into a cell and can wait for hours without doing nothing.
Okay

But in my case, user would be able to interact with cells directly.

All entries would be done with userforms
 
Upvote 0
If you are using a modeless userform, you can try the following code.

If the userform is modal or if the workbook is in edit mode as pointed out by Flashbond then, you will need to use a windows timer. I don't have a code for that at hand but, in theory, it could be done.

IdleTime.xlsm

This is the code if you are using a modeless userform:

1- Add a new class Module to your vbaproject and give the newly created class the name of CIdleTimer
Place this code in the Class Module:
VBA Code:
Option Explicit

Event OnIdleTimeReached(ByVal IdleMinutesElapsed As Long)
Private WithEvents MonitorUserInput As CommandBars

Private Type LASTINPUTINFO
    cbSize As Long
    dwTime As Long
End Type

#If VBA7 Then
    #If Win64 Then
        Private Declare PtrSafe Function GetTickCount Lib "kernel32" Alias "GetTickCount64" () As LongLong
    #Else
        Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
    #End If
    Private Declare PtrSafe Function SetThreadExecutionState Lib "Kernel32.dll" (ByVal esFlags As Long) As Long
    Private Declare PtrSafe Function GetLastInputInfo Lib "user32" (plii As Any) As Long
#Else
    Private Declare Function GetTickCount Lib "kernel32" () As Long
    Private Declare Function SetThreadExecutionState Lib "Kernel32.dll" (ByVal esFlags As Long) As Long
    Private Declare Function GetLastInputInfo Lib "user32" (plii As Any) As Long
#End If

Private lMaxIdleTime As Long


Public Property Let MaxIdleTimeInMinutes(ByVal vNewValue As Long)
    If vNewValue <= 0& Then
        Set MonitorUserInput = Nothing
        PreventSleepMode = False
        MsgBox "Error !!" & vbNewLine & "Idle time must be greater to 1 Minute.", vbCritical
        Exit Property
    End If
    lMaxIdleTime = vNewValue
End Property

Public Property Get MaxIdleTimeInMinutes() As Long
    MaxIdleTimeInMinutes = lMaxIdleTime
End Property


Private Sub Class_Initialize()
    Set MonitorUserInput = Application.CommandBars
    Call MonitorUserInput_OnUpdate
End Sub

Private Sub Class_Terminate()
    PreventSleepMode = False
End Sub

Private Sub MonitorUserInput_OnUpdate()

    Static bIdleTimeReached As Boolean
    Dim tLInfo As LASTINPUTINFO
    Dim lInterval As Double
    
    tLInfo.cbSize = LenB(tLInfo)
    Call GetLastInputInfo(tLInfo)    
   lInterval = Int(((GetTickCount() - tLInfo.dwTime) / 1000&))
    If lInterval = 0& Then
        bIdleTimeReached = False
    End If
    If (lInterval / 60& >= lMaxIdleTime) And lMaxIdleTime <> 0 Then
        If bIdleTimeReached = False Then
            bIdleTimeReached = True
            RaiseEvent OnIdleTimeReached(lMaxIdleTime)
        End If
    End If
    PreventSleepMode = True
    With Application.CommandBars.FindControl(ID:=2040&)
        .Enabled = Not .Enabled
    End With
    
End Sub

Private Property Let PreventSleepMode(ByVal bPrevent As Boolean)
    Const ES_SYSTEM_REQUIRED As Long = &H1
    Const ES_DISPLAY_REQUIRED As Long = &H2
    Const ES_AWAYMODE_REQUIRED = &H40
    Const ES_CONTINUOUS As Long = &H80000000
 
    If bPrevent Then
        Call SetThreadExecutionState(ES_CONTINUOUS Or ES_DISPLAY_REQUIRED Or ES_SYSTEM_REQUIRED Or ES_AWAYMODE_REQUIRED)
    Else
        Call SetThreadExecutionState(ES_CONTINUOUS)
    End If
End Property



2- UserForm Module:
VBA Code:
Option Explicit

Private WithEvents Wb As CIdleTimer

Private Sub UserForm_Initialize()
    Set Wb = New CIdleTimer
    Wb.MaxIdleTimeInMinutes = 1  '<== 1 Minute test.
End Sub

Private Sub Wb_OnIdleTimeReached(ByVal IdleMinutesElapsed As Long)
    MsgBox IdleMinutesElapsed & " Minute(s) have elapsed w/o user activity.", vbSystemModal, "Idle Time reached !!"
    'Do some other thing(s) here.
End Sub
 
Upvote 0
Solution
Thanks @Jaafar Tribak
Your code is working great 👍🏽
I am very grateful

About this part:
When I leave the active workbook to any other window, I want to show the alert (in this case an input box to accept user password) immediately.

Is there an easy solution to it?
 
Upvote 0
Password for what ?

And when you say "leave to any other window", does that include other excel workbooks ? Have you tried using the Window_Deactivate event ?
 
Upvote 0

Forum statistics

Threads
1,215,110
Messages
6,123,138
Members
449,098
Latest member
Doanvanhieu

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top