aboutsummaryrefslogtreecommitdiff
path: root/backends/keymapper
diff options
context:
space:
mode:
Diffstat (limited to 'backends/keymapper')
-rw-r--r--backends/keymapper/action.cpp53
-rw-r--r--backends/keymapper/action.h116
-rw-r--r--backends/keymapper/hardware-key.h128
-rw-r--r--backends/keymapper/keymap.cpp299
-rw-r--r--backends/keymapper/keymap.h148
-rw-r--r--backends/keymapper/keymapper.cpp219
-rw-r--r--backends/keymapper/keymapper.h204
-rw-r--r--backends/keymapper/remap-dialog.cpp329
-rw-r--r--backends/keymapper/remap-dialog.h92
-rw-r--r--backends/keymapper/types.h71
10 files changed, 1659 insertions, 0 deletions
diff --git a/backends/keymapper/action.cpp b/backends/keymapper/action.cpp
new file mode 100644
index 0000000000..8b2490861e
--- /dev/null
+++ b/backends/keymapper/action.cpp
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/keymap.h"
+
+namespace Common {
+
+Action::Action(Keymap *boss, const char *i, String des, ActionType typ,
+ KeyType prefKey, int pri, int flg)
+ : _boss(boss), description(des), type(typ), preferredKey(prefKey),
+ priority(pri), flags(flg), _hwKey(0) {
+ assert(i);
+ assert(_boss);
+
+ strncpy(id, i, ACTION_ID_SIZE);
+
+ _boss->addAction(this);
+}
+
+void Action::mapKey(const HardwareKey *key) {
+ if (_hwKey) _boss->unregisterMapping(this);
+ _hwKey = key;
+ if (_hwKey) _boss->registerMapping(this, _hwKey);
+}
+
+const HardwareKey *Action::getMappedKey() const {
+ return _hwKey;
+}
+
+} // end of namespace Common
diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
new file mode 100644
index 0000000000..ef47930a71
--- /dev/null
+++ b/backends/keymapper/action.h
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef COMMON_ACTION
+#define COMMON_ACTION
+
+#include "backends/keymapper/types.h"
+#include "common/events.h"
+#include "common/func.h"
+#include "common/list.h"
+#include "common/str.h"
+
+namespace Common {
+
+struct HardwareKey;
+class Keymap;
+
+#define ACTION_ID_SIZE (4)
+
+struct Action {
+ /** unique id used for saving/loading to config */
+ char id[ACTION_ID_SIZE];
+ /** Human readable description */
+ String description;
+
+ /** Events to be sent when mapped key is pressed */
+ List<Event> events;
+ ActionType type;
+ KeyType preferredKey;
+ int priority;
+ int group;
+ int flags;
+
+private:
+ /** Hardware key that is mapped to this Action */
+ const HardwareKey *_hwKey;
+ Keymap *_boss;
+
+public:
+ Action(Keymap *boss, const char *id, String des = "",
+ ActionType typ = kGenericActionType,
+ KeyType prefKey = kGenericKeyType,
+ int pri = 0, int flg = 0 );
+
+ void addEvent(const Event &evt) {
+ events.push_back(evt);
+ }
+
+ void addKeyEvent(const KeyState &ks) {
+ Event evt;
+ evt.type = EVENT_KEYDOWN;
+ evt.kbd = ks;
+ addEvent(evt);
+ }
+
+ void addLeftClickEvent() {
+ Event evt;
+ evt.type = EVENT_LBUTTONDOWN;
+ addEvent(evt);
+ }
+
+ void addMiddleClickEvent() {
+ Event evt;
+ evt.type = EVENT_MBUTTONDOWN;
+ addEvent(evt);
+ }
+
+ void addRightClickEvent() {
+ Event evt;
+ evt.type = EVENT_RBUTTONDOWN;
+ addEvent(evt);
+ }
+
+ Keymap *getBoss() {
+ return _boss;
+ }
+
+ void mapKey(const HardwareKey *key);
+ const HardwareKey *getMappedKey() const;
+
+};
+
+struct ActionPriorityComp : public BinaryFunction<Action, Action, bool> {
+ bool operator()(const Action *x, const Action *y) const {
+ return x->priority > y->priority;
+ }
+ bool operator()(const Action &x, const Action &y) const {
+ return x.priority > y.priority;
+ }
+};
+
+} // end of namespace Common
+
+#endif
diff --git a/backends/keymapper/hardware-key.h b/backends/keymapper/hardware-key.h
new file mode 100644
index 0000000000..082ecfc944
--- /dev/null
+++ b/backends/keymapper/hardware-key.h
@@ -0,0 +1,128 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef COMMON_HARDWAREKEY
+#define COMMON_HARDWAREKEY
+
+#include "backends/keymapper/types.h"
+
+namespace Common {
+
+
+#define HWKEY_ID_SIZE (4)
+/**
+* Describes an available hardware key
+*/
+struct HardwareKey {
+ /** unique id used for saving/loading to config */
+ char id[HWKEY_ID_SIZE];
+ /** Human readable description */
+ String description;
+ /**
+ * The KeyState that is generated by the back-end
+ * when this hardware key is pressed.
+ */
+ KeyState key;
+
+ KeyType type;
+ ActionType preferredAction;
+
+ HardwareKey(const char *i, KeyState ky = KeyState(), String desc = "",
+ KeyType typ = kGenericKeyType, ActionType prefAct = kGenericActionType)
+ : key(ky), description(desc), type(typ), preferredAction(prefAct) {
+ assert(i);
+ strncpy(id, i, HWKEY_ID_SIZE);
+ }
+};
+
+
+/**
+ * Simple class to encapsulate a device's set of HardwareKeys.
+ * Each device should extend this and call addHardwareKey a number of times
+ * in its constructor to define the device's available keys.
+ */
+class HardwareKeySet {
+public:
+
+ HardwareKeySet() : _count(0) {}
+ virtual ~HardwareKeySet() {
+ List<const HardwareKey*>::iterator it;
+ for (it = _keys.begin(); it != _keys.end(); it++)
+ delete *it;
+ }
+
+ void addHardwareKey(HardwareKey *key) {
+ checkForKey(key);
+ _keys.push_back(key);
+ ++_count;
+ }
+
+ const HardwareKey *findHardwareKey(const char *id) const {
+ List<const HardwareKey*>::iterator it;
+ for (it = _keys.begin(); it != _keys.end(); it++) {
+ if (strncmp((*it)->id, id, HWKEY_ID_SIZE) == 0)
+ return (*it);
+ }
+ return 0;
+ }
+
+ const HardwareKey *findHardwareKey(const KeyState& keystate) const {
+ List<const HardwareKey*>::iterator it;
+ for (it = _keys.begin(); it != _keys.end(); it++) {
+ if ((*it)->key == keystate)
+ return (*it);
+ }
+ return 0;
+ }
+
+ List<const HardwareKey*> getHardwareKeys() const {
+ return _keys;
+ }
+
+ uint count() const {
+ return _count;
+ }
+
+
+private:
+
+ void checkForKey(HardwareKey *key) {
+ List<const HardwareKey*>::iterator it;
+ for (it = _keys.begin(); it != _keys.end(); it++) {
+ if (strncmp((*it)->id, key->id, HWKEY_ID_SIZE) == 0)
+ error("Error adding HardwareKey '%s' - id of %s already in use!", key->description.c_str(), key->id);
+ else if ((*it)->key == key->key)
+ error("Error adding HardwareKey '%s' - key already in use!", key->description.c_str());
+ }
+ }
+
+ List<const HardwareKey*> _keys;
+ uint _count;
+};
+
+
+} // end of namespace Common
+
+#endif
diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
new file mode 100644
index 0000000000..ee07e36485
--- /dev/null
+++ b/backends/keymapper/keymap.cpp
@@ -0,0 +1,299 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "backends/keymapper/keymap.h"
+#include "backends/keymapper/hardware-key.h"
+
+#define KEYMAP_KEY_PREFIX "keymap_"
+
+namespace Common {
+
+Keymap::Keymap(const Keymap& km) : _actions(km._actions), _keymap(), _configDomain(0) {
+ List<Action*>::iterator it;
+ for (it = _actions.begin(); it != _actions.end(); it++) {
+ const HardwareKey *hwKey = (*it)->getMappedKey();
+ if (hwKey) {
+ _keymap[hwKey->key] = *it;
+ }
+ }
+}
+
+Keymap::~Keymap() {
+ List<Action*>::iterator it;
+ for (it = _actions.begin(); it != _actions.end(); it++)
+ delete *it;
+}
+
+void Keymap::addAction(Action *action) {
+ if (findAction(action->id))
+ error("Action with id %s already in KeyMap!", action->id);
+ _actions.push_back(action);
+}
+
+void Keymap::registerMapping(Action *action, const HardwareKey *hwKey) {
+ HashMap<KeyState, Action*>::iterator it;
+ it = _keymap.find(hwKey->key);
+ // if key is already mapped to a different action then un-map it
+ if (it != _keymap.end() && action != it->_value) {
+ it->_value->mapKey(0);
+ }
+
+ _keymap[hwKey->key] = action;
+}
+
+void Keymap::unregisterMapping(Action *action) {
+ const HardwareKey *hwKey = action->getMappedKey();
+ if (hwKey) {
+ _keymap.erase(hwKey->key);
+ }
+}
+
+Action *Keymap::getAction(const char *id) {
+ return findAction(id);
+}
+
+Action *Keymap::findAction(const char *id) {
+ List<Action*>::iterator it;
+ for (it = _actions.begin(); it != _actions.end(); it++) {
+ if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0)
+ return *it;
+ }
+ return 0;
+}
+
+const Action *Keymap::findAction(const char *id) const {
+ List<Action*>::const_iterator it;
+ for (it = _actions.begin(); it != _actions.end(); it++) {
+ if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0)
+ return *it;
+ }
+ return 0;
+}
+
+Action *Keymap::getMappedAction(const KeyState& ks) const {
+ HashMap<KeyState, Action*>::iterator it;
+ it = _keymap.find(ks);
+ if (it == _keymap.end())
+ return 0;
+ else
+ return it->_value;
+}
+
+void Keymap::setConfigDomain(ConfigManager::Domain *dom) {
+ _configDomain = dom;
+}
+
+void Keymap::loadMappings(const HardwareKeySet *hwKeys) {
+ if (!_configDomain) return;
+ ConfigManager::Domain::iterator it;
+ String prefix = KEYMAP_KEY_PREFIX + _name + "_";
+ for (it = _configDomain->begin(); it != _configDomain->end(); it++) {
+ const String& key = it->_key;
+ if (!key.hasPrefix(prefix.c_str()))
+ continue;
+
+ // parse Action ID
+ const char *actionId = key.c_str() + prefix.size();
+ Action *ua = getAction(actionId);
+ if (!ua) {
+ warning("'%s' keymap does not contain Action with ID %s",
+ _name.c_str(), actionId);
+ _configDomain->erase(key);
+ continue;
+ }
+
+ const HardwareKey *hwKey = hwKeys->findHardwareKey(it->_value.c_str());
+ if (!hwKey) {
+ warning("HardwareKey with ID %s not known", it->_value.c_str());
+ _configDomain->erase(key);
+ continue;
+ }
+
+ ua->mapKey(hwKey);
+ }
+}
+
+void Keymap::saveMappings() {
+ if (!_configDomain) return;
+ List<Action*>::const_iterator it;
+ String prefix = KEYMAP_KEY_PREFIX + _name + "_";
+ for (it = _actions.begin(); it != _actions.end(); it++) {
+ uint actIdLen = strlen((*it)->id);
+ actIdLen = (actIdLen > ACTION_ID_SIZE) ? ACTION_ID_SIZE : actIdLen;
+ String actId((*it)->id, (*it)->id + actIdLen);
+ if ((*it)->getMappedKey()) {
+ uint hwIdLen = strlen((*it)->getMappedKey()->id);
+ hwIdLen = (hwIdLen > HWKEY_ID_SIZE) ? HWKEY_ID_SIZE : hwIdLen;
+ String hwId((*it)->getMappedKey()->id, (*it)->getMappedKey()->id + hwIdLen);
+ _configDomain->setVal(prefix + actId, hwId);
+ } else {
+ _configDomain->setVal(prefix + actId, "");
+ }
+ }
+}
+
+bool Keymap::isComplete(const HardwareKeySet *hwKeys) {
+ List<Action*>::iterator it;
+ bool allMapped = true;
+ uint numberMapped = 0;
+ for (it = _actions.begin(); it != _actions.end(); it++) {
+ if ((*it)->getMappedKey()) {
+ numberMapped++;
+ } else {
+ allMapped = false;
+ }
+ }
+ return allMapped || (numberMapped == hwKeys->count());
+}
+
+// TODO:
+// - current weakness:
+// - if an action finds a key with required type but a parent action with
+// higher priority is using it, that key is never used
+void Keymap::automaticMapping(HardwareKeySet *hwKeys) {
+ // Create copies of action and key lists.
+ List<Action*> actions(_actions);
+ List<const HardwareKey*> keys(hwKeys->getHardwareKeys());
+
+ List<Action*>::iterator actIt;
+ 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 remaining actions by priority.
+ ActionPriorityComp priorityComp;
+ sort(actions.begin(), actions.end(), priorityComp);
+
+ // First mapping pass:
+ // - Match if a key's preferred action type is the same as the action's
+ // type, or vice versa.
+ // - Priority is given to:
+ // - keys that match action types over key types.
+ // - 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 matchRank = 0;
+ Action *act = *actIt;
+ for (keyIt = keys.begin(); keyIt != keys.end(); ++keyIt) {
+ if ((*keyIt)->preferredAction == act->type && act->type != kGenericActionType) {
+ Action *parentAct = getParentMappedAction((*keyIt)->key);
+ if (!parentAct) {
+ selectedKey = keyIt;
+ break;
+ } else if (parentAct->priority <= act->priority && matchRank < 3) {
+ selectedKey = keyIt;
+ matchRank = 3;
+ }
+ } else if ((*keyIt)->type == act->preferredKey && act->preferredKey != kGenericKeyType && matchRank < 2) {
+ Action *parentAct = getParentMappedAction((*keyIt)->key);
+ if (!parentAct) {
+ selectedKey = keyIt;
+ matchRank = 2;
+ } else if (parentAct->priority <= act->priority && matchRank < 1) {
+ selectedKey = keyIt;
+ matchRank = 1;
+ }
+ }
+ }
+ if (selectedKey != keys.end()) {
+ // Map action and delete action & key from local lists.
+ act->mapKey(*selectedKey);
+ keys.erase(selectedKey);
+ actIt = actions.erase(actIt);
+ } else {
+ // Skip action (will be mapped in next pass).
+ ++actIt;
+ ++skipped;
+ }
+ }
+
+ // 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 guaranteed to match a key if they are not all used up
+ for (actIt = actions.begin(); actIt != actions.end(); ++actIt) {
+ selectedKey = keys.end();
+ int matchRank = 0;
+ int lowestPriority = 0;
+ Action *act = *actIt;
+ for (keyIt = keys.begin(); keyIt != keys.end(); ++keyIt) {
+ Action *parentAct = getParentMappedAction((*keyIt)->key);
+ if (!parentAct) {
+ selectedKey = keyIt;
+ break;
+ } else if (matchRank < 2) {
+ if (parentAct->priority <= act->priority) {
+ matchRank = 2;
+ selectedKey = keyIt;
+ } else if (parentAct->priority < lowestPriority || matchRank == 0) {
+ matchRank = 1;
+ lowestPriority = parentAct->priority;
+ selectedKey = keyIt;
+ }
+ }
+ }
+ if (selectedKey != keys.end()) {
+ act->mapKey(*selectedKey);
+ keys.erase(selectedKey);
+ } else {// no match = no keys left
+ break;
+ }
+ }
+}
+
+Action *Keymap::getParentMappedAction(KeyState key) {
+ if (_parent) {
+ Action *act = _parent->getMappedAction(key);
+ if (act)
+ return act;
+ else
+ return _parent->getParentMappedAction(key);
+ } else {
+ return 0;
+ }
+}
+
+} // end of namespace Common
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
new file mode 100644
index 0000000000..438660fd4b
--- /dev/null
+++ b/backends/keymapper/keymap.h
@@ -0,0 +1,148 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef COMMON_KEYMAP
+#define COMMON_KEYMAP
+
+#include "common/config-manager.h"
+#include "common/func.h"
+#include "common/hashmap.h"
+#include "common/keyboard.h"
+#include "common/list.h"
+#include "backends/keymapper/action.h"
+
+namespace Common {
+
+struct HardwareKey;
+class HardwareKeySet;
+
+/**
+ * Hash function for KeyState
+ */
+template<> struct Hash<KeyState>
+ : public UnaryFunction<KeyState, uint> {
+
+ uint operator()(const KeyState &val) const {
+ return (uint)(val.keycode * (val.flags << 1));
+ }
+};
+
+class Keymap {
+public:
+ Keymap(const String& name, Keymap *parent = 0) : _name(name), _parent(parent) {}
+ Keymap(const Keymap& km);
+ ~Keymap();
+
+public:
+ /**
+ * Retrieves the Action with the given id
+ * @param id id of Action to retrieve
+ * @return Pointer to the Action or 0 if not found
+ */
+ Action *getAction(const char *id);
+
+ /**
+ * Get the list of all the Actions contained in this Keymap
+ */
+ List<Action*>& getActions() { return _actions; }
+
+ /**
+ * Find the Action that a key is mapped to
+ * @param key the key that is mapped to the required Action
+ * @return a pointer to the Action or 0 if no
+ */
+ Action *getMappedAction(const KeyState& ks) const;
+
+ void setConfigDomain(ConfigManager::Domain *dom);
+
+ /**
+ * Load this keymap's mappings from the config manager.
+ * @param hwKeys the set to retrieve hardware key pointers from
+ */
+ void loadMappings(const HardwareKeySet *hwKeys);
+
+ /**
+ * Save this keymap's mappings to the config manager
+ * @note Changes are *not* flushed to disk, to do so call ConfMan.flushToDisk()
+ * @note Changes are *not* flushed to disk, to do so call ConfMan.flushToDisk()
+ */
+ void saveMappings();
+
+
+ void automaticMapping(HardwareKeySet *hwKeys);
+
+ /**
+ * Returns true if all UserAction's in Keymap are mapped, or,
+ * all HardwareKey's from the given set have been used up.
+ */
+ bool isComplete(const HardwareKeySet *hwKeys);
+
+ const String& getName() { return _name; }
+ Keymap *getParent() { return _parent; }
+
+private:
+ friend struct Action;
+
+ /**
+ * Adds a new Action to this Map,
+ * adding it at the back of the internal array
+ * @param action the Action to add
+ */
+ void addAction(Action *action);
+
+ /**
+ * Registers a HardwareKey to the given Action
+ * @param action Action in this Keymap
+ * @param key pointer to HardwareKey to map
+ * @see Action::mapKey
+ */
+ void registerMapping(Action *action, const HardwareKey *key);
+
+ /**
+ * Unregisters a HardwareKey from the given Action (if one is mapped)
+ * @param action Action in this Keymap
+ * @see Action::mapKey
+ */
+ void unregisterMapping(Action *action);
+
+ Action *findAction(const char *id);
+ const Action *findAction(const char *id) const;
+
+ void internalMapKey(Action *action, HardwareKey *hwKey);
+
+ Action *getParentMappedAction(KeyState key);
+
+ String _name;
+ Keymap *_parent;
+ List<Action*> _actions;
+ HashMap<KeyState, Action*> _keymap;
+ ConfigManager::Domain *_configDomain;
+
+};
+
+
+} // end of namespace Common
+
+#endif
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
new file mode 100644
index 0000000000..5c79d445cb
--- /dev/null
+++ b/backends/keymapper/keymapper.cpp
@@ -0,0 +1,219 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "backends/keymapper/keymapper.h"
+#include "common/config-manager.h"
+namespace Common {
+
+void Keymapper::Domain::addKeymap(Keymap *map) {
+ KeymapMap::iterator it = _keymaps.find(map->getName());
+ if (it != _keymaps.end())
+ delete _keymaps[map->getName()];
+ _keymaps[map->getName()] = map;
+}
+
+void Keymapper::Domain::deleteAllKeyMaps() {
+ KeymapMap::iterator it;
+ for (it = _keymaps.begin(); it != _keymaps.end(); it++)
+ delete it->_value;
+ _keymaps.clear();
+}
+
+Keymap *Keymapper::Domain::getKeymap(const String& name) {
+ KeymapMap::iterator it = _keymaps.find(name);
+ if (it != _keymaps.end())
+ return it->_value;
+ else
+ return 0;
+}
+
+Keymapper::Keymapper(EventManager *evtMgr)
+ : _eventMan(evtMgr), _enabled(true), _hardwareKeys(0) {
+ _globalDomain.setConfigDomain(ConfMan.getDomain(ConfigManager::kApplicationDomain));
+}
+
+Keymapper::~Keymapper() {
+ delete _hardwareKeys;
+}
+
+void Keymapper::registerHardwareKeySet(HardwareKeySet *keys) {
+ if (_hardwareKeys)
+ error("Hardware key set already registered!");
+ _hardwareKeys = keys;
+}
+
+void Keymapper::addGlobalKeymap(Keymap *keymap) {
+ initKeymap(_globalDomain.getConfigDomain(), keymap);
+ _globalDomain.addKeymap(keymap);
+}
+
+void Keymapper::refreshGameDomain() {
+ if (_gameDomain.getConfigDomain() != ConfMan.getActiveDomain()) {
+ cleanupGameKeymaps();
+ _gameDomain.setConfigDomain(ConfMan.getActiveDomain());
+ }
+}
+
+void Keymapper::addGameKeymap(Keymap *keymap) {
+ if (ConfMan.getActiveDomain() == 0)
+ error("Call to Keymapper::addGameKeymap when no game loaded");
+
+ refreshGameDomain();
+ initKeymap(_gameDomain.getConfigDomain(), keymap);
+ _gameDomain.addKeymap(keymap);
+}
+
+void Keymapper::initKeymap(ConfigManager::Domain *domain, Keymap *map) {
+ map->setConfigDomain(domain);
+ map->loadMappings(_hardwareKeys);
+ if (map->isComplete(_hardwareKeys) == false) {
+ map->automaticMapping(_hardwareKeys);
+ map->saveMappings();
+ ConfMan.flushToDisk();
+ }
+}
+
+void Keymapper::cleanupGameKeymaps() {
+ _gameDomain.deleteAllKeyMaps();
+ Stack<MapRecord> newStack;
+ for (int i = 0; i < _activeMaps.size(); i++) {
+ if (!_activeMaps[i].global)
+ newStack.push(_activeMaps[i]);
+ }
+ _activeMaps = newStack;
+}
+
+Keymap *Keymapper::getKeymap(const String& name, bool &global) {
+ Keymap *keymap = _gameDomain.getKeymap(name);
+ global = false;
+ if (!keymap) {
+ keymap = _globalDomain.getKeymap(name);
+ global = true;
+ }
+ return keymap;
+}
+
+bool Keymapper::pushKeymap(const String& name, bool inherit) {
+ bool global;
+ Keymap *newMap = getKeymap(name, global);
+ if (!newMap) {
+ warning("Keymap '%s' not registered", name.c_str());
+ return false;
+ }
+ pushKeymap(newMap, inherit, global);
+ return true;
+}
+
+void Keymapper::pushKeymap(Keymap *newMap, bool inherit, bool global) {
+ MapRecord mr = {newMap, inherit, global};
+ _activeMaps.push(mr);
+}
+
+void Keymapper::popKeymap() {
+ if (!_activeMaps.empty())
+ _activeMaps.pop();
+}
+
+bool Keymapper::mapKeyDown(const KeyState& key) {
+ return mapKey(key, true);
+}
+
+bool Keymapper::mapKeyUp(const KeyState& key) {
+ return mapKey(key, false);
+}
+
+bool Keymapper::mapKey(const KeyState& key, bool keyDown) {
+ if (!_enabled) return false;
+ if (_activeMaps.empty()) return false;
+
+ Action *action = 0;
+ if (keyDown) {
+ // Search for key in active keymap stack
+ for (int i = _activeMaps.size() - 1; i >= 0; --i) {
+ MapRecord mr = _activeMaps[i];
+ action = mr.keymap->getMappedAction(key);
+ if (action || mr.inherit == false) break;
+ }
+ if (action) _keysDown[key] = action;
+ } else {
+ HashMap<KeyState, Action*>::iterator it = _keysDown.find(key);
+ if (it != _keysDown.end()) {
+ action = it->_value;
+ _keysDown.erase(key);
+ }
+ }
+ if (!action) return false;
+ executeAction(action, keyDown);
+ return true;
+}
+
+Action *Keymapper::getAction(const KeyState& key) {
+ Action *action = 0;
+ return action;
+}
+
+void Keymapper::executeAction(const Action *action, bool keyDown) {
+ List<Event>::iterator it;
+ for (it = action->events.begin(); it != action->events.end(); ++it) {
+ Event evt = *it;
+ switch (evt.type) {
+ case EVENT_KEYDOWN:
+ if (!keyDown) evt.type = EVENT_KEYUP;
+ break;
+ case EVENT_KEYUP:
+ if (keyDown) evt.type = EVENT_KEYDOWN;
+ break;
+ case EVENT_LBUTTONDOWN:
+ if (!keyDown) evt.type = EVENT_LBUTTONUP;
+ break;
+ case EVENT_LBUTTONUP:
+ if (keyDown) evt.type = EVENT_LBUTTONDOWN;
+ break;
+ case EVENT_RBUTTONDOWN:
+ if (!keyDown) evt.type = EVENT_RBUTTONUP;
+ break;
+ case EVENT_RBUTTONUP:
+ if (keyDown) evt.type = EVENT_RBUTTONDOWN;
+ break;
+ case EVENT_MBUTTONDOWN:
+ if (!keyDown) evt.type = EVENT_MBUTTONUP;
+ break;
+ case EVENT_MBUTTONUP:
+ if (keyDown) evt.type = EVENT_MBUTTONDOWN;
+ break;
+ default:
+ // don't deliver other events on key up
+ if (!keyDown) continue;
+ }
+ evt.mouse = _eventMan->getMousePos();
+ _eventMan->pushEvent(evt);
+ }
+}
+
+const HardwareKey *Keymapper::getHardwareKey(const KeyState& key) {
+ return (_hardwareKeys) ? _hardwareKeys->findHardwareKey(key) : 0;
+}
+
+} // end of namespace Common
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
new file mode 100644
index 0000000000..a13cebe39a
--- /dev/null
+++ b/backends/keymapper/keymapper.h
@@ -0,0 +1,204 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef COMMON_KEYMAPPER
+#define COMMON_KEYMAPPER
+
+#include "common/events.h"
+#include "common/list.h"
+#include "common/hashmap.h"
+#include "common/stack.h"
+#include "backends/keymapper/hardware-key.h"
+#include "backends/keymapper/keymap.h"
+
+namespace Common {
+
+class Keymapper {
+public:
+
+ struct MapRecord {
+ Keymap* keymap;
+ bool inherit;
+ bool global;
+ };
+
+ /* Nested class that represents a set of keymaps */
+ class Domain {
+ typedef HashMap<String, Keymap*,
+ IgnoreCase_Hash, IgnoreCase_EqualTo> KeymapMap;
+
+ public:
+ Domain() : _configDomain(0) {}
+ ~Domain() {
+ deleteAllKeyMaps();
+ }
+
+ void setConfigDomain(ConfigManager::Domain *confDom) {
+ _configDomain = confDom;
+ }
+ ConfigManager::Domain *getConfigDomain() {
+ return _configDomain;
+ }
+
+ void addKeymap(Keymap *map);
+
+ void deleteAllKeyMaps();
+
+ Keymap *getKeymap(const String& name);
+
+ typedef KeymapMap::iterator iterator;
+ typedef KeymapMap::const_iterator const_iterator;
+ iterator begin() { return _keymaps.begin(); }
+ const_iterator begin() const { return _keymaps.begin(); }
+ iterator end() { return _keymaps.end(); }
+ const_iterator end() const { return _keymaps.end(); }
+ uint32 count() { return _keymaps.size(); }
+ private:
+ ConfigManager::Domain *_configDomain;
+ KeymapMap _keymaps;
+ };
+
+ Keymapper(EventManager *eventMan);
+ ~Keymapper();
+
+ /**
+ * Registers a HardwareKeySet with the Keymapper
+ * @note should only be called once (during backend initialisation)
+ */
+ void registerHardwareKeySet(HardwareKeySet *keys);
+
+ /**
+ * Get the HardwareKeySet that is registered with the Keymapper
+ */
+ HardwareKeySet *getHardwareKeySet() { return _hardwareKeys; }
+
+ /**
+ * Add a keymap to the global domain.
+ * If a saved key setup exists for it in the ini file it will be used.
+ * Else, the key setup will be automatically mapped.
+ */
+ void addGlobalKeymap(Keymap *keymap);
+
+ /**
+ * Add a keymap to the game domain.
+ * @see addGlobalKeyMap
+ * @note initGame() should be called before any game keymaps are added.
+ */
+ void addGameKeymap(Keymap *keymap);
+
+ /**
+ * Should be called at end of game to tell Keymapper to deactivate and free
+ * any game keymaps that are loaded.
+ */
+ void cleanupGameKeymaps();
+
+ /**
+ * Obtain a keymap of the given name from the keymapper.
+ * Game keymaps have priority over global keymaps
+ * @param name name of the keymap to return
+ * @param global set to true if returned keymap is global, false if game
+ */
+ Keymap *getKeymap(const String& name, bool &global);
+
+ /**
+ * Push a new keymap to the top of the active stack, activating
+ * it for use.
+ * @param name name of the keymap to push
+ * @param inherit if true keymapper will iterate down the
+ * stack it cannot find a key in the new map
+ * @return true if succesful
+ */
+ bool pushKeymap(const String& name, bool inherit = false);
+
+ /**
+ * Pop the top keymap off the active stack.
+ */
+ void popKeymap();
+
+ /**
+ * @brief Map a key press event.
+ * If the active keymap contains a Action mapped to the given key, then
+ * the Action's events are pushed into the EventManager's event queue.
+ * @param key key that was pressed
+ * @param keyDown true for key down, false for key up
+ * @return true if key was mapped
+ */
+ bool mapKey(const KeyState& key, bool keyDown);
+
+ /**
+ * @brief Map a key down event.
+ * @see mapKey
+ */
+ bool mapKeyDown(const KeyState& key);
+
+ /**
+ * @brief Map a key up event.
+ * @see mapKey
+ */
+ bool mapKeyUp(const KeyState& key);
+
+ /**
+ * Enable/disable the keymapper
+ */
+ void setEnabled(bool enabled) { _enabled = enabled; }
+
+ /**
+ * Return a HardwareKey pointer for the given key state
+ */
+ const HardwareKey *getHardwareKey(const KeyState& key);
+
+ Domain& getGlobalDomain() { return _globalDomain; }
+ Domain& getGameDomain() { return _gameDomain; }
+ Stack<MapRecord>& getActiveStack() { return _activeMaps; }
+
+private:
+
+ void initKeymap(ConfigManager::Domain *domain, Keymap *keymap);
+ void refreshGameDomain();
+
+ Domain _globalDomain;
+ Domain _gameDomain;
+
+ HardwareKeySet *_hardwareKeys;
+
+ void pushKeymap(Keymap *newMap, bool inherit, bool global);
+
+ Action *getAction(const KeyState& key);
+ void executeAction(const Action *act, bool keyDown);
+
+ typedef List<HardwareKey*>::iterator Iterator;
+
+ EventManager *_eventMan;
+
+ bool _enabled;
+
+ Stack<MapRecord> _activeMaps;
+ HashMap<KeyState, Action*> _keysDown;
+
+};
+
+} // end of namespace Common
+
+#endif
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
new file mode 100644
index 0000000000..1998fa813e
--- /dev/null
+++ b/backends/keymapper/remap-dialog.cpp
@@ -0,0 +1,329 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "backends/keymapper/remap-dialog.h"
+#include "gui/eval.h"
+#include "gui/newgui.h"
+#include "gui/PopUpWidget.h"
+#include "gui/ScrollBarWidget.h"
+
+namespace Common {
+
+enum {
+ kRemapCmd = 'REMP',
+ kCloseCmd = 'CLOS'
+};
+
+RemapDialog::RemapDialog()
+ : Dialog("remap"), _keymapTable(0), _activeRemapAction(0), _topAction(0), _remapTimeout(0) {
+
+ _keymapper = g_system->getEventManager()->getKeymapper();
+ assert(_keymapper);
+
+ int labelWidth = g_gui.evaluator()->getVar("remap_popup_labelW");
+ _kmPopUp = new GUI::PopUpWidget(this, "remap_popup", "Keymap: ", labelWidth);
+
+ _scrollBar = new GUI::ScrollBarWidget(this, 0, 0, 0, 0);
+
+ new GUI::ButtonWidget(this, "remap_close_button", "Close", kCloseCmd);
+}
+
+RemapDialog::~RemapDialog() {
+ if (_keymapTable) free(_keymapTable);
+}
+
+void RemapDialog::open() {
+ bool divider = false;
+ _activeKeymaps = &_keymapper->getActiveStack();
+ if (_activeKeymaps->size() > 0) {
+ _kmPopUp->appendEntry(_activeKeymaps->top().keymap->getName() + " (Active)");
+ divider = true;
+ }
+
+ Keymapper::Domain *_globalKeymaps = &_keymapper->getGlobalDomain();
+ Keymapper::Domain *_gameKeymaps = 0;
+
+ int keymapCount = 0;
+ if (_globalKeymaps->count() == 0)
+ _globalKeymaps = 0;
+ else
+ keymapCount += _globalKeymaps->count();
+
+ if (ConfMan.getActiveDomain() != 0) {
+ _gameKeymaps = &_keymapper->getGameDomain();
+ if (_gameKeymaps->count() == 0)
+ _gameKeymaps = 0;
+ else
+ keymapCount += _gameKeymaps->count();
+ }
+
+ _keymapTable = (Keymap**)malloc(sizeof(Keymap*) * keymapCount);
+
+ Keymapper::Domain::iterator it;
+ uint32 idx = 0;
+ if (_globalKeymaps) {
+ if (divider) _kmPopUp->appendEntry("");
+ for (it = _globalKeymaps->begin(); it != _globalKeymaps->end(); it++) {
+ _kmPopUp->appendEntry(it->_value->getName() + " (Global)", idx);
+ _keymapTable[idx++] = it->_value;
+ }
+ divider = true;
+ }
+ if (_gameKeymaps) {
+ if (divider) _kmPopUp->appendEntry("");
+ for (it = _gameKeymaps->begin(); it != _gameKeymaps->end(); it++) {
+ _kmPopUp->appendEntry(it->_value->getName() + " (Game)", idx);
+ _keymapTable[idx++] = it->_value;
+ }
+ }
+
+ _changes = false;
+
+ Dialog::open();
+
+ _kmPopUp->setSelected(0);
+ loadKeymap();
+}
+
+void RemapDialog::close() {
+ _kmPopUp->clearEntries();
+ if (_keymapTable) {
+ free(_keymapTable);
+ _keymapTable = 0;
+ }
+ if (_changes)
+ ConfMan.flushToDisk();
+ Dialog::close();
+}
+
+void RemapDialog::reflowLayout() {
+ int scrollbarWidth, buttonHeight;
+ if (g_gui.getWidgetSize() == GUI::kBigWidgetSize) {
+ buttonHeight = GUI::kBigButtonHeight;
+ scrollbarWidth = GUI::kBigScrollBarWidth;
+ } else {
+ buttonHeight = GUI::kButtonHeight;
+ scrollbarWidth = GUI::kNormalScrollBarWidth;
+ }
+ int areaX = g_gui.evaluator()->getVar("remap_keymap_area.x");
+ int areaY = g_gui.evaluator()->getVar("remap_keymap_area.y");
+ int areaW = g_gui.evaluator()->getVar("remap_keymap_area.w");
+ int areaH = g_gui.evaluator()->getVar("remap_keymap_area.h");
+ int spacing = g_gui.evaluator()->getVar("remap_spacing");
+ int labelWidth = g_gui.evaluator()->getVar("remap_label_width");
+ int buttonWidth = g_gui.evaluator()->getVar("remap_button_width");
+ int colWidth = labelWidth + buttonWidth + spacing;
+ _colCount = (areaW - scrollbarWidth) / colWidth;
+ _rowCount = (areaH + spacing) / (buttonHeight + spacing);
+ if (_colCount <= 0 || _rowCount <= 0)
+ error("Remap dialog too small to display any keymaps!");
+
+ _kmPopUp->changeLabelWidth(labelWidth);
+
+ _scrollBar->resize(areaX + areaW - scrollbarWidth, areaY, scrollbarWidth, areaH);
+ _scrollBar->_entriesPerPage = _rowCount;
+ _scrollBar->_numEntries = 1;
+ _scrollBar->recalc();
+
+ uint textYOff = (buttonHeight - kLineHeight) / 2;
+ uint oldSize = _keymapWidgets.size();
+ uint newSize = _rowCount * _colCount;
+ _keymapWidgets.reserve(newSize);
+ for (uint i = 0; i < newSize; i++) {
+ ActionWidgets widg;
+ if (i >= _keymapWidgets.size()) {
+ widg.actionText =
+ new GUI::StaticTextWidget(this, 0, 0, 0, 0, "", Graphics::kTextAlignRight);
+ widg.keyButton =
+ new GUI::ButtonWidget(this, 0, 0, 0, 0, "", kRemapCmd + i);
+ _keymapWidgets.push_back(widg);
+ } else {
+ widg = _keymapWidgets[i];
+ }
+ uint x = areaX + (i % _colCount) * colWidth;
+ uint y = areaY + (i / _colCount) * (buttonHeight + spacing);
+ widg.actionText->resize(x, y + textYOff, labelWidth, kLineHeight);
+ widg.keyButton->resize(x + labelWidth, y, buttonWidth, buttonHeight);
+ }
+ while (oldSize > newSize) {
+ ActionWidgets widg = _keymapWidgets.remove_at(--oldSize);
+ removeWidget(widg.actionText);
+ delete widg.actionText;
+ removeWidget(widg.keyButton);
+ delete widg.keyButton;
+ }
+ Dialog::reflowLayout();
+}
+
+void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+ if (cmd >= kRemapCmd && cmd < kRemapCmd + _keymapWidgets.size()) {
+ startRemapping(cmd - kRemapCmd);
+ } else if (cmd == GUI::kPopUpItemSelectedCmd) {
+ loadKeymap();
+ } else if (cmd == GUI::kSetPositionCmd) {
+ refreshKeymap();
+ } else if (cmd == kCloseCmd) {
+ close();
+ } else {
+ GUI::Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void RemapDialog::startRemapping(uint i) {
+ if (_topAction + i >= _currentActions.size()) return;
+ _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);
+}
+
+void RemapDialog::handleKeyUp(Common::KeyState state) {
+ if (_activeRemapAction) {
+ const HardwareKey *hwkey = _keymapper->getHardwareKey(state);
+ if (hwkey) {
+ _activeRemapAction->mapKey(hwkey);
+ // TODO: _activeRemapAction->getParent()->saveMappings();
+ _changes = true;
+ stopRemapping();
+ }
+ } 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() {
+ _currentActions.clear();
+ if (_activeKeymaps->size() > 0 && _kmPopUp->getSelected() == 0) {
+ // load active keymaps
+
+ List<const HardwareKey*> freeKeys (_keymapper->getHardwareKeySet()->getHardwareKeys());
+
+ // add most active keymap's keys
+ Keymapper::MapRecord top = _activeKeymaps->top();
+ List<Action*>::iterator actIt;
+ for (actIt = top.keymap->getActions().begin(); actIt != top.keymap->getActions().end(); ++actIt) {
+ Action *act = *actIt;
+ ActionInfo info = {act, false, act->description};
+ _currentActions.push_back(info);
+ if (act->getMappedKey())
+ freeKeys.remove(act->getMappedKey());
+ }
+
+ // loop through remaining finding mappings for unmapped keys
+ if (top.inherit) {
+ for (int i = _activeKeymaps->size() - 2; i >= 0; --i) {
+ Keymapper::MapRecord mr = (*_activeKeymaps)[i];
+ List<const HardwareKey*>::iterator keyIt = freeKeys.begin();
+ while (keyIt != freeKeys.end()) {
+ Action *act = mr.keymap->getMappedAction((*keyIt)->key);
+ if (act) {
+ ActionInfo info = {act, true, act->description + " (" + mr.keymap->getName() + ")"};
+ _currentActions.push_back(info);
+ freeKeys.erase(keyIt++);
+ } else {
+ ++keyIt;
+ }
+ }
+ if (mr.inherit == false || freeKeys.empty()) break;
+ }
+ }
+
+ } else if (_kmPopUp->getSelected() != -1) {
+ Keymap *km = _keymapTable[_kmPopUp->getSelectedTag()];
+
+ List<Action*>::iterator it;
+ for (it = km->getActions().begin(); it != km->getActions().end(); it++) {
+ ActionInfo info = {*it, false, (*it)->description};
+ _currentActions.push_back(info);
+ }
+ }
+
+ // refresh scroll bar
+ _scrollBar->_currentPos = 0;
+ _scrollBar->_numEntries = (_currentActions.size() + _colCount - 1) / _colCount;
+ _scrollBar->recalc();
+ // force refresh
+ _topAction = -1;
+ refreshKeymap();
+}
+
+void RemapDialog::refreshKeymap() {
+ int newTopAction = _scrollBar->_currentPos * _colCount;
+ if (newTopAction == _topAction) return;
+ _topAction = newTopAction;
+
+ //_container->draw();
+ _scrollBar->draw();
+
+ uint actionI = _topAction;
+ for (uint widgetI = 0; widgetI < _keymapWidgets.size(); widgetI++) {
+ ActionWidgets& widg = _keymapWidgets[widgetI];
+ if (actionI < _currentActions.size()) {
+ ActionInfo& info = _currentActions[actionI];
+ widg.actionText->setLabel(info.description + ": ");
+ widg.actionText->setEnabled(!info.inherited);
+ const HardwareKey *mappedKey = info.action->getMappedKey();
+ if (mappedKey)
+ widg.keyButton->setLabel(mappedKey->description);
+ else
+ widg.keyButton->setLabel("-");
+ widg.actionText->clearFlags(GUI::WIDGET_INVISIBLE);
+ widg.keyButton->clearFlags(GUI::WIDGET_INVISIBLE);
+ actionI++;
+ } else {
+ widg.actionText->setFlags(GUI::WIDGET_INVISIBLE);
+ widg.keyButton->setFlags(GUI::WIDGET_INVISIBLE);
+ }
+ //widg.actionText->draw();
+ //widg.keyButton->draw();
+ }
+ // need to redraw entire Dialog so that invisible
+ // widgets disappear
+ draw();
+}
+
+
+} // end of namespace Common
diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h
new file mode 100644
index 0000000000..f9396e3b45
--- /dev/null
+++ b/backends/keymapper/remap-dialog.h
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef REMAP_DIALOG_H
+#define REMAP_DIALOG_H
+
+#include "backends/keymapper/keymapper.h"
+#include "gui/dialog.h"
+
+namespace GUI {
+ class PopupWidget;
+ class ScrollBarWidget;
+}
+
+namespace Common {
+
+class RemapDialog : public GUI::Dialog {
+public:
+ RemapDialog();
+ virtual ~RemapDialog();
+ virtual void open();
+ virtual void close();
+ virtual void reflowLayout();
+ 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 {
+ GUI::StaticTextWidget *actionText;
+ GUI::ButtonWidget *keyButton;
+ };
+ struct ActionInfo {
+ Action *action;
+ bool inherited;
+ String description;
+ };
+
+ void loadKeymap();
+ void refreshKeymap();
+ void startRemapping(uint i);
+ void stopRemapping();
+
+ Keymapper *_keymapper;
+ Stack<Keymapper::MapRecord> *_activeKeymaps;
+ Keymap** _keymapTable;
+
+ Array<ActionInfo> _currentActions;
+ int _topAction;
+
+ Rect _keymapArea;
+
+ GUI::PopUpWidget *_kmPopUp;
+ //GUI::ContainerWidget *_container;
+ GUI::ScrollBarWidget *_scrollBar;
+
+ uint _colCount, _rowCount;
+
+ Array<ActionWidgets> _keymapWidgets;
+ Action *_activeRemapAction;
+ uint32 _remapTimeout;
+ static const uint32 kRemapTimeoutDelay = 3000;
+
+ bool _changes;
+
+};
+
+} // end of namespace Common
+
+#endif
diff --git a/backends/keymapper/types.h b/backends/keymapper/types.h
new file mode 100644
index 0000000000..8031ab5e38
--- /dev/null
+++ b/backends/keymapper/types.h
@@ -0,0 +1,71 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef COMMON_TYPES
+#define COMMON_TYPES
+
+namespace Common {
+
+enum KeyType {
+ kGenericKeyType,
+ kDirUpKeyType,
+ kDirDownKeyType,
+ kDirLeftKeyType,
+ kDirRightKeyType,
+ kActionKeyType,
+ kTriggerLeftKeyType,
+ kTriggerRightKeyType,
+ kStartKeyType,
+ kSelectKeyType,
+ /* ... */
+
+ kKeyTypeMax
+};
+
+enum ActionType {
+ kGenericActionType,
+
+ // common actions
+ kDirUpActionType,
+ kDirDownActionType,
+ kDirLeftActionType,
+ kDirRightActionType,
+ kLeftClickActionType,
+ kRightClickActionType,
+ kSaveActionType,
+ kMenuActionType,
+ kQuitActionType,
+ kVirtualKeyboardActionType,
+ kKeyRemapActionType,
+ kVolumeUpActionType,
+ kVolumeDownActionType,
+
+
+ kActionTypeMax
+};
+
+} // end of namespace Common
+
+#endif