diff options
Diffstat (limited to 'backends/keymapper')
-rw-r--r-- | backends/keymapper/action.cpp | 2 | ||||
-rw-r--r-- | backends/keymapper/keymap-manager.cpp | 90 | ||||
-rw-r--r-- | backends/keymapper/remap-dialog.cpp | 19 | ||||
-rw-r--r-- | backends/keymapper/remap-dialog.h | 4 |
4 files changed, 88 insertions, 27 deletions
diff --git a/backends/keymapper/action.cpp b/backends/keymapper/action.cpp index eefd482de7..413ebdecee 100644 --- a/backends/keymapper/action.cpp +++ b/backends/keymapper/action.cpp @@ -50,7 +50,7 @@ void Action::mapKey(const HardwareKey *key) { assert(_parent); if (_hwKey) _parent->unregisterMapping(this); _hwKey = key; - if (_hwKey) _parent->registerMapping(this, key); + if (_hwKey) _parent->registerMapping(this, _hwKey); } const HardwareKey *Action::getMappedKey() const { diff --git a/backends/keymapper/keymap-manager.cpp b/backends/keymapper/keymap-manager.cpp index 93d7431ba7..f80b8770fe 100644 --- a/backends/keymapper/keymap-manager.cpp +++ b/backends/keymapper/keymap-manager.cpp @@ -92,64 +92,107 @@ void KeymapManager::initKeymap(ConfigManager::Domain *domain, automaticMap(map); } +// TODO: +// - current weaknesses: +// - if an action finds a key with required type / category but a parent +// action with higher priority is using it, that key is never used void KeymapManager::automaticMap(Keymap *map) { - List<Action*> actions(map->getActions()), unmapped; + // Create local copies of action and key lists. + List<Action*> actions(map->getActions()); + List<const HardwareKey*> keys(_hardwareKeys->getHardwareKeys()); + List<Action*>::iterator actIt; - List<const HardwareKey*> keys = _hardwareKeys->getHardwareKeys(); List<const HardwareKey*>::iterator keyIt, selectedKey; + + // Remove actions and keys from local lists that have already been mapped. + actIt = actions.begin(); + while (actIt != actions.end()) { + Action *act = *actIt; + const HardwareKey *key = act->getMappedKey(); + if (key) { + keys.remove(key); + actIt = actions.erase(actIt); + } else { + ++actIt; + } + } - // sort by priority + // Sort remaining actions by priority. ActionPriorityComp priorityComp; sort(actions.begin(), actions.end(), priorityComp); - for (actIt = actions.begin(); actIt != actions.end(); actIt++) { + // First mapping pass: + // - Match if a key's preferred type or category is same as the action's. + // - Priority is given to: + // - keys that match type over category. + // - keys that have not been used by parent maps. + // - If a key has been used by a parent map the new action must have a + // higher priority than the parent action. + // - As soon as the number of skipped actions equals the number of keys + // remaining we stop matching. This means that the second pass will assign keys + // to these higher priority skipped actions. + uint skipped = 0; + actIt = actions.begin(); + while (actIt != actions.end() && skipped < keys.size()) { selectedKey = keys.end(); - int keyScore = 0; + int matchRank = 0; Action *act = *actIt; - for (keyIt = keys.begin(); keyIt != keys.end(); keyIt++) { + for (keyIt = keys.begin(); keyIt != keys.end(); ++keyIt) { if ((*keyIt)->preferredType == act->type) { Action *parentAct = getParentMappedAction(map, (*keyIt)->key); if (!parentAct) { selectedKey = keyIt; break; - } else if (parentAct->priority <= act->priority && keyScore < 3) { + } else if (parentAct->priority <= act->priority && matchRank < 3) { selectedKey = keyIt; - keyScore = 3; + matchRank = 3; } - } else if ((*keyIt)->preferredCategory == act->category && keyScore < 2) { + } else if ((*keyIt)->preferredCategory == act->category && matchRank < 2) { Action *parentAct = getParentMappedAction(map, (*keyIt)->key); if (!parentAct) { selectedKey = keyIt; - keyScore = 2; - } else if (parentAct->priority <= act->priority && keyScore < 1) { + matchRank = 2; + } else if (parentAct->priority <= act->priority && matchRank < 1) { selectedKey = keyIt; - keyScore = 1; + matchRank = 1; } } } if (selectedKey != keys.end()) { + // Map action and delete action & key from local lists. act->mapKey(*selectedKey); keys.erase(selectedKey); - } else - unmapped.push_back(act); + actIt = actions.erase(actIt); + } else { + // Skip action (will be mapped in next pass). + ++actIt; + ++skipped; + } } - for (actIt = unmapped.begin(); actIt != unmapped.end(); actIt++) { + // Second mapping pass: + // - Maps any remaining actions to keys + // - priority given to: + // - keys that have no parent action + // - keys whose parent action has lower priority than the new action + // - keys whose parent action has the lowest priority + // - is guarantees to match a key if one is available + for (actIt = actions.begin(); actIt != actions.end(); ++actIt) { selectedKey = keys.end(); - int keyScore = 0; - int lowestPriority = 0; //dummy value + int matchRank = 0; + int lowestPriority = 0; Action *act = *actIt; - for (keyIt = keys.begin(); keyIt != keys.end(); keyIt++) { + for (keyIt = keys.begin(); keyIt != keys.end(); ++keyIt) { Action *parentAct = getParentMappedAction(map, (*keyIt)->key); if (!parentAct) { selectedKey = keyIt; break; - } else if (keyScore < 2) { + } else if (matchRank < 2) { if (parentAct->priority <= act->priority) { - keyScore = 2; + matchRank = 2; selectedKey = keyIt; - } else if (parentAct->priority < lowestPriority || keyScore == 0) { - keyScore = 1; + } else if (parentAct->priority < lowestPriority || matchRank == 0) { + matchRank = 1; lowestPriority = parentAct->priority; selectedKey = keyIt; } @@ -158,8 +201,9 @@ void KeymapManager::automaticMap(Keymap *map) { if (selectedKey != keys.end()) { act->mapKey(*selectedKey); keys.erase(selectedKey); - } else // no keys left + } else {// no match = no keys left return; + } } } diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp index 22d52575ca..456d7a2f8e 100644 --- a/backends/keymapper/remap-dialog.cpp +++ b/backends/keymapper/remap-dialog.cpp @@ -35,7 +35,7 @@ enum { }; RemapDialog::RemapDialog() - : Dialog("remap"), _activeRemapAction(0), _topAction(0) { + : Dialog("remap"), _activeRemapAction(0), _topAction(0), _remapTimeout(0) { const int screenW = g_system->getOverlayWidth(); const int screenH = g_system->getOverlayHeight(); @@ -112,15 +112,16 @@ void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 d } void RemapDialog::startRemapping(uint i) { - + _remapTimeout = getMillis() + kRemapTimeoutDelay; _activeRemapAction = _currentActions[_topAction + i].action; _keymapWidgets[i].keyButton->setLabel("..."); _keymapWidgets[i].keyButton->draw(); - _keymapper->setEnabled(false); + } void RemapDialog::stopRemapping() { + _topAction = -1; refreshKeymap(); _activeRemapAction = 0; _keymapper->setEnabled(true); @@ -136,7 +137,19 @@ void RemapDialog::handleKeyUp(Common::KeyState state) { } else { GUI::Dialog::handleKeyDown(state); } +} + +void RemapDialog::handleMouseDown(int x, int y, int button, int clickCount) { + if (_activeRemapAction) + stopRemapping(); + else + Dialog::handleMouseDown(x, y, button, clickCount); +} +void RemapDialog::handleTickle() { + if (_activeRemapAction && getMillis() > _remapTimeout) + stopRemapping(); + Dialog::handleTickle(); } void RemapDialog::loadKeymap() { diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h index 839455e74e..a9680a0f7a 100644 --- a/backends/keymapper/remap-dialog.h +++ b/backends/keymapper/remap-dialog.h @@ -42,6 +42,8 @@ public: virtual void open(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); virtual void handleKeyUp(Common::KeyState state); + virtual void handleMouseDown(int x, int y, int button, int clickCount); + virtual void handleTickle(); protected: struct ActionWidgets { @@ -77,6 +79,8 @@ protected: Array<ActionWidgets> _keymapWidgets; Action *_activeRemapAction; + uint32 _remapTimeout; + static const uint32 kRemapTimeoutDelay = 3000; }; |