aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Kennedy2008-08-13 14:33:17 +0000
committerStephen Kennedy2008-08-13 14:33:17 +0000
commit17c1dba992b5c76787ed6b52e8f7753ce3bbaef7 (patch)
tree826707007aabba7ed59fce13a218ccf8757d5c3e
parent532faef82b20802502d54fabb7364c25eb7ac875 (diff)
downloadscummvm-rg350-17c1dba992b5c76787ed6b52e8f7753ce3bbaef7.tar.gz
scummvm-rg350-17c1dba992b5c76787ed6b52e8f7753ce3bbaef7.tar.bz2
scummvm-rg350-17c1dba992b5c76787ed6b52e8f7753ce3bbaef7.zip
Keymapper WIP:
* Further improvement of automatic mapping * Remap dialog - added timeout feature svn-id: r33827
-rw-r--r--backends/keymapper/action.cpp2
-rw-r--r--backends/keymapper/keymap-manager.cpp90
-rw-r--r--backends/keymapper/remap-dialog.cpp19
-rw-r--r--backends/keymapper/remap-dialog.h4
-rw-r--r--gui/theme-config.cpp6
5 files changed, 91 insertions, 30 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;
};
diff --git a/gui/theme-config.cpp b/gui/theme-config.cpp
index 70be7ba9d0..48a93ca285 100644
--- a/gui/theme-config.cpp
+++ b/gui/theme-config.cpp
@@ -374,11 +374,11 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_extinfo.visible=true\n"
"\n"
"# Keymapper remap dialog\n"
-"remap=8 8 (w - 16) (h / 5)\n"
+"remap=(w / 4) (h / 4) (w / 2) (h / 2)\n"
"remap_spacing=10\n"
-"remap_popup=remap_spacing remap_spacing (parent.w - remap_spacing * 2) (kLineHeight + 2)\n"
+"remap_popup=remap_spacing remap_spacing (prev.w - remap_spacing * 2) (kLineHeight + 2)\n"
"remap_popup_labelW=buttonWidth\n"
-"remap_col_count=3\n"
+"remap_col_count=2\n"
"remap_keymap_area=remap_spacing (remap_popup.y + remap_popup.h + remap_spacing) (remap.w - remap_spacing * 2) (remap.h - self.y - remap_spacing)\n"
"############################################\n"
"[chooser]\n"