Search code examples
objective-ctimepython-idle

Objective C: Get notifications about a user's idle state


My cocoa app runs background tasks, which I would like to stop when the user becomes idle (no keyboard/mouse input) and then resume when the user becomes active again. Is there a way to register for idle-state notifications?


Solution

  • In case you can't link to Carbon (ie. you want to compile x86_64 bit binary) you can wrap this function (which returns current idle time in seconds resolution as double - CFTimeInterval) in a timer:

    #include <IOKit/IOKitLib.h>
    
    CFTimeInterval CFDateGetIdleTimeInterval() {
        mach_port_t port;
        io_iterator_t iter;
        CFTypeRef value = kCFNull;
        uint64_t idle = 0;
        CFMutableDictionaryRef properties = NULL;
        io_registry_entry_t entry;
    
        IOMasterPort(MACH_PORT_NULL, &port);
        IOServiceGetMatchingServices(port, IOServiceMatching("IOHIDSystem"), &iter);
        if (iter) {
            if ((entry = IOIteratorNext(iter))) {
                if (IORegistryEntryCreateCFProperties(entry, &properties, kCFAllocatorDefault, 0) == KERN_SUCCESS && properties) {
                    if (CFDictionaryGetValueIfPresent(properties, CFSTR("HIDIdleTime"), &value)) {
                        if (CFGetTypeID(value) == CFDataGetTypeID()) {
                            CFDataGetBytes(value, CFRangeMake(0, sizeof(idle)), (UInt8 *) &idle);
                        } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
                            CFNumberGetValue(value, kCFNumberSInt64Type, &idle);
                        }
                    }
                    CFRelease(properties);
                }
                IOObjectRelease(entry);
            }
            IOObjectRelease(iter);
        }
    
        return idle / 1000000000.0;
    }
    

    You'll need to link your code to IOKit.framework