Browse Source

Support for long hold actions.

We can now express hold actions in a generic way in the input mappings.
This is done by mapping a input like this:

"A": { "short": "action1", "long": "action2" }

This is most useful for remote input. If a button has a long hold
action it will not auto repeat.
Tobias Hieta 9 years ago
parent
commit
2c018529e1
4 changed files with 83 additions and 48 deletions
  1. 74 42
      src/input/InputComponent.cpp
  2. 6 1
      src/input/InputComponent.h
  3. 2 4
      src/input/InputMapping.cpp
  4. 1 1
      src/input/InputMapping.h

+ 74 - 42
src/input/InputComponent.cpp

@@ -1,4 +1,3 @@
-
 #include "QsLog.h"
 #include "InputComponent.h"
 #include "settings/SettingsComponent.h"
@@ -63,7 +62,7 @@ bool InputComponent::addInput(InputBase* base)
     qint32 multiplier = qMin(5, qMax(1, m_currentActionCount / 5));
     m_autoRepeatTimer->setInterval(100 / multiplier);
   });
-  
+
   return true;
 }
 
@@ -95,6 +94,50 @@ bool InputComponent::componentInitialize()
   return true;
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+void InputComponent::handleAction(const QString& action, bool autoRepeat)
+{
+  if (action.startsWith("host:"))
+  {
+    QStringList argList = action.mid(5).split(" ");
+    QString hostCommand = argList.value(0);
+    QString hostArguments;
+
+    if (argList.size() > 1)
+    {
+      argList.pop_front();
+      hostArguments = argList.join(" ");
+    }
+
+    QLOG_DEBUG() << "Got host command:" << hostCommand << "arguments:" << hostArguments;
+    if (m_hostCommands.contains(hostCommand))
+    {
+      ReceiverSlot* recvSlot = m_hostCommands.value(hostCommand);
+      if (recvSlot)
+      {
+        QLOG_DEBUG() << "Invoking slot" << qPrintable(recvSlot->slot.data());
+        QGenericArgument arg0 = QGenericArgument();
+        if (recvSlot->hasArguments)
+          arg0 = Q_ARG(const QString&, hostArguments);
+        QMetaObject::invokeMethod(recvSlot->receiver, recvSlot->slot.data(),
+                                  Qt::AutoConnection, arg0);
+      }
+    }
+    else
+    {
+      QLOG_WARN() << "No such host command:" << hostCommand;
+    }
+  }
+  else
+  {
+    m_currentAction = action;
+    emit receivedAction(action);
+
+    if (autoRepeat)
+      m_autoRepeatTimer->start(500);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 void InputComponent::remapInput(const QString &source, const QString &keycode, bool pressDown)
 {
@@ -105,58 +148,47 @@ void InputComponent::remapInput(const QString &source, const QString &keycode, b
     m_autoRepeatTimer->stop();
     m_currentAction.clear();
     m_currentActionCount = 0;
+
+    if (!m_currentLongPressAction.isEmpty())
+    {
+      if (m_longHoldTimer.elapsed() > 1000)
+        handleAction(m_currentLongPressAction.value("long").toString(), false);
+      else
+        handleAction(m_currentLongPressAction.value("short").toString(), false);
+
+      m_currentLongPressAction.clear();
+    }
+
     return;
   }
 
   // hide mouse if it's visible.
   SystemComponent::Get().setCursorVisibility(false);
 
-  QString action = m_mappings->mapToAction(source, keycode);
-  if (!action.isEmpty())
+  QVariant action = m_mappings->mapToAction(source, keycode);
+  if (action.isNull())
   {
-    if (action.startsWith("host:"))
-    {
-      QStringList argList = action.mid(5).split(" ");
-      QString hostCommand = argList.value(0);
-      QString hostArguments;
-
-      if (argList.size() > 1)
-      {
-        argList.pop_front();
-        hostArguments = argList.join(" ");
-      }
+    QLOG_WARN() << "Could not map:" << source << keycode << "to any useful action";
+    return;
+  }
 
-      QLOG_DEBUG() << "Got host command:" << hostCommand << "arguments:" << hostArguments;
-      if (m_hostCommands.contains(hostCommand))
-      {
-        ReceiverSlot* recvSlot = m_hostCommands.value(hostCommand);
-        if (recvSlot)
-        {
-          QLOG_DEBUG() << "Invoking slot" << qPrintable(recvSlot->slot.data());
-          QGenericArgument arg0 = QGenericArgument();
-          if (recvSlot->hasArguments)
-            arg0 = Q_ARG(const QString&, hostArguments);
-          QMetaObject::invokeMethod(recvSlot->receiver, recvSlot->slot.data(),
-                                    Qt::AutoConnection, arg0);
-        }
-      }
-      else
-      {
-        QLOG_WARN() << "No such host command:" << hostCommand;
-      }
+  if (action.type() == QVariant::String)
+  {
+    handleAction(action.toString());
+  }
+  else if (action.type() == QVariant::Map)
+  {
+    QVariantMap map = action.toMap();
+    if (map.contains("long"))
+    {
+      m_longHoldTimer.start();
+      m_currentLongPressAction = map;
     }
-    else
+    else if (map.contains("short"))
     {
-      m_currentAction = action;
-      emit receivedAction(action);
-
-      m_autoRepeatTimer->start(500);
+      handleAction(map.value("short").toString());
     }
   }
-  else
-  {
-    QLOG_WARN() << "Could not map:" << source << keycode << "to any useful action";
-  }
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////

+ 6 - 1
src/input/InputComponent.h

@@ -4,6 +4,7 @@
 #include <QThread>
 #include <QVariantMap>
 #include <QTimer>
+#include <QTime>
 #include "ComponentManager.h"
 #include "InputMapping.h"
 
@@ -95,13 +96,17 @@ private Q_SLOTS:
 private:
   InputComponent(QObject *parent = 0);
   bool addInput(InputBase* input);
+  void handleAction(const QString& action, bool autoRepeat = true);
 
   QHash<QString, ReceiverSlot*> m_hostCommands;
   QList<InputBase*> m_inputs;
   InputMapping* m_mappings;
   QTimer* m_autoRepeatTimer;
-  QString m_currentAction;
+  QVariantMap m_currentLongPressAction;
   qint32 m_currentActionCount;
+
+  QTime m_longHoldTimer;
+  QString m_currentAction;
 };
 
 #endif // INPUTADAPTER_H

+ 2 - 4
src/input/InputMapping.cpp

@@ -52,7 +52,7 @@ bool InputMapping::loadMappings()
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
-QString InputMapping::mapToAction(const QString& source, const QString& keycode)
+QVariant InputMapping::mapToAction(const QString& source, const QString& keycode)
 {
   // if the source is direct we will just use the keycode as the action
   if (source == "direct")
@@ -64,9 +64,7 @@ QString InputMapping::mapToAction(const QString& source, const QString& keycode)
   {
     QVariant action = m_inputMatcher.value(sourceName.toString())->match(keycode);
     if (action.isValid())
-    {
-      return action.toString();
-    }
+      return action;
   }
   return QString();
 }

+ 1 - 1
src/input/InputMapping.h

@@ -16,7 +16,7 @@ class InputMapping : public QObject
 public:
   explicit InputMapping(QObject *parent = 0);
   bool loadMappings();
-  QString mapToAction(const QString& source, const QString& keycode);
+  QVariant mapToAction(const QString& source, const QString& keycode);
 
 private Q_SLOTS:
   void dirChange();