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");
16 #define LOG(msg, ...) do { \
18 printf(msg " [%s:%d]\n", ##__VA_ARGS__, __FILE__, __LINE__); \
21 #define ERROR(msg, ...) fprintf(stderr, msg " [%s:%d]\n", ##__VA_ARGS__, __FILE__, __LINE__)
23 class ScopedIOHIDManager
{
26 : manager_(IOHIDManagerCreate(nullptr, kIOHIDManagerOptionNone
)) {}
28 ~ScopedIOHIDManager() {
29 IOHIDManagerClose(manager_
, kIOHIDManagerOptionNone
);
32 ScopedIOHIDManager(const ScopedIOHIDManager
&) = delete;
34 IOHIDManagerRef
get() { return manager_
; }
37 IOHIDManagerRef manager_
;
41 class ScopedCFTypeRef
{
43 ScopedCFTypeRef(T t
= nullptr) : t_(t
) {}
50 ScopedCFTypeRef(const ScopedCFTypeRef
<T
>&) = delete;
52 operator bool() { return t_
!= nullptr; }
54 T
get() { return t_
; }
56 T
* pointer_to() { return &t_
; }
62 bool IsIRAvailable() {
63 ScopedIOHIDManager manager
;
64 IOHIDManagerSetDeviceMatching(manager
.get(), nullptr);
65 ScopedCFTypeRef
<CFSetRef
> devices(IOHIDManagerCopyDevices(manager
.get()));
67 ERROR("Failed to IOHIDManagerCopyDevices");
70 std
::vector
<void*> devices_array(CFSetGetCount(devices
.get()), nullptr);
71 CFSetGetValues(devices
.get(), const_cast<const void**>(devices_array
.data()));
72 for (const auto& device
: devices_array
) {
74 IOHIDDeviceGetProperty(reinterpret_cast<IOHIDDeviceRef
>(device
),
75 CFSTR("HIDRemoteControl"));
78 LOG("Located HIDRemoteControl:");
87 const char* GetBooleanDescription(CFTypeRef boolean
) {
88 if (CFGetTypeID(boolean
) != CFBooleanGetTypeID()) {
89 ERROR("Unexpected non-boolean CFTypeRef");
92 return CFBooleanGetValue(static_cast<CFBooleanRef
>(boolean
)) ?
"on" : "off";
95 bool SynchronizePrefs() {
96 bool rv
= CFPreferencesSynchronize(kPrefDomain
, kCFPreferencesAnyUser
,
97 kCFPreferencesCurrentHost
);
99 ERROR("Failed to CFPreferencesSynchronize");
104 CFTypeRef
GetUserPropertyValue() {
105 return CFPreferencesCopyValue(kPrefEnabled
, kPrefDomain
,
106 kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
109 io_iterator_t
CreateIOServiceIterator() {
110 CFMutableDictionaryRef matching_dict
= IOServiceMatching("AppleIRController");
111 io_iterator_t iterator
;
112 kern_return_t kr
= IOServiceGetMatchingServices(
113 kIOMasterPortDefault
, matching_dict
, &iterator
);
114 if (kr
!= KERN_SUCCESS
) {
115 ERROR("Failed to IOServiceGetMatchingServices: 0x%x", kr
);
122 if (!SynchronizePrefs())
125 CFTypeRef user_prop
= GetUserPropertyValue();
126 printf("Userspace property value: %s\n", GetBooleanDescription(user_prop
));
128 io_iterator_t iterator
= CreateIOServiceIterator();
133 bool did_find
= false;
134 while ((service
= IOIteratorNext(iterator
))) {
138 kern_return_t kr
= IORegistryEntryGetName(service
, name
);
139 if (kr
!= KERN_SUCCESS
) {
140 ERROR("Failed to IORegistryEntryGetName: 0x%x", kr
);
144 LOG("Found AppleIRController: %s", name
);
146 ScopedCFTypeRef
<CFTypeRef
> device_enabled(
147 IORegistryEntryCreateCFProperty(service
, kPrefEnabled
, nullptr, 0));
148 printf("Kernel property value %s: %s\n",
149 name
, GetBooleanDescription(device_enabled
.get()));
152 ScopedCFTypeRef
<CFMutableDictionaryRef
> props
;
153 kr
= IORegistryEntryCreateCFProperties(service
, props
.pointer_to(), nullptr, 0);
154 if (kr
!= KERN_SUCCESS
) {
155 ERROR("Failed to IORegistryEntryCreateCFProperties(%s) = 0x%x", name
, kr
);
163 ERROR("Failed to match AppleIRController");
170 int HandleWrite(bool enable
) {
171 const CFBooleanRef enabled_value
= enable ? kCFBooleanTrue
: kCFBooleanFalse
;
173 CFPreferencesSetValue(kPrefEnabled
, enabled_value
, kPrefDomain
,
174 kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
175 if (!SynchronizePrefs())
178 io_iterator_t iterator
= CreateIOServiceIterator();
180 while ((service
= IOIteratorNext(iterator
))) {
182 kern_return_t kr
= IORegistryEntryGetName(service
, name
);
183 if (kr
!= KERN_SUCCESS
) {
184 ERROR("Failed to IORegistryEntryGetName: 0x%x", kr
);
188 LOG("Setting property for %s to %d", name
, enable
);
190 kr
= IORegistryEntrySetCFProperty(service
, kPrefEnabled
, enabled_value
);
191 if (kr
!= KERN_SUCCESS
) {
192 ERROR("Failed to IORegistryEntrySetCFProperty: 0x%x", kr
);
200 int main(int argc
, char* argv
[]) {
201 if (!IsIRAvailable()) {
202 ERROR("No HIDRemoteControl available");
208 } else if (argc
== 2) {
209 if (strcmp("on", argv
[1]) == 0) {
210 return HandleWrite(true);
211 } else if (strcmp("off", argv
[1]) == 0) {
212 return HandleWrite(false);
216 fprintf(stderr
, "Usage: %s [on|off]\n", argv
[0]);