Skip to content

Instantly share code, notes, and snippets.

@alessaba
Last active September 8, 2025 07:23
Show Gist options
  • Save alessaba/098f83c587e1372d30dea36a7c18b7cc to your computer and use it in GitHub Desktop.
Save alessaba/098f83c587e1372d30dea36a7c18b7cc to your computer and use it in GitHub Desktop.
Read the angle of the lid sensors on MacBooks (2019 and newer)
#include <IOKit/hid/IOHIDManager.h>
#include <CoreFoundation/CoreFoundation.h>
#include <stdio.h>
#include <stdlib.h>
// clang -o lidangle LidAngle.c -framework IOKit -framework CoreFoundation
static IOHIDDeviceRef findSensor(void) {
IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (!manager) {
fprintf(stderr, "Failed to create IOHIDManager\n");
return NULL;
}
if (IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone) != kIOReturnSuccess) {
fprintf(stderr, "Failed to open IOHIDManager\n");
CFRelease(manager);
return NULL;
}
CFMutableDictionaryRef matching = CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
int vendor = 0x05AC; CFDictionarySetValue(matching, CFSTR("VendorID"), CFNumberCreate(NULL, kCFNumberIntType, &vendor));
int product = 0x8104; CFDictionarySetValue(matching, CFSTR("ProductID"), CFNumberCreate(NULL, kCFNumberIntType, &product));
int usagePage = 0x0020; CFDictionarySetValue(matching, CFSTR("UsagePage"), CFNumberCreate(NULL, kCFNumberIntType, &usagePage));
int usage = 0x008A; CFDictionarySetValue(matching, CFSTR("Usage"), CFNumberCreate(NULL, kCFNumberIntType, &usage));
IOHIDManagerSetDeviceMatching(manager, matching);
CFRelease(matching);
CFSetRef devices = IOHIDManagerCopyDevices(manager);
IOHIDDeviceRef device = NULL;
if (devices && CFSetGetCount(devices) > 0) {
CFIndex count = CFSetGetCount(devices);
const void **array = malloc(sizeof(void *) * count);
CFSetGetValues(devices, array);
for (CFIndex i = 0; i < count; i++) {
IOHIDDeviceRef testDevice = (IOHIDDeviceRef)array[i];
if (IOHIDDeviceOpen(testDevice, kIOHIDOptionsTypeNone) == kIOReturnSuccess) {
uint8_t report[8] = {0};
CFIndex len = sizeof(report);
IOReturn res = IOHIDDeviceGetReport(testDevice, kIOHIDReportTypeFeature, 1, report, &len);
if (res == kIOReturnSuccess && len >= 3) { // Found working lid angle sensor
device = (IOHIDDeviceRef)CFRetain(testDevice);
IOHIDDeviceClose(testDevice, kIOHIDOptionsTypeNone);
break;
}
IOHIDDeviceClose(testDevice, kIOHIDOptionsTypeNone);
}
}
free(array);
}
if (devices) CFRelease(devices);
IOHIDManagerClose(manager, kIOHIDOptionsTypeNone);
CFRelease(manager);
return device;
}
int getLidAngle(IOHIDDeviceRef dev) {
if (!dev) return -1;
uint8_t report[8] = {0};
CFIndex len = sizeof(report);
IOReturn res = IOHIDDeviceGetReport(dev, kIOHIDReportTypeFeature, 1, report, &len);
if (res == kIOReturnSuccess && len >= 3) {
return (report[2] << 8) | report[1];
}
return -1;
}
int main(void) {
IOHIDDeviceRef dev = findSensor();
if (dev) {
IOHIDDeviceOpen(dev, kIOHIDOptionsTypeNone);
int angle = getLidAngle(dev);
if (angle == 1) printf("Docked");
else printf("Lid Angle: %d°\n", angle);
IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone);
CFRelease(dev);
} else {
printf("No lid angle sensor found\n");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment