diff options
Diffstat (limited to 'backends/keymapper')
-rw-r--r-- | backends/keymapper/action.cpp | 53 | ||||
-rw-r--r-- | backends/keymapper/action.h | 116 | ||||
-rw-r--r-- | backends/keymapper/hardware-key.h | 128 | ||||
-rw-r--r-- | backends/keymapper/keymap.cpp | 299 | ||||
-rw-r--r-- | backends/keymapper/keymap.h | 148 | ||||
-rw-r--r-- | backends/keymapper/keymapper.cpp | 219 | ||||
-rw-r--r-- | backends/keymapper/keymapper.h | 204 | ||||
-rw-r--r-- | backends/keymapper/remap-dialog.cpp | 329 | ||||
-rw-r--r-- | backends/keymapper/remap-dialog.h | 92 | ||||
-rw-r--r-- | backends/keymapper/types.h | 71 |
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 |