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.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. AppleRemoteDevice::AppleRemoteDevice()
  19. : device (0),
  20. queue (0),
  21. remoteId (0)
  22. {
  23. }
  24. AppleRemoteDevice::~AppleRemoteDevice()
  25. {
  26. stop();
  27. }
  28. namespace
  29. {
  30. io_object_t getAppleRemoteDevice()
  31. {
  32. CFMutableDictionaryRef dict = IOServiceMatching ("AppleIRController");
  33. io_iterator_t iter = 0;
  34. io_object_t iod = 0;
  35. if (IOServiceGetMatchingServices (kIOMasterPortDefault, dict, &iter) == kIOReturnSuccess
  36. && iter != 0)
  37. {
  38. iod = IOIteratorNext (iter);
  39. }
  40. IOObjectRelease (iter);
  41. return iod;
  42. }
  43. bool createAppleRemoteInterface (io_object_t iod, void** device)
  44. {
  45. jassert (*device == nullptr);
  46. io_name_t classname;
  47. if (IOObjectGetClass (iod, classname) == kIOReturnSuccess)
  48. {
  49. IOCFPlugInInterface** cfPlugInInterface = nullptr;
  50. SInt32 score = 0;
  51. if (IOCreatePlugInInterfaceForService (iod,
  52. kIOHIDDeviceUserClientTypeID,
  53. kIOCFPlugInInterfaceID,
  54. &cfPlugInInterface,
  55. &score) == kIOReturnSuccess)
  56. {
  57. HRESULT hr = (*cfPlugInInterface)->QueryInterface (cfPlugInInterface,
  58. CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID),
  59. device);
  60. (void) hr;
  61. (*cfPlugInInterface)->Release (cfPlugInInterface);
  62. }
  63. }
  64. return *device != 0;
  65. }
  66. void appleRemoteQueueCallback (void* const target, const IOReturn result, void*, void*)
  67. {
  68. if (result == kIOReturnSuccess)
  69. ((AppleRemoteDevice*) target)->handleCallbackInternal();
  70. }
  71. }
  72. bool AppleRemoteDevice::start (const bool inExclusiveMode)
  73. {
  74. if (queue != 0)
  75. return true;
  76. stop();
  77. bool result = false;
  78. io_object_t iod = getAppleRemoteDevice();
  79. if (iod != 0)
  80. {
  81. if (createAppleRemoteInterface (iod, &device) && open (inExclusiveMode))
  82. result = true;
  83. else
  84. stop();
  85. IOObjectRelease (iod);
  86. }
  87. return result;
  88. }
  89. void AppleRemoteDevice::stop()
  90. {
  91. if (queue != 0)
  92. {
  93. (*(IOHIDQueueInterface**) queue)->stop ((IOHIDQueueInterface**) queue);
  94. (*(IOHIDQueueInterface**) queue)->dispose ((IOHIDQueueInterface**) queue);
  95. (*(IOHIDQueueInterface**) queue)->Release ((IOHIDQueueInterface**) queue);
  96. queue = 0;
  97. }
  98. if (device != 0)
  99. {
  100. (*(IOHIDDeviceInterface**) device)->close ((IOHIDDeviceInterface**) device);
  101. (*(IOHIDDeviceInterface**) device)->Release ((IOHIDDeviceInterface**) device);
  102. device = 0;
  103. }
  104. }
  105. bool AppleRemoteDevice::isActive() const
  106. {
  107. return queue != 0;
  108. }
  109. bool AppleRemoteDevice::open (const bool openInExclusiveMode)
  110. {
  111. Array <int> cookies;
  112. CFArrayRef elements;
  113. IOHIDDeviceInterface122** const device122 = (IOHIDDeviceInterface122**) device;
  114. if ((*device122)->copyMatchingElements (device122, 0, &elements) != kIOReturnSuccess)
  115. return false;
  116. for (int i = 0; i < CFArrayGetCount (elements); ++i)
  117. {
  118. CFDictionaryRef element = (CFDictionaryRef) CFArrayGetValueAtIndex (elements, i);
  119. // get the cookie
  120. CFTypeRef object = CFDictionaryGetValue (element, CFSTR (kIOHIDElementCookieKey));
  121. if (object == 0 || CFGetTypeID (object) != CFNumberGetTypeID())
  122. continue;
  123. long number;
  124. if (! CFNumberGetValue ((CFNumberRef) object, kCFNumberLongType, &number))
  125. continue;
  126. cookies.add ((int) number);
  127. }
  128. CFRelease (elements);
  129. if ((*(IOHIDDeviceInterface**) device)
  130. ->open ((IOHIDDeviceInterface**) device,
  131. openInExclusiveMode ? kIOHIDOptionsTypeSeizeDevice
  132. : kIOHIDOptionsTypeNone) == KERN_SUCCESS)
  133. {
  134. queue = (*(IOHIDDeviceInterface**) device)->allocQueue ((IOHIDDeviceInterface**) device);
  135. if (queue != 0)
  136. {
  137. (*(IOHIDQueueInterface**) queue)->create ((IOHIDQueueInterface**) queue, 0, 12);
  138. for (int i = 0; i < cookies.size(); ++i)
  139. {
  140. IOHIDElementCookie cookie = (IOHIDElementCookie) cookies.getUnchecked(i);
  141. (*(IOHIDQueueInterface**) queue)->addElement ((IOHIDQueueInterface**) queue, cookie, 0);
  142. }
  143. CFRunLoopSourceRef eventSource;
  144. if ((*(IOHIDQueueInterface**) queue)
  145. ->createAsyncEventSource ((IOHIDQueueInterface**) queue, &eventSource) == KERN_SUCCESS)
  146. {
  147. if ((*(IOHIDQueueInterface**) queue)->setEventCallout ((IOHIDQueueInterface**) queue,
  148. appleRemoteQueueCallback, this, 0) == KERN_SUCCESS)
  149. {
  150. CFRunLoopAddSource (CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
  151. (*(IOHIDQueueInterface**) queue)->start ((IOHIDQueueInterface**) queue);
  152. return true;
  153. }
  154. }
  155. }
  156. }
  157. return false;
  158. }
  159. void AppleRemoteDevice::handleCallbackInternal()
  160. {
  161. int totalValues = 0;
  162. AbsoluteTime nullTime = { 0, 0 };
  163. char cookies [12];
  164. int numCookies = 0;
  165. while (numCookies < numElementsInArray (cookies))
  166. {
  167. IOHIDEventStruct e;
  168. if ((*(IOHIDQueueInterface**) queue)->getNextEvent ((IOHIDQueueInterface**) queue, &e, nullTime, 0) != kIOReturnSuccess)
  169. break;
  170. if ((int) e.elementCookie == 19)
  171. {
  172. remoteId = e.value;
  173. buttonPressed (switched, false);
  174. }
  175. else
  176. {
  177. totalValues += e.value;
  178. cookies [numCookies++] = (char) (pointer_sized_int) e.elementCookie;
  179. }
  180. }
  181. cookies [numCookies++] = 0;
  182. //DBG (String::toHexString ((uint8*) cookies, numCookies, 1) + " " + String (totalValues));
  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. }