The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. AppleRemoteDevice::AppleRemoteDevice()
  20. : device (nullptr),
  21. queue (nullptr),
  22. remoteId (0)
  23. {
  24. }
  25. AppleRemoteDevice::~AppleRemoteDevice()
  26. {
  27. stop();
  28. }
  29. namespace
  30. {
  31. io_object_t getAppleRemoteDevice()
  32. {
  33. CFMutableDictionaryRef dict = IOServiceMatching ("AppleIRController");
  34. io_iterator_t iter = 0;
  35. io_object_t iod = 0;
  36. if (IOServiceGetMatchingServices (kIOMasterPortDefault, dict, &iter) == kIOReturnSuccess
  37. && iter != 0)
  38. {
  39. iod = IOIteratorNext (iter);
  40. }
  41. IOObjectRelease (iter);
  42. return iod;
  43. }
  44. bool createAppleRemoteInterface (io_object_t iod, void** device)
  45. {
  46. jassert (*device == nullptr);
  47. io_name_t classname;
  48. if (IOObjectGetClass (iod, classname) == kIOReturnSuccess)
  49. {
  50. IOCFPlugInInterface** cfPlugInInterface = nullptr;
  51. SInt32 score = 0;
  52. if (IOCreatePlugInInterfaceForService (iod,
  53. kIOHIDDeviceUserClientTypeID,
  54. kIOCFPlugInInterfaceID,
  55. &cfPlugInInterface,
  56. &score) == kIOReturnSuccess)
  57. {
  58. HRESULT hr = (*cfPlugInInterface)->QueryInterface (cfPlugInInterface,
  59. CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID),
  60. device);
  61. ignoreUnused (hr);
  62. (*cfPlugInInterface)->Release (cfPlugInInterface);
  63. }
  64. }
  65. return *device != nullptr;
  66. }
  67. void appleRemoteQueueCallback (void* const target, const IOReturn result, void*, void*)
  68. {
  69. if (result == kIOReturnSuccess)
  70. ((AppleRemoteDevice*) target)->handleCallbackInternal();
  71. }
  72. }
  73. bool AppleRemoteDevice::start (const bool inExclusiveMode)
  74. {
  75. if (queue != nullptr)
  76. return true;
  77. stop();
  78. bool result = false;
  79. io_object_t iod = getAppleRemoteDevice();
  80. if (iod != 0)
  81. {
  82. if (createAppleRemoteInterface (iod, &device) && open (inExclusiveMode))
  83. result = true;
  84. else
  85. stop();
  86. IOObjectRelease (iod);
  87. }
  88. return result;
  89. }
  90. void AppleRemoteDevice::stop()
  91. {
  92. if (queue != nullptr)
  93. {
  94. (*(IOHIDQueueInterface**) queue)->stop ((IOHIDQueueInterface**) queue);
  95. (*(IOHIDQueueInterface**) queue)->dispose ((IOHIDQueueInterface**) queue);
  96. (*(IOHIDQueueInterface**) queue)->Release ((IOHIDQueueInterface**) queue);
  97. queue = nullptr;
  98. }
  99. if (device != nullptr)
  100. {
  101. (*(IOHIDDeviceInterface**) device)->close ((IOHIDDeviceInterface**) device);
  102. (*(IOHIDDeviceInterface**) device)->Release ((IOHIDDeviceInterface**) device);
  103. device = nullptr;
  104. }
  105. }
  106. bool AppleRemoteDevice::isActive() const
  107. {
  108. return queue != nullptr;
  109. }
  110. bool AppleRemoteDevice::open (const bool openInExclusiveMode)
  111. {
  112. Array <int> cookies;
  113. CFArrayRef elements;
  114. IOHIDDeviceInterface122** const device122 = (IOHIDDeviceInterface122**) device;
  115. if ((*device122)->copyMatchingElements (device122, 0, &elements) != kIOReturnSuccess)
  116. return false;
  117. for (int i = 0; i < CFArrayGetCount (elements); ++i)
  118. {
  119. CFDictionaryRef element = (CFDictionaryRef) CFArrayGetValueAtIndex (elements, i);
  120. // get the cookie
  121. CFTypeRef object = CFDictionaryGetValue (element, CFSTR (kIOHIDElementCookieKey));
  122. if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID())
  123. continue;
  124. long number;
  125. if (! CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number))
  126. continue;
  127. cookies.add ((int) number);
  128. }
  129. CFRelease (elements);
  130. if ((*(IOHIDDeviceInterface**) device)
  131. ->open ((IOHIDDeviceInterface**) device,
  132. openInExclusiveMode ? kIOHIDOptionsTypeSeizeDevice
  133. : kIOHIDOptionsTypeNone) == KERN_SUCCESS)
  134. {
  135. queue = (*(IOHIDDeviceInterface**) device)->allocQueue ((IOHIDDeviceInterface**) device);
  136. if (queue != 0)
  137. {
  138. (*(IOHIDQueueInterface**) queue)->create ((IOHIDQueueInterface**) queue, 0, 12);
  139. for (int i = 0; i < cookies.size(); ++i)
  140. {
  141. IOHIDElementCookie cookie = (IOHIDElementCookie) cookies.getUnchecked(i);
  142. (*(IOHIDQueueInterface**) queue)->addElement ((IOHIDQueueInterface**) queue, cookie, 0);
  143. }
  144. CFRunLoopSourceRef eventSource;
  145. if ((*(IOHIDQueueInterface**) queue)
  146. ->createAsyncEventSource ((IOHIDQueueInterface**) queue, &eventSource) == KERN_SUCCESS)
  147. {
  148. if ((*(IOHIDQueueInterface**) queue)->setEventCallout ((IOHIDQueueInterface**) queue,
  149. appleRemoteQueueCallback, this, 0) == KERN_SUCCESS)
  150. {
  151. CFRunLoopAddSource (CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
  152. (*(IOHIDQueueInterface**) queue)->start ((IOHIDQueueInterface**) queue);
  153. return true;
  154. }
  155. }
  156. }
  157. }
  158. return false;
  159. }
  160. void AppleRemoteDevice::handleCallbackInternal()
  161. {
  162. int totalValues = 0;
  163. AbsoluteTime nullTime = { 0, 0 };
  164. char cookies [12];
  165. int numCookies = 0;
  166. while (numCookies < numElementsInArray (cookies))
  167. {
  168. IOHIDEventStruct e;
  169. if ((*(IOHIDQueueInterface**) queue)->getNextEvent ((IOHIDQueueInterface**) queue, &e, nullTime, 0) != kIOReturnSuccess)
  170. break;
  171. if ((int) e.elementCookie == 19)
  172. {
  173. remoteId = e.value;
  174. buttonPressed (switched, false);
  175. }
  176. else
  177. {
  178. totalValues += e.value;
  179. cookies [numCookies++] = (char) (pointer_sized_int) e.elementCookie;
  180. }
  181. }
  182. cookies [numCookies++] = 0;
  183. static const char buttonPatterns[] =
  184. {
  185. 0x1f, 0x14, 0x12, 0x1f, 0x14, 0x12, 0,
  186. 0x1f, 0x15, 0x12, 0x1f, 0x15, 0x12, 0,
  187. 0x1f, 0x1d, 0x1c, 0x12, 0,
  188. 0x1f, 0x1e, 0x1c, 0x12, 0,
  189. 0x1f, 0x16, 0x12, 0x1f, 0x16, 0x12, 0,
  190. 0x1f, 0x17, 0x12, 0x1f, 0x17, 0x12, 0,
  191. 0x1f, 0x12, 0x04, 0x02, 0,
  192. 0x1f, 0x12, 0x03, 0x02, 0,
  193. 0x1f, 0x12, 0x1f, 0x12, 0,
  194. 0x23, 0x1f, 0x12, 0x23, 0x1f, 0x12, 0,
  195. 19, 0
  196. };
  197. int buttonNum = (int) menuButton;
  198. int i = 0;
  199. while (i < numElementsInArray (buttonPatterns))
  200. {
  201. if (strcmp (cookies, buttonPatterns + i) == 0)
  202. {
  203. buttonPressed ((ButtonType) buttonNum, totalValues > 0);
  204. break;
  205. }
  206. i += (int) strlen (buttonPatterns + i) + 1;
  207. ++buttonNum;
  208. }
  209. }