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 bool SynchronizePrefs() {
92 bool rv
= CFPreferencesSynchronize(kPrefDomain
, kCFPreferencesAnyUser
,
93 kCFPreferencesCurrentHost
);
95 ERROR("Failed to CFPreferencesSynchronize");
100 CFTypeRef
GetUserPropertyValue() {
101 return CFPreferencesCopyValue(kPrefEnabled
, kPrefDomain
,
102 kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
105 io_iterator_t
CreateIOServiceIterator() {
106 CFMutableDictionaryRef matching_dict
= IOServiceMatching("AppleIRController");
107 io_iterator_t iterator
;
108 kern_return_t kr
= IOServiceGetMatchingServices(
109 kIOMasterPortDefault
, matching_dict
, &iterator
);
110 if (kr
!= KERN_SUCCESS
) {
111 ERROR("Failed to IOServiceGetMatchingServices: 0x%x", kr
);
118 if (!SynchronizePrefs())
121 CFTypeRef user_prop
= GetUserPropertyValue();
122 printf("Userspace property value: %s\n", GetBooleanDescription(user_prop
));
124 io_iterator_t iterator
= CreateIOServiceIterator();
129 bool did_find
= false;
130 while ((service
= IOIteratorNext(iterator
))) {
134 kern_return_t kr
= IORegistryEntryGetName(service
, name
);
135 if (kr
!= KERN_SUCCESS
) {
136 ERROR("Failed to IORegistryEntryGetName: 0x%x", kr
);
140 LOG("Found AppleIRController: %s", name
);
142 ScopedCFTypeRef
<CFTypeRef
> device_enabled(
143 IORegistryEntryCreateCFProperty(service
, kPrefEnabled
, nullptr, 0));
144 printf("Kernel property value %s: %s\n",
145 name
, GetBooleanDescription(device_enabled
.get()));
148 ScopedCFTypeRef
<CFMutableDictionaryRef
> props
;
149 kr
= IORegistryEntryCreateCFProperties(service
, props
.pointer_to(), nullptr, 0);
150 if (kr
!= KERN_SUCCESS
) {
151 ERROR("Failed to IORegistryEntryCreateCFProperties(%s) = 0x%x", name
, kr
);
159 ERROR("Failed to match AppleIRController");
166 int HandleWrite(bool enable
) {
167 const CFBooleanRef enabled_value
= enable ? kCFBooleanTrue
: kCFBooleanFalse
;
169 CFPreferencesSetValue(kPrefEnabled
, enabled_value
, kPrefDomain
,
170 kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
171 if (!SynchronizePrefs())
174 io_iterator_t iterator
= CreateIOServiceIterator();
176 while ((service
= IOIteratorNext(iterator
))) {
178 kern_return_t kr
= IORegistryEntryGetName(service
, name
);
179 if (kr
!= KERN_SUCCESS
) {
180 ERROR("Failed to IORegistryEntryGetName: 0x%x", kr
);
184 LOG("Setting property for %s to %d", name
, enable
);
186 kr
= IORegistryEntrySetCFProperty(service
, kPrefEnabled
, enabled_value
);
187 if (kr
!= KERN_SUCCESS
) {
188 ERROR("Failed to IORegistryEntrySetCFProperty: 0x%x", kr
);
196 int main(int argc
, char* argv
[]) {
197 if (!IsIRAvailable()) {
198 ERROR("No HIDRemoteControl available");
204 } else if (argc
== 2) {
205 if (strcmp("on", argv
[1]) == 0) {
206 return HandleWrite(true);
207 } else if (strcmp("off", argv
[1]) == 0) {
208 return HandleWrite(false);
212 fprintf(stderr
, "Usage: %s [on|off]\n", argv
[0]);