Search code examples
macosscreensensors

How do you programmatically access the ambient light sensor on Mac OS X 10.5+?


I'm trying to programmatically access the ambient light sensor in a Mac application running on OS X 10.5 and above, but can't find a way to do this.

Two other questions had been posed about this here, "Accessing mac's sensor data" and "Disable ambient-light sensor screen dimming programmatically on OS X", but they either didn't address this or present solutions that break on 10.5 and up.

What private API does Apple use to access the ambient light-sensor data on OS X and/or how would I find it?


Solution

  • While @Landak's answer is good for the time, that ambient light sensor api seems to have been deprecated.

    The code that works now is as follows:

    // lmutracker.mm
    //
    // clang -o lmutracker lmutracker.mm -F /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks -framework Foundation -framework IOKit -framework CoreFoundation -framework BezelServices
    
    #include <mach/mach.h>
    #import <Foundation/Foundation.h>
    #import <IOKit/IOKitLib.h>
    #import <IOKit/hidsystem/IOHIDServiceClient.h>
    
    typedef struct __IOHIDEvent *IOHIDEventRef;
    
    #define kAmbientLightSensorEvent 12
    
    #define IOHIDEventFieldBase(type) (type << 16)
    
    extern "C" {
      IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t, int32_t, int64_t);
      double IOHIDEventGetFloatValue(IOHIDEventRef, int32_t);
    
      IOHIDServiceClientRef ALCALSCopyALSServiceClient(void);
    }
    
    static double updateInterval = 0.1;
    static IOHIDServiceClientRef client;
    static IOHIDEventRef event;
    
    void updateTimerCallBack(CFRunLoopTimerRef timer, void *info) {
      double value;
    
      event = IOHIDServiceClientCopyEvent(client, kAmbientLightSensorEvent, 0, 0);
    
      value = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kAmbientLightSensorEvent));
    
      printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%8f", value);
    
      CFRelease(event);
    }
    
    int main(void) {
      kern_return_t kr;
      CFRunLoopTimerRef updateTimer;
    
      client = ALCALSCopyALSServiceClient();
      if (client) {
        event = IOHIDServiceClientCopyEvent(client, kAmbientLightSensorEvent, 0, 0);
      }
      if (!event) {
        fprintf(stderr, "failed to find ambient light sensors\n");
        exit(1);
      }
    
      CFRelease(event);
    
      setbuf(stdout, NULL);
      printf("%8f", 0.0);
    
      updateTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
                      CFAbsoluteTimeGetCurrent() + updateInterval, updateInterval,
                      0, 0, updateTimerCallBack, NULL);
      CFRunLoopAddTimer(CFRunLoopGetCurrent(), updateTimer, kCFRunLoopDefaultMode);
      CFRunLoopRun();
    
      exit(0);
    }
    

    I found this in DarkModeBuddy (BSD 2-clause license), and adapted it into a cli tool in my dotfiles.