KEYMAPPER: Multiple inputs can map to the same action
This commit is contained in:
parent
d5e2b5d8f2
commit
ade0efa762
4 changed files with 84 additions and 41 deletions
|
@ -25,6 +25,7 @@
|
||||||
#ifdef ENABLE_KEYMAPPER
|
#ifdef ENABLE_KEYMAPPER
|
||||||
|
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
#include "common/tokenizer.h"
|
||||||
|
|
||||||
#include "backends/keymapper/action.h"
|
#include "backends/keymapper/action.h"
|
||||||
#include "backends/keymapper/hardware-input.h"
|
#include "backends/keymapper/hardware-input.h"
|
||||||
|
@ -54,27 +55,43 @@ void Keymap::addAction(Action *action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keymap::registerMapping(Action *action, const HardwareInput *hwInput) {
|
void Keymap::registerMapping(Action *action, const HardwareInput *hwInput) {
|
||||||
unregisterMapping(action);
|
ActionArray &actionArray = _hwActionMap.getVal(hwInput);
|
||||||
|
|
||||||
_hwActionMap[hwInput] = action;
|
// Don't allow an input to map to the same action multiple times
|
||||||
|
ActionArray::const_iterator found = find(actionArray.begin(), actionArray.end(), action);
|
||||||
|
if (found == actionArray.end()) {
|
||||||
|
actionArray.push_back(action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keymap::unregisterMapping(Action *action) {
|
void Keymap::unregisterMapping(Action *action) {
|
||||||
for (HardwareActionMap::iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
|
// Remove the action from all the input mappings
|
||||||
if (it->_value == action) {
|
for (HardwareActionMap::iterator itInput = _hwActionMap.begin(); itInput != _hwActionMap.end(); itInput++) {
|
||||||
_hwActionMap.erase(it);
|
for (ActionArray::iterator itAction = itInput->_value.begin(); itAction != itInput->_value.end(); itAction++) {
|
||||||
|
if (*itAction == action) {
|
||||||
|
itInput->_value.erase(itAction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (itInput->_value.empty()) {
|
||||||
|
_hwActionMap.erase(itInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const HardwareInput *Keymap::getActionMapping(Action *action) const {
|
Array<const HardwareInput *> Keymap::getActionMapping(Action *action) const {
|
||||||
for (HardwareActionMap::const_iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
|
Array<const HardwareInput *> inputs;
|
||||||
if (it->_value == action) {
|
|
||||||
return it->_key;
|
for (HardwareActionMap::iterator itInput = _hwActionMap.begin(); itInput != _hwActionMap.end(); itInput++) {
|
||||||
|
for (ActionArray::iterator itAction = itInput->_value.begin(); itAction != itInput->_value.end(); itAction++) {
|
||||||
|
if (*itAction == action) {
|
||||||
|
inputs.push_back(itInput->_key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Action *Keymap::findAction(const char *id) const {
|
const Action *Keymap::findAction(const char *id) const {
|
||||||
|
@ -86,7 +103,7 @@ const Action *Keymap::findAction(const char *id) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Action *Keymap::getMappedAction(const HardwareInput *hardwareInput) const {
|
const Keymap::ActionArray &Keymap::getMappedActions(const HardwareInput *hardwareInput) const {
|
||||||
return _hwActionMap[hardwareInput];
|
return _hwActionMap[hardwareInput];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,25 +112,25 @@ void Keymap::setConfigDomain(ConfigManager::Domain *dom) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
|
void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
|
||||||
if (!_configDomain)
|
assert(_configDomain);
|
||||||
return;
|
|
||||||
|
|
||||||
if (_actions.empty())
|
if (_actions.empty()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String prefix = KEYMAP_KEY_PREFIX + _name + "_";
|
String prefix = KEYMAP_KEY_PREFIX + _name + "_";
|
||||||
|
|
||||||
|
_hwActionMap.clear();
|
||||||
for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
|
for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
|
||||||
Action* ua = *it;
|
Action* ua = *it;
|
||||||
String actionId(ua->id);
|
String actionId(ua->id);
|
||||||
String confKey = prefix + actionId;
|
String confKey = prefix + actionId;
|
||||||
|
|
||||||
String hwInputId = _configDomain->getVal(confKey);
|
// The configuration value is a list of space separated hardware input ids
|
||||||
|
StringTokenizer hwInputIds = _configDomain->getVal(confKey);
|
||||||
// there's no mapping
|
|
||||||
if (hwInputId.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
String hwInputId;
|
||||||
|
while ((hwInputId = hwInputIds.nextToken()) != "") {
|
||||||
const HardwareInput *hwInput = hwKeys->findHardwareInput(hwInputId.c_str());
|
const HardwareInput *hwInput = hwKeys->findHardwareInput(hwInputId.c_str());
|
||||||
|
|
||||||
if (!hwInput) {
|
if (!hwInput) {
|
||||||
|
@ -122,7 +139,8 @@ void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// map the key
|
// map the key
|
||||||
_hwActionMap[hwInput] = ua;
|
registerMapping(ua, hwInput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +150,21 @@ void Keymap::saveMappings() {
|
||||||
|
|
||||||
String prefix = KEYMAP_KEY_PREFIX + _name + "_";
|
String prefix = KEYMAP_KEY_PREFIX + _name + "_";
|
||||||
|
|
||||||
for (HardwareActionMap::const_iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
|
for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); it++) {
|
||||||
const Action *action = it->_value;
|
Action *action = *it;
|
||||||
const HardwareInput *input = it->_key;
|
Array<const HardwareInput *> mappedInputs = getActionMapping(action);
|
||||||
|
|
||||||
_configDomain->setVal(prefix + action->id, input->id);
|
// The configuration value is a list of space separated hardware input ids
|
||||||
|
String confValue;
|
||||||
|
for (uint j = 0; j < mappedInputs.size(); j++) {
|
||||||
|
if (!confValue.empty()) {
|
||||||
|
confValue += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
confValue += mappedInputs[j]->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
_configDomain->setVal(prefix + action->id, confValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,14 +70,14 @@ public:
|
||||||
/**
|
/**
|
||||||
* Find the hardware input an action is mapped to, if any
|
* Find the hardware input an action is mapped to, if any
|
||||||
*/
|
*/
|
||||||
const HardwareInput *getActionMapping(Action *action) const;
|
Array<const HardwareInput *> getActionMapping(Action *action) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the Action that a hardware input is mapped to
|
* Find the Actions that a hardware input is mapped to
|
||||||
* @param hardwareInput the input that is mapped to the required Action
|
* @param hardwareInput the input that is mapped to the required Action
|
||||||
* @return a pointer to the Action or 0 if no
|
* @return an array containing pointers to the actions
|
||||||
*/
|
*/
|
||||||
Action *getMappedAction(const HardwareInput *hardwareInput) const;
|
const ActionArray &getMappedActions(const HardwareInput *hardwareInput) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of all the Actions contained in this Keymap
|
* Get the list of all the Actions contained in this Keymap
|
||||||
|
@ -120,7 +120,7 @@ private:
|
||||||
|
|
||||||
const Action *findAction(const char *id) const;
|
const Action *findAction(const char *id) const;
|
||||||
|
|
||||||
typedef HashMap<const HardwareInput *, Action *> HardwareActionMap;
|
typedef HashMap<const HardwareInput *, ActionArray> HardwareActionMap;
|
||||||
|
|
||||||
KeymapType _type;
|
KeymapType _type;
|
||||||
String _name;
|
String _name;
|
||||||
|
|
|
@ -135,6 +135,8 @@ List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
|
||||||
return DefaultEventMapper::mapEvent(ev, source);
|
return DefaultEventMapper::mapEvent(ev, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IncomingEventType incomingEventType = convertToIncomingEventType(ev);
|
||||||
|
|
||||||
List<Event> mappedEvents;
|
List<Event> mappedEvents;
|
||||||
for (int i = _keymaps.size() - 1; i >= 0; --i) {
|
for (int i = _keymaps.size() - 1; i >= 0; --i) {
|
||||||
if (!_keymaps[i]->isEnabled()) {
|
if (!_keymaps[i]->isEnabled()) {
|
||||||
|
@ -148,10 +150,13 @@ List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
|
||||||
|
|
||||||
debug(5, "Keymapper::mapKey keymap: %s", _keymaps[i]->getName().c_str());
|
debug(5, "Keymapper::mapKey keymap: %s", _keymaps[i]->getName().c_str());
|
||||||
|
|
||||||
Action *action = _keymaps[i]->getMappedAction(hwInput);
|
const Keymap::ActionArray &actions = _keymaps[i]->getMappedActions(hwInput);
|
||||||
if (action) {
|
for (Keymap::ActionArray::const_iterator it = actions.begin(); it != actions.end(); it++) {
|
||||||
IncomingEventType incomingEventType = convertToIncomingEventType(ev);
|
mappedEvents.push_back(executeAction(*it, incomingEventType));
|
||||||
mappedEvents.push_back(executeAction(action, incomingEventType));
|
}
|
||||||
|
if (!actions.empty()) {
|
||||||
|
// If we found actions matching this input in a keymap, no need to look at the other keymaps.
|
||||||
|
// An input resulting in actions from system and game keymaps would lead to unexpected user experience.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,9 +241,19 @@ void RemapDialog::refreshKeymap() {
|
||||||
|
|
||||||
Keymap *keymap = row.action->getParent();
|
Keymap *keymap = row.action->getParent();
|
||||||
|
|
||||||
const HardwareInput *mappedInput = keymap->getActionMapping(row.action);
|
Array<const HardwareInput *> mappedInputs = keymap->getActionMapping(row.action);
|
||||||
if (mappedInput)
|
|
||||||
row.keyButton->setLabel(mappedInput->description);
|
String keysLabel;
|
||||||
|
for (uint j = 0; j < mappedInputs.size(); j++) {
|
||||||
|
if (!keysLabel.empty()) {
|
||||||
|
keysLabel += ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
keysLabel += mappedInputs[j]->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keysLabel.empty())
|
||||||
|
row.keyButton->setLabel(keysLabel);
|
||||||
else
|
else
|
||||||
row.keyButton->setLabel("-");
|
row.keyButton->setLabel("-");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue