refs #453 Refactor CInputManger and low level input handlers

This commit is contained in:
Roland Winklmeier
2015-08-14 20:21:27 +02:00
committed by Mathew Sutcliffe
parent 63c7c6be0d
commit 199a1e5fcb
31 changed files with 609 additions and 1086 deletions

View File

@@ -28,11 +28,6 @@ namespace BlackCore
// this->m_dBusInterface = new CGenericDBusInterface(serviceName, IContextApplication::ObjectPath(), IContextApplication::InterfaceName(), connection, this);
this->relaySignals(serviceName, connection);
// Enable event forwarding from GUI process to core
CInputManager *inputManager = CInputManager::getInstance();
connect(inputManager, &CInputManager::hotkeyFuncEvent, this, &CContextApplicationProxy::processHotkeyFuncEvent);
inputManager->setEventForwarding(true);
connect(this, &IContextApplication::messageLogged, this, [](const CStatusMessage & message, const CIdentifier & origin)
{
if (!origin.isFromSameProcess())

View File

@@ -26,7 +26,7 @@
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Audio;
using namespace BlackMisc::Hardware;
using namespace BlackMisc::Input;
using namespace BlackSound;
namespace BlackCore
@@ -42,10 +42,6 @@ namespace BlackCore
// own aircraft may or may not be available
const CCallsign ownCallsign = (this->getIContextOwnAircraft()) ? getIContextOwnAircraft()->getOwnAircraft().getCallsign() : CCallsign();
// Register PTT hotkey function
m_inputManager = CInputManager::getInstance();
m_handlePtt = m_inputManager->registerHotkeyFunc(CHotkeyFunction::Ptt(), this, &CContextAudio::ps_setVoiceTransmission);
m_channel1 = m_voice->createVoiceChannel();
m_channel1->setOwnAircraftCallsign(ownCallsign);
connect(m_channel1.data(), &IVoiceChannel::connectionStatusChanged, this, &CContextAudio::ps_connectionStatusChanged);

View File

@@ -21,7 +21,6 @@
#include "voice_channel.h"
#include "audio_device.h"
#include "audio_mixer.h"
#include "input_manager.h"
#include "blackinput/keyboard.h"
#include "blackmisc/audio/voiceroomlist.h"
@@ -154,8 +153,6 @@ namespace BlackCore
QSharedPointer<IVoiceChannel> getVoiceChannelBy(const BlackMisc::Audio::CVoiceRoom &voiceRoom);
CInputManager *m_inputManager = nullptr;
CInputManager::RegistrationHandle m_handlePtt;
std::unique_ptr<IVoice> m_voice; //!< underlying voice lib
std::unique_ptr<IAudioMixer> m_audioMixer;

View File

@@ -4,107 +4,152 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "input_manager.h"
#include "blackmisc/input/keyboardkeylist.h"
using namespace BlackInput;
using namespace BlackMisc;
using namespace BlackMisc::Hardware;
using namespace BlackMisc::Input;
namespace BlackCore
{
CInputManager *CInputManager::m_instance = nullptr;
CInputManager::CInputManager(QObject *parent) :
QObject(parent),
m_keyboard(IKeyboard::getInstance()),
m_joystick(IJoystick::getInstance())
m_keyboard(std::move(IKeyboard::create(this))),
m_joystick(std::move(IJoystick::create(this)))
{
connect(m_keyboard, &IKeyboard::keyUp, this, &CInputManager::ps_processKeyboardKeyUp);
connect(m_keyboard, &IKeyboard::keyDown, this, &CInputManager::ps_processKeyboardKeyDown);
connect(m_joystick, &IJoystick::buttonUp, this, &CInputManager::ps_processJoystickButtonUp);
connect(m_joystick, &IJoystick::buttonDown, this, &CInputManager::ps_processJoystickButtonDown);
connect(m_keyboard.get(), &IKeyboard::keyCombinationChanged, this, &CInputManager::ps_processKeyCombinationChanged);
connect(m_joystick.get(), &IJoystick::buttonCombinationChanged, this, &CInputManager::ps_processButtonCombinationChanged);
}
CInputManager *CInputManager::getInstance()
CInputManager *CInputManager::instance()
{
if (!m_instance)
static CInputManager instance;
return &instance;
}
void CInputManager::registerAction(const QString &action)
{
if (!m_availableActions.contains(action))
{
m_instance = new CInputManager();
m_availableActions.push_back(action);
emit hotkeyActionRegistered( { action } );
}
return m_instance;
}
void CInputManager::changeHotkeySettings(Settings::CSettingKeyboardHotkeyList hotkeys)
void CInputManager::registerRemoteActions(const QStringList &actions)
{
CKeyboardKeyList keyList;
for (Settings::CSettingKeyboardHotkey settingHotkey : hotkeys)
for (const auto &action : actions)
{
CKeyboardKey key = settingHotkey.getKey();
if (key.isEmpty()) continue;
m_hashKeyboardKeyFunctions.insert(key, settingHotkey.getFunction());
keyList.push_back(key);
if (!m_availableActions.contains(action))
{
m_availableActions.push_back(action);
emit hotkeyActionRegistered( { action } );
}
}
m_keyboard->setKeysToMonitor(keyList);
}
void CInputManager::ps_processKeyboardKeyDown(const CKeyboardKey &key)
void CInputManager::unbind(int index)
{
if (!m_hashKeyboardKeyFunctions.contains(key)) return;
// Get configured hotkey function
CHotkeyFunction hotkeyFunc = m_hashKeyboardKeyFunctions.value(key);
callFunctionsBy(hotkeyFunc, true);
auto info = std::find_if (m_boundActions.begin(), m_boundActions.end(), [index] (const BindInfo &info) { return info.m_index == index; });
if (info != m_boundActions.end())
{
m_boundActions.erase(info);
}
}
void CInputManager::ps_processKeyboardKeyUp(const CKeyboardKey &key)
void CInputManager::ps_changeHotkeySettings()
{
if (!m_hashKeyboardKeyFunctions.contains(key)) return;
m_configuredActions.clear();
for (CActionHotkey actionHotkey : m_actionHotkeys.get())
{
CHotkeyCombination combination = actionHotkey.getCombination();
if (combination.isEmpty()) continue;
// Get configured hotkey function
CHotkeyFunction hotkeyFunc = m_hashKeyboardKeyFunctions.value(key);
callFunctionsBy(hotkeyFunc, false);
m_configuredActions.insert(combination, actionHotkey.getAction());
}
}
void CInputManager::ps_processJoystickButtonDown(const CJoystickButton &button)
void CInputManager::ps_processKeyCombinationChanged(const CHotkeyCombination &combination)
{
qDebug() << "Pressed Button" << button.getButtonIndex();
if (!m_hashJoystickKeyFunctions.contains(button)) return;
// Get configured hotkey function
CHotkeyFunction hotkeyFunc = m_hashJoystickKeyFunctions.value(button);
callFunctionsBy(hotkeyFunc, true);
// Merge in the joystick part
CHotkeyCombination copy(combination);
copy.setJoystickButtons(m_lastCombination.getJoystickButtons());
processCombination(copy);
}
void CInputManager::ps_processJoystickButtonUp(const CJoystickButton &button)
void CInputManager::ps_processButtonCombinationChanged(const CHotkeyCombination &combination)
{
qDebug() << "Released Button" << button.getButtonIndex();
if (!m_hashJoystickKeyFunctions.contains(button)) return;
// Get configured hotkey function
CHotkeyFunction hotkeyFunc = m_hashJoystickKeyFunctions.value(button);
callFunctionsBy(hotkeyFunc, false);
// Merge in the keyboard keys
CHotkeyCombination copy(combination);
copy.setKeyboardKeys(m_lastCombination.getKeyboardKeys());
processCombination(copy);
}
void CInputManager::callFunctionsBy(const CHotkeyFunction &hotkeyFunction, bool isKeyDown)
void CInputManager::startCapture()
{
BlackMisc::Event::CEventHotkeyFunction hotkeyEvent(hotkeyFunction, isKeyDown);
if(m_eventForwardingEnabled) emit hotkeyFuncEvent(hotkeyEvent);
if (!m_hashRegisteredFunctions.contains(hotkeyFunction)) return;
auto func = m_hashRegisteredFunctions.value(hotkeyFunction);
func(isKeyDown);
m_captureActive = true;
m_capturedCombination = {};
}
CInputManager::RegistrationHandle CInputManager::registerHotkeyFuncImpl(const BlackMisc::CHotkeyFunction &hotkeyFunction,
QObject *receiver,
std::function<void (bool)> function)
void CInputManager::callFunctionsBy(const QString &action, bool isKeyDown)
{
m_hashRegisteredFunctions.insert(hotkeyFunction, function);
if (action.isEmpty()) { return; }
if(m_actionRelayingEnabled) emit remoteActionFromLocal(action, isKeyDown);
RegistrationHandle handle;
handle.function = function;
handle.hotkeyFunction = hotkeyFunction;
handle.m_receiver = receiver;
return handle;
for (const auto &boundAction : m_boundActions)
{
if (boundAction.m_action == action)
{
boundAction.m_function(isKeyDown);
}
}
}
void CInputManager::triggerKey(const CHotkeyCombination &combination, bool isPressed)
{
Q_UNUSED(isPressed)
QString previousAction = m_configuredActions.value(m_lastCombination);
QString action = m_configuredActions.value(combination);
callFunctionsBy(previousAction, false);
callFunctionsBy(action, true);
m_lastCombination = combination;
}
int CInputManager::bindImpl(const QString &action, QObject *receiver, std::function<void (bool)> function)
{
static int index = 0;
Q_ASSERT(index < INT_MAX);
BindInfo info;
info.m_index = index;
++index;
info.m_function = function;
info.m_action = action;
info.m_receiver = receiver;
m_boundActions.push_back(info);
return info.m_index;
}
void CInputManager::processCombination(const CHotkeyCombination &combination)
{
if (m_captureActive)
{
if (combination.size() < m_capturedCombination.size())
{
emit combinationSelectionFinished(m_capturedCombination);
m_captureActive = false;
}
else
{
emit combinationSelectionChanged(combination);
m_capturedCombination = combination;
}
}
QString previousAction = m_configuredActions.value(m_lastCombination);
QString action = m_configuredActions.value(combination);
m_lastCombination = combination;
callFunctionsBy(previousAction, false);
callFunctionsBy(action, true);
}
}

View File

@@ -7,15 +7,13 @@
#define BLACKCORE_INPUTMANAGER_H
#include "blackcoreexport.h"
#include "blackcore/settings/application.h"
#include "blackinput/keyboard.h"
#include "blackinput/joystick.h"
#include "blackmisc/hardware/keyboardkeylist.h"
#include "blackmisc/hardware/joystickbutton.h"
#include "blackmisc/hotkeyfunction.h"
#include "blackmisc/setkeyboardhotkeylist.h"
#include "blackmisc/eveventhotkeyfunction.h"
#include "blackmisc/input/hotkeycombination.h"
#include <QObject>
#include <QHash>
#include <QVector>
#include <type_traits>
#include <functional>
@@ -29,62 +27,67 @@ namespace BlackCore
Q_OBJECT
public:
//! Register new action
void registerAction(const QString &action);
//! \brief Handle to a registered hotkey function
struct RegistrationHandle
{
//! \brief Constructor
RegistrationHandle() {}
BlackMisc::CHotkeyFunction hotkeyFunction; //!< Registered hotkey function
QPointer<QObject> m_receiver; //!< Registered receiver
std::function<void(bool)> function; //!< Registered function
};
//! Register remote actions
void registerRemoteActions(const QStringList &actions);
//! Register a new hotkey function
RegistrationHandle registerHotkeyFunc(const BlackMisc::CHotkeyFunction &hotkeyFunction, QObject *receiver, const QByteArray &slotName)
{
auto function = [=](bool isKeyDown){ QMetaObject::invokeMethod(receiver, slotName, Q_ARG(bool, isKeyDown)); };
return registerHotkeyFuncImpl(hotkeyFunction, receiver, function);
}
//! Register a new hotkey function
template <class RecvObj>
RegistrationHandle registerHotkeyFunc(const BlackMisc::CHotkeyFunction &hotkeyFunction, RecvObj *receiver, void (RecvObj:: *slotPointer)(bool))
template <typename RecvObj>
int bind(const QString &action, RecvObj *receiver, void (RecvObj:: *slotPointer)(bool))
{
using namespace std::placeholders;
auto function = std::bind(slotPointer, receiver, _1);
return registerHotkeyFuncImpl(hotkeyFunction, receiver, function);
return bindImpl(action, receiver, function);
}
//! Register a new hotkey function
template <class Func>
RegistrationHandle registerHotkeyFunc(const BlackMisc::CHotkeyFunction &hotkeyFunction, QObject *receiver, Func functionObject)
template <typename Func>
int bind(const QString &action, QObject *receiver, Func functionObject)
{
return registerHotkeyFuncImpl(hotkeyFunction, receiver, functionObject);
return bindImpl(action, receiver, functionObject);
}
//! Unbind a slot
void unbind(int index);
//!
//! Select a key combination as hotkey. This method returns immediatly.
//! Listen for signals combinationSelectionChanged and combinationSelectionFinished
//! to retrieve the user input.
void startCapture();
//! Deletes all registered hotkeys. Be careful with this method!
void resetAllHotkeyFuncs() { m_hashRegisteredFunctions.clear(); }
void resetAllActions() { m_configuredActions.clear(); }
//! Get all available and known actions
QStringList allAvailableActions() const { return m_availableActions; }
//! Enable event forwarding to core
void setEventForwarding(bool enabled) { m_eventForwardingEnabled = enabled; }
//! Creates a native keyboard handler object
static CInputManager *getInstance();
public slots:
//! Change hotkey settings
void changeHotkeySettings(BlackMisc::Settings::CSettingKeyboardHotkeyList hotkeys);
void setForwarding(bool enabled) { m_actionRelayingEnabled = enabled; }
//! Call functions by hotkeyfunction
void callFunctionsBy(const BlackMisc::CHotkeyFunction &hotkeyFunction, bool isKeyDown);
void callFunctionsBy(const QString &action, bool isKeyDown);
//! Triggers a key event manually and calls the registered functions.
void triggerKey(const BlackMisc::Input::CHotkeyCombination &combination, bool isPressed);
//! Creates a native keyboard handler object
static CInputManager *instance();
signals:
//! Event hotkeyfunction occured
void hotkeyFuncEvent(const BlackMisc::Event::CEventHotkeyFunction &event);
void remoteActionFromLocal(const QString &action, bool argument);
//! Selected combination has changed
void combinationSelectionChanged(const BlackMisc::Input::CHotkeyCombination &combination);
//! Combination selection has finished
void combinationSelectionFinished(const BlackMisc::Input::CHotkeyCombination &combination);
//! New hotkey action is registered
void hotkeyActionRegistered(const QStringList &actions);
protected:
//! Constructor
@@ -92,28 +95,43 @@ namespace BlackCore
private slots:
void ps_processKeyboardKeyDown(const BlackMisc::Hardware::CKeyboardKey &);
void ps_processKeyCombinationChanged(const BlackMisc::Input::CHotkeyCombination &combination);
void ps_processKeyboardKeyUp(const BlackMisc::Hardware::CKeyboardKey &);
void ps_processButtonCombinationChanged(const BlackMisc::Input::CHotkeyCombination &combination);
void ps_processJoystickButtonDown(const BlackMisc::Hardware::CJoystickButton &button);
void ps_processJoystickButtonUp(const BlackMisc::Hardware::CJoystickButton &button);
//! Change hotkey settings
void ps_changeHotkeySettings();
private:
//! Handle to a bound action
struct BindInfo
{
// Using unique int intex for identification because std::function does not have a operator==
int m_index = 0;
QString m_action;
QPointer<QObject> m_receiver;
std::function<void(bool)> m_function;
};
RegistrationHandle registerHotkeyFuncImpl(const BlackMisc::CHotkeyFunction &hotkeyFunction, QObject *receiver, std::function<void(bool)> function);
int bindImpl(const QString &action, QObject *receiver, std::function<void(bool)> function);
void processCombination(const BlackMisc::Input::CHotkeyCombination &combination);
static CInputManager *m_instance;
BlackInput::IKeyboard *m_keyboard = nullptr;
BlackInput::IJoystick *m_joystick = nullptr;
std::unique_ptr<BlackInput::IKeyboard> m_keyboard;
std::unique_ptr<BlackInput::IJoystick> m_joystick;
QHash<BlackMisc::CHotkeyFunction, std::function<void(bool)> > m_hashRegisteredFunctions;
QHash<BlackMisc::Hardware::CKeyboardKey, BlackMisc::CHotkeyFunction> m_hashKeyboardKeyFunctions;
QHash<BlackMisc::Hardware::CJoystickButton, BlackMisc::CHotkeyFunction> m_hashJoystickKeyFunctions;
QStringList m_availableActions;
QHash<BlackMisc::Input::CHotkeyCombination, QString> m_configuredActions;
QVector<BindInfo> m_boundActions;
bool m_eventForwardingEnabled = false;
bool m_actionRelayingEnabled = false;
bool m_captureActive = false;
BlackMisc::Input::CHotkeyCombination m_lastCombination;
BlackMisc::Input::CHotkeyCombination m_capturedCombination;
BlackCore::CSetting<BlackCore::Settings::Application::ActionHotkeys> m_actionHotkeys { this, &CInputManager::ps_changeHotkeySettings };
};
}

View File

@@ -0,0 +1,46 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKCORE_SETTINGS_APPLICATION_H
#define BLACKCORE_SETTINGS_APPLICATION_H
#include "blackcore/settingscache.h"
#include "blackmisc/input/actionhotkeylist.h"
namespace BlackCore
{
namespace Settings
{
namespace Application
{
//! User configured hotkeys
struct ActionHotkeys : public CSettingTrait<BlackMisc::Input::CActionHotkeyList>
{
//! \copydoc BlackCore::CSetting::key
static const char *key() { return "application/actionhotkeys"; }
//! \copydoc BlackCore::CSetting::isValid
static bool isValid(const BlackMisc::Input::CActionHotkeyList &value)
{
for (const auto &actionHotkey : value)
{
if (actionHotkey.getApplicableMachine().getMachineName().isEmpty() ||
actionHotkey.getAction().isEmpty() ||
actionHotkey.getCombination().isEmpty()) { return false; }
}
return true;
}
};
}
}
}
#endif