Ticket #2017: appleremote0.19_friendly.patch
File appleremote0.19_friendly.patch, 19.8 KB (added by , 18 years ago) |
---|
-
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 ~AppleRemote(); 38 39 bool isRemoteAvailable(); 40 bool isListeningToRemote(); 41 42 void setListener(Listener* listener); 43 Listener* listener() { return _listener; } 44 void setOpenInExclusiveMode(bool in) { openInExclusiveMode = in; }; 45 bool isOpenInExclusiveMode() { return openInExclusiveMode; }; 46 void startListening(); 47 void stopListening(); 48 void runLoop(); 49 50 protected: 51 AppleRemote(); // will be a singleton class 52 53 static AppleRemote* _instance; 54 static const char* const AppleRemoteDeviceName; 55 static const int REMOTE_SWITCH_COOKIE; 56 57 58 private: 59 bool openInExclusiveMode; 60 IOHIDDeviceInterface** hidDeviceInterface; 61 IOHIDQueueInterface** queue; 62 std::vector<int> cookies; 63 std::map< std::string, Event > cookieToButtonMapping; 64 int remoteId; 65 Listener* _listener; 66 67 void _initCookieMap(); 68 io_object_t _findAppleRemoteDevice(); 69 bool _initCookies(); 70 bool _createDeviceInterface(io_object_t hidDevice); 71 bool _openDevice(); 72 73 static void QueueCallbackFunction(void* target, IOReturn result, 74 void* refcon, void* sender); 75 void _queueCallbackFunction(IOReturn result, void* refcon, void* sender); 76 void _handleEventWithCookieString(std::string cookieString, SInt32 sumOfValues); 77 }; 78 79 #endif // APPLEREMOTE -
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 AppleRemote::Listener::~Listener() { 30 } 31 32 // public 33 AppleRemote& 34 AppleRemote::instance() { 35 if (_instance==0) { 36 _instance = new AppleRemote(); 37 } 38 return *_instance; 39 } 40 41 AppleRemote::~AppleRemote() { 42 stopListening(); 43 } 44 45 bool 46 AppleRemote::isRemoteAvailable() { 47 io_object_t hidDevice = _findAppleRemoteDevice(); 48 if (hidDevice != 0) { 49 IOObjectRelease(hidDevice); 50 return true; 51 } 52 return false; 53 } 54 55 bool 56 AppleRemote::isListeningToRemote() { 57 return (hidDeviceInterface != NULL && !cookies.empty() && queue != NULL); 58 } 59 60 void 61 AppleRemote::setListener(AppleRemote::Listener* listener) { 62 _listener = listener; 63 } 64 65 void 66 AppleRemote::startListening() { 67 if (queue != NULL) { 68 // already listening 69 return; 70 } 71 io_object_t hidDevice = _findAppleRemoteDevice(); 72 if (hidDevice == 0) goto error; 73 if (!_createDeviceInterface(hidDevice)) goto error; 74 if (!_initCookies()) goto error; 75 if (!_openDevice()) goto error; 76 goto cleanup; 77 78 error: 79 stopListening(); 80 81 cleanup: 82 IOObjectRelease(hidDevice); 83 } 84 85 void 86 AppleRemote::stopListening() { 87 if (queue != NULL) { 88 (*queue)->stop(queue); 89 (*queue)->dispose(queue); 90 (*queue)->Release(queue); 91 queue = NULL; 92 } 93 94 if (!cookies.empty()) { 95 cookies.clear(); 96 } 97 98 if (hidDeviceInterface != NULL) { 99 (*hidDeviceInterface)->close(hidDeviceInterface); 100 (*hidDeviceInterface)->Release(hidDeviceInterface); 101 hidDeviceInterface = NULL; 102 } 103 } 104 105 void 106 AppleRemote::runLoop() { 107 CFRunLoopRun(); 108 } 109 110 // protected 111 AppleRemote::AppleRemote(): 112 openInExclusiveMode(true), 113 hidDeviceInterface(0), 114 queue(0), 115 _listener(0) { 116 _initCookieMap(); 117 } 118 119 // private 120 void 121 AppleRemote::_initCookieMap() { 122 cookieToButtonMapping["14_12_11_6_5_"] = VolumePlus; 123 cookieToButtonMapping["14_13_11_6_5_"] = VolumeMinus; 124 cookieToButtonMapping["14_7_6_5_14_7_6_5_"] = Menu; 125 cookieToButtonMapping["14_8_6_5_14_8_6_5_"] = Play; 126 cookieToButtonMapping["14_9_6_5_14_9_6_5_"] = Right; 127 cookieToButtonMapping["14_10_6_5_14_10_6_5_"] = Left; 128 cookieToButtonMapping["14_6_5_4_2_"] = RightHold; 129 cookieToButtonMapping["14_6_5_3_2_"] = LeftHold; 130 cookieToButtonMapping["14_6_5_14_6_5_"] = MenuHold; 131 cookieToButtonMapping["18_14_6_5_18_14_6_5_"] = PlaySleep; 132 cookieToButtonMapping["19_"] = ControlSwitched; 133 } 134 135 // private 136 io_object_t 137 AppleRemote::_findAppleRemoteDevice() { 138 CFMutableDictionaryRef hidMatchDictionary = 0; 139 io_iterator_t hidObjectIterator = 0; 140 io_object_t hidDevice = 0; 141 142 hidMatchDictionary = IOServiceMatching(AppleRemoteDeviceName); 143 144 // check for matching devices 145 IOReturn ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, 146 hidMatchDictionary, 147 &hidObjectIterator); 148 if ((ioReturnValue == kIOReturnSuccess) 149 && (hidObjectIterator != 0)) { 150 hidDevice = IOIteratorNext(hidObjectIterator); 151 } 152 153 // IOServiceGetMatchingServices consumes a reference to the dictionary, so we 154 // don't need to release the dictionary ref. 155 hidMatchDictionary = 0; 156 return hidDevice; 157 } 158 159 // private 160 bool 161 AppleRemote::_initCookies() { 162 IOHIDDeviceInterface122** handle = (IOHIDDeviceInterface122**)hidDeviceInterface; 163 164 CFArrayRef elements; 165 IOReturn success = 166 (*handle)->copyMatchingElements(handle,NULL,(CFArrayRef*)&elements); 167 168 if (success == kIOReturnSuccess) { 169 for (CFIndex i = 0; i < CFArrayGetCount(elements); i++) { 170 CFDictionaryRef element = (CFDictionaryRef)CFArrayGetValueAtIndex(elements, i); 171 172 CFTypeRef object = CFDictionaryGetValue(element, 173 CFSTR(kIOHIDElementCookieKey)); 174 if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue; 175 long number; 176 if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType, &number)) { 177 continue; 178 } 179 IOHIDElementCookie cookie = (IOHIDElementCookie)number; 180 181 cookies.push_back((int)cookie); 182 } 183 return true; 184 } 185 return false; 186 } 187 188 // private 189 bool 190 AppleRemote::_createDeviceInterface(io_object_t hidDevice) { 191 SInt32 score = 0; 192 IOCFPlugInInterface** plugInInterface = NULL; 193 194 IOReturn ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice, 195 kIOHIDDeviceUserClientTypeID, 196 kIOCFPlugInInterfaceID, 197 &plugInInterface, 198 &score); 199 if (ioReturnValue == kIOReturnSuccess) { 200 HRESULT plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, 201 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), 202 (LPVOID*) (&hidDeviceInterface)); 203 if (plugInResult != S_OK) { 204 std::cerr << "AppleRemote Error: couldn't create device interface " << std::endl; 205 } 206 // Release 207 if (plugInInterface) (*plugInInterface)->Release(plugInInterface); 208 } 209 return hidDeviceInterface != 0; 210 } 211 212 // private 213 bool 214 AppleRemote::_openDevice() { 215 IOHIDOptionsType openMode = kIOHIDOptionsTypeNone; 216 if (openInExclusiveMode) openMode = kIOHIDOptionsTypeSeizeDevice; 217 IOReturn ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, openMode); 218 219 if (ioReturnValue != KERN_SUCCESS) { 220 std::cerr << "AppleRemote Error: when opening device" << std::endl; 221 return false; 222 } 223 queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface); 224 if (!queue) { 225 std::cerr << "AppleRemote Error allocating queue" << std::endl; 226 return false; 227 } 228 229 HRESULT result = (*queue)->create(queue, 0, 12); 230 if (result != S_OK || !queue) { 231 std::cerr << "AppleRemote Error creating queue" << std::endl; 232 } 233 234 for (std::vector<int>::iterator iter = cookies.begin(); 235 iter != cookies.end(); 236 iter++) { 237 IOHIDElementCookie cookie = (IOHIDElementCookie)(*iter); 238 (*queue)->addElement(queue, cookie, 0); 239 } 240 241 CFRunLoopSourceRef eventSource; 242 ioReturnValue = (*queue)->createAsyncEventSource(queue, &eventSource); 243 if (ioReturnValue != KERN_SUCCESS) { 244 std::cerr << "AppleRemote Error creating async event source" << std::endl; 245 return false; 246 } 247 248 ioReturnValue = (*queue)->setEventCallout(queue,QueueCallbackFunction, this, NULL); 249 if (ioReturnValue != KERN_SUCCESS) { 250 std::cerr << "AppleRemote Error registering callback" << std::endl; 251 return false; 252 } 253 CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode); 254 (*queue)->start(queue); 255 return true; 256 } 257 258 // static 259 void 260 AppleRemote::QueueCallbackFunction(void* target, IOReturn result, 261 void* refcon, void* sender) { 262 AppleRemote* remote = (AppleRemote*)target; 263 remote->_queueCallbackFunction(result,refcon,sender); 264 } 265 266 void 267 AppleRemote::_queueCallbackFunction(IOReturn result, void* /*refcon*/, void* /*sender*/) { 268 AbsoluteTime zeroTime = {0,0}; 269 SInt32 sumOfValues = 0; 270 std::stringstream cookieString; 271 272 while (result == kIOReturnSuccess) { 273 IOHIDEventStruct event; 274 result = (*queue)->getNextEvent(queue, &event, zeroTime, 0); 275 if (result != kIOReturnSuccess) break; 276 277 if (REMOTE_SWITCH_COOKIE == (int)event.elementCookie) { 278 remoteId=event.value; 279 _handleEventWithCookieString("19_",0); 280 } else { 281 sumOfValues+=event.value; 282 cookieString << std::dec << (int)event.elementCookie << "_"; 283 } 284 } 285 286 _handleEventWithCookieString(cookieString.str(), sumOfValues); 287 } 288 289 void 290 AppleRemote::_handleEventWithCookieString(std::string cookieString, 291 SInt32 sumOfValues) { 292 std::map<std::string,AppleRemote::Event>::iterator ii = cookieToButtonMapping.find(cookieString); 293 if (ii != cookieToButtonMapping.end() && _listener) { 294 AppleRemote::Event buttonid = ii->second; 295 if (_listener) _listener->appleRemoteButton(buttonid, sumOfValues>0); 296 } 297 } -
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; … … 247 277 qApp->quit(); 248 278 } 249 279 280 #ifdef Q_WS_MACX 281 bool MythMainWindow::event(QEvent* e) { 282 switch (e->type()) { 283 case QEvent::WindowActivate: { 284 AppleRemote::instance().startListening(); 285 }break; 286 case QEvent::WindowDeactivate: { 287 // relinquish the remote 288 AppleRemote::instance().stopListening(); 289 }break; 290 } 291 return QWidget::event(e); 292 } 293 #endif 294 250 295 void MythMainWindow::Init(void) 251 296 { 252 297 gContext->GetScreenSettings(d->xbase, d->screenwidth, d->wmult, … … 810 855 } 811 856 } 812 857 } 858 #if defined(USE_LIRC) || defined(Q_WS_MACX) 859 else if (ce->type() == kLircKeycodeEventType 813 860 #ifdef USE_LIRC 814 else if (ce->type() == kLircKeycodeEventType && !d->ignore_lirc_keys) 861 && !d->ignore_lirc_keys 862 #endif 863 ) 815 864 { 816 865 LircKeycodeEvent *lke = (LircKeycodeEvent *)ce; 817 866 int keycode = lke->getKeycode(); … … 851 900 " your key mappings.\n"; 852 901 } 853 902 } 903 #endif 904 #ifdef USE_LIRC 854 905 else if (ce->type() == kLircMuteEventType) 855 906 { 856 907 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/mythdialogs.h
123 123 void keyPressEvent(QKeyEvent *e); 124 124 void customEvent(QCustomEvent *ce); 125 125 void closeEvent(QCloseEvent *e); 126 #ifdef Q_WS_MACX 127 bool event(QEvent* e); 128 #endif 126 129 127 130 void ExitToMainMenu(); 128 131 -
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 -
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"); … … 357 386 d->repaintRegion = d->repaintRegion.unite(pe->region()); 358 387 } 359 388 389 #ifdef Q_WS_MACX 390 bool MythMainWindow::event(QEvent* e) { 391 switch (e->type()) { 392 case QEvent::WindowActivate: { 393 AppleRemote::instance().startListening(); 394 }break; 395 case QEvent::WindowDeactivate: { 396 // relinquish the remote 397 AppleRemote::instance().stopListening(); 398 }break; 399 } 400 return QWidget::event(e); 401 } 402 #endif 403 360 404 void MythMainWindow::Init(void) 361 405 { 362 406 gContext->GetScreenSettings(d->xbase, d->screenwidth, d->wmult, … … 901 945 } 902 946 } 903 947 } 904 #if def USE_LIRC948 #if defined(USE_LIRC) || defined(Q_WS_MACX) 905 949 else if (ce->type() == kLircKeycodeEventType && !d->ignore_lirc_keys) 906 950 { 907 951 LircKeycodeEvent *lke = (LircKeycodeEvent *)ce; -
libs/libmythui/mythmainwindow.h
94 94 void customEvent(QCustomEvent *ce); 95 95 void closeEvent(QCloseEvent *e); 96 96 void paintEvent(QPaintEvent *e); 97 #ifdef Q_WS_MACX 98 bool event(QEvent* e); 99 #endif 97 100 98 101 void ExitToMainMenu(); 99 102