1 #include <CoreFoundation/CoreFoundation.h>
2 #include <IOKit/hid/IOHIDLib.h>
3 #include <IOKit/IOKitLib.h>
7 const CFStringRef kPrefDomain
= CFSTR("com.apple.driver.AppleIRController");
8 const CFStringRef kPrefEnabled
= CFSTR("DeviceEnabled");
12 #define LOG(msg, ...) do { \
14 printf(msg " [%s:%d]\n", ##__VA_ARGS__, __FILE__, __LINE__); \
17 #define ERROR(msg, ...) fprintf(stderr, msg " [%s:%d]\n", ##__VA_ARGS__, __FILE__, __LINE__)
19 class ScopedIOHIDManager
{
22 : manager_(IOHIDManagerCreate(nullptr, kIOHIDManagerOptionNone
)) {}
24 ~ScopedIOHIDManager() {
25 IOHIDManagerClose(manager_
, kIOHIDManagerOptionNone
);
28 ScopedIOHIDManager(const ScopedIOHIDManager
&) = delete;
30 IOHIDManagerRef
get() { return manager_
; }
33 IOHIDManagerRef manager_
;
37 class ScopedCFTypeRef
{
39 ScopedCFTypeRef(T t
= nullptr) : t_(t
) {}
46 ScopedCFTypeRef(const ScopedCFTypeRef
<T
>&) = delete;
48 operator bool() { return t_
!= nullptr; }
50 T
get() { return t_
; }
52 T
* pointer_to() { return &t_
; }
58 bool IsIRAvailable() {
59 ScopedIOHIDManager manager
;
60 IOHIDManagerSetDeviceMatching(manager
.get(), nullptr);
61 ScopedCFTypeRef
<CFSetRef
> devices(IOHIDManagerCopyDevices(manager
.get()));
63 ERROR("Failed to IOHIDManagerCopyDevices");
66 std
::vector
<void*> devices_array(CFSetGetCount(devices
.get()), nullptr);
67 CFSetGetValues(devices
.get(), const_cast<const void**>(devices_array
.data()));
68 for (const auto& device
: devices_array
) {
70 IOHIDDeviceGetProperty(reinterpret_cast<IOHIDDeviceRef
>(device
),
71 CFSTR("HIDRemoteControl"));
74 LOG("Located HIDRemoteControl:");
83 const char* GetBooleanDescription(CFTypeRef boolean
) {
84 if (CFGetTypeID(boolean
) != CFBooleanGetTypeID()) {
85 ERROR("Unexpected non-boolean CFTypeRef");
88 return CFBooleanGetValue(static_cast<CFBooleanRef
>(boolean
)) ?
"on" : "off";
91 CFTypeRef
GetUserPropertyValue() {
92 return CFPreferencesCopyValue(kPrefEnabled
, kPrefDomain
,
93 kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
96 io_iterator_t
CreateIOServiceIterator() {
97 CFMutableDictionaryRef matching_dict
= IOServiceMatching("AppleIRController");
98 io_iterator_t iterator
;
99 kern_return_t kr
= IOServiceGetMatchingServices(kIOMasterPortDefault
, matching_dict
, &iterator
);
100 if (kr
!= KERN_SUCCESS
) {
101 ERROR("Failed to IOServiceGetMatchingServices: 0x%x", kr
);
108 CFTypeRef user_prop
= GetUserPropertyValue();
109 printf("Userspace property value: %s\n", GetBooleanDescription(user_prop
));
111 io_iterator_t iterator
= CreateIOServiceIterator();
116 bool did_find
= false;
117 while ((service
= IOIteratorNext(iterator
))) {
121 kern_return_t kr
= IORegistryEntryGetName(service
, name
);
122 if (kr
!= KERN_SUCCESS
) {
123 ERROR("Failed to IORegistryEntryGetName: 0x%x", kr
);
127 LOG("Found AppleIRController: %s", name
);
129 ScopedCFTypeRef
<CFTypeRef
> device_enabled(
130 IORegistryEntryCreateCFProperty(service
, kPrefEnabled
, nullptr, 0));
131 printf("Kernel property value %s: %s\n",
132 name
, GetBooleanDescription(device_enabled
.get()));
135 ScopedCFTypeRef
<CFMutableDictionaryRef
> props
;
136 kr
= IORegistryEntryCreateCFProperties(service
, props
.pointer_to(), nullptr, 0);
137 if (kr
!= KERN_SUCCESS
) {
138 ERROR("Failed to IORegistryEntryCreateCFProperties(%s) = 0x%x", name
, kr
);
146 ERROR("Failed to match AppleIRController");
153 int HandleWrite(bool enable
) {
157 int main(int argc
, char* argv
[]) {
158 if (!IsIRAvailable()) {
159 ERROR("No HIDRemoteControl available");
165 } else if (argc
== 2) {
166 if (strcmp("on", argv
[1])) {
167 return HandleWrite(true);
168 } else if (strcmp("off", argv
[1])) {
169 return HandleWrite(false);
173 fprintf(stderr
, "Usage: %s [on|off]\n", argv
[0]);