Ticket #2017: appleremote0.20.patch

File appleremote0.20.patch, 15.9 KB (added by mythtv@…, 15 years ago)

patch trimmed down for 0.20

  • 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
     14class AppleRemote {
     15public:
     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
     50protected:
     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
     58private:
     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
     7AppleRemoteListener::AppleRemoteListener(QObject* mainWindow_): mainWindow(mainWindow_) {
     8}
     9
     10void
     11AppleRemoteListener::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
     23AppleRemote* AppleRemote::_instance = 0;
     24// static
     25const char* const AppleRemote::AppleRemoteDeviceName = "AppleIRController";
     26// static
     27const int AppleRemote::REMOTE_SWITCH_COOKIE=19;
     28
     29AppleRemote::Listener::~Listener() {
     30}
     31
     32// public
     33AppleRemote&
     34AppleRemote::instance() {
     35  if (_instance==0) {
     36    _instance = new AppleRemote();
     37  }
     38  return *_instance;
     39}
     40
     41AppleRemote::~AppleRemote() {
     42  stopListening();
     43}
     44
     45bool
     46AppleRemote::isRemoteAvailable() {
     47  io_object_t hidDevice = _findAppleRemoteDevice();
     48  if (hidDevice != 0) {
     49    IOObjectRelease(hidDevice);
     50    return true;
     51  }
     52  return false;
     53}
     54
     55bool
     56AppleRemote::isListeningToRemote() {
     57  return (hidDeviceInterface != NULL && !cookies.empty() && queue != NULL);
     58}
     59
     60void
     61AppleRemote::setListener(AppleRemote::Listener* listener) {
     62  _listener = listener;
     63}
     64
     65void
     66AppleRemote::startListening() {
     67  io_object_t hidDevice = _findAppleRemoteDevice();
     68  if (hidDevice == 0) goto error;
     69  if (!_createDeviceInterface(hidDevice)) goto error;
     70  if (!_initCookies()) goto error;
     71  if (!_openDevice()) goto error;
     72  goto cleanup;
     73
     74error:
     75  stopListening();
     76
     77cleanup:
     78  IOObjectRelease(hidDevice);
     79}
     80
     81void
     82AppleRemote::stopListening() {
     83  if (queue != NULL) {
     84    (*queue)->stop(queue);
     85    (*queue)->dispose(queue);
     86    (*queue)->Release(queue);
     87    queue = NULL;
     88  }
     89
     90  if (!cookies.empty()) {
     91    cookies.clear();
     92  }
     93
     94  if (hidDeviceInterface != NULL) {
     95    (*hidDeviceInterface)->close(hidDeviceInterface);
     96    (*hidDeviceInterface)->Release(hidDeviceInterface);
     97    hidDeviceInterface = NULL;
     98  }
     99}
     100
     101void
     102AppleRemote::runLoop() {
     103  CFRunLoopRun();
     104}
     105
     106// protected
     107AppleRemote::AppleRemote():
     108    openInExclusiveMode(true),
     109    hidDeviceInterface(0),
     110    queue(0),
     111    _listener(0) {
     112  _initCookieMap();
     113}
     114
     115// private
     116void
     117AppleRemote::_initCookieMap() {
     118  cookieToButtonMapping["14_12_11_6_5_"] = VolumePlus;
     119  cookieToButtonMapping["14_13_11_6_5_"] = VolumeMinus;
     120  cookieToButtonMapping["14_7_6_5_14_7_6_5_"] = Menu;
     121  cookieToButtonMapping["14_8_6_5_14_8_6_5_"] = Play;
     122  cookieToButtonMapping["14_9_6_5_14_9_6_5_"] = Right;
     123  cookieToButtonMapping["14_10_6_5_14_10_6_5_"] = Left;
     124  cookieToButtonMapping["14_6_5_4_2_"] = RightHold;
     125  cookieToButtonMapping["14_6_5_3_2_"] = LeftHold;
     126  cookieToButtonMapping["14_6_5_14_6_5_"] = MenuHold;
     127  cookieToButtonMapping["18_14_6_5_18_14_6_5_"] = PlaySleep;
     128  cookieToButtonMapping["19_"] = ControlSwitched;
     129}
     130
     131// private
     132io_object_t
     133AppleRemote::_findAppleRemoteDevice() {
     134  CFMutableDictionaryRef hidMatchDictionary = 0;
     135  io_iterator_t hidObjectIterator = 0;
     136  io_object_t hidDevice = 0;
     137
     138  hidMatchDictionary = IOServiceMatching(AppleRemoteDeviceName);
     139
     140  // check for matching devices
     141  IOReturn ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault,
     142                                               hidMatchDictionary,
     143                                               &hidObjectIterator);
     144  if ((ioReturnValue == kIOReturnSuccess)
     145                       && (hidObjectIterator != 0)) {
     146    hidDevice = IOIteratorNext(hidObjectIterator);
     147  }
     148
     149  // IOServiceGetMatchingServices consumes a reference to the dictionary, so we
     150  // don't need to release the dictionary ref.
     151  hidMatchDictionary = 0;
     152  return hidDevice;
     153}
     154
     155// private
     156bool
     157AppleRemote::_initCookies() {
     158  IOHIDDeviceInterface122** handle = (IOHIDDeviceInterface122**)hidDeviceInterface;
     159
     160  CFArrayRef elements;
     161  IOReturn success =
     162  (*handle)->copyMatchingElements(handle,NULL,(CFArrayRef*)&elements);
     163
     164  if (success == kIOReturnSuccess) {
     165    for (CFIndex i = 0; i < CFArrayGetCount(elements); i++) {
     166      CFDictionaryRef element = (CFDictionaryRef)CFArrayGetValueAtIndex(elements, i);
     167
     168      CFTypeRef object = CFDictionaryGetValue(element,
     169                                            CFSTR(kIOHIDElementCookieKey));
     170      if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue;
     171      long number;
     172      if (!CFNumberGetValue((CFNumberRef)object, kCFNumberLongType, &number)) {
     173        continue;
     174      }
     175      IOHIDElementCookie cookie = (IOHIDElementCookie)number;
     176
     177      cookies.push_back((int)cookie);
     178    }
     179    return true;
     180  }
     181  return false;
     182}
     183
     184// private
     185bool
     186AppleRemote::_createDeviceInterface(io_object_t hidDevice) {
     187  SInt32 score = 0;
     188  IOCFPlugInInterface** plugInInterface = NULL;
     189
     190  IOReturn ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice,
     191                                                    kIOHIDDeviceUserClientTypeID,
     192                                                    kIOCFPlugInInterfaceID,
     193                                                    &plugInInterface,
     194                                                    &score);
     195  if (ioReturnValue == kIOReturnSuccess) {
     196    HRESULT plugInResult = (*plugInInterface)->QueryInterface(plugInInterface,
     197                                CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
     198                                (LPVOID*) (&hidDeviceInterface));
     199    if (plugInResult != S_OK) {
     200      std::cerr << "AppleRemote Error: couldn't create device interface " << std::endl;
     201    }
     202    // Release
     203    if (plugInInterface) (*plugInInterface)->Release(plugInInterface);
     204  }
     205  return hidDeviceInterface != 0;
     206}
     207
     208// private
     209bool
     210AppleRemote::_openDevice() {
     211  IOHIDOptionsType openMode = kIOHIDOptionsTypeNone;
     212  if (openInExclusiveMode) openMode = kIOHIDOptionsTypeSeizeDevice;
     213  IOReturn ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, openMode);
     214
     215  if (ioReturnValue != KERN_SUCCESS) {
     216    std::cerr << "AppleRemote Error: when opening device" << std::endl;
     217    return false;
     218  }
     219  queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface);
     220  if (!queue) {
     221    std::cerr << "AppleRemote Error allocating queue" << std::endl;
     222    return false;
     223  }
     224
     225  HRESULT result = (*queue)->create(queue, 0, 12);
     226  if (result != S_OK || !queue) {
     227        std::cerr << "AppleRemote Error creating queue" << std::endl;
     228  }
     229
     230  for (std::vector<int>::iterator iter = cookies.begin();
     231       iter != cookies.end();
     232       iter++) {
     233    IOHIDElementCookie cookie = (IOHIDElementCookie)(*iter);
     234    (*queue)->addElement(queue, cookie, 0);
     235  }
     236
     237  CFRunLoopSourceRef eventSource;
     238  ioReturnValue = (*queue)->createAsyncEventSource(queue, &eventSource);
     239  if (ioReturnValue != KERN_SUCCESS) {
     240    std::cerr << "AppleRemote Error creating async event source" << std::endl;
     241    return false;
     242  }
     243
     244  ioReturnValue = (*queue)->setEventCallout(queue,QueueCallbackFunction, this, NULL);
     245  if (ioReturnValue != KERN_SUCCESS) {
     246    std::cerr << "AppleRemote Error registering callback" << std::endl;
     247    return false;
     248  }
     249  CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
     250  (*queue)->start(queue);
     251  return true;
     252}
     253
     254// static
     255void
     256AppleRemote::QueueCallbackFunction(void* target, IOReturn result,
     257                                    void* refcon, void* sender) {
     258  AppleRemote* remote = (AppleRemote*)target;
     259  remote->_queueCallbackFunction(result,refcon,sender);
     260}
     261
     262void
     263AppleRemote::_queueCallbackFunction(IOReturn result, void* /*refcon*/, void* /*sender*/) {
     264  AbsoluteTime zeroTime = {0,0};
     265  SInt32 sumOfValues = 0;
     266  std::stringstream cookieString;
     267
     268  while (result == kIOReturnSuccess) {
     269    IOHIDEventStruct event;
     270    result = (*queue)->getNextEvent(queue, &event, zeroTime, 0);
     271    if (result != kIOReturnSuccess) break;
     272
     273    if (REMOTE_SWITCH_COOKIE == (int)event.elementCookie) {
     274      remoteId=event.value;
     275      _handleEventWithCookieString("19_",0);
     276    } else {
     277      sumOfValues+=event.value;
     278      cookieString << std::dec << (int)event.elementCookie << "_";
     279    }
     280  }
     281
     282  _handleEventWithCookieString(cookieString.str(), sumOfValues);
     283}
     284
     285void
     286AppleRemote::_handleEventWithCookieString(std::string cookieString,
     287                                          SInt32 sumOfValues) {
     288  std::map<std::string,AppleRemote::Event>::iterator ii = cookieToButtonMapping.find(cookieString);
     289  if (ii  != cookieToButtonMapping.end() && _listener) {
     290    AppleRemote::Event buttonid = ii->second;
     291    if (_listener) _listener->appleRemoteButton(buttonid, sumOfValues>0);
     292  }
     293}
  • libs/libmyth/libmyth.pro

     
    7575macx {
    7676    HEADERS += audiooutputca.h   screensaver-osx.h   DisplayResOSX.h
    7777    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
    8080
    8181    # Mac OS X Frameworks
    8282    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
     8class AppleRemoteListener: public AppleRemote::Listener {
     9public:
     10        AppleRemoteListener(QObject* mainWindow_);
     11    // virtual
     12    void appleRemoteButton(AppleRemote::Event button, bool pressedDown);
     13private:
     14        QObject *mainWindow;
     15};
     16
     17#endif // APPLEREMOTELISTENER
     18 No newline at end of file
  • libs/libmythui/mythmainwindow.cpp

     
    1010#include <qwindowsystem_qws.h>
    1111#endif
    1212#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"
    1418#endif
    1519
    1620#ifdef USE_LIRC
     
    4650}
    4751#endif
    4852
     53#ifdef Q_WS_MACX
     54static 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
    4969class KeyContext
    5070{
    5171  public:
     
    214234    pthread_create(&lirc_tid, &attr, SpawnLirc, this);
    215235#endif
    216236
     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
    217246    d->keyContexts.setAutoDelete(true);
    218247
    219248    RegisterKey("Global", "UP", "Up Arrow", "Up");
     
    901930            }
    902931        }
    903932    }
    904 #ifdef USE_LIRC
     933#if defined(USE_LIRC) || defined(Q_WS_MACX)
    905934    else if (ce->type() == kLircKeycodeEventType && !d->ignore_lirc_keys)
    906935    {
    907936        LircKeycodeEvent *lke = (LircKeycodeEvent *)ce;