فهرست منبع

Support PHT style harmony apple remote input

This following code emulates the harmony remotes input to PHT. The Apple API is actually
limited to just the number of keys that are on Apple specific remotes so we had to work
around that with the following hack: deviceID was used as a prefix for what the keys meant
so for example if we send deviceID 150 and keycode UP it means up, but instead deviceID 151
and UP it can be mapped to a different key.

The harmony profile for this is using deviceID's 150-160 to prefix the keycode, so we will
treat them differently here than the other keycodes. We append the deviceID to the keycode
when the deviceID falls inside the 150-160 range, otherwise we assume the keycode is coming
from a "normal" remote and only forward the keycode.

Since it's unknown if this will cause problems with any remotes I have added a setting:
appleremote.emulatepht to turn this off if needed, but for now we'll keep it defaulted to on
Tobias Hieta 8 سال پیش
والد
کامیت
ee099bcba3

+ 62 - 15
resources/inputmaps/apple-remote.json

@@ -1,20 +1,67 @@
+// This keymap handles two different kind of apple remotes,
+// the standard one that you pick up for your appletv or old mac mini
+// and the old PHT style harmony remote. PHT had a interesting hack that
+// changed the device-id between keypresses to be able to emulate more
+// buttons than was physically on the remote. In PMP we emulate this mode
+// by sending the deviceID (XXX) first in the keycode like: XXX-Y
+//
+// The harmony sends out deviceId's between 150 and 160 for this mode so
+// the host code makes sure that deviceId comes through on those ranges
+// but not on any other deviceID, then we just emit the keycode.
+//
 {
   "name": "Apple Remote",
   "idmatcher": "AppleRemote.*",
-  "mapping": 
-  {
-      "1": {
-        "short": "up",
-        "long": "cycle_audio"
-      },
-      "2": {
-        "short": "down",
-        "long": "cycle_audio_back"
-      },
-      "3": "left",
-      "4": "right",
-      "5": "enter",
-      "6": "back",
-      "7": "play_pause"
+  "mapping": {
+    // Standard Apple Remote mapping
+    "1": {
+      "short": "up",
+      "long": "cycle_audio"
+    },
+    "2": {
+      "short": "down",
+      "long": "cycle_audio_back"
+    },
+    "3": "left",
+    "4": "right",
+    "5": "enter",
+    "6": "back",
+    "7": "play_pause",
+
+    // PHT harmony emulation in format "DEVICEID-KEYCODE"
+    "150-1": "up",
+    "150-2": "down",
+    "150-3": "left",
+    "150-4": "right",
+    "150-5": "enter",
+    "150-6": "back",
+    "151-1": "1",
+    "151-2": "2",
+    "151-3": "3",
+    "151-4": "4",
+    "152-3": "5",
+    "152-4": "6",
+    "153-3": "7",
+    "153-4": "8",
+    "154-3": "9",
+    "154-4": "0",
+    "153-2": "back",
+    "151-5": "stop",
+    "151-6": "play",
+    "152-6": "pause",
+    "154-1": "step_backward",
+    "154-2": "step_forward",
+    "155-1": "home",
+    "153-1": "host:toggleDebug",
+    "154-6": "host:suspend",
+    "158-1": "seek_backward",
+    "158-2": "seek_forward"
+
+    // Keys that are mapped in the harmony but not used in PMP
+    //"157-1": "aspect",
+    //"154-5": "clear",
+    //"157-6": "power toggle",
+    //"153-6": "enter",
+    //"157-2": "queue"
   }
 }

+ 10 - 0
resources/settings/settings_description.json

@@ -357,6 +357,16 @@
       }
     ]
   },
