After fighting with trying to get the amount of time since a user has done something with the system, I’ve determined that CGEventSourceSecondsSinceLastEventType is broken. The documentation indicates that calling it like:
CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType)
will tell me how many seconds since the user last moved the mouse, touched the keyboard, etc. The docs say:
The various system and app defined events do not contribute to this event type’s time.
Unfortunately this just isn’t true. In one app I’m working on, I have a timer that fires every 5 seconds and prints the idle time. It starts going up, but then a notification comes in and it resets back to zero without me touching the keyboard. So, this call is almost useless as I need to know when things are idle in order to perform some tasks. While some of you are saying that I can use a Carbon Event Idle Timer, it turns out that they don’t work in background only apps. My only solution is to make the above call using something like:
+ (double) idleTimeInSeconds { double idleTime = 0; double tempIdleTime = 0; tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventLeftMouseDown); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventLeftMouseUp); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventRightMouseDown); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventRightMouseUp); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventMouseMoved); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventLeftMouseDragged); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventRightMouseDragged); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventKeyDown); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventKeyUp); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventFlagsChanged); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventScrollWheel); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventTabletPointer); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventTabletProximity); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventOtherMouseDown); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventOtherMouseUp); if (idleTime == 0 || tempIdleTime < idleTime) { idleTime = tempIdleTime; } tempIdleTime = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGEventOtherMouseDragged); return idleTime; }
Wow, that is freaking ugly, but at least I know exactly when a user event occurred. Feel free to use my code in any way you see fit. I've searched the web and found answers to a lot of my problems, so here's a small contribution back to the community.