Initial version of apple-ir-control.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 13 Mar 2016 22:24:15 +0000 (18:24 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 13 Mar 2016 22:24:49 +0000 (18:24 -0400)
Get user and kernel value of the DeviceEnabled setting.

.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
apple-ir-control.cc [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b67f936
--- /dev/null
@@ -0,0 +1,2 @@
+apple-ir-control
+apple-ir-control.dSYM/
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..8a6f5df
--- /dev/null
@@ -0,0 +1,171 @@
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/IOKitLib.h>
+#include <unistd.h>
+#include <vector>
+
+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 <typename T>
+class ScopedCFTypeRef {
+ public:
+  ScopedCFTypeRef(T t = nullptr) : t_(t) {}
+  ~ScopedCFTypeRef() {
+    if (t_) {
+      CFRelease(t_);
+    }
+  }
+
+  ScopedCFTypeRef(const ScopedCFTypeRef<T>&) = 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<CFSetRef> devices(IOHIDManagerCopyDevices(manager.get()));
+  if (!devices) {
+    ERROR("Failed to IOHIDManagerCopyDevices");
+    return false;
+  }
+  std::vector<void*> devices_array(CFSetGetCount(devices.get()), nullptr);
+  CFSetGetValues(devices.get(), const_cast<const void**>(devices_array.data()));
+  for (const auto& device : devices_array) {
+    CFTypeRef prop =
+        IOHIDDeviceGetProperty(reinterpret_cast<IOHIDDeviceRef>(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<CFTypeRef> device_enabled(
+        IORegistryEntryCreateCFProperty(service, kPrefEnabled, nullptr, 0));
+    CFShow(device_enabled.get());
+
+#if 0
+    ScopedCFTypeRef<CFMutableDictionaryRef> 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;
+}