Ticket #2017: appleremote.patch

File appleremote.patch, 17.8 KB (added by mythtv@…, 15 years ago)

patch file (created with 'svn diff')

  • 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;
  • 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
     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
     49protected:
     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
     57private:
     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
     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
     29// public
     30AppleRemote&
     31AppleRemote::instance() {
     32  if (_instance==0) {
     33    _instance = new AppleRemote();
     34  }
     35  return *_instance;
     36}
     37
     38bool
     39AppleRemote::isRemoteAvailable() {
     40  io_object_t hidDevice = _findAppleRemoteDevice();
     41  if (hidDevice != 0) {
     42    IOObjectRelease(hidDevice);
     43    return true;
     44  }
     45  return false;
     46}
     47
     48bool
     49AppleRemote::isListeningToRemote() {
     50  return (hidDeviceInterface != NULL && !cookies.empty() && queue != NULL);
     51}
     52
     53void
     54AppleRemote::setListener(AppleRemote::Listener* listener) {
     55  _listener = listener;
     56}
     57
     58void
     59AppleRemote::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
     67error:
     68  stopListening();
     69
     70cleanup:
     71  IOObjectRelease(hidDevice);
     72}
     73
     74void
     75AppleRemote::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
     94void
     95AppleRemote::runLoop() {
     96  CFRunLoopRun();
     97}
     98
     99// protected
     100AppleRemote::AppleRemote():
     101    openInExclusiveMode(true),
     102    hidDeviceInterface(0),
     103    queue(0),
     104    _listener(0) {
     105  _initCookieMap();
     106}
     107
     108// private
     109void
     110AppleRemote::_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
     125io_object_t
     126AppleRemote::_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
     149bool
     150AppleRemote::_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
     178bool
     179AppleRemote::_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
     202bool
     203AppleRemote::_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
     248void
     249AppleRemote::QueueCallbackFunction(void* target, IOReturn result,
     250                                    void* refcon, void* sender) {
     251  AppleRemote* remote = (AppleRemote*)target;
     252  remote->_queueCallbackFunction(result,refcon,sender);
     253}
     254
     255void
     256AppleRemote::_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
     278void
     279AppleRemote::_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

     
    2323using namespace std;
    2424
    2525#include <pthread.h>
     26#ifdef Q_WS_MACX
     27#include "lircevent.h"
     28#include "AppleRemote.h"
     29#include "AppleRemoteListener.h"
     30#endif
    2631#ifdef USE_LIRC
    2732#include "lirc.h"
    2833#include "lircevent.h"
     
    5661}
    5762#endif
    5863
     64#ifdef Q_WS_MACX
     65static 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
    5980#ifdef USE_JOYSTICK_MENU
    6081static void *SpawnJoystickMenu(void *param)
    6182{
     
    194215    pthread_create(&lirc_tid, &attr, SpawnLirc, this);
    195216#endif
    196217
     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
    197227#ifdef USE_JOYSTICK_MENU
    198228    d->ignore_joystick_keys = false;
    199229    pthread_t js_tid;
     
    810840            }
    811841        }
    812842    }
     843#if defined(USE_LIRC) || defined(Q_WS_MACX)
     844    else if (ce->type() == kLircKeycodeEventType
    813845#ifdef USE_LIRC
    814     else if (ce->type() == kLircKeycodeEventType && !d->ignore_lirc_keys)
     846    && !d->ignore_lirc_keys
     847#endif
     848        )
    815849    {
    816850        LircKeycodeEvent *lke = (LircKeycodeEvent *)ce;
    817851        int keycode = lke->getKeycode();
     
    851885                                           " your key mappings.\n";
    852886        }
    853887    }
     888#endif
     889#ifdef USE_LIRC
    854890    else if (ce->type() == kLircMuteEventType)
    855891    {
    856892        LircMuteEvent *lme = (LircMuteEvent *)ce;
  • 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