fix(macos): treat screen lock as AFK - #84
Conversation
HID idle time alone misses lock-screen sessions when input still occurs (mouse jiggle, background audio, etc.). Detect lock via CGSessionCopyCurrentDictionary / CGSSessionScreenIsLocked and force AFK while locked; do not return to not-afk until the screen is unlocked. Fixes ActivityWatch#66
Greptile SummaryThis PR adds macOS screen-lock detection to AFK classification.
Confidence Score: 3/5The PR should not merge until lock-triggered AFK transitions use the lock-detection time rather than backdating the interval to the last HID input. The new lock condition reaches the existing idle-time transition code, causing AFK events to begin before the screen was locked whenever the latest input predates lock detection. Files Needing Attention: aw_watcher_afk/afk.py Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Poll idle and lock state] --> B{Currently AFK?}
B -->|Yes| C{Unlocked and input below timeout?}
C -->|Yes| D[Transition to not-afk]
C -->|No| E[Continue AFK]
B -->|No| F{Locked or idle above timeout?}
F -->|Yes| G[Transition to AFK]
F -->|No| H[Continue not-afk]
|
|
Tested on MacOS |
|
@TimeToBuildBob review |
Summary
Fixes #66 — when the macOS screen is locked, aw-watcher-afk now reports AFK even if HID idle time is still low (e.g. mouse jiggle or background audio).
Previously, idle detection only used
CGEventSourceSecondsSinceLastEventType, which has no awareness of lock state. Locking the screen therefore often left the user asnot-afk.Changes
CGSessionCopyCurrentDictionary/CGSSessionScreenIsLocked(as suggested in the issue thread)is_screen_locked()returningFalse(same shape as macOS for a shared call site; real implementations left as TODO)Unlock handling is unchanged: once unlocked, normal idle timeout decides when to leave AFK (typing/Touch ID counts as input).
Note on existing PR
Related to #69, which takes a similar approach but still allows leaving AFK while locked if HID idle resets, and adds a fixed 5s delay before lock counts as AFK. This PR forces AFK for the whole lock period with no extra delay.
Test plan
is_screen_locked()returnsFalsewhen unlocked and thatCGSSessionScreenIsLockedis absent from the session dict when unlockedaw-watcher-afk --testing --verbose, lock screen (Ctrl-Cmd-Q), confirm logs showBecame AFK (screen locked)/Screen locked: Trueafkeven if idle would otherwise resetnot-afkafter activityFalse)