From 1fa1a1e5278c4c47837ce32298607c60ec31e99e Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Sun, 13 Mar 2016 18:24:15 -0400 Subject: [PATCH] Initial version of apple-ir-control. Get user and kernel value of the DeviceEnabled setting. --- .gitignore | 2 + Makefile | 2 + apple-ir-control.cc | 171 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 apple-ir-control.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b67f936 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +apple-ir-control +apple-ir-control.dSYM/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..de7c089 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +apple-ir-control: apple-ir-control.cc + clang++ -o $@ -g -std=c++11 -Wall -framework CoreFoundation -framework IOKit $< diff --git a/apple-ir-control.cc b/apple-ir-control.cc new file mode 100644 index 0000000..8a6f5df --- /dev/null +++ b/apple-ir-control.cc @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +const CFStringRef kPrefDomain = CFSTR("com.apple.driver.AppleIRController"); +const CFStringRef kPrefEnabled = CFSTR("DeviceEnabled"); + +bool VERBOSE = true; + +#define LOG(msg, ...) do { \ + if (VERBOSE) { \ + printf(msg " [%s:%d]\n", ##__VA_ARGS__, __FILE__, __LINE__); \ + } \ + } while(0) +#define ERROR(msg, ...) fprintf(stderr, msg " [%s:%d]\n", ##__VA_ARGS__, __FILE__, __LINE__) + +class ScopedIOHIDManager { + public: + ScopedIOHIDManager() + : manager_(IOHIDManagerCreate(nullptr, kIOHIDManagerOptionNone)) {} + + ~ScopedIOHIDManager() { + IOHIDManagerClose(manager_, kIOHIDManagerOptionNone); + } + + ScopedIOHIDManager(const ScopedIOHIDManager&) = delete; + + bool Open() { + IOReturn ret = IOHIDManagerOpen(manager_, kIOHIDManagerOptionNone); + if (ret != kIOReturnSuccess) { + ERROR("Failed to IOHIDManagerOpen: 0x%x", ret); + return false; + } + return true; + } + + IOHIDManagerRef get() { return manager_; } + + private: + IOHIDManagerRef manager_; +}; + +template +class ScopedCFTypeRef { + public: + ScopedCFTypeRef(T t = nullptr) : t_(t) {} + ~ScopedCFTypeRef() { + if (t_) { + CFRelease(t_); + } + } + + ScopedCFTypeRef(const ScopedCFTypeRef&) = delete; + + operator bool() { return t_ != nullptr; } + + T get() { return t_; } + + T* pointer_to() { return &t_; } + + private: + T t_; +}; + +bool IsIRAvailable() { + ScopedIOHIDManager manager; + IOHIDManagerSetDeviceMatching(manager.get(), nullptr); + if (!manager.Open()) { + //return false; + } + ScopedCFTypeRef devices(IOHIDManagerCopyDevices(manager.get())); + if (!devices) { + ERROR("Failed to IOHIDManagerCopyDevices"); + return false; + } + std::vector devices_array(CFSetGetCount(devices.get()), nullptr); + CFSetGetValues(devices.get(), const_cast(devices_array.data())); + for (const auto& device : devices_array) { + CFTypeRef prop = + IOHIDDeviceGetProperty(reinterpret_cast(device), + CFSTR("HIDRemoteControl")); + if (prop) { + if (VERBOSE) { + LOG("Located HIDRemoteControl:"); + CFShow(device); + } + return true; + } + } + return false; +} + +CFTypeRef GetUserPropertyValue() { + return CFPreferencesCopyValue(kPrefEnabled, kPrefDomain, + kCFPreferencesAnyUser, kCFPreferencesCurrentHost); +} + +int HandleRead() { + CFTypeRef user_prop = GetUserPropertyValue(); + CFShow(user_prop); + + CFMutableDictionaryRef matching_dict = IOServiceMatching("AppleIRController"); + io_iterator_t iterator; + kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dict, &iterator); + if (kr != KERN_SUCCESS) { + ERROR("Failed to IOServiceGetMatchingServices: 0x%x", kr); + return EXIT_FAILURE; + } + + io_object_t service; + bool did_find = false; + while ((service = IOIteratorNext(iterator))) { + did_find = true; + + io_name_t name; + kern_return_t kr = IORegistryEntryGetName(service, name); + if (kr != KERN_SUCCESS) { + ERROR("Failed to IORegistryEntryGetName: 0x%x", kr); + continue; + } + + LOG("Found AppleIRController: %s", name); + + ScopedCFTypeRef device_enabled( + IORegistryEntryCreateCFProperty(service, kPrefEnabled, nullptr, 0)); + CFShow(device_enabled.get()); + +#if 0 + ScopedCFTypeRef props; + kr = IORegistryEntryCreateCFProperties(service, props.pointer_to(), nullptr, 0); + if (kr != KERN_SUCCESS) { + ERROR("Failed to IORegistryEntryCreateCFProperties(%s) = 0x%x", name, kr); + continue; + } + CFShow(props.get()); +#endif + } + + if (!did_find) { + ERROR("Failed to match AppleIRController"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int HandleWrite(bool enable) { + return EXIT_SUCCESS; +} + +int main(int argc, char* argv[]) { + if (!IsIRAvailable()) { + ERROR("No HIDRemoteControl available"); + return EXIT_FAILURE; + } + + if (argc == 1) { + return HandleRead(); + } else if (argc == 2) { + if (strcmp("on", argv[1])) { + return HandleWrite(true); + } else if (strcmp("off", argv[1])) { + return HandleWrite(false); + } + } + + fprintf(stderr, "Usage: %s [on|off]\n", argv[0]); + return EXIT_FAILURE; +} -- 2.22.5