+  {
+    "section": "appleremote",
+    "hidden": true,
+    "values": [
+      {
+        "value": "emulatepht",
+        "default": true
+      }
+    ]
+  },
   {
     "section": "webclient",
     "hidden": true,

+ 9 - 2
src/input/apple/AppleRemoteDelegate.mm

@@ -55,15 +55,22 @@ fromHardwareWithAttributes:(NSMutableDictionary *)attributes
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-- (void) hidRemote:(HIDRemote *)hidRemote releasedHardwareWithAttributes:(NSMutableDictionary *)attributes
+- (void)hidRemote:(HIDRemote *)hidRemote releasedHardwareWithAttributes:(NSMutableDictionary *)attributes
 {
   m_remoteHandler->removeRemote([self remoteNameFromAttributes:attributes]);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-- (void) hidRemote:(HIDRemote *)hidRemote failedNewHardwareWithError:(NSError *)error
+- (void)hidRemote:(HIDRemote *)hidRemote failedNewHardwareWithError:(NSError *)error
 {
   m_remoteHandler->addRemoteFailed(QString([[error localizedDescription] UTF8String]));
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+- (void)hidRemote:(HIDRemote *)hidRemote remoteIDChangedOldID:(SInt32)old newID:(SInt32)newID
+                                    forHardwareWithAttributes:(NSMutableDictionary *)attributes
+{
+  m_remoteHandler->changeRemoteID(newID);
+}
+
 @end

+ 5 - 4
src/input/apple/InputAppleRemote.h

@@ -16,7 +16,7 @@ typedef void delegate;
 class InputAppleRemote : public InputBase
 {
 public:
-  explicit InputAppleRemote(QObject* parent = nullptr) : InputBase(parent) { }
+  explicit InputAppleRemote(QObject* parent = nullptr) : InputBase(parent), m_remoteID(0) { }
   const char* inputName() override { return "AppleRemote"; }
   bool initInput() override;
   
@@ -25,11 +25,12 @@ public:
   void addRemote(const QString& name);
   void removeRemote(const QString& name);
   void addRemoteFailed(const QString& error);
-  
+  void changeRemoteID(quint32 newID);
+
 private:
   delegate* m_delegate;
   QStringList m_remotes;
-  
+  quint32 m_remoteID;
 };
 
-#endif
+#endif

+ 29 - 1
src/input/apple/InputAppleRemote.mm

@@ -1,3 +1,4 @@
+#include "settings/SettingsComponent.h"
 #include "InputAppleRemote.h"
 #include "QsLog.h"
 
@@ -34,5 +35,32 @@ void InputAppleRemote::removeRemote(const QString &name)
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 void InputAppleRemote::remoteButtonEvent(quint8 code, bool pressed, const QString &name)
 {
-  emit receivedInput("AppleRemote", QString::number(code), pressed);
+  // This following code emulates the harmony remotes input to PHT. The Apple API is actually
+  // limited to just the number of keys that are on Apple specific remotes so we had to work
+  // around that with the following hack: deviceID was used as a prefix for what the keys meant
+  // so for example if we send deviceID 150 and keycode UP it means up, but instead deviceID 151
+  // and UP it can be mapped to a different key.
+  //
+  // The harmony profile for this is using deviceID's 150-160 to prefix the keycode, so we will
+  // treat them differently here than the other keycodes. We append the deviceID to the keycode
+  // when the deviceID falls inside the 150-160 range, otherwise we assume the keycode is coming
+  // from a "normal" remote and only forward the keycode.
+  //
+  // Since it's unknown if this will cause problems with any remotes I have added a setting:
+  // appleremote.emulatepht to turn this off if needed, but for now we'll keep it defaulted to on
+  //
+  QString eventName;
+  if (SettingsComponent::Get().value(SETTINGS_SECTION_APPLEREMOTE, "emulatepht").toBool() &&
+      (m_remoteID >= 150 && m_remoteID <= 160))
+    eventName = QString("%1-%2").arg(m_remoteID).arg(code);
+  else
+    eventName = QString::number(code);
+
+  emit receivedInput("AppleRemote", eventName, pressed);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+void InputAppleRemote::changeRemoteID(quint32 newID)
+{
+  m_remoteID = newID;
 }

+ 1 - 0
src/settings/SettingsComponent.h

@@ -16,6 +16,7 @@
 #define SETTINGS_SECTION_OVERRIDES "overrides"
 #define SETTINGS_SECTION_CEC "cec"
 #define SETTINGS_SECTION_OPENELEC "openelec"
+#define SETTINGS_SECTION_APPLEREMOTE "appleremote"
 
 #define AUDIO_DEVICE_TYPE_BASIC "basic"
 #define AUDIO_DEVICE_TYPE_SPDIF "spdif"