Ticket #2017: appleremote.patch
File appleremote.patch, 17.8 KB (added by , 18 years ago) |
---|
-
libs/libmythui/mythmainwindow.cpp
10 10 #include <qwindowsystem_qws.h> 11 11 #endif 12 12 #ifdef Q_WS_MACX 13 #import <HIToolbox/Menus.h> // For GetMBarHeight() 13 #include <HIToolbox/Menus.h> // For GetMBarHeight() 14 #include <pthread.h> 15 #include "lircevent.h" 16 #include "AppleRemote.h" 17 #include "AppleRemoteListener.h" 14 18 #endif 15 19 16 20 #ifdef USE_LIRC … … 46 50 } 47 51 #endif 48 52 53 #ifdef Q_WS_MACX 54 static void* SpawnAppleRemote(void* param) 55 { 56 MythMainWindow *main_window = (MythMainWindow *)param; 57 AppleRemoteListener *arl = new AppleRemoteListener(main_window); 58 AppleRemote& remote(AppleRemote::instance()); 59 remote.setListener(arl); 60 remote.startListening(); 61 if (!remote.isListeningToRemote()) { 62 return NULL; 63 } 64 remote.runLoop(); 65 return NULL; 66 } 67 #endif 68 49 69 class KeyContext 50 70 { 51 71 public: … … 214 234 pthread_create(&lirc_tid, &attr, SpawnLirc, this); 215 235 #endif 216 236 237 #ifdef Q_WS_MACX 238 pthread_t appleremote_tid; 239 pthread_attr_t arattr; 240 pthread_attr_init(&arattr); 241 pthread_attr_setdetachstate(&arattr, PTHREAD_CREATE_DETACHED); 242 243 pthread_create(&appleremote_tid, &arattr, SpawnAppleRemote, this); 244 #endif 245 217 246 d->keyContexts.setAutoDelete(true); 218 247 219 248 RegisterKey("Global", "UP", "Up Arrow", "Up"); … … 901 930 } 902 931 } 903 932 } 904 #if def USE_LIRC933 #if defined(USE_LIRC) || defined(Q_WS_MACX) 905 934 else if (ce->type() == kLircKeycodeEventType && !d->ignore_lirc_keys) 906 935 { 907 936 LircKeycodeEvent *lke = (LircKeycodeEvent *)ce; -
libs/libmyth/AppleRemote.h
1 #ifndef APPLEREMOTE 2 #define APPLEREMOTE 3 4 #include <string> 5 #include <vector> 6 #include <map> 7 8 #include <IOKit/IOKitLib.h> 9 #include <IOKit/IOCFPlugIn.h> 10 #include <IOKit/hid/IOHIDLib.h> 11 #include <IOKit/hid/IOHIDKeys.h> 12 #include <CoreFoundation/CoreFoundation.h> 13 14 class AppleRemote { 15 public: 16 enum Event { 17 VolumePlus = 0, 18 VolumeMinus, 19 Menu, 20 Play, 21 Right, 22 Left, 23 RightHold, 24 LeftHold, 25 MenuHold, 26 PlaySleep, 27 ControlSwitched 28 }; 29 30 class Listener { 31 public: 32 virtual ~Listener() {}; 33 virtual void appleRemoteButton(Event button, bool pressedDown) = 0; 34 }; 35 36 static AppleRemote& instance(); 37 38 bool isRemoteAvailable(); 39 bool isListeningToRemote(); 40 41 void setListener(Listener* listener); 42 Listener* listener() { return _listener; } 43 void setOpenInExclusiveMode(bool in) { openInExclusiveMode = in; }; 44 bool isOpenInExclusiveMode() { return openInExclusiveMode; }; 45 void startListening(); 46 void stopListening(); 47 void runLoop(); 48 49 protected: 50 AppleRemote(); // will be a singleton class 51 52 static AppleRemote* _instance; 53 static const char* const AppleRemoteDeviceName; 54 static const int REMOTE_SWITCH_COOKIE; 55 56 57 private: 58 bool openInExclusiveMode; 59 IOHIDDeviceInterface** hidDeviceInterface; 60 IOHIDQueueInterface** queue; 61 std::vector<int> cookies; 62 std::map< std::string, Event > cookieToButtonMapping; 63 int remoteId; 64 Listener* _listener; 65 66 void _initCookieMap(); 67 io_object_t _findAppleRemoteDevice(); 68 bool _initCookies(); 69 bool _createDeviceInterface(io_object_t hidDevice); 70 bool _openDevice(); 71 72 static void QueueCallbackFunction(void* target, IOReturn result, 73 void* refcon, void* sender); 74 void _queueCallbackFunction(IOReturn result, void* refcon, void* sender); 75 void _handleEventWithCookieString(std::string cookieString, SInt32 sumOfValues); 76 }; 77 78 #endif // APPLEREMOTE 79 No newline at end of file -
libs/libmyth/AppleRemoteListener.cpp
1 #include <qapplication.h> 2 #include <qkeysequence.h> 3 #include "lircevent.h" 4 5 #include "AppleRemoteListener.h" 6 7 AppleRemoteListener::AppleRemoteListener(QObject* mainWindow_): mainWindow(mainWindow_) { 8 } 9 10 void 11 AppleRemoteListener::appleRemoteButton(AppleRemote::Event button, bool pressedDown) { 12 char* code = 0; 13 bool separateRelease = false; 14 switch (button) { 15 case AppleRemote::VolumePlus: { 16 code="Up"; 17 separateRelease=true; 18 break; 19 } 20 case AppleRemote::VolumeMinus: { 21 code="Down"; 22 separateRelease=true; 23 break; 24 } 25 case AppleRemote::Menu: { 26 code="Esc"; 27 break; 28 } 29 case AppleRemote::Play: { 30 code="Enter"; 31 break; 32 } 33 case AppleRemote::Right: { 34 code="Right"; 35 break; 36 } 37 case AppleRemote::Left: { 38 code="Left"; 39 break; 40 } 41 case AppleRemote::RightHold: { 42 code="End"; 43 separateRelease=true; 44 break; 45 } 46 case AppleRemote::LeftHold: { 47 code="Home"; 48 separateRelease=true; 49 break; 50 } 51 case AppleRemote::MenuHold: { 52 code="M"; 53 break; 54 } 55 case AppleRemote::PlaySleep: { 56 code="P"; 57 break; 58 } 59 case AppleRemote::ControlSwitched: { 60 return; 61 } 62 } 63 QKeySequence a(code); 64 int keycode = 0; 65 for (unsigned int i = 0; i < a.count(); i++) 66 { 67 keycode = a[i]; 68 69 QApplication::postEvent(mainWindow, new LircKeycodeEvent(code, 70 keycode, pressedDown)); 71 if (!separateRelease) { 72 QApplication::postEvent(mainWindow, new LircKeycodeEvent(code, 73 keycode, false)); 74 } 75 } 76 77 } -
libs/libmyth/AppleRemote.cpp
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <ctype.h> 5 #include <sys/errno.h> 6 #include <sysexits.h> 7 #include <mach/mach.h> 8 #include <mach/mach_error.h> 9 #include <IOKit/IOKitLib.h> 10 #include <IOKit/IOCFPlugIn.h> 11 #include <IOKit/hid/IOHIDLib.h> 12 #include <IOKit/hid/IOHIDKeys.h> 13 #include <CoreFoundation/CoreFoundation.h> 14 15 16 #include <map> 17 #include <sstream> 18 #include <iostream> 19 20 #include "AppleRemote.h" 21 22 // static 23 AppleRemote* AppleRemote::_instance = 0; 24 // static 25 const char* const AppleRemote::AppleRemoteDeviceName = "AppleIRController"; 26 // static 27 const int AppleRemote::REMOTE_SWITCH_COOKIE=19; 28 29 // public 30 AppleRemote& 31 AppleRemote::instance() { 32 if (_instance==0) { 33 _instance = new AppleRemote(); 34 } 35 return *_instance; 36 } 37 38 bool 39 AppleRemote::isRemoteAvailable() { 40 io_object_t hidDevice = _findAppleRemoteDevice(); 41 if (hidDevice != 0) { 42 IOObjectRelease(hidDevice); 43 return true; 44 } 45 return false; 46 } 47 48 bool 49 AppleRemote::isListeningToRemote() { 50 return (hidDeviceInterface != NULL && !cookies.empty() && queue != NULL); 51 } 52 53 void 54 AppleRemote::setListener(AppleRemote::Listener* listener) { 55 _listener = listener; 56 } 57 58 void 59 AppleRemote::startListening() { 60 io_object_t hidDevice = _findAppleRemoteDevice(); 61 if (hidDevice == 0) goto error; 62 if (!_createDeviceInterface(hidDevice)) goto error; 63 if (!_initCookies()) goto error; 64 if (!_openDevice()) goto error; 65 goto cleanup; 66 67 error: 68 stopListening(); 69 70 cleanup: 71 IOObjectRelease(hidDevice); 72 } 73 74 void 75 AppleRemote::stopListening() { 76 if (queue != NULL) { 77 (*queue)->stop(queue); 78 (*queue)->dispose(queue); 79 (*queue)->Release(queue); 80 queue = NULL; 81 } 82 83 if (!cookies.empty()) { 84 cookies.clear(); 85 } 86 87 if (hidDeviceInterface != NULL) { 88 (*hidDeviceInterface)->close(hidDeviceInterface); 89 (*hidDeviceInterface)->Release(hidDeviceInterface); 90 hidDeviceInterface = NULL; 91 } 92 } 93 94 void 95 AppleRemote::runLoop() { 96 CFRunLoopRun(); 97 } 98 99 // protected 100 AppleRemote::AppleRemote(): 101 openInExclusiveMode(true), 102 hidDeviceInterface(0), 103 queue(0), 104 _listener(0) { 105 _initCookieMap(); 106 } 107 108 // private 109 void 110 AppleRemote::_initCookieMap() { 111 cookieToButtonMapping["14_12_11_6_5_"] = VolumePlus; 112 cookieToButtonMapping["14_13_11_6_5_"] = VolumeMinus; 113 cookieToButtonMapping["14_7_6_5_14_7_6_5_"] = Menu; 114 cookieToButtonMapping["14_8_6_5_14_8_6_5_"] = Play; 115 cookieToButtonMapping["14_9_6_5_14_9_6_5_"] = Right; 116 cookieToButtonMapping["14_10_6_5_14_10_6_5_"] = Left; 117 cookieToButtonMapping["14_6_5_4_2_"] = RightHold; 118 cookieToButtonMapping["14_6_5_3_2_"] = LeftHold; 119 cookieToButtonMapping["14_6_5_14_6_5_"] = MenuHold; 120 cookieToButtonMapping["18_14_6_5_18_14_6_5_"] = PlaySleep; 121 cookieToButtonMapping["19_"] = ControlSwitched; 122 } 123 124 // private 125 io_object_t 126 AppleRemote::_findAppleRemoteDevice() { 127 CFMutableDictionaryRef hidMatchDictionary = 0; 128 io_iterator_t hidObjectIterator = 0; 129 io_object_t hidDevice = 0; 130 131 hidMatchDictionary = IOServiceMatching(AppleRemoteDeviceName); 132 133 // check for matching devices 134 IOReturn ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, 135 hidMatchDictionary, 136 &hidObjectIterator); 137 if ((ioReturnValue == kIOReturnSuccess) 138 && (hidObjectIterator != 0)) { 139 hidDevice = IOIteratorNext(hidObjectIterator); 140 } 141 142 // IOServiceGetMatchingServices consumes a reference to the dictionary, so we 143 // don't need to release the dictionary ref. 144 hidMatchDictionary = 0; 145 return hidDevice; 146 } 147 148 // private 149 bool 150 AppleRemote::_initCookies() { 151 IOHIDDeviceInterface122** handle = (IOHIDDeviceInterface122**)hidDeviceInterface; 152 153 CFArrayRef elements; 154 IOReturn success = 155 (*handle)->copyMatchingElements(handle,NULL,(CFArrayRef*)&elements); 156 157 if (success == kIOReturnSuccess) { 158 for (CFIndex i = 0; i < CFArrayGetCount(elements); i++) { 159 CFDictionaryRef element = (CFDictionaryRef)CFArrayGetValueAtIndex(elements, i); 160 161 CFTypeRef object = CFDictionaryGetValue(element, 162 CFSTR(kIOHIDElementCookieKey)); 163 if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue; 164 long number; 165 if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType, &number)) { 166 continue; 167 } 168 IOHIDElementCookie cookie = (IOHIDElementCookie)number; 169 170 cookies.push_back((int)cookie); 171 } 172 return true; 173 } 174 return false; 175 } 176 177 // private 178 bool 179 AppleRemote::_createDeviceInterface(io_object_t hidDevice) { 180 SInt32 score = 0; 181 IOCFPlugInInterface** plugInInterface = NULL; 182 183 IOReturn ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice, 184 kIOHIDDeviceUserClientTypeID, 185 kIOCFPlugInInterfaceID, 186 &plugInInterface, 187 &score); 188 if (ioReturnValue == kIOReturnSuccess) { 189 HRESULT plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, 190 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), 191 (LPVOID*) (&hidDeviceInterface)); 192 if (plugInResult != S_OK) { 193 std::cerr << "AppleRemote Error: couldn't create device interface " << std::endl; 194 } 195 // Release 196 if (plugInInterface) (*plugInInterface)->Release(plugInInterface); 197 } 198 return hidDeviceInterface != 0; 199 } 200 201 // private 202 bool 203 AppleRemote::_openDevice() { 204 IOHIDOptionsType openMode = kIOHIDOptionsTypeNone; 205 if (openInExclusiveMode) openMode = kIOHIDOptionsTypeSeizeDevice; 206 IOReturn ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, openMode); 207 208 if (ioReturnValue != KERN_SUCCESS) { 209 std::cerr << "AppleRemote Error: when opening device" << std::endl; 210 return false; 211 } 212 queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface); 213 if (!queue) { 214 std::cerr << "AppleRemote Error allocating queue" << std::endl; 215 return false; 216 } 217 218 HRESULT result = (*queue)->create(queue, 0, 12); 219 if (result != S_OK || !queue) { 220 std::cerr << "AppleRemote Error creating queue" << std::endl; 221 } 222 223 for (std::vector<int>::iterator iter = cookies.begin(); 224 iter != cookies.end(); 225 iter++) { 226 IOHIDElementCookie cookie = (IOHIDElementCookie)(*iter); 227 (*queue)->addElement(queue, cookie, 0); 228 } 229 230 CFRunLoopSourceRef eventSource; 231 ioReturnValue = (*queue)->createAsyncEventSource(queue, &eventSource); 232 if (ioReturnValue != KERN_SUCCESS) { 233 std::cerr << "AppleRemote Error creating async event source" << std::endl; 234 return false; 235 } 236 237 ioReturnValue = (*queue)->setEventCallout(queue,QueueCallbackFunction, this, NULL); 238 if (ioReturnValue != KERN_SUCCESS) { 239 std::cerr << "AppleRemote Error registering callback" << std::endl; 240 return false; 241 } 242 CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode); 243 (*queue)->start(queue); 244 return true; 245 } 246 247 // static 248 void 249 AppleRemote::QueueCallbackFunction(void* target, IOReturn result, 250 void* refcon, void* sender) { 251 AppleRemote* remote = (AppleRemote*)target; 252 remote->_queueCallbackFunction(result,refcon,sender); 253 } 254 255 void 256 AppleRemote::_queueCallbackFunction(IOReturn result, void* /*refcon*/, void* /*sender*/) { 257 AbsoluteTime zeroTime = {0,0}; 258 SInt32 sumOfValues = 0; 259 std::stringstream cookieString; 260 261 while (result == kIOReturnSuccess) { 262 IOHIDEventStruct event; 263 result = (*queue)->getNextEvent(queue, &event, zeroTime, 0); 264 if (result != kIOReturnSuccess) break; 265 266 if (REMOTE_SWITCH_COOKIE == (int)event.elementCookie) { 267 remoteId=event.value; 268 _handleEventWithCookieString("19_",0); 269 } else { 270 sumOfValues+=event.value; 271 cookieString << std::dec << (int)event.elementCookie << "_"; 272 } 273 } 274 275 _handleEventWithCookieString(cookieString.str(), sumOfValues); 276 } 277 278 void 279 AppleRemote::_handleEventWithCookieString(std::string cookieString, 280 SInt32 sumOfValues) { 281 std::map<std::string,AppleRemote::Event>::iterator ii = cookieToButtonMapping.find(cookieString); 282 if (ii != cookieToButtonMapping.end() && _listener) { 283 AppleRemote::Event buttonid = ii->second; 284 if (_listener) _listener->appleRemoteButton(buttonid, sumOfValues>0); 285 } 286 } -
libs/libmyth/mythdialogs.cpp
23 23 using namespace std; 24 24 25 25 #include <pthread.h> 26 #ifdef Q_WS_MACX 27 #include "lircevent.h" 28 #include "AppleRemote.h" 29 #include "AppleRemoteListener.h" 30 #endif 26 31 #ifdef USE_LIRC 27 32 #include "lirc.h" 28 33 #include "lircevent.h" … … 56 61 } 57 62 #endif 58 63 64 #ifdef Q_WS_MACX 65 static void* SpawnAppleRemote(void* param) 66 { 67 MythMainWindow *main_window = (MythMainWindow *)param; 68 AppleRemoteListener *arl = new AppleRemoteListener(main_window); 69 AppleRemote& remote(AppleRemote::instance()); 70 remote.setListener(arl); 71 remote.startListening(); 72 if (!remote.isListeningToRemote()) { 73 return NULL; 74 } 75 remote.runLoop(); 76 return NULL; 77 } 78 #endif 79 59 80 #ifdef USE_JOYSTICK_MENU 60 81 static void *SpawnJoystickMenu(void *param) 61 82 { … … 194 215 pthread_create(&lirc_tid, &attr, SpawnLirc, this); 195 216 #endif 196 217 218 #ifdef Q_WS_MACX 219 pthread_t appleremote_tid; 220 pthread_attr_t arattr; 221 pthread_attr_init(&arattr); 222 pthread_attr_setdetachstate(&arattr, PTHREAD_CREATE_DETACHED); 223 224 pthread_create(&appleremote_tid, &arattr, SpawnAppleRemote, this); 225 #endif 226 197 227 #ifdef USE_JOYSTICK_MENU 198 228 d->ignore_joystick_keys = false; 199 229 pthread_t js_tid; … … 810 840 } 811 841 } 812 842 } 843 #if defined(USE_LIRC) || defined(Q_WS_MACX) 844 else if (ce->type() == kLircKeycodeEventType 813 845 #ifdef USE_LIRC 814 else if (ce->type() == kLircKeycodeEventType && !d->ignore_lirc_keys) 846 && !d->ignore_lirc_keys 847 #endif 848 ) 815 849 { 816 850 LircKeycodeEvent *lke = (LircKeycodeEvent *)ce; 817 851 int keycode = lke->getKeycode(); … … 851 885 " your key mappings.\n"; 852 886 } 853 887 } 888 #endif 889 #ifdef USE_LIRC 854 890 else if (ce->type() == kLircMuteEventType) 855 891 { 856 892 LircMuteEvent *lme = (LircMuteEvent *)ce; -
libs/libmyth/libmyth.pro
75 75 macx { 76 76 HEADERS += audiooutputca.h screensaver-osx.h DisplayResOSX.h 77 77 SOURCES += audiooutputca.cpp screensaver-osx.cpp DisplayResOSX.cpp 78 HEADERS += util-osx.h 79 SOURCES += util-osx.cpp 78 HEADERS += util-osx.h AppleRemote.h AppleRemoteListener.h lircevent.h 79 SOURCES += util-osx.cpp AppleRemote.cpp AppleRemoteListener.cpp lircevent.cpp 80 80 81 81 # Mac OS X Frameworks 82 82 FWKS = ApplicationServices AudioUnit Carbon CoreAudio IOKit -
libs/libmyth/AppleRemoteListener.h
1 #ifndef APPLEREMOTELISTENER 2 #define APPLEREMOTELISTENER 3 4 #include "AppleRemote.h" 5 6 #include <iostream> 7 8 class AppleRemoteListener: public AppleRemote::Listener { 9 public: 10 AppleRemoteListener(QObject* mainWindow_); 11 // virtual 12 void appleRemoteButton(AppleRemote::Event button, bool pressedDown); 13 private: 14 QObject *mainWindow; 15 }; 16 17 #endif // APPLEREMOTELISTENER 18 No newline at end of file