#include <iostream>
#include <IOKit/IOKitLib.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <mach/mach.h>
#include "lib.h"
__attribute__((constructor))
void init(){
}
static void onPMrootDomainChange(void *refcon, io_service_t service, uint32_t messageType, void *messageArgument) {
if (messageType == kIOPMMessageClamshellStateChange) {
const int isClamshellClosed = (reinterpret_cast<uint64_t>(messageArgument) & kClamshellStateBit);
CallbackFunc cb = reinterpret_cast<CallbackFunc>(refcon);
cb(isClamshellClosed == 0);
}
}
dispatch_queue_t serialQueue = nullptr;
IONotificationPortRef notifyPort = nullptr;
io_object_t notification = 0;
void register_callback_for_clamshell_change(CallbackFunc callback) {
if(notification){
return;
}
io_connect_t connection = IO_OBJECT_NULL;
io_service_t pmRootDomain = IOServiceGetMatchingService(kIOMainPortDefault,
IOServiceMatching("IOPMrootDomain"));
if(pmRootDomain)
{
serialQueue = dispatch_queue_create("com.dustinrue.ControlPlane.LaptopLidEvidenceSource", DISPATCH_QUEUE_SERIAL);
if (!serialQueue) {
return;
}
dispatch_set_target_queue(serialQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
notifyPort = IONotificationPortCreate(kIOMainPortDefault);
if (!notifyPort) {
return;
}
IONotificationPortSetDispatchQueue(notifyPort, serialQueue);
kern_return_t kr = IOServiceAddInterestNotification(
notifyPort,
pmRootDomain,
kIOGeneralInterest,
onPMrootDomainChange,
reinterpret_cast<void *>(callback),
¬ification);
IOObjectRelease(pmRootDomain);
}
}
void unregister_callback_for_clamshell_change() {
if (notification) {
IOObjectRelease(notification);
notification = 0;
}
if (notifyPort) {
IONotificationPortSetDispatchQueue(notifyPort, nullptr);
IONotificationPortDestroy(notifyPort);
notifyPort = nullptr;
}
if (serialQueue) {
dispatch_release(serialQueue);
serialQueue = nullptr;
}
}