in Snippets

Detect User idle time on Mac OS X

When you’re developing an application to track time or some work done on a computer, you need to know how long that user was actually in front of the screen, working on a task. If user has left his seat, your application should detect that and pause the timer.

This can be done by comparing user idle time with predefined amount of seconds, for which we are shure that user is left his place, usualy 300 or 600 seconds (5-10 minutes).

The idle time is stored as a property of the IOHIDSystem class; the name is HIDIdleTime. It’s stored as a 64-bit int, measured in nanoseconds. To figure out the idle time of the system we use IOKit. Here’s the code that will return how long user was inactive in seconds:

#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CFNumber.h>

/**
Returns the number of seconds the machine has been idle or -1 if an error occurs.
The code is compatible with Tiger/10.4 and later (but not iOS).
*/
int64_t SystemIdleTime(void) {
	int64_t idlesecs = -1;
	io_iterator_t iter = 0;
	if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"), &iter) == KERN_SUCCESS) {
		io_registry_entry_t entry = IOIteratorNext(iter);
		if (entry)  {
			CFMutableDictionaryRef dict = NULL;
			if (IORegistryEntryCreateCFProperties(entry, &dict, kCFAllocatorDefault, 0) == KERN_SUCCESS) {
				CFNumberRef obj = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("HIDIdleTime"));
				if (obj) {
					int64_t nanoseconds = 0;
					if (CFNumberGetValue(obj, kCFNumberSInt64Type, &nanoseconds)) {
						idlesecs = (nanoseconds / 1000000000); // Convert from nanoseconds to seconds.
					}
				}
				CFRelease(dict);
			}
			IOObjectRelease(entry);
		}
		IOObjectRelease(iter);
	}
	return idlesecs;
}

This code has been released as public domain, so you are free to copy it and use it for your own projects.

In the end I just want to point out the two things:

1. If you need “user idle time” in other units then seconds, you need to change the divisor in line:

idlesecs = (nanoseconds / 1000000000); // Slower and accurate

2. If you need dirty speedup of this code and you don’t need really accurate time you can change calculation from  to:

idlesecs = (nanoseconds &gt;&gt; 30); // Faster

Note: To use this code in X Code project, you need to add frameworks:

  • IOKit.framework
  • CoreFoundation.framework

Add Frameworks

Write a Comment

Comment