[Scummvm-git-logs] scummvm master -> 285b10beef9c896ad38bf8e6e51ff815cee6127b

bgK bastien.bouclet at gmail.com
Sun Jan 26 18:08:08 UTC 2020


This automated email contains information about 21 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
b7a816f1eb KEYMAPPER: Clean up the classes dependencies
a449b87c5d KEYMAPPER: Remove action id length restriction
e197a75829 KEYMAPPER: Action can generate only a single event
28e3f2aed7 KEYMAPPER: Remove dead code
63142d8090 COMMON: Event observers can't eat poll notifications anymore
7edff01e69 KEYMAPPER: Move the remap event capture logic out of the keymapper
930ff55421 KEYMAPPER: Simplify the event mapping logic
ada44ca760 GUI: Remove unneeded includes
ac44469558 KEYMAPPER: Remove the domain class
9c0bc2b633 KEYMAPPER: Simplify the way keymaps are enabled and disabled
3b5016a62d KEYMAPPER: Change the remap dialog to use a scrollable container
729cd24c0b KEYMAPPER: Change the keymap action list to be an Array
d5e2b5d8f2 KEYMAPPER: Make it clear the keymaps are owned by the keymapper
ade0efa762 KEYMAPPER: Multiple inputs can map to the same action
17791e2f7d KEYMAPPER: Actions can now have default mappings
576982bc33 KEYMAPPER: Use the default action bindings defined by the backends
d60190b12e ENGINES: Define default bindings for the existing engine keymaps
5a62837f04 MAEMO: Adapt to the new keymapper API
52be1c8c63 EVENTRECORDER: Register as an event observer rather than a mapper
3d48b54288 KEYMAPPER: Remove the ascii value from the hardware keys
285b10beef KEYMAPPER: Store hardware inputs into maps


Commit: b7a816f1ebdaf68f04fa36ae81b53b3bf9927473
    https://github.com/scummvm/scummvm/commit/b7a816f1ebdaf68f04fa36ae81b53b3bf9927473
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Clean up the classes dependencies

Changed paths:
    backends/keymapper/action.cpp
    backends/keymapper/action.h
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/keymapper-defaults.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    backends/keymapper/remap-dialog.cpp
    base/main.cpp
    gui/gui-manager.cpp


diff --git a/backends/keymapper/action.cpp b/backends/keymapper/action.cpp
index 5108590..eadcea6 100644
--- a/backends/keymapper/action.cpp
+++ b/backends/keymapper/action.cpp
@@ -29,7 +29,7 @@
 namespace Common {
 
 Action::Action(Keymap *boss, const char *i,	String des)
-	: _boss(boss), description(des), _hwInput(0) {
+	: _boss(boss), description(des) {
 	assert(i);
 	assert(_boss);
 
@@ -38,20 +38,6 @@ Action::Action(Keymap *boss, const char *i,	String des)
 	_boss->addAction(this);
 }
 
-void Action::mapInput(const HardwareInput *input) {
-	if (_hwInput)
-		_boss->unregisterMapping(this);
-
-	_hwInput = input;
-
-	if (_hwInput)
-		_boss->registerMapping(this, _hwInput);
-}
-
-const HardwareInput *Action::getMappedInput() const {
-	return _hwInput;
-}
-
 } // End of namespace Common
 
 #endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
index 17b1153..00347ea 100644
--- a/backends/keymapper/action.h
+++ b/backends/keymapper/action.h
@@ -55,8 +55,6 @@ struct Action {
 	List<Event> events;
 
 private:
-	/** Hardware input that is mapped to this Action */
-	const HardwareInput *_hwInput;
 	Keymap *_boss;
 
 public:
@@ -97,9 +95,6 @@ public:
 		return _boss;
 	}
 
-	void mapInput(const HardwareInput *input);
-	const HardwareInput *getMappedInput() const;
-
 };
 
 } // End of namespace Common
diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index eaa774c..2a3d0b6 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -26,32 +26,18 @@
 
 #include "common/system.h"
 
+#include "backends/keymapper/action.h"
 #include "backends/keymapper/hardware-input.h"
-#include "backends/keymapper/keymapper-defaults.h"
 
 #define KEYMAP_KEY_PREFIX "keymap_"
 
 namespace Common {
 
-Keymap::Keymap(const Keymap& km) : _actions(km._actions), _keymap(), _nonkeymap(), _configDomain(0) {
-	List<Action *>::iterator it;
-
-	for (it = _actions.begin(); it != _actions.end(); ++it) {
-		const HardwareInput *hwInput = (*it)->getMappedInput();
-
-		if (hwInput) {
-			if (hwInput->type == kHardwareInputTypeKeyboard)
-				_keymap[hwInput->key] = *it;
-			else if (hwInput->type == kHardwareInputTypeGeneric)
-				_nonkeymap[hwInput->inputCode] = *it;
-		}
-	}
+Keymap::Keymap(const Keymap& km) : _actions(km._actions), _hwActionMap(), _configDomain(0) {
 }
 
 Keymap::~Keymap() {
-	List<Action *>::iterator it;
-
-	for (it = _actions.begin(); it != _actions.end(); ++it)
+	for (ActionList::iterator it = _actions.begin(); it != _actions.end(); ++it)
 		delete *it;
 }
 
@@ -63,79 +49,40 @@ void Keymap::addAction(Action *action) {
 }
 
 void Keymap::registerMapping(Action *action, const HardwareInput *hwInput) {
-	if (hwInput->type == kHardwareInputTypeKeyboard) {
-		HashMap<KeyState, Action *>::iterator it = _keymap.find(hwInput->key);
-		// if input is already mapped to a different action then unmap it from there
-		if (it != _keymap.end() && action != it->_value)
-			it->_value->mapInput(0);
-		// now map it
-		_keymap[hwInput->key] = action;
-	} else if (hwInput->type == kHardwareInputTypeGeneric) {
-		HashMap<HardwareInputCode, Action *>::iterator it = _nonkeymap.find(hwInput->inputCode);
-		// if input is already mapped to a different action then unmap it from there
-		if (it != _nonkeymap.end() && action != it->_value)
-			it->_value->mapInput(0);
-		// now map it
-		_nonkeymap[hwInput->inputCode] = action;
-	}
+	unregisterMapping(action);
+
+	_hwActionMap[hwInput] = action;
 }
 
 void Keymap::unregisterMapping(Action *action) {
-	const HardwareInput *hwInput = action->getMappedInput();
-
-	if (hwInput) {
-		if (hwInput->type == kHardwareInputTypeKeyboard)
-			_keymap.erase(hwInput->key);
-		else if (hwInput->type == kHardwareInputTypeGeneric)
-			_nonkeymap.erase(hwInput->inputCode);
+	for (HardwareActionMap::iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
+		if (it->_value == action) {
+			_hwActionMap.erase(it);
+		}
 	}
 }
 
-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;
+const HardwareInput *Keymap::getActionMapping(Action *action) const {
+	for (HardwareActionMap::const_iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
+		if (it->_value == action) {
+			return it->_key;
+		}
 	}
-	return 0;
+
+	return nullptr;
 }
 
 const Action *Keymap::findAction(const char *id) const {
-	List<Action *>::const_iterator it;
-
-	for (it = _actions.begin(); it != _actions.end(); ++it) {
+	for (ActionList::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
 		if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0)
 			return *it;
 	}
 
-	return 0;
+	return nullptr;
 }
 
-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;
-}
-
-Action *Keymap::getMappedAction(const HardwareInputCode code) const {
-	HashMap<HardwareInputCode, Action *>::iterator it;
-
-	it = _nonkeymap.find(code);
-
-	if (it == _nonkeymap.end())
-		return 0;
-	else
-		return it->_value;
+Action *Keymap::getMappedAction(const HardwareInput *hardwareInput) const {
+	return _hwActionMap[hardwareInput];
 }
 
 void Keymap::setConfigDomain(ConfigManager::Domain *dom) {
@@ -149,26 +96,15 @@ void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
 	if (_actions.empty())
 		return;
 
-	Common::KeymapperDefaultBindings *defaults = g_system->getKeymapperDefaultBindings();
-
-	HashMap<String, const HardwareInput *> mappedInputs;
-	List<Action*>::iterator it;
 	String prefix = KEYMAP_KEY_PREFIX + _name + "_";
 
-	for (it = _actions.begin(); it != _actions.end(); ++it) {
+	for (ActionList::iterator it = _actions.begin(); it != _actions.end(); ++it) {
 		Action* ua = *it;
 		String actionId(ua->id);
 		String confKey = prefix + actionId;
 
 		String hwInputId = _configDomain->getVal(confKey);
 
-		bool defaulted = false;
-		// fall back to the platform-specific defaults
-		if (hwInputId.empty() && defaults) {
-			hwInputId = defaults->getDefaultBinding(_name, actionId);
-			if (!hwInputId.empty())
-				defaulted = true;
-		}
 		// there's no mapping
 		if (hwInputId.empty())
 			continue;
@@ -180,17 +116,8 @@ void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
 			continue;
 		}
 
-		if (defaulted) {
-			if (mappedInputs.contains(hwInputId)) {
-				debug(1, "Action [%s] not falling back to hardcoded default value [%s] because the hardware input is in use", confKey.c_str(), hwInputId.c_str());
-				continue;
-			}
-			warning("Action [%s] fell back to hardcoded default value [%s]", confKey.c_str(), hwInputId.c_str());
-		}
-
-		mappedInputs.setVal(hwInputId, hwInput);
 		// map the key
-		ua->mapInput(hwInput);
+		_hwActionMap[hwInput] = ua;
 	}
 }
 
@@ -198,38 +125,20 @@ 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);
+	for (HardwareActionMap::iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
+		const Action *action = it->_value;
+		const HardwareInput *input = it->_key;
 
-		actIdLen = (actIdLen > ACTION_ID_SIZE) ? ACTION_ID_SIZE : actIdLen;
-
-		String actId((*it)->id, (*it)->id + actIdLen);
-		String hwId = "";
+		uint actIdLen = strlen(action->id);
 
-		if ((*it)->getMappedInput()) {
-			hwId = (*it)->getMappedInput()->id;
-		}
-		_configDomain->setVal(prefix + actId, hwId);
-	}
-}
+		actIdLen = (actIdLen > ACTION_ID_SIZE) ? ACTION_ID_SIZE : actIdLen;
 
-bool Keymap::isComplete(const HardwareInputSet *hwInputs) {
-	List<Action *>::iterator it;
-	bool allMapped = true;
-	uint numberMapped = 0;
+		String actId(action->id, action->id + actIdLen);
 
-	for (it = _actions.begin(); it != _actions.end(); ++it) {
-		if ((*it)->getMappedInput()) {
-			++numberMapped;
-		} else {
-			allMapped = false;
-		}
+		_configDomain->setVal(prefix + actId, input->id);
 	}
-
-	return allMapped || (numberMapped == hwInputs->size());
 }
 
 } // End of namespace Common
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
index 0694dc3..a4e53e3 100644
--- a/backends/keymapper/keymap.h
+++ b/backends/keymapper/keymap.h
@@ -30,23 +30,14 @@
 #include "common/config-manager.h"
 #include "common/func.h"
 #include "common/hashmap.h"
-#include "common/keyboard.h"
+#include "common/hash-ptr.h"
 #include "common/list.h"
-#include "backends/keymapper/action.h"
-#include "backends/keymapper/hardware-input.h"
 
 namespace Common {
 
-/**
- * Hash function for KeyState
- */
-template<> struct Hash<KeyState>
-	: public UnaryFunction<KeyState, uint> {
-
-	uint operator()(const KeyState &val) const {
-		return (uint)val.keycode | ((uint)val.flags << 24);
-	}
-};
+class Action;
+class HardwareInput;
+class HardwareInputSet;
 
 class Keymap {
 public:
@@ -56,30 +47,36 @@ public:
 
 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);
+	* Registers a HardwareInput to the given Action
+	* @param action Action in this Keymap
+	* @param key pointer to HardwareInput to map
+	* @see Action::mapKey
+	*/
+	void registerMapping(Action *action, const HardwareInput *input);
 
 	/**
-	 * Get the list of all the Actions contained in this Keymap
+	* Unregisters a HardwareInput from the given Action (if one is mapped)
+	* @param action Action in this Keymap
+	* @see Action::mapKey
+	*/
+	void unregisterMapping(Action *action);
+
+	/**
+	 * Find the hardware input an action is mapped to, if any
 	 */
-	List<Action *>& getActions() { return _actions; }
+	const HardwareInput *getActionMapping(Action *action) const;
 
 	/**
-	 * Find the Action that a key is mapped to
-	 * @param key	the key that is mapped to the required Action
+	 * Find the Action that a hardware input is mapped to
+	 * @param hardwareInput	the input that is mapped to the required Action
 	 * @return		a pointer to the Action or 0 if no
 	 */
-	Action *getMappedAction(const KeyState& ks) const;
+	Action *getMappedAction(const HardwareInput *hardwareInput) const;
 
 	/**
-	 * Find the Action that a generic input is mapped to
-	 * @param code	the input code that is mapped to the required Action
-	 * @return			a pointer to the Action or 0 if no
+	 * Get the list of all the Actions contained in this Keymap
 	 */
-	Action *getMappedAction(const HardwareInputCode code) const;
+	List<Action *>& getActions() { return _actions; }
 
 	void setConfigDomain(ConfigManager::Domain *dom);
 
@@ -96,12 +93,6 @@ public:
 	 */
 	void saveMappings();
 
-	/**
-	 * Returns true if all UserAction's in Keymap are mapped, or,
-	 * all HardwareInputs from the given set have been used up.
-	 */
-	bool isComplete(const HardwareInputSet *hwInputs);
-
 	const String& getName() { return _name; }
 
 private:
@@ -114,28 +105,14 @@ private:
 	 */
 	void addAction(Action *action);
 
-	/**
-	* Registers a HardwareInput to the given Action
-	* @param action Action in this Keymap
-	* @param key pointer to HardwareInput to map
-	* @see Action::mapKey
-	*/
-	void registerMapping(Action *action, const HardwareInput *input);
-
-	/**
-	* Unregisters a HardwareInput 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;
 
+	typedef List<Action *> ActionList;
+	typedef HashMap<const HardwareInput *, Action *> HardwareActionMap;
+
 	String _name;
-	List<Action *> _actions;
-	HashMap<KeyState, Action *> _keymap;
-	HashMap<HardwareInputCode, Action *> _nonkeymap;
+	ActionList _actions;
+	HardwareActionMap _hwActionMap;
 	ConfigManager::Domain *_configDomain;
 
 };
diff --git a/backends/keymapper/keymapper-defaults.h b/backends/keymapper/keymapper-defaults.h
index aedde87..11a0e58 100644
--- a/backends/keymapper/keymapper-defaults.h
+++ b/backends/keymapper/keymapper-defaults.h
@@ -47,7 +47,7 @@ public:
 	 * @param actionId String representing Action id (Action.id)
 	 * @return String representing the HardwareInput id (HardwareInput.id)
 	 */
-	String getDefaultBinding(String keymapId, String actionId) { return getVal(keymapId + "_" + actionId); }
+	String getDefaultBinding(String keymapId, String actionId) const { return getVal(keymapId + "_" + actionId); }
 };
 
 } //namespace Common
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index aba00c5..832ee88 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -24,6 +24,8 @@
 
 #ifdef ENABLE_KEYMAPPER
 
+#include "backends/keymapper/action.h"
+
 #include "common/config-manager.h"
 #include "common/system.h"
 
@@ -108,11 +110,6 @@ void Keymapper::initKeymap(Domain &domain, Keymap *map) {
 	map->setConfigDomain(domain.getConfigDomain());
 	map->loadMappings(_hardwareInputs);
 
-	if (map->isComplete(_hardwareInputs) == false) {
-		map->saveMappings();
-		ConfMan.flushToDisk();
-	}
-
 	domain.addKeymap(map);
 }
 
@@ -227,11 +224,14 @@ List<Event> Keymapper::mapKey(const KeyState& key, bool keyDown) {
 	Action *action = 0;
 
 	if (keyDown) {
+		// FIXME: Performance
+		const HardwareInput *hwInput = _hardwareInputs->findHardwareInput(key);
+
 		// Search for key in active keymap stack
 		for (int i = _activeMaps.size() - 1; i >= 0; --i) {
 			MapRecord mr = _activeMaps[i];
 			debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
-			action = mr.keymap->getMappedAction(key);
+			action = mr.keymap->getMappedAction(hwInput);
 
 			if (action || !mr.transparent)
 				break;
@@ -259,13 +259,16 @@ List<Event> Keymapper::mapNonKey(const HardwareInputCode code) {
 	if (!_enabled || _activeMaps.empty())
 		return List<Event>();
 
+	// FIXME: Performance
+	const HardwareInput *hwInput = _hardwareInputs->findHardwareInput(code);
+
 	Action *action = 0;
 
 	// Search for nonkey in active keymap stack
 	for (int i = _activeMaps.size() - 1; i >= 0; --i) {
 		MapRecord mr = _activeMaps[i];
 		debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
-		action = mr.keymap->getMappedAction(code);
+		action = mr.keymap->getMappedAction(hwInput);
 
 		if (action || !mr.transparent)
 			break;
@@ -375,8 +378,10 @@ List<Event> Keymapper::remap(const Event &ev) {
 		break;
 	}
 	if (hwInput) {
-		_actionToRemap->mapInput(hwInput);
-		_actionToRemap->getParent()->saveMappings();
+		Keymap *keymap = _actionToRemap->getParent();
+		keymap->registerMapping(_actionToRemap, hwInput);
+		keymap->saveMappings();
+
 		_remapping = false;
 		_actionToRemap = 0;
 		mappedEvent.type = EVENT_GUI_REMAP_COMPLETE_ACTION;
@@ -385,6 +390,12 @@ List<Event> Keymapper::remap(const Event &ev) {
 	return list;
 }
 
+void Keymapper::clearMapping(Action *action) {
+	Keymap *keymap = action->getParent();
+	keymap->unregisterMapping(action);
+	keymap->saveMappings();
+}
+
 } // End of namespace Common
 
 #endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index ea6fc14..0ebb207 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -39,6 +39,17 @@ namespace Common {
 const char *const kGuiKeymapName = "gui";
 const char *const kGlobalKeymapName = "global";
 
+/**
+ * Hash function for KeyState
+ */
+template<> struct Hash<KeyState>
+		: public UnaryFunction<KeyState, uint> {
+
+	uint operator()(const KeyState &val) const {
+		return (uint)val.keycode | ((uint)val.flags << 24);
+	}
+};
+
 class Keymapper : public Common::DefaultEventMapper {
 public:
 
@@ -200,6 +211,8 @@ public:
 	Domain& getGameDomain() { return _gameDomain; }
 	const Stack<MapRecord>& getActiveStack() const { return _activeMaps; }
 
+	void clearMapping(Action *action);
+
 private:
 
 	enum IncomingEventType {
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index 02400b4..69f8ffd 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -24,6 +24,8 @@
 
 #ifdef ENABLE_KEYMAPPER
 
+#include "backends/keymapper/action.h"
+
 #include "common/system.h"
 #include "gui/gui-manager.h"
 #include "gui/widgets/popup.h"
@@ -248,8 +250,7 @@ void RemapDialog::clearMapping(uint i) {
 
 	debug(3, "clear the mapping %u", i);
 	Action *activeRemapAction = _currentActions[_topAction + i].action;
-	activeRemapAction->mapInput(0);
-	activeRemapAction->getParent()->saveMappings();
+	_keymapper->clearMapping(activeRemapAction);
 	_changes = true;
 
 	// force refresh
@@ -351,8 +352,9 @@ void RemapDialog::loadKeymap() {
 
 			_currentActions.push_back(info);
 
-			if (act->getMappedInput())
-				freeInputs.remove(act->getMappedInput());
+			const HardwareInput *mappedInput = top.keymap->getActionMapping(act);
+			if (mappedInput)
+				freeInputs.remove(mappedInput);
 		}
 
 		// loop through remaining finding mappings for unmapped keys
@@ -364,12 +366,7 @@ void RemapDialog::loadKeymap() {
 				const HardwareInput *input = *inputIt;
 				while (inputIt != freeInputs.end()) {
 
-					Action *act = 0;
-					if (input->type == kHardwareInputTypeKeyboard)
-						act = mr.keymap->getMappedAction(input->key);
-					else if (input->type == kHardwareInputTypeGeneric)
-						act = mr.keymap->getMappedAction(input->inputCode);
-
+					Action *act = mr.keymap->getMappedAction(input);
 					if (act) {
 						ActionInfo info = {act, true, act->description + " (" + mr.keymap->getName() + ")"};
 						_currentActions.push_back(info);
@@ -432,8 +429,9 @@ void RemapDialog::refreshKeymap() {
 			widg.actionText->setLabel(info.description);
 			widg.actionText->setEnabled(!info.inherited);
 
-			const HardwareInput *mappedInput = info.action->getMappedInput();
+			Keymap *keymap = info.action->getParent();
 
+			const HardwareInput *mappedInput = keymap->getActionMapping(info.action);
 			if (mappedInput)
 				widg.keyButton->setLabel(mappedInput->description);
 			else
diff --git a/base/main.cpp b/base/main.cpp
index 462acfc..d09c023 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -68,6 +68,8 @@
 #endif
 
 #include "backends/keymapper/keymapper.h"
+#include "backends/keymapper/action.h"
+
 #ifdef USE_CLOUD
 #ifdef USE_LIBCURL
 #include "backends/cloud/cloudmanager.h"
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 0505177..3ce602f 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -31,6 +31,7 @@
 #include "gui/EventRecorder.h"
 
 #include "backends/keymapper/keymapper.h"
+#include "backends/keymapper/action.h"
 
 #include "gui/gui-manager.h"
 #include "gui/dialog.h"


Commit: a449b87c5db8522188020c404cd8405507cdf1f7
    https://github.com/scummvm/scummvm/commit/a449b87c5db8522188020c404cd8405507cdf1f7
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Remove action id length restriction

Changed paths:
    backends/keymapper/action.cpp
    backends/keymapper/action.h
    backends/keymapper/keymap.cpp


diff --git a/backends/keymapper/action.cpp b/backends/keymapper/action.cpp
index eadcea6..75071f1 100644
--- a/backends/keymapper/action.cpp
+++ b/backends/keymapper/action.cpp
@@ -29,12 +29,10 @@
 namespace Common {
 
 Action::Action(Keymap *boss, const char *i,	String des)
-	: _boss(boss), description(des) {
+	: _boss(boss), description(des), id(i) {
 	assert(i);
 	assert(_boss);
 
-	Common::strlcpy(id, i, ACTION_ID_SIZE);
-
 	_boss->addAction(this);
 }
 
diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
index 00347ea..6473ed2 100644
--- a/backends/keymapper/action.h
+++ b/backends/keymapper/action.h
@@ -37,8 +37,6 @@ namespace Common {
 struct HardwareInput;
 class Keymap;
 
-#define ACTION_ID_SIZE (5)
-
 struct KeyActionEntry {
 	const KeyState ks;
 	const char *id;
@@ -47,7 +45,7 @@ struct KeyActionEntry {
 
 struct Action {
 	/** unique id used for saving/loading to config */
-	char id[ACTION_ID_SIZE];
+	const char *id;
 	/** Human readable description */
 	String description;
 
diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index 2a3d0b6..7ff611c 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -74,7 +74,7 @@ const HardwareInput *Keymap::getActionMapping(Action *action) const {
 
 const Action *Keymap::findAction(const char *id) const {
 	for (ActionList::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
-		if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0)
+		if (strcmp((*it)->id, id) == 0)
 			return *it;
 	}
 
@@ -131,13 +131,7 @@ void Keymap::saveMappings() {
 		const Action *action = it->_value;
 		const HardwareInput *input = it->_key;
 
-		uint actIdLen = strlen(action->id);
-
-		actIdLen = (actIdLen > ACTION_ID_SIZE) ? ACTION_ID_SIZE : actIdLen;
-
-		String actId(action->id, action->id + actIdLen);
-
-		_configDomain->setVal(prefix + actId, input->id);
+		_configDomain->setVal(prefix + action->id, input->id);
 	}
 }
 


Commit: e197a7582991f9a203e817b5d46a16d130e2a06e
    https://github.com/scummvm/scummvm/commit/e197a7582991f9a203e817b5d46a16d130e2a06e
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Action can generate only a single event

Changed paths:
    backends/keymapper/action.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    base/main.cpp
    engines/kyra/engine/eobcommon.cpp
    engines/kyra/engine/lol.cpp
    engines/mohawk/riven.cpp
    engines/pegasus/pegasus.cpp
    gui/gui-manager.cpp


diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
index 6473ed2..0771596 100644
--- a/backends/keymapper/action.h
+++ b/backends/keymapper/action.h
@@ -29,7 +29,6 @@
 
 #include "common/events.h"
 #include "common/func.h"
-#include "common/list.h"
 #include "common/str.h"
 
 namespace Common {
@@ -49,8 +48,8 @@ struct Action {
 	/** Human readable description */
 	String description;
 
-	/** Events to be sent when mapped key is pressed */
-	List<Event> events;
+	/** Event to be sent when mapped key is pressed */
+	Event event;
 
 private:
 	Keymap *_boss;
@@ -58,35 +57,31 @@ private:
 public:
 	Action(Keymap *boss, const char *id, String des = "");
 
-	void addEvent(const Event &evt) {
-		events.push_back(evt);
+	void setEvent(const Event &evt) {
+		event = evt;
 	}
 
-	void addEvent(const EventType evtType) {
-		Event evt;
-
-		evt.type = evtType;
-		events.push_back(evt);
+	void setEvent(const EventType evtType) {
+		event = Event();
+		event.type = evtType;
 	}
 
-	void addKeyEvent(const KeyState &ks) {
-		Event evt;
-
-		evt.type = EVENT_KEYDOWN;
-		evt.kbd = ks;
-		addEvent(evt);
+	void setKeyEvent(const KeyState &ks) {
+		event = Event();
+		event.type = EVENT_KEYDOWN;
+		event.kbd = ks;
 	}
 
-	void addLeftClickEvent() {
-		addEvent(EVENT_LBUTTONDOWN);
+	void setLeftClickEvent() {
+		setEvent(EVENT_LBUTTONDOWN);
 	}
 
-	void addMiddleClickEvent() {
-		addEvent(EVENT_MBUTTONDOWN);
+	void setMiddleClickEvent() {
+		setEvent(EVENT_MBUTTONDOWN);
 	}
 
-	void addRightClickEvent() {
-		addEvent(EVENT_RBUTTONDOWN);
+	void setRightClickEvent() {
+		setEvent(EVENT_RBUTTONDOWN);
 	}
 
 	Keymap *getParent() {
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 832ee88..3296db4 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -280,47 +280,39 @@ List<Event> Keymapper::mapNonKey(const HardwareInputCode code) {
 	return executeAction(action);
 }
 
-Action *Keymapper::getAction(const KeyState& key) {
-	Action *action = 0;
-
-	return action;
-}
-
 List<Event> Keymapper::executeAction(const Action *action, IncomingEventType incomingType) {
 	List<Event> mappedEvents;
-	List<Event>::const_iterator it;
-	Event evt;
-	for (it = action->events.begin(); it != action->events.end(); ++it) {
-		evt = Event(*it);
-		EventType convertedType = convertDownToUp(evt.type);
-
-		// hardware keys need to send up instead when they are up
-		if (incomingType == kIncomingKeyUp) {
-			if (convertedType == EVENT_INVALID)
-				continue; // don't send any non-down-converted events on up they were already sent on down
-			evt.type = convertedType;
-		}
 
-		evt.mouse = _eventMan->getMousePos();
-
-		// Check if the event is coming from a non-key hardware event
-		// that is mapped to a key event
-		if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID)
-			// WORKAROUND: Delay the down events coming from non-key hardware events
-			// with a zero delay. This is to prevent DOWN1 DOWN2 UP1 UP2.
-			addDelayedEvent(0, evt);
-		else
-			mappedEvents.push_back(evt);
-
-		// non-keys need to send up as well
-		if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID) {
-			// WORKAROUND: Delay the up events coming from non-key hardware events
-			// This is for engines that run scripts that check on key being down
-			evt.type = convertedType;
-			const uint32 delay = (convertedType == EVENT_KEYUP ? kDelayKeyboardEventMillis : kDelayMouseEventMillis);
-			addDelayedEvent(delay, evt);
-		}
+	Event evt = Event(action->event);
+	EventType convertedType = convertDownToUp(evt.type);
+
+	// hardware keys need to send up instead when they are up
+	if (incomingType == kIncomingKeyUp) {
+		if (convertedType == EVENT_INVALID)
+			return List<Event>(); // don't send any non-down-converted events on up they were already sent on down
+		evt.type = convertedType;
+	}
+
+	evt.mouse = _eventMan->getMousePos();
+
+	// Check if the event is coming from a non-key hardware event
+	// that is mapped to a key event
+	if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID)
+		// WORKAROUND: Delay the down events coming from non-key hardware events
+		// with a zero delay. This is to prevent DOWN1 DOWN2 UP1 UP2.
+		addDelayedEvent(0, evt);
+	else
+		mappedEvents.push_back(evt);
+
+	// non-keys need to send up as well
+	if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID) {
+		// WORKAROUND: Delay the up events coming from non-key hardware events
+		// This is for engines that run scripts that check on key being down
+		evt.type = convertedType;
+		const uint32 delay = (convertedType == EVENT_KEYUP ? kDelayKeyboardEventMillis : kDelayMouseEventMillis);
+		addDelayedEvent(delay, evt);
 	}
+
 	return mappedEvents;
 }
 
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index 0ebb207..d8b7c43 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -230,7 +230,6 @@ private:
 
 	void pushKeymap(Keymap *newMap, bool transparent, bool global);
 
-	Action *getAction(const KeyState& key);
 	List<Event> executeAction(const Action *act, IncomingEventType incomingType = kIncomingNonKey);
 	EventType convertDownToUp(EventType eventType);
 	List<Event> remap(const Event &ev);
diff --git a/base/main.cpp b/base/main.cpp
index d09c023..ac5b65a 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -363,36 +363,36 @@ static void setupKeymapper(OSystem &system) {
 	Keymap *primaryGlobalKeymap = new Keymap(kGlobalKeymapName);
 	Action *act;
 	act = new Action(primaryGlobalKeymap, "MENU", _("Menu"));
-	act->addEvent(EVENT_MAINMENU);
+	act->setEvent(EVENT_MAINMENU);
 
 	act = new Action(primaryGlobalKeymap, "SKCT", _("Skip"));
-	act->addKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));
+	act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));
 
 	act = new Action(primaryGlobalKeymap, "PAUS", _("Pause"));
-	act->addKeyEvent(KeyState(KEYCODE_SPACE, ' ', 0));
+	act->setKeyEvent(KeyState(KEYCODE_SPACE, ' ', 0));
 
 	act = new Action(primaryGlobalKeymap, "SKLI", _("Skip line"));
-	act->addKeyEvent(KeyState(KEYCODE_PERIOD, '.', 0));
+	act->setKeyEvent(KeyState(KEYCODE_PERIOD, '.', 0));
 
 #ifdef ENABLE_VKEYBD
 	act = new Action(primaryGlobalKeymap, "VIRT", _("Display keyboard"));
-	act->addEvent(EVENT_VIRTUAL_KEYBOARD);
+	act->setEvent(EVENT_VIRTUAL_KEYBOARD);
 #endif
 
 	act = new Action(primaryGlobalKeymap, "REMP", _("Remap keys"));
-	act->addEvent(EVENT_KEYMAPPER_REMAP);
+	act->setEvent(EVENT_KEYMAPPER_REMAP);
 
 	act = new Action(primaryGlobalKeymap, "FULS", _("Toggle fullscreen"));
-	act->addKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN, KBD_ALT));
+	act->setKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN, KBD_ALT));
 
 	act = new Action(primaryGlobalKeymap, "LCLK", _("Left Click"));
-	act->addLeftClickEvent();
+	act->setLeftClickEvent();
 
 	act = new Action(primaryGlobalKeymap, "MCLK", _("Middle Click"));
-	act->addMiddleClickEvent();
+	act->setMiddleClickEvent();
 
 	act = new Action(primaryGlobalKeymap, "RCLK", _("Right Click"));
-	act->addRightClickEvent();
+	act->setRightClickEvent();
 
 	mapper->addGlobalKeymap(primaryGlobalKeymap);
 	mapper->pushKeymap(kGlobalKeymapName, true);
diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp
index d1c7a6b..6e5349c 100644
--- a/engines/kyra/engine/eobcommon.cpp
+++ b/engines/kyra/engine/eobcommon.cpp
@@ -35,6 +35,7 @@
 
 #include "gui/error.h"
 
+#include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
 
 namespace Kyra {
@@ -374,12 +375,12 @@ void EoBCoreEngine::initKeymap() {
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); ++i) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
-		act->addKeyEvent(keyActionEntries[i].ks);
+		act->setKeyEvent(keyActionEntries[i].ks);
 	}
 
 	if (_flags.gameID == GI_EOB2) {
 		Common::Action *const act = new Common::Action(engineKeyMap, "SL6", _("Spell Level 6"));
-		act->addKeyEvent(Common::KeyState(Common::KEYCODE_6));
+		act->setKeyEvent(Common::KeyState(Common::KEYCODE_6));
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/kyra/engine/lol.cpp b/engines/kyra/engine/lol.cpp
index bd79941..81cc26d 100644
--- a/engines/kyra/engine/lol.cpp
+++ b/engines/kyra/engine/lol.cpp
@@ -36,6 +36,7 @@
 #include "common/system.h"
 #include "common/translation.h"
 
+#include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
 
 namespace Kyra {
@@ -492,7 +493,7 @@ void LoLEngine::initKeymap() {
 
 	for (const Common::KeyActionEntry *entry = keyActionEntries; entry->id; ++entry) {
 		Common::Action *const act = new Common::Action(engineKeyMap, entry->id, entry->description);
-		act->addKeyEvent(entry->ks);
+		act->setKeyEvent(entry->ks);
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index a8a9487..93abc05 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -26,6 +26,7 @@
 #include "common/keyboard.h"
 #include "common/translation.h"
 #include "common/system.h"
+#include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
 #include "graphics/scaler.h"
 #include "gui/saveload.h"
@@ -903,22 +904,22 @@ void MohawkEngine_Riven::initKeymap() {
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
-		act->addKeyEvent(keyActionEntries[i].ks);
+		act->setKeyEvent(keyActionEntries[i].ks);
 	}
 
 	if (getFeatures() & GF_DEMO) {
 		for (uint i = 0; i < ARRAYSIZE(keyActionEntriesDemo); i++) {
 			Common::Action* const act = new Common::Action(engineKeyMap, keyActionEntriesDemo[i].id, keyActionEntriesDemo[i].description);
-			act->addKeyEvent(keyActionEntriesDemo[i].ks);
+			act->setKeyEvent(keyActionEntriesDemo[i].ks);
 		}
 	}
 
 	if (getFeatures() & GF_25TH) {
 		Common::Action* const act = new Common::Action(engineKeyMap, "SMNU", _("Skip / Open main menu"));
-		act->addKeyEvent(Common::KEYCODE_ESCAPE);
+		act->setKeyEvent(Common::KEYCODE_ESCAPE);
 	} else {
 		Common::Action* const act = new Common::Action(engineKeyMap, "SKIP", _("Skip"));
-		act->addKeyEvent(Common::KEYCODE_ESCAPE);
+		act->setKeyEvent(Common::KEYCODE_ESCAPE);
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 78991cd..06e1103 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -33,6 +33,7 @@
 #include "common/textconsole.h"
 #include "common/translation.h"
 #include "common/random.h"
+#include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
 #include "base/plugins.h"
 #include "base/version.h"
@@ -2517,7 +2518,7 @@ void PegasusEngine::initKeymap() {
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
-		act->addKeyEvent(keyActionEntries[i].ks);
+		act->setKeyEvent(keyActionEntries[i].ks);
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 3ce602f..f53b382 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -122,10 +122,10 @@ void GuiManager::initKeymap() {
 	Keymap *guiMap = new Keymap(kGuiKeymapName);
 
 	act = new Action(guiMap, "CLOS", _("Close"));
-	act->addKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));
+	act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));
 
 	act = new Action(guiMap, "CLIK", _("Mouse click"));
-	act->addLeftClickEvent();
+	act->setLeftClickEvent();
 
 #ifdef ENABLE_VKEYBD
 	act = new Action(guiMap, "VIRT", _("Display keyboard"));
@@ -133,10 +133,10 @@ void GuiManager::initKeymap() {
 #endif
 
 	act = new Action(guiMap, "REMP", _("Remap keys"));
-	act->addEvent(EVENT_KEYMAPPER_REMAP);
+	act->setEvent(EVENT_KEYMAPPER_REMAP);
 
 	act = new Action(guiMap, "FULS", _("Toggle fullscreen"));
-	act->addKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN, KBD_ALT));
+	act->setKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN, KBD_ALT));
 
 	mapper->addGlobalKeymap(guiMap);
 }


Commit: 28e3f2aed792630a874dddc859af846d3235a55f
    https://github.com/scummvm/scummvm/commit/28e3f2aed792630a874dddc859af846d3235a55f
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Remove dead code

Changed paths:
    backends/keymapper/keymapper.cpp
    backends/keymapper/remap-dialog.cpp
    backends/keymapper/remap-dialog.h


diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 3296db4..ba55819 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -356,9 +356,6 @@ List<Event> Keymapper::remap(const Event &ev) {
 
 	switch (ev.type) {
 	case EVENT_KEYDOWN:
-		// eat the event by returning an event invalid
-		mappedEvent.type = EVENT_INVALID;
-		list.push_back(mappedEvent);
 		break;
 	case EVENT_KEYUP:
 		hwInput = findHardwareInput(ev.kbd);
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index 69f8ffd..f337048 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -25,6 +25,7 @@
 #ifdef ENABLE_KEYMAPPER
 
 #include "backends/keymapper/action.h"
+#include "backends/keymapper/keymapper.h"
 
 #include "common/system.h"
 #include "gui/gui-manager.h"
diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h
index 8fd961a..046ccd2 100644
--- a/backends/keymapper/remap-dialog.h
+++ b/backends/keymapper/remap-dialog.h
@@ -27,7 +27,6 @@
 
 #ifdef ENABLE_KEYMAPPER
 
-#include "backends/keymapper/keymapper.h"
 #include "gui/dialog.h"
 
 namespace GUI {
@@ -39,6 +38,10 @@ class StaticTextWidget;
 
 namespace Common {
 
+class Action;
+class Keymap;
+class Keymapper;
+
 class RemapDialog : public GUI::Dialog {
 public:
 	RemapDialog();
@@ -79,7 +82,6 @@ protected:
 
 	GUI::StaticTextWidget *_kmPopUpDesc;
 	GUI::PopUpWidget *_kmPopUp;
-	//GUI::ContainerWidget *_container;
 	GUI::ScrollBarWidget *_scrollBar;
 
 	uint _rowCount;


Commit: 63142d80908b9359686382adb8e14db151b3e9b7
    https://github.com/scummvm/scummvm/commit/63142d80908b9359686382adb8e14db151b3e9b7
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
COMMON: Event observers can't eat poll notifications anymore

It did not make much sense, and was unused.

Changed paths:
    common/EventDispatcher.cpp
    common/events.h
    gui/EventRecorder.h


diff --git a/common/EventDispatcher.cpp b/common/EventDispatcher.cpp
index 617ce32..259c233 100644
--- a/common/EventDispatcher.cpp
+++ b/common/EventDispatcher.cpp
@@ -148,9 +148,8 @@ void EventDispatcher::dispatchEvent(const Event &event) {
 
 void EventDispatcher::dispatchPoll() {
 	for (List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) {
-		if (i->poll == true)
-			if (i->observer->notifyPoll())
-				break;
+		if (i->poll)
+			i->observer->notifyPoll();
 	}
 }
 
diff --git a/common/events.h b/common/events.h
index 134f1ea..afc81d3 100644
--- a/common/events.h
+++ b/common/events.h
@@ -277,11 +277,8 @@ public:
 
 	/**
 	 * Notifies the observer of pollEvent() query.
-	 *
-	 * @return  true if the event should not be passed to other observers,
-	 *          false otherwise.
 	 */
-	virtual bool notifyPoll() { return false; }
+	virtual void notifyPoll() { }
 };
 
 /**
diff --git a/gui/EventRecorder.h b/gui/EventRecorder.h
index 15b5db0..eb38769 100644
--- a/gui/EventRecorder.h
+++ b/gui/EventRecorder.h
@@ -177,7 +177,6 @@ public:
 
 private:
 	Common::List<Common::Event> mapEvent(const Common::Event &ev, Common::EventSource *source) override;
-	bool notifyPoll();
 	bool pollEvent(Common::Event &ev) override;
 	bool _initialized;
 	volatile uint32 _fakeTimer;


Commit: 7edff01e696a16fd0309bdb8eeb0eae166749fc4
    https://github.com/scummvm/scummvm/commit/7edff01e696a16fd0309bdb8eeb0eae166749fc4
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Move the remap event capture logic out of the keymapper

Changed paths:
  A backends/keymapper/input-watcher.cpp
  A backends/keymapper/input-watcher.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    backends/keymapper/remap-dialog.cpp
    backends/keymapper/remap-dialog.h
    backends/module.mk
    common/events.h
    gui/dialog.cpp
    gui/dialog.h
    gui/launcher.cpp
    gui/launcher.h


diff --git a/backends/keymapper/input-watcher.cpp b/backends/keymapper/input-watcher.cpp
new file mode 100644
index 0000000..045c725
--- /dev/null
+++ b/backends/keymapper/input-watcher.cpp
@@ -0,0 +1,93 @@
+/* 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.
+ *
+ */
+
+#include "backends/keymapper/input-watcher.h"
+
+#ifdef ENABLE_KEYMAPPER
+
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/keymapper.h"
+
+namespace Common {
+
+InputWatcher::InputWatcher(EventDispatcher *eventDispatcher, Keymapper *keymapper) :
+		_eventDispatcher(eventDispatcher),
+		_keymapper(keymapper),
+		_watching(false),
+		_hwInput(nullptr) {
+
+}
+
+void InputWatcher::startWatching() {
+	assert(!_watching);
+	assert(!_hwInput);
+
+	_keymapper->setEnabled(false);
+	_eventDispatcher->registerObserver(this, EventManager::kEventRemapperPriority, false);
+	_watching = true;
+}
+
+void InputWatcher::stopWatching() {
+	_keymapper->setEnabled(true);
+	_eventDispatcher->unregisterObserver(this);
+	_watching = false;
+}
+
+bool InputWatcher::isWatching() const {
+	return _watching;
+}
+
+bool InputWatcher::notifyEvent(const Event &event) {
+	assert(_watching);
+	assert(!_hwInput);
+
+	switch (event.type) {
+		case EVENT_KEYDOWN:
+			return true;
+		case EVENT_KEYUP:
+			_hwInput = _keymapper->findHardwareInput(event.kbd);
+			if (_hwInput) {
+				stopWatching();
+			}
+			return true;
+		case EVENT_CUSTOM_BACKEND_HARDWARE:
+			_hwInput = _keymapper->findHardwareInput(event.customType);
+			if (_hwInput) {
+				stopWatching();
+			}
+			return true;
+		default:
+			break;
+	}
+
+	return false;
+}
+
+const HardwareInput *InputWatcher::checkForCapturedInput() {
+	const HardwareInput *hwInput = _hwInput;
+	_hwInput = nullptr;
+	return hwInput;
+}
+
+} // End of namespace Common
+
+#endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/input-watcher.h b/backends/keymapper/input-watcher.h
new file mode 100644
index 0000000..1663e1e
--- /dev/null
+++ b/backends/keymapper/input-watcher.h
@@ -0,0 +1,69 @@
+/* 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.
+ *
+ */
+
+#ifndef COMMON_INPUT_WATCHER_H
+#define COMMON_INPUT_WATCHER_H
+
+#include "common/scummsys.h"
+
+#ifdef ENABLE_KEYMAPPER
+
+#include "common/events.h"
+
+namespace Common {
+
+class HardwareInput;
+
+/**
+ * Watches events for inputs that can be bound to actions
+ * 
+ * When the watch mode is enabled, the watcher disables the Keymapper
+ * and sets itself as an event observer. Once an event corresponding
+ * to an hardware input is received, it is saved for later retrieval.
+ *
+ * Used by the remap dialog to capture input.
+ */
+class InputWatcher : private EventObserver {
+public:
+	InputWatcher(EventDispatcher *eventDispatcher, Keymapper *keymapper);
+
+	void startWatching();
+	void stopWatching();
+
+	bool isWatching() const;
+	const HardwareInput *checkForCapturedInput();
+
+private:
+	bool notifyEvent(const Event &event) override;
+
+	EventDispatcher *_eventDispatcher;
+	Keymapper *_keymapper;
+
+	bool _watching;
+	const HardwareInput *_hwInput;
+};
+
+} // End of namespace Common
+
+#endif // #ifdef ENABLE_KEYMAPPER
+
+#endif // #ifndef COMMON_INPUT_WATCHER_H
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index ba55819..5a5bf5f 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -61,7 +61,7 @@ Keymap *Keymapper::Domain::getKeymap(const String& name) {
 }
 
 Keymapper::Keymapper(EventManager *evtMgr)
-	: _eventMan(evtMgr), _enabled(true), _remapping(false), _hardwareInputs(0), _actionToRemap(0) {
+	: _eventMan(evtMgr), _enabled(true), _hardwareInputs(0) {
 	ConfigManager::Domain *confDom = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
 
 	_globalDomain.setConfigDomain(confDom);
@@ -187,9 +187,7 @@ List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
 	}
 	List<Event> mappedEvents;
 
-	if (_remapping)
-		mappedEvents = remap(ev);
-	else if (ev.type == Common::EVENT_KEYDOWN)
+	if (ev.type == Common::EVENT_KEYDOWN)
 		mappedEvents = mapKeyDown(ev.kbd);
 	else if (ev.type == Common::EVENT_KEYUP)
 		mappedEvents = mapKeyUp(ev.kbd);
@@ -202,13 +200,6 @@ List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
 		return DefaultEventMapper::mapEvent(ev, source);
 }
 
-void Keymapper::startRemappingMode(Action *actionToRemap) {
-	assert(!_remapping);
-
-	_remapping = true;
-	_actionToRemap = actionToRemap;
-}
-
 List<Event> Keymapper::mapKeyDown(const KeyState& key) {
 	return mapKey(key, true);
 }
@@ -345,38 +336,10 @@ const HardwareInput *Keymapper::findHardwareInput(const HardwareInputCode code)
 	return (_hardwareInputs) ? _hardwareInputs->findHardwareInput(code) : 0;
 }
 
-List<Event> Keymapper::remap(const Event &ev) {
-	assert(_remapping);
-	assert(_actionToRemap);
-
-	List<Event> list;
-
-	const HardwareInput *hwInput = 0;
-	Event mappedEvent;
-
-	switch (ev.type) {
-	case EVENT_KEYDOWN:
-		break;
-	case EVENT_KEYUP:
-		hwInput = findHardwareInput(ev.kbd);
-		break;
-	case EVENT_CUSTOM_BACKEND_HARDWARE:
-		hwInput = findHardwareInput(ev.customType);
-		break;
-	default:
-		break;
-	}
-	if (hwInput) {
-		Keymap *keymap = _actionToRemap->getParent();
-		keymap->registerMapping(_actionToRemap, hwInput);
-		keymap->saveMappings();
-
-		_remapping = false;
-		_actionToRemap = 0;
-		mappedEvent.type = EVENT_GUI_REMAP_COMPLETE_ACTION;
-		list.push_back(mappedEvent);
-	}
-	return list;
+void Keymapper::registerMapping(Action *action, const HardwareInput *input) {
+	Keymap *keymap = action->getParent();
+	keymap->registerMapping(action, input);
+	keymap->saveMappings();
 }
 
 void Keymapper::clearMapping(Action *action) {
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index d8b7c43..7c9006d 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -180,24 +180,6 @@ public:
 	void setEnabled(bool enabled) { _enabled = enabled; }
 
 	/**
-	 * @brief Activate remapping mode
-	 * While this mode is active, any mappable event will be bound to the action
-	 * provided.
-	 * @param actionToRemap Action that is the target of the remap
-	 */
-	void startRemappingMode(Action *actionToRemap);
-
-	/**
-	 * @brief Force-stop the remapping mode
-	 */
-	void stopRemappingMode() { _remapping = false; }
-
-	/**
-	 * Query whether the keymapper is currently in the remapping mode
-	 */
-	bool isRemapping() const { return _remapping; }
-
-	/**
 	 * Return a HardwareInput pointer for the given key state
 	 */
 	const HardwareInput *findHardwareInput(const KeyState& key);
@@ -211,6 +193,14 @@ public:
 	Domain& getGameDomain() { return _gameDomain; }
 	const Stack<MapRecord>& getActiveStack() const { return _activeMaps; }
 
+	/**
+	 * Register the binding of a hardware input to an action
+	 */
+	void registerMapping(Action *action, const HardwareInput *input);
+
+	/**
+	 * Unbind hardware inputs from an action
+	 */
 	void clearMapping(Action *action);
 
 private:
@@ -232,14 +222,11 @@ private:
 
 	List<Event> executeAction(const Action *act, IncomingEventType incomingType = kIncomingNonKey);
 	EventType convertDownToUp(EventType eventType);
-	List<Event> remap(const Event &ev);
 
 	EventManager *_eventMan;
 
 	bool _enabled;
-	bool _remapping;
 
-	Action *_actionToRemap;
 	Stack<MapRecord> _activeMaps;
 	HashMap<KeyState, Action *> _keysDown;
 
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index f337048..246c8ef 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -26,6 +26,7 @@
 
 #include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
+#include "backends/keymapper/input-watcher.h"
 
 #include "common/system.h"
 #include "gui/gui-manager.h"
@@ -43,11 +44,14 @@ enum {
 };
 
 RemapDialog::RemapDialog()
-	: Dialog("KeyMapper"), _keymapTable(0), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false) {
+	: Dialog("KeyMapper"), _keymapTable(0), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false), _remapAction(nullptr) {
 
 	_keymapper = g_system->getEventManager()->getKeymapper();
 	assert(_keymapper);
 
+	EventDispatcher *eventDispatcher = g_system->getEventManager()->getEventDispatcher();
+	_remapInputWatcher = new InputWatcher(eventDispatcher, _keymapper);
+
 	_kmPopUpDesc = new GUI::StaticTextWidget(this, "KeyMapper.PopupDesc", _("Keymap:"));
 	_kmPopUp = new GUI::PopUpWidget(this, "KeyMapper.Popup");
 
@@ -61,6 +65,7 @@ RemapDialog::RemapDialog()
 
 RemapDialog::~RemapDialog() {
 	free(_keymapTable);
+	delete _remapInputWatcher;
 }
 
 void RemapDialog::open() {
@@ -254,8 +259,7 @@ void RemapDialog::clearMapping(uint i) {
 	_keymapper->clearMapping(activeRemapAction);
 	_changes = true;
 
-	// force refresh
-	stopRemapping(true);
+	stopRemapping();
 	refreshKeymap();
 }
 
@@ -263,63 +267,47 @@ void RemapDialog::startRemapping(uint i) {
 	if (_topAction + i >= _currentActions.size())
 		return;
 
-	if (_keymapper->isRemapping()) {
+	if (_remapInputWatcher->isWatching()) {
 		// Handle a second click on the button as a stop to remapping
-		stopRemapping(true);
+		stopRemapping();
 		return;
 	}
 
+	_remapAction = _currentActions[_topAction + i].action;
 	_remapTimeout = g_system->getMillis() + kRemapTimeoutDelay;
-	Action *activeRemapAction = _currentActions[_topAction + i].action;
+	_remapInputWatcher->startWatching();
+
 	_keymapWidgets[i].keyButton->setLabel("...");
 	_keymapWidgets[i].keyButton->markAsDirty();
-	_keymapper->startRemappingMode(activeRemapAction);
-
 }
 
-void RemapDialog::stopRemapping(bool force) {
+void RemapDialog::stopRemapping() {
 	_topAction = -1;
+	_remapAction = nullptr;
 
 	refreshKeymap();
 
-	if (force)
-		_keymapper->stopRemappingMode();
+	_remapInputWatcher->stopWatching();
 }
 
-void RemapDialog::handleKeyDown(Common::KeyState state) {
-	if (_keymapper->isRemapping())
-		return;
-
-	GUI::Dialog::handleKeyDown(state);
+void RemapDialog::handleMouseDown(int x, int y, int button, int clickCount) {
+	if (_remapInputWatcher->isWatching())
+		stopRemapping();
+	else
+		Dialog::handleMouseDown(x, y, button, clickCount);
 }
 
-void RemapDialog::handleKeyUp(Common::KeyState state) {
-	if (_keymapper->isRemapping())
-		return;
-
-	GUI::Dialog::handleKeyUp(state);
-}
+void RemapDialog::handleTickle() {
+	const HardwareInput *hardwareInput = _remapInputWatcher->checkForCapturedInput();
+	if (hardwareInput) {
+		_keymapper->registerMapping(_remapAction, hardwareInput);
 
-void RemapDialog::handleOtherEvent(Event ev) {
-	if (ev.type == EVENT_GUI_REMAP_COMPLETE_ACTION) {
-		// _keymapper is telling us that something changed
 		_changes = true;
 		stopRemapping();
-	} else {
-		GUI::Dialog::handleOtherEvent(ev);
 	}
-}
 
-void RemapDialog::handleMouseDown(int x, int y, int button, int clickCount) {
-	if (_keymapper->isRemapping())
+	if (_remapInputWatcher->isWatching() && g_system->getMillis() > _remapTimeout)
 		stopRemapping();
-	else
-		Dialog::handleMouseDown(x, y, button, clickCount);
-}
-
-void RemapDialog::handleTickle() {
-	if (_keymapper->isRemapping() && g_system->getMillis() > _remapTimeout)
-		stopRemapping(true);
 	Dialog::handleTickle();
 }
 
diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h
index 046ccd2..2b72a12 100644
--- a/backends/keymapper/remap-dialog.h
+++ b/backends/keymapper/remap-dialog.h
@@ -41,6 +41,7 @@ namespace Common {
 class Action;
 class Keymap;
 class Keymapper;
+class InputWatcher;
 
 class RemapDialog : public GUI::Dialog {
 public:
@@ -50,11 +51,8 @@ public:
 	virtual void close();
 	virtual void reflowLayout();
 	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
-	virtual void handleKeyDown(Common::KeyState state);
-	virtual void handleKeyUp(Common::KeyState state);
 	virtual void handleMouseDown(int x, int y, int button, int clickCount);
 	virtual void handleTickle();
-	virtual void handleOtherEvent(Common::Event ev);
 
 protected:
 	struct ActionWidgets {
@@ -72,11 +70,15 @@ protected:
 	void refreshKeymap();
 	void clearMapping(uint i);
 	void startRemapping(uint i);
-	void stopRemapping(bool force = false);
+	void stopRemapping();
 
 	Keymapper *_keymapper;
 	Keymap** _keymapTable;
 
+	InputWatcher *_remapInputWatcher;
+	Action *_remapAction;
+	uint32 _remapTimeout;
+
 	Array<ActionInfo> _currentActions;
 	int _topAction;
 
@@ -87,7 +89,6 @@ protected:
 	uint _rowCount;
 
 	Array<ActionWidgets> _keymapWidgets;
-	uint32 _remapTimeout;
 	static const uint32 kRemapTimeoutDelay = 3000;
 
 	bool _changes;
diff --git a/backends/module.mk b/backends/module.mk
index 88acd4c..21bae7e 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -105,6 +105,7 @@ ifdef ENABLE_KEYMAPPER
 MODULE_OBJS += \
 	keymapper/action.o \
 	keymapper/hardware-input.o \
+	keymapper/input-watcher.o \
 	keymapper/keymap.o \
 	keymapper/keymapper.o \
 	keymapper/remap-dialog.o
diff --git a/common/events.h b/common/events.h
index afc81d3..f4ca5bb 100644
--- a/common/events.h
+++ b/common/events.h
@@ -79,7 +79,6 @@ enum EventType {
 	// this, please talk to tsoliman and/or LordHoto.
 	EVENT_CUSTOM_BACKEND_ACTION = 18,
 	EVENT_CUSTOM_BACKEND_HARDWARE = 21,
-	EVENT_GUI_REMAP_COMPLETE_ACTION = 22,
 	EVENT_KEYMAPPER_REMAP = 19,
 #endif
 #ifdef ENABLE_VKEYBD
@@ -516,7 +515,12 @@ public:
 		 * Priority of the event recorder. It has to go after event manager
 		 * in order to record events generated by it
 		 */
-		kEventRecorderPriority = 1
+		kEventRecorderPriority = 1,
+		/**
+		 * Priority of the remap dialog. It has to go first to capture all
+		 * the events before they are consumed by other observers.
+		 */
+		kEventRemapperPriority = 999
 	};
 
 	/**
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index 2ad4c1b..7d88d19 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -364,8 +364,6 @@ void Dialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
 	}
 }
 
-void Dialog::handleOtherEvent(Common::Event evt) { }
-
 /*
  * Determine the widget at location (x,y) if any. Assumes the coordinates are
  * in the local coordinate system, i.e. relative to the top left of the dialog.
diff --git a/gui/dialog.h b/gui/dialog.h
index 8cc4906..eac9974 100644
--- a/gui/dialog.h
+++ b/gui/dialog.h
@@ -102,9 +102,9 @@ protected:
 	virtual void handleKeyDown(Common::KeyState state);
 	virtual void handleKeyUp(Common::KeyState state);
 	virtual void handleMouseMoved(int x, int y, int button);
-	virtual void handleMouseLeft(int button) {};
+	virtual void handleMouseLeft(int button) {}
+	virtual void handleOtherEvent(const Common::Event &evt) {}
 	void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) override;
-	virtual void handleOtherEvent(Common::Event evt);
 
 	Widget *findWidget(int x, int y); // Find the widget at pos x,y if any
 	Widget *findWidget(const char *name);
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 8653f23..0e88a5a 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -510,7 +510,7 @@ void LauncherDialog::handleKeyUp(Common::KeyState state) {
 	updateButtons();
 }
 
-void LauncherDialog::handleOtherEvent(Common::Event evt) {
+void LauncherDialog::handleOtherEvent(const Common::Event &evt) {
 	Dialog::handleOtherEvent(evt);
 	if (evt.type == Common::EVENT_DROP_FILE) {
 		doGameDetection(evt.path);
diff --git a/gui/launcher.h b/gui/launcher.h
index 0461a19..5367d0e 100644
--- a/gui/launcher.h
+++ b/gui/launcher.h
@@ -51,7 +51,7 @@ public:
 
 	void handleKeyDown(Common::KeyState state) override;
 	void handleKeyUp(Common::KeyState state) override;
-	void handleOtherEvent(Common::Event evt) override;
+	void handleOtherEvent(const Common::Event &evt) override;
 	bool doGameDetection(const Common::String &path);
 protected:
 	EditTextWidget  *_searchWidget;


Commit: 930ff55421196d10f9a88272fc987199589f081a
    https://github.com/scummvm/scummvm/commit/930ff55421196d10f9a88272fc987199589f081a
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Simplify the event mapping logic

Changed paths:
    backends/keymapper/input-watcher.cpp
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h


diff --git a/backends/keymapper/input-watcher.cpp b/backends/keymapper/input-watcher.cpp
index 045c725..c457931 100644
--- a/backends/keymapper/input-watcher.cpp
+++ b/backends/keymapper/input-watcher.cpp
@@ -64,13 +64,8 @@ bool InputWatcher::notifyEvent(const Event &event) {
 		case EVENT_KEYDOWN:
 			return true;
 		case EVENT_KEYUP:
-			_hwInput = _keymapper->findHardwareInput(event.kbd);
-			if (_hwInput) {
-				stopWatching();
-			}
-			return true;
 		case EVENT_CUSTOM_BACKEND_HARDWARE:
-			_hwInput = _keymapper->findHardwareInput(event.customType);
+			_hwInput = _keymapper->findHardwareInput(event);
 			if (_hwInput) {
 				stopWatching();
 			}
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 5a5bf5f..153b7ad 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -182,105 +182,57 @@ void Keymapper::popKeymap(const char *name) {
 }
 
 List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
+	if (!_enabled || _activeMaps.empty()) {
+		return DefaultEventMapper::mapEvent(ev, source);
+	}
 	if (source && !source->allowMapping()) {
 		return DefaultEventMapper::mapEvent(ev, source);
 	}
-	List<Event> mappedEvents;
 
-	if (ev.type == Common::EVENT_KEYDOWN)
-		mappedEvents = mapKeyDown(ev.kbd);
-	else if (ev.type == Common::EVENT_KEYUP)
-		mappedEvents = mapKeyUp(ev.kbd);
-	else if (ev.type == Common::EVENT_CUSTOM_BACKEND_HARDWARE)
-		mappedEvents = mapNonKey(ev.customType);
-
-	if (!mappedEvents.empty())
-		return mappedEvents;
-	else
+	const HardwareInput *hwInput = findHardwareInput(ev);
+	if (!hwInput) {
 		return DefaultEventMapper::mapEvent(ev, source);
-}
-
-List<Event> Keymapper::mapKeyDown(const KeyState& key) {
-	return mapKey(key, true);
-}
-
-List<Event> Keymapper::mapKeyUp(const KeyState& key) {
-	return mapKey(key, false);
-}
-
-List<Event> Keymapper::mapKey(const KeyState& key, bool keyDown) {
-	if (!_enabled || _activeMaps.empty())
-		return List<Event>();
-
-	Action *action = 0;
-
-	if (keyDown) {
-		// FIXME: Performance
-		const HardwareInput *hwInput = _hardwareInputs->findHardwareInput(key);
-
-		// Search for key in active keymap stack
-		for (int i = _activeMaps.size() - 1; i >= 0; --i) {
-			MapRecord mr = _activeMaps[i];
-			debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
-			action = mr.keymap->getMappedAction(hwInput);
-
-			if (action || !mr.transparent)
-				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 List<Event>();
-
-	return executeAction(action, keyDown ? kIncomingKeyDown : kIncomingKeyUp);
-}
-
-
-List<Event> Keymapper::mapNonKey(const HardwareInputCode code) {
-	if (!_enabled || _activeMaps.empty())
-		return List<Event>();
-
-	// FIXME: Performance
-	const HardwareInput *hwInput = _hardwareInputs->findHardwareInput(code);
-
-	Action *action = 0;
-
-	// Search for nonkey in active keymap stack
+	List<Event> mappedEvents;
 	for (int i = _activeMaps.size() - 1; i >= 0; --i) {
 		MapRecord mr = _activeMaps[i];
 		debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
-		action = mr.keymap->getMappedAction(hwInput);
 
-		if (action || !mr.transparent)
+		Action *action = mr.keymap->getMappedAction(hwInput);
+		if (action) {
+			IncomingEventType incomingEventType = convertToIncomingEventType(ev);
+			mappedEvents.push_back(executeAction(action, incomingEventType));
+			break;
+		}
+
+		if (!mr.transparent)
 			break;
 	}
 
-	if (!action)
-		return List<Event>();
+	if (mappedEvents.empty()) {
+		return DefaultEventMapper::mapEvent(ev, source);
+	}
 
-	return executeAction(action);
+	return mappedEvents;
 }
 
-List<Event> Keymapper::executeAction(const Action *action, IncomingEventType incomingType) {
-	List<Event> mappedEvents;
+Keymapper::IncomingEventType Keymapper::convertToIncomingEventType(const Event &ev) const {
+	if (ev.type == EVENT_CUSTOM_BACKEND_HARDWARE) {
+		return kIncomingNonKey;
+	} else if (ev.type == EVENT_KEYDOWN) {
+		return kIncomingKeyDown;
+	} else {
+		return kIncomingKeyUp;
+	}
+}
 
+Event Keymapper::executeAction(const Action *action, IncomingEventType incomingType) {
 	Event evt = Event(action->event);
 	EventType convertedType = convertDownToUp(evt.type);
 
 	// hardware keys need to send up instead when they are up
 	if (incomingType == kIncomingKeyUp) {
-		if (convertedType == EVENT_INVALID)
-			return List<Event>(); // don't send any non-down-converted events on up they were already sent on down
 		evt.type = convertedType;
 	}
 
@@ -288,15 +240,12 @@ List<Event> Keymapper::executeAction(const Action *action, IncomingEventType inc
 
 	// Check if the event is coming from a non-key hardware event
 	// that is mapped to a key event
-	if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID)
+	if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID) {
 		// WORKAROUND: Delay the down events coming from non-key hardware events
 		// with a zero delay. This is to prevent DOWN1 DOWN2 UP1 UP2.
 		addDelayedEvent(0, evt);
-	else
-		mappedEvents.push_back(evt);
 
-	// non-keys need to send up as well
-	if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID) {
+		// non-keys need to send up as well
 		// WORKAROUND: Delay the up events coming from non-key hardware events
 		// This is for engines that run scripts that check on key being down
 		evt.type = convertedType;
@@ -304,7 +253,7 @@ List<Event> Keymapper::executeAction(const Action *action, IncomingEventType inc
 		addDelayedEvent(delay, evt);
 	}
 
-	return mappedEvents;
+	return evt;
 }
 
 EventType Keymapper::convertDownToUp(EventType type) {
@@ -328,12 +277,17 @@ EventType Keymapper::convertDownToUp(EventType type) {
 	return result;
 }
 
-const HardwareInput *Keymapper::findHardwareInput(const KeyState& key) {
-	return (_hardwareInputs) ? _hardwareInputs->findHardwareInput(key) : 0;
-}
-
-const HardwareInput *Keymapper::findHardwareInput(const HardwareInputCode code) {
-	return (_hardwareInputs) ? _hardwareInputs->findHardwareInput(code) : 0;
+const HardwareInput *Keymapper::findHardwareInput(const Event &event) {
+	// FIXME: Performance
+	switch (event.type) {
+		case EVENT_KEYDOWN:
+		case EVENT_KEYUP:
+			return _hardwareInputs->findHardwareInput(event.kbd);
+		case EVENT_CUSTOM_BACKEND_HARDWARE:
+			return _hardwareInputs->findHardwareInput(event.customType);
+		default:
+			return nullptr;
+	}
 }
 
 void Keymapper::registerMapping(Action *action, const HardwareInput *input) {
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index 7c9006d..ea3b342 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -152,42 +152,14 @@ public:
 	void popKeymap(const char *name = 0);
 
 	/**
-	 * @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			mapped events
-	 */
-	List<Event> mapKey(const KeyState& key, bool keyDown);
-	List<Event> mapNonKey(const HardwareInputCode code);
-
-	/**
-	 * @brief Map a key down event.
-	 * @see mapKey
-	 */
-	List<Event> mapKeyDown(const KeyState& key);
-
-	/**
-	 * @brief Map a key up event.
-	 * @see mapKey
-	 */
-	List<Event> mapKeyUp(const KeyState& key);
-
-	/**
 	 * Enable/disable the keymapper
 	 */
 	void setEnabled(bool enabled) { _enabled = enabled; }
 
 	/**
-	 * Return a HardwareInput pointer for the given key state
-	 */
-	const HardwareInput *findHardwareInput(const KeyState& key);
-
-	/**
-	 * Return a HardwareInput pointer for the given input code
+	 * Return a HardwareInput pointer for the given event
 	 */
-	const HardwareInput *findHardwareInput(const HardwareInputCode code);
+	const HardwareInput *findHardwareInput(const Event &event);
 
 	Domain& getGlobalDomain() { return _globalDomain; }
 	Domain& getGameDomain() { return _gameDomain; }
@@ -220,15 +192,15 @@ private:
 
 	void pushKeymap(Keymap *newMap, bool transparent, bool global);
 
-	List<Event> executeAction(const Action *act, IncomingEventType incomingType = kIncomingNonKey);
+	Event executeAction(const Action *act, IncomingEventType incomingType);
 	EventType convertDownToUp(EventType eventType);
+	IncomingEventType convertToIncomingEventType(const Event &ev) const;
 
 	EventManager *_eventMan;
 
 	bool _enabled;
 
 	Stack<MapRecord> _activeMaps;
-	HashMap<KeyState, Action *> _keysDown;
 
 };
 


Commit: ada44ca760e6353681be9df5ae3ea46e1659eb59
    https://github.com/scummvm/scummvm/commit/ada44ca760e6353681be9df5ae3ea46e1659eb59
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
GUI: Remove unneeded includes

Changed paths:
    gui/EventRecorder.h
    gui/dialog.cpp


diff --git a/gui/EventRecorder.h b/gui/EventRecorder.h
index eb38769..c2c4d6a 100644
--- a/gui/EventRecorder.h
+++ b/gui/EventRecorder.h
@@ -36,7 +36,6 @@
 #include "common/mutex.h"
 #include "common/array.h"
 #include "common/memstream.h"
-#include "backends/keymapper/keymapper.h"
 #include "backends/mixer/sdl/sdl-mixer.h"
 #include "common/hashmap.h"
 #include "common/hash-str.h"
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index 7d88d19..8ca61a6 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -21,7 +21,6 @@
  */
 
 #include "common/rect.h"
-#include "common/events.h"
 
 #include "gui/gui-manager.h"
 #include "gui/dialog.h"


Commit: ac44469558bfc95f1dc97796e06f99325c9b1a8e
    https://github.com/scummvm/scummvm/commit/ac44469558bfc95f1dc97796e06f99325c9b1a8e
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Remove the domain class

Changed paths:
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    backends/keymapper/remap-dialog.cpp
    backends/keymapper/remap-dialog.h
    base/main.cpp
    engines/kyra/engine/eobcommon.cpp
    engines/kyra/engine/lol.cpp
    engines/mohawk/riven.cpp
    engines/pegasus/pegasus.cpp
    gui/gui-manager.cpp


diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index 7ff611c..7cef4d1 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -33,7 +33,11 @@
 
 namespace Common {
 
-Keymap::Keymap(const Keymap& km) : _actions(km._actions), _hwActionMap(), _configDomain(0) {
+Keymap::Keymap(KeymapType type, const String &name) :
+		_type(type),
+		_name(name),
+		_configDomain(nullptr) {
+
 }
 
 Keymap::~Keymap() {
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
index a4e53e3..2c1a458 100644
--- a/backends/keymapper/keymap.h
+++ b/backends/keymapper/keymap.h
@@ -41,11 +41,15 @@ class HardwareInputSet;
 
 class Keymap {
 public:
-	Keymap(const String& name) : _name(name) {}
-	Keymap(const Keymap& km);
+	enum KeymapType {
+		kKeymapTypeGlobal,
+		kKeymapTypeGui,
+		kKeymapTypeGame
+	};
+
+	Keymap(KeymapType type, const String &name);
 	~Keymap();
 
-public:
 	/**
 	* Registers a HardwareInput to the given Action
 	* @param action Action in this Keymap
@@ -95,6 +99,8 @@ public:
 
 	const String& getName() { return _name; }
 
+	KeymapType getType() const { return _type; }
+
 private:
 	friend struct Action;
 
@@ -110,6 +116,7 @@ private:
 	typedef List<Action *> ActionList;
 	typedef HashMap<const HardwareInput *, Action *> HardwareActionMap;
 
+	KeymapType _type;
 	String _name;
 	ActionList _actions;
 	HardwareActionMap _hwActionMap;
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 153b7ad..7b8c850 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -35,36 +35,8 @@ namespace Common {
 static const uint32 kDelayKeyboardEventMillis = 250;
 static const uint32 kDelayMouseEventMillis = 50;
 
-void Keymapper::Domain::addKeymap(Keymap *map) {
-	iterator it = find(map->getName());
-
-	if (it != end())
-		delete it->_value;
-
-	setVal(map->getName(), map);
-}
-
-void Keymapper::Domain::deleteAllKeyMaps() {
-	for (iterator it = begin(); it != end(); ++it)
-		delete it->_value;
-
-	clear();
-}
-
-Keymap *Keymapper::Domain::getKeymap(const String& name) {
-	iterator it = find(name);
-
-	if (it != end())
-		return it->_value;
-	else
-		return 0;
-}
-
 Keymapper::Keymapper(EventManager *evtMgr)
 	: _eventMan(evtMgr), _enabled(true), _hardwareInputs(0) {
-	ConfigManager::Domain *confDom = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
-
-	_globalDomain.setConfigDomain(confDom);
 }
 
 Keymapper::~Keymapper() {
@@ -84,84 +56,89 @@ void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) {
 }
 
 void Keymapper::addGlobalKeymap(Keymap *keymap) {
-	initKeymap(_globalDomain, keymap);
+	assert(keymap->getType() == Keymap::kKeymapTypeGlobal
+	       || keymap->getType() == Keymap::kKeymapTypeGui);
+
+	ConfigManager::Domain *keymapperDomain = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
+	initKeymap(keymap, keymapperDomain);
 }
 
 void Keymapper::addGameKeymap(Keymap *keymap) {
-	if (ConfMan.getActiveDomain() == 0)
-		error("Call to Keymapper::addGameKeymap when no game loaded");
+	assert(keymap->getType() == Keymap::kKeymapTypeGame);
+
+	ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain();
 
-	// Detect whether the active game changed since last call.
-	// If so, flush the game key configuration.
-	if (_gameDomain.getConfigDomain() != ConfMan.getActiveDomain()) {
-		cleanupGameKeymaps();
-		_gameDomain.setConfigDomain(ConfMan.getActiveDomain());
+	if (!gameDomain) {
+		error("Call to Keymapper::addGameKeymap when no game loaded");
 	}
 
-	initKeymap(_gameDomain, keymap);
+	cleanupGameKeymaps();
+
+	initKeymap(keymap, gameDomain);
 }
 
-void Keymapper::initKeymap(Domain &domain, Keymap *map) {
+void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
 	if (!_hardwareInputs) {
-		warning("No hardware inputs were registered yet (%s)", map->getName().c_str());
+		warning("No hardware inputs were registered yet (%s)", keymap->getName().c_str());
 		return;
 	}
 
-	map->setConfigDomain(domain.getConfigDomain());
-	map->loadMappings(_hardwareInputs);
+	keymap->setConfigDomain(domain);
+	keymap->loadMappings(_hardwareInputs);
 
-	domain.addKeymap(map);
+	_keymaps.push_back(keymap);
 }
 
 void Keymapper::cleanupGameKeymaps() {
 	// Flush all game specific keymaps
-	_gameDomain.deleteAllKeyMaps();
+	KeymapArray::iterator it = _keymaps.begin();
+	while (it != _keymaps.end()) {
+		if ((*it)->getType() == Keymap::kKeymapTypeGame) {
+			delete *it;
+			it = _keymaps.erase(it);
+		} else {
+			it++;
+		}
+	}
 
 	// Now restore the stack of active maps. Re-add all global keymaps, drop
 	// the game specific (=deleted) ones.
 	Stack<MapRecord> newStack;
 
 	for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) {
-		if (_activeMaps[i].global)
+		if (_activeMaps[i].keymap->getType() == Keymap::kKeymapTypeGlobal)
 			newStack.push(_activeMaps[i]);
 	}
 
 	_activeMaps = newStack;
 }
 
-Keymap *Keymapper::getKeymap(const String& name, bool *globalReturn) {
-	Keymap *keymap = _gameDomain.getKeymap(name);
-	bool global = false;
-
-	if (!keymap) {
-		keymap = _globalDomain.getKeymap(name);
-		global = true;
+Keymap *Keymapper::getKeymap(const String &name) {
+	for (KeymapArray::const_iterator it = _keymaps.begin(); it != _keymaps.end(); it++) {
+		if ((*it)->getName() == name) {
+			return *it;
+		}
 	}
 
-	if (globalReturn)
-		*globalReturn = global;
-
-	return keymap;
+	return nullptr;
 }
 
-bool Keymapper::pushKeymap(const String& name, bool transparent) {
-	bool global;
-
+bool Keymapper::pushKeymap(const String &name, bool transparent) {
 	assert(!name.empty());
-	Keymap *newMap = getKeymap(name, &global);
+	Keymap *newMap = getKeymap(name);
 
 	if (!newMap) {
 		warning("Keymap '%s' not registered", name.c_str());
 		return false;
 	}
 
-	pushKeymap(newMap, transparent, global);
+	pushKeymap(newMap, transparent);
 
 	return true;
 }
 
-void Keymapper::pushKeymap(Keymap *newMap, bool transparent, bool global) {
-	MapRecord mr = {newMap, transparent, global};
+void Keymapper::pushKeymap(Keymap *newMap, bool transparent) {
+	MapRecord mr = {newMap, transparent};
 
 	_activeMaps.push(mr);
 }
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index ea3b342..af4cea5 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -56,33 +56,6 @@ public:
 	struct MapRecord {
 		Keymap* keymap;
 		bool transparent;
-		bool global;
-	};
-
-	/* Nested class that represents a set of keymaps */
-	class Domain : public HashMap<String, Keymap*,
-				IgnoreCase_Hash, IgnoreCase_EqualTo>  {
-	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);
-
-	private:
-		ConfigManager::Domain *_configDomain;
 	};
 
 	Keymapper(EventManager *eventMan);
@@ -129,9 +102,10 @@ public:
 	 * 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 = 0);
+	Keymap *getKeymap(const String &name);
+
+	const Array<Keymap *> &getKeymaps() const { return _keymaps; }
 
 	/**
 	 * Push a new keymap to the top of the active stack, activating
@@ -161,8 +135,6 @@ public:
 	 */
 	const HardwareInput *findHardwareInput(const Event &event);
 
-	Domain& getGlobalDomain() { return _globalDomain; }
-	Domain& getGameDomain() { return _gameDomain; }
 	const Stack<MapRecord>& getActiveStack() const { return _activeMaps; }
 
 	/**
@@ -183,14 +155,11 @@ private:
 		kIncomingNonKey
 	};
 
-	void initKeymap(Domain &domain, Keymap *keymap);
-
-	Domain _globalDomain;
-	Domain _gameDomain;
+	void initKeymap(Keymap *keymap, ConfigManager::Domain *domain);
 
 	HardwareInputSet *_hardwareInputs;
 
-	void pushKeymap(Keymap *newMap, bool transparent, bool global);
+	void pushKeymap(Keymap *newMap, bool transparent);
 
 	Event executeAction(const Action *act, IncomingEventType incomingType);
 	EventType convertDownToUp(EventType eventType);
@@ -200,6 +169,9 @@ private:
 
 	bool _enabled;
 
+	typedef Array<Keymap *> KeymapArray;
+	KeymapArray _keymaps;
+
 	Stack<MapRecord> _activeMaps;
 
 };
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index 246c8ef..eaf43f9 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -44,7 +44,7 @@ enum {
 };
 
 RemapDialog::RemapDialog()
-	: Dialog("KeyMapper"), _keymapTable(0), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false), _remapAction(nullptr) {
+	: Dialog("KeyMapper"), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false), _remapAction(nullptr) {
 
 	_keymapper = g_system->getEventManager()->getKeymapper();
 	assert(_keymapper);
@@ -64,81 +64,17 @@ RemapDialog::RemapDialog()
 }
 
 RemapDialog::~RemapDialog() {
-	free(_keymapTable);
 	delete _remapInputWatcher;
 }
 
 void RemapDialog::open() {
-	const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack();
+	_keymapTable = _keymapper->getKeymaps();
 
-	if (activeKeymaps.size() > 0) {
-		if (activeKeymaps.top().keymap->getName() == Common::kGuiKeymapName)
-			_topKeymapIsGui = true;
-		// Add the entry for the "effective" special view. See RemapDialog::loadKeymap()
-		_kmPopUp->appendEntry(activeKeymaps.top().keymap->getName() + _(" (Effective)"));
-	}
-
-	Keymapper::Domain *_globalKeymaps = &_keymapper->getGlobalDomain();
-	Keymapper::Domain *_gameKeymaps = 0;
-
-	int keymapCount = 0;
-
-	if (_globalKeymaps->empty())
-		_globalKeymaps = 0;
-	else
-		keymapCount += _globalKeymaps->size();
-
-	if (ConfMan.getActiveDomain() != 0) {
-		_gameKeymaps = &_keymapper->getGameDomain();
-
-		if (_gameKeymaps->empty())
-			_gameKeymaps = 0;
-		else
-			keymapCount += _gameKeymaps->size();
-	}
-
-	if (activeKeymaps.size() > 1) {
-		keymapCount += activeKeymaps.size() - 1;
-	}
+	debug(3, "RemapDialog::open keymaps: %d", _keymapTable.size());
 
-	debug(3, "RemapDialog::open keymaps: %d", keymapCount);
-
-	_keymapTable = (Keymap **)malloc(sizeof(Keymap *) * keymapCount);
-
-	Keymapper::Domain::iterator it;
-	uint32 idx = 0;
-
-	if (activeKeymaps.size() > 1) {
-		int topIndex = activeKeymaps.size() - 1;
-		bool active = activeKeymaps[topIndex].transparent;
-		for (int i = topIndex - 1; i >= 0; --i) {
-			Keymapper::MapRecord mr = activeKeymaps[i];
-			// Add an entry for each keymap in the stack after the top keymap. Mark it Active if it is
-			// reachable or Blocked if an opaque keymap is on top of it thus blocking access to it.
-			_kmPopUp->appendEntry(mr.keymap->getName() + (active ? _(" (Active)") : _(" (Blocked)")), idx);
-			_keymapTable[idx++] = mr.keymap;
-			active &= mr.transparent;
-		}
-	}
-
-	_kmPopUp->appendEntry("");
-
-	// Now add entries for all known keymaps. Note that there will be duplicates with the stack entries.
-
-	if (_globalKeymaps) {
-		for (it = _globalKeymaps->begin(); it != _globalKeymaps->end(); ++it) {
-			// "global" means its keybindings apply to all games; saved in a global conf domain
-			_kmPopUp->appendEntry(it->_value->getName() + _(" (Global)"), idx);
-			_keymapTable[idx++] = it->_value;
-		}
-	}
-
-	if (_gameKeymaps) {
-		for (it = _gameKeymaps->begin(); it != _gameKeymaps->end(); ++it) {
-			// "game" means its keybindings are saved per-target
-			_kmPopUp->appendEntry(it->_value->getName() + _(" (Game)"), idx);
-			_keymapTable[idx++] = it->_value;
-		}
+	// Show the keymaps by order of priority (game keymaps first)
+	for (int i = _keymapTable.size() - 1; i >= 0; i--) {
+		_kmPopUp->appendEntry(_keymapTable[i]->getName(), i);
 	}
 
 	_changes = false;
@@ -152,9 +88,6 @@ void RemapDialog::open() {
 void RemapDialog::close() {
 	_kmPopUp->clearEntries();
 
-	free(_keymapTable);
-	_keymapTable = 0;
-
 	if (_changes)
 		ConfMan.flushToDisk();
 
@@ -255,7 +188,7 @@ void RemapDialog::clearMapping(uint i) {
 		return;
 
 	debug(3, "clear the mapping %u", i);
-	Action *activeRemapAction = _currentActions[_topAction + i].action;
+	Action *activeRemapAction = _currentActions[_topAction + i];
 	_keymapper->clearMapping(activeRemapAction);
 	_changes = true;
 
@@ -273,7 +206,7 @@ void RemapDialog::startRemapping(uint i) {
 		return;
 	}
 
-	_remapAction = _currentActions[_topAction + i].action;
+	_remapAction = _currentActions[_topAction + i];
 	_remapTimeout = g_system->getMillis() + kRemapTimeoutDelay;
 	_remapInputWatcher->startWatching();
 
@@ -313,64 +246,8 @@ void RemapDialog::handleTickle() {
 
 void RemapDialog::loadKeymap() {
 	_currentActions.clear();
-	const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack();
-
-	debug(3, "RemapDialog::loadKeymap active keymaps: %u", activeKeymaps.size());
-
-	if (!activeKeymaps.empty() && _kmPopUp->getSelected() == 0) {
-		// This is the "effective" view which shows all effective actions:
-		// - all of the topmost keymap action
-		// - all mapped actions that are reachable
-
-		List<const HardwareInput *> freeInputs(_keymapper->getHardwareInputs());
-
-		int topIndex = activeKeymaps.size() - 1;
-
-		// This is a WORKAROUND for changing the popup list selected item and changing it back
-		// to the top entry. Upon changing it back, the top keymap is always "gui".
-		if (!_topKeymapIsGui && activeKeymaps[topIndex].keymap->getName() == kGuiKeymapName)
-			--topIndex;
 
-		// add most active keymap's keys
-		Keymapper::MapRecord top = activeKeymaps[topIndex];
-		List<Action *>::iterator actIt;
-		debug(3, "RemapDialog::loadKeymap top keymap: %s", top.keymap->getName().c_str());
-		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);
-
-			const HardwareInput *mappedInput = top.keymap->getActionMapping(act);
-			if (mappedInput)
-				freeInputs.remove(mappedInput);
-		}
-
-		// loop through remaining finding mappings for unmapped keys
-		if (top.transparent && topIndex >= 0) {
-			for (int i = topIndex - 1; i >= 0; --i) {
-				Keymapper::MapRecord mr = activeKeymaps[i];
-				debug(3, "RemapDialog::loadKeymap keymap: %s", mr.keymap->getName().c_str());
-				List<const HardwareInput *>::iterator inputIt = freeInputs.begin();
-				const HardwareInput *input = *inputIt;
-				while (inputIt != freeInputs.end()) {
-
-					Action *act = mr.keymap->getMappedAction(input);
-					if (act) {
-						ActionInfo info = {act, true, act->description + " (" + mr.keymap->getName() + ")"};
-						_currentActions.push_back(info);
-						freeInputs.erase(inputIt);
-					} else {
-						++inputIt;
-					}
-				}
-
-				if (mr.transparent == false || freeInputs.empty())
-					break;
-			}
-		}
-
-	} else if (_kmPopUp->getSelected() != -1) {
+	if (_kmPopUp->getSelected() != -1) {
 		// This is the regular view of a keymap that isn't the topmost one.
 		// It shows all of that keymap's actions
 
@@ -379,9 +256,7 @@ void RemapDialog::loadKeymap() {
 		List<Action *>::iterator it;
 
 		for (it = km->getActions().begin(); it != km->getActions().end(); ++it) {
-			ActionInfo info = {*it, false, (*it)->description};
-
-			_currentActions.push_back(info);
+			_currentActions.push_back(*it);
 		}
 	}
 
@@ -409,18 +284,17 @@ void RemapDialog::refreshKeymap() {
 	uint actionI = _topAction;
 
 	for (uint widgetI = 0; widgetI < _keymapWidgets.size(); widgetI++) {
-		ActionWidgets& widg = _keymapWidgets[widgetI];
+		ActionWidgets &widg = _keymapWidgets[widgetI];
 
 		if (actionI < _currentActions.size()) {
 			debug(8, "RemapDialog::refreshKeymap actionI=%u", actionI);
-			ActionInfo&    info = _currentActions[actionI];
+			Action *action = _currentActions[actionI];
 
-			widg.actionText->setLabel(info.description);
-			widg.actionText->setEnabled(!info.inherited);
+			widg.actionText->setLabel(action->description);
 
-			Keymap *keymap = info.action->getParent();
+			Keymap *keymap = action->getParent();
 
-			const HardwareInput *mappedInput = keymap->getActionMapping(info.action);
+			const HardwareInput *mappedInput = keymap->getActionMapping(action);
 			if (mappedInput)
 				widg.keyButton->setLabel(mappedInput->description);
 			else
@@ -436,11 +310,9 @@ void RemapDialog::refreshKeymap() {
 			widg.keyButton->setVisible(false);
 			widg.clearButton->setVisible(false);
 		}
-		//widg.actionText->markAsDirty();
-		//widg.keyButton->markAsDirty();
 	}
-	// need to redraw entire Dialog so that invisible
-	// widgets disappear
+
+	// need to redraw entire Dialog so that invisible widgets disappear
 	g_gui.scheduleTopDialogRedraw();
 }
 
diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h
index 2b72a12..58fcf8c 100644
--- a/backends/keymapper/remap-dialog.h
+++ b/backends/keymapper/remap-dialog.h
@@ -60,11 +60,6 @@ protected:
 		GUI::ButtonWidget *keyButton;
 		GUI::ButtonWidget *clearButton;
 	};
-	struct ActionInfo {
-		Action *action;
-		bool inherited;
-		String description;
-	};
 
 	void loadKeymap();
 	void refreshKeymap();
@@ -73,13 +68,13 @@ protected:
 	void stopRemapping();
 
 	Keymapper *_keymapper;
-	Keymap** _keymapTable;
+	Common::Array<Keymap *> _keymapTable;
 
 	InputWatcher *_remapInputWatcher;
 	Action *_remapAction;
 	uint32 _remapTimeout;
 
-	Array<ActionInfo> _currentActions;
+	Array<Action *> _currentActions;
 	int _topAction;
 
 	GUI::StaticTextWidget *_kmPopUpDesc;
diff --git a/base/main.cpp b/base/main.cpp
index ac5b65a..afe78ea 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -360,7 +360,7 @@ static void setupKeymapper(OSystem &system) {
 	mapper->registerHardwareInputSet(inputSet);
 
 	// Now create the global keymap
-	Keymap *primaryGlobalKeymap = new Keymap(kGlobalKeymapName);
+	Keymap *primaryGlobalKeymap = new Keymap(Keymap::kKeymapTypeGlobal, kGlobalKeymapName);
 	Action *act;
 	act = new Action(primaryGlobalKeymap, "MENU", _("Menu"));
 	act->setEvent(EVENT_MAINMENU);
diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp
index 6e5349c..14f83b1 100644
--- a/engines/kyra/engine/eobcommon.cpp
+++ b/engines/kyra/engine/eobcommon.cpp
@@ -351,7 +351,7 @@ void EoBCoreEngine::initKeymap() {
 	if (mapper->getKeymap(kKeymapName) != 0)
 		return;
 
-	Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	const Common::KeyActionEntry keyActionEntries[] = {
 		{ Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward") },
diff --git a/engines/kyra/engine/lol.cpp b/engines/kyra/engine/lol.cpp
index 81cc26d..c5d4fb0 100644
--- a/engines/kyra/engine/lol.cpp
+++ b/engines/kyra/engine/lol.cpp
@@ -473,7 +473,7 @@ void LoLEngine::initKeymap() {
 	if (mapper->getKeymap(kKeymapName) != 0)
 		return;
 
-	Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	const Common::KeyActionEntry keyActionEntries[] = {
 		{Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1), "AT1", _("Attack 1")},
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 93abc05..2cf239a 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -882,7 +882,7 @@ void MohawkEngine_Riven::initKeymap() {
 	if (mapper->getKeymap(kKeymapName) != 0)
 		return;
 
-	Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	const Common::KeyActionEntry keyActionEntries[] = {
 		{ Common::KEYCODE_UP, "UP", _("Move Forward") },
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 06e1103..0125955 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -2498,7 +2498,7 @@ void PegasusEngine::initKeymap() {
 	if (mapper->getKeymap(kKeymapName) != 0)
 		return;
 
-	Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	// Since the game has multiple built-in keys for each of these anyway,
 	// this just attempts to remap one of them.
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index f53b382..6f8c8c6 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -119,7 +119,7 @@ void GuiManager::initKeymap() {
 		return;
 
 	Action *act;
-	Keymap *guiMap = new Keymap(kGuiKeymapName);
+	Keymap *guiMap = new Keymap(Keymap::kKeymapTypeGui, kGuiKeymapName);
 
 	act = new Action(guiMap, "CLOS", _("Close"));
 	act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));


Commit: 9c0bc2b63306d07f183f9d511a630165da443856
    https://github.com/scummvm/scummvm/commit/9c0bc2b63306d07f183f9d511a630165da443856
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Simplify the way keymaps are enabled and disabled

Changed paths:
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    backends/keymapper/remap-dialog.cpp
    base/main.cpp
    engines/kyra/engine/eobcommon.cpp
    engines/kyra/engine/lol.cpp
    engines/kyra/gui/gui_eob.cpp
    engines/kyra/gui/gui_lol.cpp
    engines/mohawk/riven.cpp
    engines/pegasus/pegasus.cpp
    gui/gui-manager.cpp
    gui/gui-manager.h


diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index 7cef4d1..4f90a69 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -36,7 +36,8 @@ namespace Common {
 Keymap::Keymap(KeymapType type, const String &name) :
 		_type(type),
 		_name(name),
-		_configDomain(nullptr) {
+		_configDomain(nullptr),
+		_enabled(true) {
 
 }
 
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
index 2c1a458..5baadb2 100644
--- a/backends/keymapper/keymap.h
+++ b/backends/keymapper/keymap.h
@@ -80,7 +80,7 @@ public:
 	/**
 	 * Get the list of all the Actions contained in this Keymap
 	 */
-	List<Action *>& getActions() { return _actions; }
+	List<Action *> &getActions() { return _actions; }
 
 	void setConfigDomain(ConfigManager::Domain *dom);
 
@@ -97,10 +97,15 @@ public:
 	 */
 	void saveMappings();
 
-	const String& getName() { return _name; }
-
+	const String &getName() { return _name; }
 	KeymapType getType() const { return _type; }
 
+	/**
+	 * Defines if the keymap is considered when mapping events
+	 */
+	bool isEnabled() const { return _enabled; }
+	void setEnabled(bool enabled) { _enabled = enabled; }
+
 private:
 	friend struct Action;
 
@@ -118,6 +123,9 @@ private:
 
 	KeymapType _type;
 	String _name;
+
+	bool _enabled;
+
 	ActionList _actions;
 	HardwareActionMap _hwActionMap;
 	ConfigManager::Domain *_configDomain;
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 7b8c850..0fbb734 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -25,8 +25,8 @@
 #ifdef ENABLE_KEYMAPPER
 
 #include "backends/keymapper/action.h"
+#include "backends/keymapper/hardware-input.h"
 
-#include "common/config-manager.h"
 #include "common/system.h"
 
 namespace Common {
@@ -35,8 +35,11 @@ namespace Common {
 static const uint32 kDelayKeyboardEventMillis = 250;
 static const uint32 kDelayMouseEventMillis = 50;
 
-Keymapper::Keymapper(EventManager *evtMgr)
-	: _eventMan(evtMgr), _enabled(true), _hardwareInputs(0) {
+Keymapper::Keymapper(EventManager *evtMgr) :
+		_eventMan(evtMgr),
+		_enabled(true),
+		_enabledKeymapType(Keymap::kKeymapTypeGlobal),
+		_hardwareInputs(nullptr) {
 }
 
 Keymapper::~Keymapper() {
@@ -61,6 +64,9 @@ void Keymapper::addGlobalKeymap(Keymap *keymap) {
 
 	ConfigManager::Domain *keymapperDomain = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
 	initKeymap(keymap, keymapperDomain);
+
+	// Global keymaps have the lowest priority, they need to be first in the array
+	_keymaps.insert_at(0, keymap);
 }
 
 void Keymapper::addGameKeymap(Keymap *keymap) {
@@ -72,9 +78,8 @@ void Keymapper::addGameKeymap(Keymap *keymap) {
 		error("Call to Keymapper::addGameKeymap when no game loaded");
 	}
 
-	cleanupGameKeymaps();
-
 	initKeymap(keymap, gameDomain);
+	_keymaps.push_back(keymap);
 }
 
 void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
@@ -85,8 +90,6 @@ void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
 
 	keymap->setConfigDomain(domain);
 	keymap->loadMappings(_hardwareInputs);
-
-	_keymaps.push_back(keymap);
 }
 
 void Keymapper::cleanupGameKeymaps() {
@@ -100,17 +103,6 @@ void Keymapper::cleanupGameKeymaps() {
 			it++;
 		}
 	}
-
-	// Now restore the stack of active maps. Re-add all global keymaps, drop
-	// the game specific (=deleted) ones.
-	Stack<MapRecord> newStack;
-
-	for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) {
-		if (_activeMaps[i].keymap->getType() == Keymap::kKeymapTypeGlobal)
-			newStack.push(_activeMaps[i]);
-	}
-
-	_activeMaps = newStack;
 }
 
 Keymap *Keymapper::getKeymap(const String &name) {
@@ -123,43 +115,12 @@ Keymap *Keymapper::getKeymap(const String &name) {
 	return nullptr;
 }
 
-bool Keymapper::pushKeymap(const String &name, bool transparent) {
-	assert(!name.empty());
-	Keymap *newMap = getKeymap(name);
-
-	if (!newMap) {
-		warning("Keymap '%s' not registered", name.c_str());
-		return false;
-	}
-
-	pushKeymap(newMap, transparent);
-
-	return true;
-}
-
-void Keymapper::pushKeymap(Keymap *newMap, bool transparent) {
-	MapRecord mr = {newMap, transparent};
-
-	_activeMaps.push(mr);
-}
-
-void Keymapper::popKeymap(const char *name) {
-	if (!_activeMaps.empty()) {
-		if (name) {
-			String topKeymapName = _activeMaps.top().keymap->getName();
-			if (topKeymapName.equals(name))
-				_activeMaps.pop();
-			else
-				warning("An attempt to pop wrong keymap was blocked (expected %s but was %s)", name, topKeymapName.c_str());
-		} else {
-			_activeMaps.pop();
-		}
-	}
-
+void Keymapper::setEnabledKeymapType(Keymap::KeymapType type) {
+	_enabledKeymapType = type;
 }
 
 List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
-	if (!_enabled || _activeMaps.empty()) {
+	if (!_enabled) {
 		return DefaultEventMapper::mapEvent(ev, source);
 	}
 	if (source && !source->allowMapping()) {
@@ -172,19 +133,24 @@ List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
 	}
 
 	List<Event> mappedEvents;
-	for (int i = _activeMaps.size() - 1; i >= 0; --i) {
-		MapRecord mr = _activeMaps[i];
-		debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
+	for (int i = _keymaps.size() - 1; i >= 0; --i) {
+		if (!_keymaps[i]->isEnabled()) {
+			continue;
+		}
+
+		Keymap::KeymapType keymapType = _keymaps[i]->getType();
+		if (keymapType != _enabledKeymapType && keymapType != Keymap::kKeymapTypeGlobal) {
+			continue; // Ignore GUI keymaps while in game and vice versa
+		}
 
-		Action *action = mr.keymap->getMappedAction(hwInput);
+		debug(5, "Keymapper::mapKey keymap: %s", _keymaps[i]->getName().c_str());
+
+		Action *action = _keymaps[i]->getMappedAction(hwInput);
 		if (action) {
 			IncomingEventType incomingEventType = convertToIncomingEventType(ev);
 			mappedEvents.push_back(executeAction(action, incomingEventType));
 			break;
 		}
-
-		if (!mr.transparent)
-			break;
 	}
 
 	if (mappedEvents.empty()) {
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index af4cea5..417177f 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -27,37 +27,24 @@
 
 #ifdef ENABLE_KEYMAPPER
 
-#include "common/events.h"
-#include "common/list.h"
-#include "common/hashmap.h"
-#include "common/stack.h"
-#include "backends/keymapper/hardware-input.h"
 #include "backends/keymapper/keymap.h"
 
+#include "common/array.h"
+#include "common/config-manager.h"
+#include "common/events.h"
+
 namespace Common {
 
 const char *const kGuiKeymapName = "gui";
 const char *const kGlobalKeymapName = "global";
 
-/**
- * Hash function for KeyState
- */
-template<> struct Hash<KeyState>
-		: public UnaryFunction<KeyState, uint> {
-
-	uint operator()(const KeyState &val) const {
-		return (uint)val.keycode | ((uint)val.flags << 24);
-	}
-};
+class Action;
+class HardwareInput;
+class HardwareInputSet;
 
 class Keymapper : public Common::DefaultEventMapper {
 public:
 
-	struct MapRecord {
-		Keymap* keymap;
-		bool transparent;
-	};
-
 	Keymapper(EventManager *eventMan);
 	~Keymapper();
 
@@ -71,14 +58,6 @@ public:
 	void registerHardwareInputSet(HardwareInputSet *inputs);
 
 	/**
-	 * Get a list of all registered HardwareInputs
-	 */
-	const List<const HardwareInput *> &getHardwareInputs() const {
-		assert(_hardwareInputs);
-		return _hardwareInputs->getHardwareInputs();
-	}
-
-	/**
 	 * 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.
@@ -105,25 +84,17 @@ public:
 	 */
 	Keymap *getKeymap(const String &name);
 
-	const Array<Keymap *> &getKeymaps() const { return _keymaps; }
-
 	/**
-	 * Push a new keymap to the top of the active stack, activating
-	 * it for use.
-	 * @param name			name of the keymap to push
-	 * @param transparent	if true keymapper will iterate down the
-	 *						stack if it cannot find a key in the new map
-	 * @return				true if successful
+	 * Obtain a list of all the keymaps registered with the keymapper
 	 */
-	bool pushKeymap(const String& name, bool transparent = false);
+	const Array<Keymap *> &getKeymaps() const { return _keymaps; }
 
 	/**
-	 * Pop the top keymap off the active stack.
-	 * @param name	(optional) name of keymap expected to be popped
-	 * 				if provided, will not pop unless name is the same
-	 * 				as the top keymap
+	 * Set which kind of keymap is currently used to map events
+	 *
+	 * Keymaps with the global type are always enabled
 	 */
-	void popKeymap(const char *name = 0);
+	void setEnabledKeymapType(Keymap::KeymapType type);
 
 	/**
 	 * Enable/disable the keymapper
@@ -135,8 +106,6 @@ public:
 	 */
 	const HardwareInput *findHardwareInput(const Event &event);
 
-	const Stack<MapRecord>& getActiveStack() const { return _activeMaps; }
-
 	/**
 	 * Register the binding of a hardware input to an action
 	 */
@@ -159,8 +128,6 @@ private:
 
 	HardwareInputSet *_hardwareInputs;
 
-	void pushKeymap(Keymap *newMap, bool transparent);
-
 	Event executeAction(const Action *act, IncomingEventType incomingType);
 	EventType convertDownToUp(EventType eventType);
 	IncomingEventType convertToIncomingEventType(const Event &ev) const;
@@ -168,12 +135,11 @@ private:
 	EventManager *_eventMan;
 
 	bool _enabled;
+	Keymap::KeymapType _enabledKeymapType;
 
 	typedef Array<Keymap *> KeymapArray;
 	KeymapArray _keymaps;
 
-	Stack<MapRecord> _activeMaps;
-
 };
 
 } // End of namespace Common
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index eaf43f9..fb84a02 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -25,8 +25,10 @@
 #ifdef ENABLE_KEYMAPPER
 
 #include "backends/keymapper/action.h"
-#include "backends/keymapper/keymapper.h"
+#include "backends/keymapper/hardware-input.h"
 #include "backends/keymapper/input-watcher.h"
+#include "backends/keymapper/keymap.h"
+#include "backends/keymapper/keymapper.h"
 
 #include "common/system.h"
 #include "gui/gui-manager.h"
diff --git a/base/main.cpp b/base/main.cpp
index afe78ea..eb6aff1 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -67,8 +67,9 @@
 #include "graphics/fonts/ttf.h"
 #endif
 
-#include "backends/keymapper/keymapper.h"
 #include "backends/keymapper/action.h"
+#include "backends/keymapper/keymap.h"
+#include "backends/keymapper/keymapper.h"
 
 #ifdef USE_CLOUD
 #ifdef USE_LIBCURL
@@ -395,14 +396,12 @@ static void setupKeymapper(OSystem &system) {
 	act->setRightClickEvent();
 
 	mapper->addGlobalKeymap(primaryGlobalKeymap);
-	mapper->pushKeymap(kGlobalKeymapName, true);
 
 	// Get the platform-specific global keymap (if it exists)
 	Keymap *platformGlobalKeymap = system.getGlobalKeymap();
 	if (platformGlobalKeymap) {
 		String platformGlobalKeymapName = platformGlobalKeymap->getName();
 		mapper->addGlobalKeymap(platformGlobalKeymap);
-		mapper->pushKeymap(platformGlobalKeymapName, true);
 	}
 #endif
 
diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp
index 14f83b1..c79f7a5 100644
--- a/engines/kyra/engine/eobcommon.cpp
+++ b/engines/kyra/engine/eobcommon.cpp
@@ -572,10 +572,6 @@ Common::Error EoBCoreEngine::init() {
 	// Prevent autosave on game startup
 	_lastAutosave = _system->getMillis();
 
-#ifdef ENABLE_KEYMAPPER
-	_eventMan->getKeymapper()->pushKeymap(kKeymapName, true);
-#endif
-
 	return Common::kNoError;
 }
 
diff --git a/engines/kyra/engine/lol.cpp b/engines/kyra/engine/lol.cpp
index c5d4fb0..0d09f11 100644
--- a/engines/kyra/engine/lol.cpp
+++ b/engines/kyra/engine/lol.cpp
@@ -458,10 +458,6 @@ Common::Error LoLEngine::init() {
 	_spellProcs.push_back(new SpellProc(this, 0));
 	_spellProcs.push_back(new SpellProc(this, &LoLEngine::castGuardian));
 
-#ifdef ENABLE_KEYMAPPER
-	_eventMan->getKeymapper()->pushKeymap(kKeymapName, true);
-#endif
-
 	return Common::kNoError;
 }
 
diff --git a/engines/kyra/gui/gui_eob.cpp b/engines/kyra/gui/gui_eob.cpp
index 558766d..943dfee 100644
--- a/engines/kyra/gui/gui_eob.cpp
+++ b/engines/kyra/gui/gui_eob.cpp
@@ -2581,8 +2581,10 @@ void GUI_EoB::updateBoxFrameHighLight(int box) {
 
 int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColor1, int textColor2, int cursorColor) {
 #ifdef ENABLE_KEYMAPPER
-	Common::Keymapper *const keymapper = _vm->getEventManager()->getKeymapper();
-	keymapper->pushKeymap(Common::kGlobalKeymapName);
+	// Disable the keymap during text input
+	Common::Keymapper *const mapper = _vm->_eventMan->getKeymapper();
+	Common::Keymap *const lolKeymap = mapper->getKeymap(EoBCoreEngine::kKeymapName);
+	lolKeymap->setEnabled(false);
 #endif
 
 	uint8 cursorState = 1;
@@ -2760,7 +2762,7 @@ int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColo
 	} while (_keyPressed.keycode != Common::KEYCODE_RETURN && _keyPressed.keycode != Common::KEYCODE_ESCAPE && !_vm->shouldQuit());
 
 #ifdef ENABLE_KEYMAPPER
-	keymapper->popKeymap(Common::kGlobalKeymapName);
+	lolKeymap->setEnabled(true);
 #endif
 
 	return _keyPressed.keycode == Common::KEYCODE_ESCAPE ? -1 : len;
diff --git a/engines/kyra/gui/gui_lol.cpp b/engines/kyra/gui/gui_lol.cpp
index 3776c83..84e3aa6 100644
--- a/engines/kyra/gui/gui_lol.cpp
+++ b/engines/kyra/gui/gui_lol.cpp
@@ -2560,8 +2560,10 @@ int GUI_LoL::getInput() {
 		return 0;
 
 #ifdef ENABLE_KEYMAPPER
-	Common::Keymapper *const keymapper = _vm->getEventManager()->getKeymapper();
-	keymapper->pushKeymap(Common::kGlobalKeymapName);
+	// Disable the keymap during text input
+	Common::Keymapper *const mapper = _vm->_eventMan->getKeymapper();
+	Common::Keymap *const lolKeymap = mapper->getKeymap(LoLEngine::kKeymapName);
+	lolKeymap->setEnabled(false);
 #endif
 
 	Common::Point p = _vm->getMousePos();
@@ -2602,7 +2604,7 @@ int GUI_LoL::getInput() {
 	_vm->delay(8);
 
 #ifdef ENABLE_KEYMAPPER
-	keymapper->popKeymap(Common::kGlobalKeymapName);
+	lolKeymap->setEnabled(true);
 #endif
 
 	return inputFlag & 0x8000 ? 1 : 0;
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 2cf239a..1f3e6c4 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -923,7 +923,6 @@ void MohawkEngine_Riven::initKeymap() {
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
-	mapper->pushKeymap(kKeymapName, true);
 #endif
 }
 
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index 0125955..e8ff92e 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -2522,7 +2522,6 @@ void PegasusEngine::initKeymap() {
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
-	mapper->pushKeymap(kKeymapName, true);
 #endif
 }
 
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 6f8c8c6..892c0ad 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -30,8 +30,9 @@
 #include "common/translation.h"
 #include "gui/EventRecorder.h"
 
-#include "backends/keymapper/keymapper.h"
 #include "backends/keymapper/action.h"
+#include "backends/keymapper/keymap.h"
+#include "backends/keymapper/keymapper.h"
 
 #include "gui/gui-manager.h"
 #include "gui/dialog.h"
@@ -141,13 +142,11 @@ void GuiManager::initKeymap() {
 	mapper->addGlobalKeymap(guiMap);
 }
 
-void GuiManager::pushKeymap() {
-	_system->getEventManager()->getKeymapper()->pushKeymap(Common::kGuiKeymapName);
+void GuiManager::enableKeymap(bool enabled) {
+	Common::Keymapper *keymapper = _system->getEventManager()->getKeymapper();
+	keymapper->setEnabledKeymapType(enabled ? Common::Keymap::kKeymapTypeGui : Common::Keymap::kKeymapTypeGame);
 }
 
-void GuiManager::popKeymap() {
-	_system->getEventManager()->getKeymapper()->popKeymap(Common::kGuiKeymapName);
-}
 #endif
 
 bool GuiManager::loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx, bool forced) {
@@ -429,7 +428,7 @@ void GuiManager::runLoop() {
 void GuiManager::saveState() {
 #ifdef ENABLE_KEYMAPPER
 	initKeymap();
-	pushKeymap();
+	enableKeymap(true);
 #endif
 	// Backup old cursor
 	_lastClick.x = _lastClick.y = 0;
@@ -441,7 +440,7 @@ void GuiManager::saveState() {
 
 void GuiManager::restoreState() {
 #ifdef ENABLE_KEYMAPPER
-	popKeymap();
+	enableKeymap(false);
 #endif
 	if (_useStdCursor) {
 		CursorMan.popCursor();
diff --git a/gui/gui-manager.h b/gui/gui-manager.h
index c3fb9a6..d20ade3 100644
--- a/gui/gui-manager.h
+++ b/gui/gui-manager.h
@@ -157,8 +157,7 @@ protected:
 	Common::List<GuiObjectTrashItem> _guiObjectTrash;
 
 	void initKeymap();
-	void pushKeymap();
-	void popKeymap();
+	void enableKeymap(bool enabled);
 
 	void saveState();
 	void restoreState();
@@ -168,8 +167,6 @@ protected:
 
 	void redraw();
 
-	void loop();
-
 	void setupCursor();
 	void animateCursor();
 


Commit: 3b5016a62d3b48a43edaae79e83738dadbcdeffc
    https://github.com/scummvm/scummvm/commit/3b5016a62d3b48a43edaae79e83738dadbcdeffc
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Change the remap dialog to use a scrollable container

Changed paths:
    backends/keymapper/remap-dialog.cpp
    backends/keymapper/remap-dialog.h
    gui/themes/default.inc
    gui/themes/scummclassic.zip
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx
    gui/themes/scummmodern.zip
    gui/themes/scummmodern/scummmodern_layout.stx
    gui/themes/scummmodern/scummmodern_layout_lowres.stx
    gui/themes/scummremastered.zip
    gui/themes/scummremastered/remastered_layout.stx


diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index fb84a02..8d5ba3c 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -33,20 +33,21 @@
 #include "common/system.h"
 #include "gui/gui-manager.h"
 #include "gui/widgets/popup.h"
-#include "gui/widgets/scrollbar.h"
+#include "gui/widgets/scrollcontainer.h"
 #include "gui/ThemeEval.h"
 #include "common/translation.h"
 
 namespace Common {
 
 enum {
-	kRemapCmd = 'REMP',
-	kClearCmd = 'CLER',
-	kCloseCmd = 'CLOS'
+	kRemapCmd  = 'REMP',
+	kClearCmd  = 'CLER',
+	kCloseCmd  = 'CLOS',
+	kReflowCmd = 'REFL'
 };
 
 RemapDialog::RemapDialog()
-	: Dialog("KeyMapper"), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false), _remapAction(nullptr) {
+	: Dialog("KeyMapper"), _remapTimeout(0), _remapAction(nullptr) {
 
 	_keymapper = g_system->getEventManager()->getKeymapper();
 	assert(_keymapper);
@@ -57,10 +58,8 @@ RemapDialog::RemapDialog()
 	_kmPopUpDesc = new GUI::StaticTextWidget(this, "KeyMapper.PopupDesc", _("Keymap:"));
 	_kmPopUp = new GUI::PopUpWidget(this, "KeyMapper.Popup");
 
-	_scrollBar = new GUI::ScrollBarWidget(this, 0, 0, 0, 0);
-
-	GUI::ContainerWidget *keymapArea = new GUI::ContainerWidget(this, "KeyMapper.KeymapArea");
-	keymapArea->setBackgroundType(GUI::ThemeEngine::kWidgetBackgroundNo);
+	_scrollContainer = new GUI::ScrollContainerWidget(this, "KeyMapper.KeymapArea", "", kReflowCmd);
+	_scrollContainer->setTarget(this);
 
 	new GUI::ButtonWidget(this, "KeyMapper.Close", _("Close"), 0, kCloseCmd);
 }
@@ -81,10 +80,13 @@ void RemapDialog::open() {
 
 	_changes = false;
 
-	Dialog::open();
-
 	_kmPopUp->setSelected(0);
+
 	loadKeymap();
+	refreshKeymap();
+	reflowActionWidgets();
+
+	Dialog::open();
 }
 
 void RemapDialog::close() {
@@ -96,101 +98,54 @@ void RemapDialog::close() {
 	Dialog::close();
 }
 
-void RemapDialog::reflowLayout() {
-	Dialog::reflowLayout();
-
+void RemapDialog::reflowActionWidgets() {
 	int buttonHeight = g_gui.xmlEval()->getVar("Globals.Button.Height", 0);
-	int scrollbarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
-
-	int16 areaX, areaY;
-	uint16 areaW, areaH;
-	g_gui.xmlEval()->getWidgetData((const String&)String("KeyMapper.KeymapArea"), areaX, areaY, areaW, areaH);
 
 	int spacing = g_gui.xmlEval()->getVar("Globals.KeyMapper.Spacing");
 	int keyButtonWidth = g_gui.xmlEval()->getVar("Globals.KeyMapper.ButtonWidth");
 	int clearButtonWidth = g_gui.xmlEval()->getVar("Globals.Line.Height");
 	int clearButtonHeight = g_gui.xmlEval()->getVar("Globals.Line.Height");
-
-	int colWidth = areaW - scrollbarWidth;
-	int labelWidth =  colWidth - (keyButtonWidth + spacing + clearButtonWidth + spacing);
-
-	_rowCount = (areaH + spacing) / (buttonHeight + spacing);
-	debug(7, "rowCount = %d" , _rowCount);
-	if (colWidth <= 0  || _rowCount <= 0)
-		error("Remap dialog too small to display any keymaps");
-
-	_scrollBar->resize(areaX + areaW - scrollbarWidth, areaY, scrollbarWidth, areaH);
-	_scrollBar->_entriesPerPage = _rowCount;
-	_scrollBar->_numEntries = 1;
-	_scrollBar->recalc();
+	int labelWidth = getWidth() - (spacing + keyButtonWidth + spacing + clearButtonWidth + spacing);
 
 	uint textYOff = (buttonHeight - kLineHeight) / 2;
 	uint clearButtonYOff = (buttonHeight - clearButtonHeight) / 2;
-	uint oldSize = _keymapWidgets.size();
-	uint newSize = _rowCount;
-
-	_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::kTextAlignLeft);
-			widg.keyButton =
-				new GUI::ButtonWidget(this, 0, 0, 0, 0, "", 0, kRemapCmd + i);
-			widg.clearButton = addClearButton(this, "", kClearCmd + i, 0, 0, clearButtonWidth, clearButtonHeight);
-			_keymapWidgets.push_back(widg);
-		} else {
-			widg = _keymapWidgets[i];
-		}
-
-		uint x = areaX;
-		uint y = areaY + (i) * (buttonHeight + spacing);
-
-		widg.keyButton->resize(x, y, keyButtonWidth, buttonHeight);
-		widg.clearButton->resize(x + keyButtonWidth + spacing, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
-		widg.actionText->resize(x + keyButtonWidth + spacing + clearButtonWidth + spacing, y + textYOff, labelWidth, kLineHeight);
-
-	}
-	while (oldSize > newSize) {
-		ActionWidgets widg = _keymapWidgets.remove_at(--oldSize);
-
-		removeWidget(widg.actionText);
-		delete widg.actionText;
 
-		removeWidget(widg.keyButton);
-		delete widg.keyButton;
+	for (uint i = 0; i < _actions.size(); i++) {
+		uint x = spacing;
+		uint y = spacing + (i) * (buttonHeight + spacing);
 
-		removeWidget(widg.clearButton);
-		delete widg.clearButton;
+		ActionRow &row = _actions[i];
+		row.keyButton->resize(x, y, keyButtonWidth, buttonHeight);
+		row.clearButton->resize(x + keyButtonWidth + spacing, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
+		row.actionText->resize(x + keyButtonWidth + spacing + clearButtonWidth + spacing, y + textYOff, labelWidth, kLineHeight);
 	}
 }
 
 void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
 	debug(3, "RemapDialog::handleCommand %u %u", cmd, data);
 
-	if (cmd >= kRemapCmd && cmd < kRemapCmd + _keymapWidgets.size()) {
+	if (cmd >= kRemapCmd && cmd < kRemapCmd + _actions.size()) {
 		startRemapping(cmd - kRemapCmd);
-	} else if (cmd >= kClearCmd && cmd < kClearCmd + _keymapWidgets.size()) {
+	} else if (cmd >= kClearCmd && cmd < kClearCmd + _actions.size()) {
 		clearMapping(cmd - kClearCmd);
+	} else if (cmd == kCloseCmd) {
+		close();
+	} else if (cmd == kReflowCmd) {
+		reflowActionWidgets();
 	} else if (cmd == GUI::kPopUpItemSelectedCmd) {
+		clearKeymap();
 		loadKeymap();
-	} else if (cmd == GUI::kSetPositionCmd) {
 		refreshKeymap();
-	} else if (cmd == kCloseCmd) {
-		close();
+		_scrollContainer->reflowLayout();
+		g_gui.scheduleTopDialogRedraw();
 	} else {
 		GUI::Dialog::handleCommand(sender, cmd, data);
 	}
 }
 
 void RemapDialog::clearMapping(uint i) {
-	if (_topAction + i >= _currentActions.size())
-		return;
-
 	debug(3, "clear the mapping %u", i);
-	Action *activeRemapAction = _currentActions[_topAction + i];
+	Action *activeRemapAction = _actions[i].action;
 	_keymapper->clearMapping(activeRemapAction);
 	_changes = true;
 
@@ -199,25 +154,21 @@ void RemapDialog::clearMapping(uint i) {
 }
 
 void RemapDialog::startRemapping(uint i) {
-	if (_topAction + i >= _currentActions.size())
-		return;
-
 	if (_remapInputWatcher->isWatching()) {
 		// Handle a second click on the button as a stop to remapping
 		stopRemapping();
 		return;
 	}
 
-	_remapAction = _currentActions[_topAction + i];
+	_remapAction = _actions[i].action;
 	_remapTimeout = g_system->getMillis() + kRemapTimeoutDelay;
 	_remapInputWatcher->startWatching();
 
-	_keymapWidgets[i].keyButton->setLabel("...");
-	_keymapWidgets[i].keyButton->markAsDirty();
+	_actions[i].keyButton->setLabel("...");
+	_actions[i].keyButton->markAsDirty();
 }
 
 void RemapDialog::stopRemapping() {
-	_topAction = -1;
 	_remapAction = nullptr;
 
 	refreshKeymap();
@@ -246,79 +197,58 @@ void RemapDialog::handleTickle() {
 	Dialog::handleTickle();
 }
 
-void RemapDialog::loadKeymap() {
-	_currentActions.clear();
-
-	if (_kmPopUp->getSelected() != -1) {
-		// This is the regular view of a keymap that isn't the topmost one.
-		// It shows all of that keymap's actions
-
-		Keymap *km = _keymapTable[_kmPopUp->getSelectedTag()];
-
-		List<Action *>::iterator it;
+void RemapDialog::clearKeymap() {
+	for (uint i = 0; i < _actions.size(); i++) {
+		if (_actions[i].keyButton)   _scrollContainer->removeWidget(_actions[i].keyButton);
+		if (_actions[i].actionText)  _scrollContainer->removeWidget(_actions[i].actionText);
+		if (_actions[i].clearButton) _scrollContainer->removeWidget(_actions[i].clearButton);
 
-		for (it = km->getActions().begin(); it != km->getActions().end(); ++it) {
-			_currentActions.push_back(*it);
-		}
+		delete _actions[i].keyButton;
+		delete _actions[i].actionText;
+		delete _actions[i].clearButton;
 	}
 
-	// refresh scroll bar
-	_scrollBar->_currentPos = 0;
-	_scrollBar->_numEntries = _currentActions.size();
-	_scrollBar->recalc();
-
-	// force refresh
-	_topAction = -1;
-	refreshKeymap();
+	_actions.clear();
 }
 
-void RemapDialog::refreshKeymap() {
-	int newTopAction = _scrollBar->_currentPos;
-
-	if (newTopAction == _topAction)
-		return;
-
-	_topAction = newTopAction;
-
-	//_container->markAsDirty();
-	_scrollBar->markAsDirty();
+void RemapDialog::loadKeymap() {
+	assert(_actions.empty());
+	assert(_kmPopUp->getSelected() != -1);
 
-	uint actionI = _topAction;
+	Keymap *km = _keymapTable[_kmPopUp->getSelectedTag()];
+	for (List<Action *>::iterator it = km->getActions().begin(); it != km->getActions().end(); ++it) {
+		ActionRow row;
+		row.action = *it;
 
-	for (uint widgetI = 0; widgetI < _keymapWidgets.size(); widgetI++) {
-		ActionWidgets &widg = _keymapWidgets[widgetI];
+		_actions.push_back(row);
+	}
+}
 
-		if (actionI < _currentActions.size()) {
-			debug(8, "RemapDialog::refreshKeymap actionI=%u", actionI);
-			Action *action = _currentActions[actionI];
+void RemapDialog::refreshKeymap() {
+	int clearButtonWidth = g_gui.xmlEval()->getVar("Globals.Line.Height");
+	int clearButtonHeight = g_gui.xmlEval()->getVar("Globals.Line.Height");
 
-			widg.actionText->setLabel(action->description);
+	for (uint i = 0; i < _actions.size(); i++) {
+		ActionRow &row = _actions[i];
 
-			Keymap *keymap = action->getParent();
+		if (!row.actionText) {
+			row.actionText = new GUI::StaticTextWidget(_scrollContainer, 0, 0, 0, 0, "", Graphics::kTextAlignLeft);
+			row.keyButton = new GUI::ButtonWidget(_scrollContainer, 0, 0, 0, 0, "", 0, kRemapCmd + i);
+			row.clearButton = addClearButton(_scrollContainer, "", kClearCmd + i, 0, 0, clearButtonWidth, clearButtonHeight);
+		}
 
-			const HardwareInput *mappedInput = keymap->getActionMapping(action);
-			if (mappedInput)
-				widg.keyButton->setLabel(mappedInput->description);
-			else
-				widg.keyButton->setLabel("-");
+		row.actionText->setLabel(row.action->description);
 
-			widg.actionText->setVisible(true);
-			widg.keyButton->setVisible(true);
-			widg.clearButton->setVisible(true);
+		Keymap *keymap = row.action->getParent();
 
-			actionI++;
-		} else {
-			widg.actionText->setVisible(false);
-			widg.keyButton->setVisible(false);
-			widg.clearButton->setVisible(false);
-		}
+		const HardwareInput *mappedInput = keymap->getActionMapping(row.action);
+		if (mappedInput)
+			row.keyButton->setLabel(mappedInput->description);
+		else
+			row.keyButton->setLabel("-");
 	}
-
-	// need to redraw entire Dialog so that invisible widgets disappear
-	g_gui.scheduleTopDialogRedraw();
 }
 
-
 } // End of namespace Common
 
 #endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h
index 58fcf8c..3e887aa 100644
--- a/backends/keymapper/remap-dialog.h
+++ b/backends/keymapper/remap-dialog.h
@@ -32,7 +32,7 @@
 namespace GUI {
 class ButtonWidget;
 class PopUpWidget;
-class ScrollBarWidget;
+class ScrollContainerWidget;
 class StaticTextWidget;
 }
 
@@ -49,20 +49,25 @@ public:
 	virtual ~RemapDialog();
 	virtual void open();
 	virtual void close();
-	virtual void reflowLayout();
 	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
 	virtual void handleMouseDown(int x, int y, int button, int clickCount);
 	virtual void handleTickle();
 
 protected:
-	struct ActionWidgets {
+	struct ActionRow {
+		Common::Action *action;
+
 		GUI::StaticTextWidget *actionText;
 		GUI::ButtonWidget *keyButton;
 		GUI::ButtonWidget *clearButton;
+
+		ActionRow() : action(nullptr), actionText(nullptr), keyButton(nullptr), clearButton(nullptr) { }
 	};
 
 	void loadKeymap();
 	void refreshKeymap();
+	void clearKeymap();
+	void reflowActionWidgets();
 	void clearMapping(uint i);
 	void startRemapping(uint i);
 	void stopRemapping();
@@ -74,22 +79,15 @@ protected:
 	Action *_remapAction;
 	uint32 _remapTimeout;
 
-	Array<Action *> _currentActions;
-	int _topAction;
-
 	GUI::StaticTextWidget *_kmPopUpDesc;
 	GUI::PopUpWidget *_kmPopUp;
-	GUI::ScrollBarWidget *_scrollBar;
+	GUI::ScrollContainerWidget *_scrollContainer;
 
-	uint _rowCount;
-
-	Array<ActionWidgets> _keymapWidgets;
 	static const uint32 kRemapTimeoutDelay = 3000;
 
 	bool _changes;
 
-	bool _topKeymapIsGui;
-
+	Array<ActionRow> _actions;
 };
 
 } // End of namespace Common
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 60a81b5..8f568c6 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -2536,8 +2536,8 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "</layout>"
 "</dialog>"
 "<dialog name='KeyMapper' overlays='screen_center' shading='dim'>"
-"<layout type='vertical' padding='8,8,32,8' spacing='10' align='center'>"
-"<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
+"<layout type='vertical' padding='8,8,8,8' spacing='10' align='center'>"
+"<layout type='horizontal' padding='8,8,8,8' spacing='10' align='center'>"
 "<widget name='PopupDesc' "
 "type='OptionsLabel' "
 "/>"
@@ -2551,10 +2551,12 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "width='600' "
 "height='280' "
 "/>"
+"<layout type='horizontal' padding='8,8,8,8' align='center'>"
 "<widget name='Close' "
 "type='Button' "
 "/>"
 "</layout>"
+"</layout>"
 "</dialog>"
 "<dialog name='Predictive' overlays='screen_center'>"
 "<layout type='vertical' padding='5,5,5,5' align='center'>"
@@ -4281,10 +4283,12 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "width='300' "
 "height='120' "
 "/>"
+"<layout type='horizontal' padding='8,8,8,8' align='center'>"
 "<widget name='Close' "
 "type='Button' "
 "/>"
 "</layout>"
+"</layout>"
 "</dialog>"
 "<dialog name='Predictive' overlays='screen_center'>"
 "<layout type='vertical' padding='1,1,1,1' align='center'>"
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index e60ad7b..233e750 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 7e9c2c0..8c4a44e 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -1705,8 +1705,8 @@
 	</dialog>
 
 	<dialog name = 'KeyMapper' overlays = 'screen_center' shading = 'dim'>
-		<layout type = 'vertical' padding = '8, 8, 32, 8' spacing = '10' align = 'center'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '10' align = 'center'>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' spacing = '10' align = 'center'>
 				<widget name = 'PopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -1720,9 +1720,11 @@
 					width = '600'
 					height = '280'
 			/>
-			<widget name = 'Close'
-					type = 'Button'
-			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' align = 'center'>
+				<widget name = 'Close'
+						type = 'Button'
+				/>
+			</layout>
 		</layout>
 	</dialog>
 
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index a96c8fe..01934aa 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -1689,9 +1689,11 @@
 					width = '300'
 					height = '120'
 			/>
-			<widget name = 'Close'
-					type = 'Button'
-			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' align = 'center'>
+				<widget name = 'Close'
+						type = 'Button'
+				/>
+			</layout>
 		</layout>
 	</dialog>
 
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 659af99..fbaf621 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 204a6fb..a55530e 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -1719,8 +1719,8 @@
 	</dialog>
 
 	<dialog name = 'KeyMapper' overlays = 'screen_center' shading = 'dim'>
-		<layout type = 'vertical' padding = '8, 8, 32, 8' spacing = '10' align = 'center'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '10' align = 'center'>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' spacing = '10' align = 'center'>
 				<widget name = 'PopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -1734,11 +1734,14 @@
 					width = '600'
 					height = '280'
 			/>
-			<widget name = 'Close'
-					type = 'Button'
-			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' align = 'center'>
+				<widget name = 'Close'
+						type = 'Button'
+				/>
+			</layout>
 		</layout>
 	</dialog>
+
 	<dialog name = 'Predictive' overlays = 'screen_center'>
 		<layout type = 'vertical' padding = '5, 5, 5, 5' align = 'center'>
 			<widget name = 'Headline'
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index a2c2b61..c61f2ef 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -1708,9 +1708,11 @@
 					width = '300'
 					height = '120'
 			/>
-			<widget name = 'Close'
-					type = 'Button'
-			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' align = 'center'>
+				<widget name = 'Close'
+						type = 'Button'
+				/>
+			</layout>
 		</layout>
 	</dialog>
 	<dialog name = 'Predictive' overlays = 'screen_center'>
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index b28e12f..ffe5eed 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ
diff --git a/gui/themes/scummremastered/remastered_layout.stx b/gui/themes/scummremastered/remastered_layout.stx
index 4e62314..2281c06 100644
--- a/gui/themes/scummremastered/remastered_layout.stx
+++ b/gui/themes/scummremastered/remastered_layout.stx
@@ -1719,8 +1719,8 @@
 	</dialog>
 
 	<dialog name = 'KeyMapper' overlays = 'screen_center' shading = 'dim'>
-		<layout type = 'vertical' padding = '8, 8, 32, 8' spacing = '10' align = 'center'>
-			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+		<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '10' align = 'center'>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' spacing = '10' align = 'center'>
 				<widget name = 'PopupDesc'
 						type = 'OptionsLabel'
 				/>
@@ -1734,11 +1734,14 @@
 					width = '600'
 					height = '280'
 			/>
-			<widget name = 'Close'
-					type = 'Button'
-			/>
+			<layout type = 'horizontal' padding = '8, 8, 8, 8' align = 'center'>
+				<widget name = 'Close'
+						type = 'Button'
+				/>
+			</layout>
 		</layout>
 	</dialog>
+
 	<dialog name = 'Predictive' overlays = 'screen_center'>
 		<layout type = 'vertical' padding = '5, 5, 5, 5' align = 'center'>
 			<widget name = 'Headline'


Commit: 729cd24c0b67d85137e388d97bb7de39d532de5b
    https://github.com/scummvm/scummvm/commit/729cd24c0b67d85137e388d97bb7de39d532de5b
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Change the keymap action list to be an Array

Changed paths:
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/remap-dialog.cpp


diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index 4f90a69..bfb6416 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -42,7 +42,7 @@ Keymap::Keymap(KeymapType type, const String &name) :
 }
 
 Keymap::~Keymap() {
-	for (ActionList::iterator it = _actions.begin(); it != _actions.end(); ++it)
+	for (ActionArray::iterator it = _actions.begin(); it != _actions.end(); ++it)
 		delete *it;
 }
 
@@ -78,7 +78,7 @@ const HardwareInput *Keymap::getActionMapping(Action *action) const {
 }
 
 const Action *Keymap::findAction(const char *id) const {
-	for (ActionList::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
+	for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
 		if (strcmp((*it)->id, id) == 0)
 			return *it;
 	}
@@ -103,7 +103,7 @@ void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
 
 	String prefix = KEYMAP_KEY_PREFIX + _name + "_";
 
-	for (ActionList::iterator it = _actions.begin(); it != _actions.end(); ++it) {
+	for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
 		Action* ua = *it;
 		String actionId(ua->id);
 		String confKey = prefix + actionId;
@@ -132,7 +132,7 @@ void Keymap::saveMappings() {
 
 	String prefix = KEYMAP_KEY_PREFIX + _name + "_";
 
-	for (HardwareActionMap::iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
+	for (HardwareActionMap::const_iterator it = _hwActionMap.begin(); it != _hwActionMap.end(); it++) {
 		const Action *action = it->_value;
 		const HardwareInput *input = it->_key;
 
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
index 5baadb2..fd72c6f 100644
--- a/backends/keymapper/keymap.h
+++ b/backends/keymapper/keymap.h
@@ -47,6 +47,8 @@ public:
 		kKeymapTypeGame
 	};
 
+	typedef Array<Action *> ActionArray;
+
 	Keymap(KeymapType type, const String &name);
 	~Keymap();
 
@@ -80,7 +82,7 @@ public:
 	/**
 	 * Get the list of all the Actions contained in this Keymap
 	 */
-	List<Action *> &getActions() { return _actions; }
+	const ActionArray &getActions() const { return _actions; }
 
 	void setConfigDomain(ConfigManager::Domain *dom);
 
@@ -97,7 +99,7 @@ public:
 	 */
 	void saveMappings();
 
-	const String &getName() { return _name; }
+	const String &getName() const { return _name; }
 	KeymapType getType() const { return _type; }
 
 	/**
@@ -118,7 +120,6 @@ private:
 
 	const Action *findAction(const char *id) const;
 
-	typedef List<Action *> ActionList;
 	typedef HashMap<const HardwareInput *, Action *> HardwareActionMap;
 
 	KeymapType _type;
@@ -126,7 +127,7 @@ private:
 
 	bool _enabled;
 
-	ActionList _actions;
+	ActionArray _actions;
 	HardwareActionMap _hwActionMap;
 	ConfigManager::Domain *_configDomain;
 
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index 8d5ba3c..82f402c 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -216,7 +216,7 @@ void RemapDialog::loadKeymap() {
 	assert(_kmPopUp->getSelected() != -1);
 
 	Keymap *km = _keymapTable[_kmPopUp->getSelectedTag()];
-	for (List<Action *>::iterator it = km->getActions().begin(); it != km->getActions().end(); ++it) {
+	for (Keymap::ActionArray::const_iterator it = km->getActions().begin(); it != km->getActions().end(); ++it) {
 		ActionRow row;
 		row.action = *it;
 


Commit: d5e2b5d8f2bfaf80c29fedfd27224da693f58a15
    https://github.com/scummvm/scummvm/commit/d5e2b5d8f2bfaf80c29fedfd27224da693f58a15
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Make it clear the keymaps are owned by the keymapper

Also free all the remaining keymaps when freeing the keymapper.

Changed paths:
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h


diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 0fbb734..2fbd571 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -44,6 +44,9 @@ Keymapper::Keymapper(EventManager *evtMgr) :
 
 Keymapper::~Keymapper() {
 	delete _hardwareInputs;
+	for (KeymapArray::iterator it = _keymaps.begin(); it != _keymaps.end(); it++) {
+		delete *it;
+	}
 }
 
 void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) {
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index 417177f..fc65723 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -61,11 +61,16 @@ public:
 	 * 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.
+	 *
+	 * Transfers ownership of the keymap to the Keymapper
 	 */
 	void addGlobalKeymap(Keymap *keymap);
 
 	/**
 	 * Add a keymap to the game domain.
+	 *
+	 * Transfers ownership of the keymap to the Keymapper
+	 *
 	 * @see addGlobalKeyMap
 	 * @note initGame() should be called before any game keymaps are added.
 	 */


Commit: ade0efa762f9ae453cc9be42adcb35469f61d35a
    https://github.com/scummvm/scummvm/commit/ade0efa762f9ae453cc9be42adcb35469f61d35a
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Multiple inputs can map to the same action

Changed paths:
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/remap-dialog.cpp


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


Commit: 17791e2f7d81155666e66fe2160777aef66fa356
    https://github.com/scummvm/scummvm/commit/17791e2f7d81155666e66fe2160777aef66fa356
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Actions can now have default mappings

Changed paths:
    backends/keymapper/action.cpp
    backends/keymapper/action.h
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    backends/keymapper/remap-dialog.cpp
    backends/keymapper/remap-dialog.h
    base/main.cpp
    engines/engine.cpp
    engines/engine.h
    gui/gui-manager.cpp


diff --git a/backends/keymapper/action.cpp b/backends/keymapper/action.cpp
index 75071f1..50ef2ed 100644
--- a/backends/keymapper/action.cpp
+++ b/backends/keymapper/action.cpp
@@ -36,6 +36,14 @@ Action::Action(Keymap *boss, const char *i,	String des)
 	_boss->addAction(this);
 }
 
+void Action::addDefaultInputMapping(const String &hwId) {
+	// Don't allow an input to map to the same action multiple times
+	Array<String>::const_iterator found = find(_defaultInputMapping.begin(), _defaultInputMapping.end(), hwId);
+	if (found == _defaultInputMapping.end()) {
+		_defaultInputMapping.push_back(hwId);
+	}
+}
+
 } // End of namespace Common
 
 #endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
index 0771596..b0e96b3 100644
--- a/backends/keymapper/action.h
+++ b/backends/keymapper/action.h
@@ -27,6 +27,7 @@
 
 #ifdef ENABLE_KEYMAPPER
 
+#include "common/array.h"
 #include "common/events.h"
 #include "common/func.h"
 #include "common/str.h"
@@ -54,6 +55,8 @@ struct Action {
 private:
 	Keymap *_boss;
 
+	Array<String> _defaultInputMapping;
+
 public:
 	Action(Keymap *boss, const char *id, String des = "");
 
@@ -84,6 +87,21 @@ public:
 		setEvent(EVENT_RBUTTONDOWN);
 	}
 
+	/**
+	 * Add a default input mapping for the action
+	 *
+	 * Unknown hardware inputs will be silently ignored.
+	 * Having keyboard bindings by default will not cause trouble
+	 * on devices without a keyboard.
+	 *
+	 * @param hwId Hardware input identifier as registered with the keymapper
+	 */
+	void addDefaultInputMapping(const String &hwId);
+
+	const Array<String> &getDefaultInputMapping() const {
+		return _defaultInputMapping;
+	}
+
 	Keymap *getParent() {
 		return _boss;
 	}
diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index 101ae1f..f769077 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -38,7 +38,8 @@ Keymap::Keymap(KeymapType type, const String &name) :
 		_type(type),
 		_name(name),
 		_configDomain(nullptr),
-		_enabled(true) {
+		_enabled(true),
+		_hardwareInputSet(nullptr) {
 
 }
 
@@ -79,6 +80,13 @@ void Keymap::unregisterMapping(Action *action) {
 	}
 }
 
+void Keymap::resetMapping(Action *action) {
+	unregisterMapping(action);
+
+	const Array<String> &hwInputIds = action->getDefaultInputMapping();
+	registerMappings(action, hwInputIds);
+}
+
 Array<const HardwareInput *> Keymap::getActionMapping(Action *action) const {
 	Array<const HardwareInput *> inputs;
 
@@ -107,12 +115,17 @@ const Keymap::ActionArray &Keymap::getMappedActions(const HardwareInput *hardwar
 	return _hwActionMap[hardwareInput];
 }
 
-void Keymap::setConfigDomain(ConfigManager::Domain *dom) {
-	_configDomain = dom;
+void Keymap::setConfigDomain(ConfigManager::Domain *configDomain) {
+	_configDomain = configDomain;
 }
 
-void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
+void Keymap::setHardwareInputs(HardwareInputSet *hardwareInputSet) {
+	_hardwareInputSet = hardwareInputSet;
+}
+
+void Keymap::loadMappings() {
 	assert(_configDomain);
+	assert(_hardwareInputSet);
 
 	if (_actions.empty()) {
 		return;
@@ -122,26 +135,42 @@ void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
 
 	_hwActionMap.clear();
 	for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
-		Action* ua = *it;
-		String actionId(ua->id);
-		String confKey = prefix + actionId;
+		Action *action = *it;
+		String confKey = prefix + action->id;
 
-		// The configuration value is a list of space separated hardware input ids
-		StringTokenizer hwInputIds = _configDomain->getVal(confKey);
+		Array<String> hwInputIds;
+		if (_configDomain->contains(confKey)) {
+			// The configuration value is a list of space separated hardware input ids
+			StringTokenizer hwInputTokenizer = _configDomain->getVal(confKey);
+
+			String hwInputId;
+			while ((hwInputId = hwInputTokenizer.nextToken()) != "") {
+				hwInputIds.push_back(hwInputId);
+			}
+		} else {
+			// If the configuration key was not found, use the default mapping
+			hwInputIds = action->getDefaultInputMapping();
+		}
+
+		registerMappings(action, hwInputIds);
+	}
+}
+
+void Keymap::registerMappings(Action *action, const Array <String> &hwInputIds) {
+	assert(_hardwareInputSet);
 
-		String hwInputId;
-		while ((hwInputId = hwInputIds.nextToken()) != "") {
-			const HardwareInput *hwInput = hwKeys->findHardwareInput(hwInputId.c_str());
+	for (uint i = 0; i < hwInputIds.size(); i++) {
+			const HardwareInput *hwInput = _hardwareInputSet->findHardwareInput(hwInputIds[i].c_str());
 
 			if (!hwInput) {
-				warning("HardwareInput with ID '%s' not known", hwInputId.c_str());
+				// Silently ignore unknown hardware ids because the current device may not have inputs matching the defaults
+				debug(1, "HardwareInput with ID '%s' not known", hwInputIds[i].c_str());
 				continue;
 			}
 
 			// map the key
-			registerMapping(ua, hwInput);
+			registerMapping(action, hwInput);
 		}
-	}
 }
 
 void Keymap::saveMappings() {
@@ -154,6 +183,12 @@ void Keymap::saveMappings() {
 		Action *action = *it;
 		Array<const HardwareInput *> mappedInputs = getActionMapping(action);
 
+		if (areMappingsIdentical(mappedInputs, action->getDefaultInputMapping())) {
+			// If the current mapping is the default, don't write anything to the config manager
+			_configDomain->erase(prefix + action->id);
+			continue;
+		}
+
 		// The configuration value is a list of space separated hardware input ids
 		String confValue;
 		for (uint j = 0; j < mappedInputs.size(); j++) {
@@ -168,6 +203,26 @@ void Keymap::saveMappings() {
 	}
 }
 
+bool Keymap::areMappingsIdentical(const Array<const HardwareInput *> &inputs, const Array<String> &mapping) {
+	if (inputs.size() != mapping.size()) {
+		return false;
+	}
+
+	// Assumes array values are not duplicated, but registerMapping and addDefaultInputMapping ensure that
+
+	uint foundCount = 0;
+	for (uint i = 0; i < inputs.size(); i++) {
+		for (uint j = 0; j < mapping.size(); j++) {
+			if (inputs[i]->id == mapping[j]) {
+				foundCount++;
+				break;
+			}
+		}
+	}
+
+	return foundCount == inputs.size();
+}
+
 } // End of namespace Common
 
 #endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
index deb3c3e..516a158 100644
--- a/backends/keymapper/keymap.h
+++ b/backends/keymapper/keymap.h
@@ -51,6 +51,8 @@ public:
 
 	Keymap(KeymapType type, const String &name);
 	~Keymap();
+	void setConfigDomain(ConfigManager::Domain *configDomain);
+	void setHardwareInputs(HardwareInputSet *hardwareInputSet);
 
 	/**
 	* Registers a HardwareInput to the given Action
@@ -68,6 +70,12 @@ public:
 	void unregisterMapping(Action *action);
 
 	/**
+	 * Reset an action's mapping to its defaults
+	 * @param action
+	 */
+	void resetMapping(Action *action);
+
+	/**
 	 * Find the hardware input an action is mapped to, if any
 	 */
 	Array<const HardwareInput *> getActionMapping(Action *action) const;
@@ -84,13 +92,11 @@ public:
 	 */
 	const ActionArray &getActions() const { return _actions; }
 
-	void setConfigDomain(ConfigManager::Domain *dom);
-
 	/**
 	 * Load this keymap's mappings from the config manager.
 	 * @param hwInputs	the set to retrieve hardware input pointers from
 	 */
-	void loadMappings(const HardwareInputSet *hwInputs);
+	void loadMappings();
 
 	/**
 	 * Save this keymap's mappings to the config manager
@@ -120,6 +126,9 @@ private:
 
 	const Action *findAction(const char *id) const;
 
+	void registerMappings(Action *action, const Array<String> &hwInputIds);
+	bool areMappingsIdentical(const Array<const HardwareInput *> &inputs, const Array <String> &mapping);
+
 	typedef HashMap<const HardwareInput *, ActionArray> HardwareActionMap;
 
 	KeymapType _type;
@@ -129,7 +138,9 @@ private:
 
 	ActionArray _actions;
 	HardwareActionMap _hwActionMap;
+
 	ConfigManager::Domain *_configDomain;
+	HardwareInputSet *_hardwareInputSet;
 
 };
 
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index bf32014..569b4a3 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -92,7 +92,8 @@ void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
 	}
 
 	keymap->setConfigDomain(domain);
-	keymap->loadMappings(_hardwareInputs);
+	keymap->setHardwareInputs(_hardwareInputs);
+	keymap->loadMappings();
 }
 
 void Keymapper::cleanupGameKeymaps() {
@@ -241,18 +242,6 @@ const HardwareInput *Keymapper::findHardwareInput(const Event &event) {
 	}
 }
 
-void Keymapper::registerMapping(Action *action, const HardwareInput *input) {
-	Keymap *keymap = action->getParent();
-	keymap->registerMapping(action, input);
-	keymap->saveMappings();
-}
-
-void Keymapper::clearMapping(Action *action) {
-	Keymap *keymap = action->getParent();
-	keymap->unregisterMapping(action);
-	keymap->saveMappings();
-}
-
 } // End of namespace Common
 
 #endif // #ifdef ENABLE_KEYMAPPER
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index fc65723..8eac321 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -111,16 +111,6 @@ public:
 	 */
 	const HardwareInput *findHardwareInput(const Event &event);
 
-	/**
-	 * Register the binding of a hardware input to an action
-	 */
-	void registerMapping(Action *action, const HardwareInput *input);
-
-	/**
-	 * Unbind hardware inputs from an action
-	 */
-	void clearMapping(Action *action);
-
 private:
 
 	enum IncomingEventType {
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index b78acab..168314d 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -42,6 +42,7 @@ namespace Common {
 enum {
 	kRemapCmd  = 'REMP',
 	kClearCmd  = 'CLER',
+	kResetCmd  = 'RSET',
 	kCloseCmd  = 'CLOS',
 	kReflowCmd = 'REFL'
 };
@@ -92,8 +93,14 @@ void RemapDialog::open() {
 void RemapDialog::close() {
 	_kmPopUp->clearEntries();
 
-	if (_changes)
+	if (_changes) {
+		const Array<Keymap *> &keymaps = _keymapper->getKeymaps();
+		for (uint i = 0; i < keymaps.size(); i++) {
+			keymaps[i]->saveMappings();
+		}
+
 		ConfMan.flushToDisk();
+	}
 
 	Dialog::close();
 }
@@ -111,13 +118,20 @@ void RemapDialog::reflowActionWidgets() {
 	uint clearButtonYOff = (buttonHeight - clearButtonHeight) / 2;
 
 	for (uint i = 0; i < _actions.size(); i++) {
-		uint x = spacing;
+		ActionRow &row = _actions[i];
 		uint y = spacing + (i) * (buttonHeight + spacing);
 
-		ActionRow &row = _actions[i];
+		uint x = spacing;
 		row.keyButton->resize(x, y, keyButtonWidth, buttonHeight);
-		row.clearButton->resize(x + keyButtonWidth + spacing, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
-		row.actionText->resize(x + keyButtonWidth + spacing + clearButtonWidth + spacing, y + textYOff, labelWidth, kLineHeight);
+
+		x += keyButtonWidth + spacing;
+		row.clearButton->resize(x, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
+
+		x += clearButtonWidth + spacing;
+		row.resetButton->resize(x, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
+
+		x += clearButtonWidth + spacing;
+		row.actionText->resize(x, y + textYOff, labelWidth, kLineHeight);
 	}
 }
 
@@ -128,6 +142,8 @@ void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 d
 		startRemapping(cmd - kRemapCmd);
 	} else if (cmd >= kClearCmd && cmd < kClearCmd + _actions.size()) {
 		clearMapping(cmd - kClearCmd);
+	} else if (cmd >= kResetCmd && cmd < kResetCmd + _actions.size()) {
+		resetMapping(cmd - kResetCmd);
 	} else if (cmd == kCloseCmd) {
 		close();
 	} else if (cmd == kReflowCmd) {
@@ -145,8 +161,22 @@ void RemapDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 d
 
 void RemapDialog::clearMapping(uint i) {
 	debug(3, "clear the mapping %u", i);
-	Action *activeRemapAction = _actions[i].action;
-	_keymapper->clearMapping(activeRemapAction);
+	Action *action = _actions[i].action;
+	Keymap *keymap = action->getParent();
+	keymap->unregisterMapping(action);
+
+	_changes = true;
+
+	stopRemapping();
+	refreshKeymap();
+}
+
+void RemapDialog::resetMapping(uint i) {
+	debug(3, "Reset the mapping %u", i);
+	Action *action = _actions[i].action;
+	Keymap *keymap = action->getParent();
+	keymap->resetMapping(action);
+
 	_changes = true;
 
 	stopRemapping();
@@ -186,7 +216,8 @@ void RemapDialog::handleMouseDown(int x, int y, int button, int clickCount) {
 void RemapDialog::handleTickle() {
 	const HardwareInput *hardwareInput = _remapInputWatcher->checkForCapturedInput();
 	if (hardwareInput) {
-		_keymapper->registerMapping(_remapAction, hardwareInput);
+		Keymap *keymap = _remapAction->getParent();
+		keymap->registerMapping(_remapAction, hardwareInput);
 
 		_changes = true;
 		stopRemapping();
@@ -202,10 +233,12 @@ void RemapDialog::clearKeymap() {
 		if (_actions[i].keyButton)   _scrollContainer->removeWidget(_actions[i].keyButton);
 		if (_actions[i].actionText)  _scrollContainer->removeWidget(_actions[i].actionText);
 		if (_actions[i].clearButton) _scrollContainer->removeWidget(_actions[i].clearButton);
+		if (_actions[i].resetButton) _scrollContainer->removeWidget(_actions[i].resetButton);
 
 		delete _actions[i].keyButton;
 		delete _actions[i].actionText;
 		delete _actions[i].clearButton;
+		delete _actions[i].resetButton;
 	}
 
 	_actions.clear();
@@ -235,6 +268,7 @@ void RemapDialog::refreshKeymap() {
 			row.actionText = new GUI::StaticTextWidget(_scrollContainer, 0, 0, 0, 0, "", Graphics::kTextAlignLeft);
 			row.keyButton = new GUI::ButtonWidget(_scrollContainer, 0, 0, 0, 0, "", 0, kRemapCmd + i);
 			row.clearButton = addClearButton(_scrollContainer, "", kClearCmd + i, 0, 0, clearButtonWidth, clearButtonHeight);
+			row.resetButton = new GUI::ButtonWidget(_scrollContainer, 0, 0, 0, 0, "", 0, kResetCmd + i);
 		}
 
 		row.actionText->setLabel(row.action->description);
@@ -252,10 +286,16 @@ void RemapDialog::refreshKeymap() {
 			keysLabel += mappedInputs[j]->description;
 		}
 
-		if (!keysLabel.empty())
+		if (!keysLabel.empty()) {
 			row.keyButton->setLabel(keysLabel);
-		else
+			row.keyButton->setTooltip(keysLabel);
+		} else {
 			row.keyButton->setLabel("-");
+		}
+
+		// I18N: Button to reset key mapping to defaults
+		row.resetButton->setLabel(_("R"));
+		row.resetButton->setTooltip(_("Reset to defaults"));
 	}
 }
 
diff --git a/backends/keymapper/remap-dialog.h b/backends/keymapper/remap-dialog.h
index 3e887aa..b94081d 100644
--- a/backends/keymapper/remap-dialog.h
+++ b/backends/keymapper/remap-dialog.h
@@ -60,8 +60,9 @@ protected:
 		GUI::StaticTextWidget *actionText;
 		GUI::ButtonWidget *keyButton;
 		GUI::ButtonWidget *clearButton;
+		GUI::ButtonWidget *resetButton;
 
-		ActionRow() : action(nullptr), actionText(nullptr), keyButton(nullptr), clearButton(nullptr) { }
+		ActionRow() : action(nullptr), actionText(nullptr), keyButton(nullptr), clearButton(nullptr), resetButton(nullptr) { }
 	};
 
 	void loadKeymap();
@@ -69,6 +70,7 @@ protected:
 	void clearKeymap();
 	void reflowActionWidgets();
 	void clearMapping(uint i);
+	void resetMapping(uint i);
 	void startRemapping(uint i);
 	void stopRemapping();
 
diff --git a/base/main.cpp b/base/main.cpp
index eb6aff1..83399dd 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -364,26 +364,21 @@ static void setupKeymapper(OSystem &system) {
 	Keymap *primaryGlobalKeymap = new Keymap(Keymap::kKeymapTypeGlobal, kGlobalKeymapName);
 	Action *act;
 	act = new Action(primaryGlobalKeymap, "MENU", _("Menu"));
+	act->addDefaultInputMapping("C+F5");
 	act->setEvent(EVENT_MAINMENU);
 
-	act = new Action(primaryGlobalKeymap, "SKCT", _("Skip"));
-	act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));
-
-	act = new Action(primaryGlobalKeymap, "PAUS", _("Pause"));
-	act->setKeyEvent(KeyState(KEYCODE_SPACE, ' ', 0));
-
-	act = new Action(primaryGlobalKeymap, "SKLI", _("Skip line"));
-	act->setKeyEvent(KeyState(KEYCODE_PERIOD, '.', 0));
-
 #ifdef ENABLE_VKEYBD
 	act = new Action(primaryGlobalKeymap, "VIRT", _("Display keyboard"));
+	act->addDefaultInputMapping("C+F7");
 	act->setEvent(EVENT_VIRTUAL_KEYBOARD);
 #endif
 
 	act = new Action(primaryGlobalKeymap, "REMP", _("Remap keys"));
+	act->addDefaultInputMapping("C+F8");
 	act->setEvent(EVENT_KEYMAPPER_REMAP);
 
 	act = new Action(primaryGlobalKeymap, "FULS", _("Toggle fullscreen"));
+	act->addDefaultInputMapping("A+RETURN");
 	act->setKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN, KBD_ALT));
 
 	act = new Action(primaryGlobalKeymap, "LCLK", _("Left Click"));
diff --git a/engines/engine.cpp b/engines/engine.cpp
index a177f44..dfc24f5 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -46,6 +46,7 @@
 #include "common/translation.h"
 #include "common/singleton.h"
 
+#include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
 #include "base/version.h"
 
@@ -614,6 +615,34 @@ void Engine::syncSoundSettings() {
 	_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
 }
 
+void Engine::initKeymap() {
+#ifdef ENABLE_KEYMAPPER
+	static const char *const kKeymapName = "engine-default";
+	Common::Keymapper *const mapper = _eventMan->getKeymapper();
+
+	// Do not try to recreate same keymap over again
+	if (mapper->getKeymap(kKeymapName))
+		return;
+
+	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
+
+	// Since the game has multiple built-in keys for each of these anyway,
+	// this just attempts to remap one of them.
+	const Common::KeyActionEntry keyActionEntries[] = {
+		{ Common::KeyState(Common::KEYCODE_SPACE, ' ', 0),                   "PAUS",  _("Pause")     },
+		{ Common::KeyState(Common::KEYCODE_ESCAPE, Common::ASCII_ESCAPE, 0), "SKCT", _("Skip")      },
+		{ Common::KeyState(Common::KEYCODE_PERIOD, '.', 0),                  "SKLI", _("Skip line") }
+	};
+
+	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
+		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
+		act->setKeyEvent(keyActionEntries[i].ks);
+	}
+
+	mapper->addGameKeymap(engineKeyMap);
+#endif
+}
+
 void Engine::deinitKeymap() {
 #ifdef ENABLE_KEYMAPPER
 	_eventMan->getKeymapper()->cleanupGameKeymaps();
diff --git a/engines/engine.h b/engines/engine.h
index cc7994e..af55aa9 100644
--- a/engines/engine.h
+++ b/engines/engine.h
@@ -208,7 +208,7 @@ public:
 	/*
 	 * Initialize any engine-specific keymaps.
 	 */
-	virtual void initKeymap() {}
+	virtual void initKeymap();
 
 	/*
 	 * Cleanup any engine-specific keymaps.
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 892c0ad..9680d8e 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -123,22 +123,9 @@ void GuiManager::initKeymap() {
 	Keymap *guiMap = new Keymap(Keymap::kKeymapTypeGui, kGuiKeymapName);
 
 	act = new Action(guiMap, "CLOS", _("Close"));
+	act->addDefaultInputMapping("ESCAPE");
 	act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));
 
-	act = new Action(guiMap, "CLIK", _("Mouse click"));
-	act->setLeftClickEvent();
-
-#ifdef ENABLE_VKEYBD
-	act = new Action(guiMap, "VIRT", _("Display keyboard"));
-	act->addEvent(EVENT_VIRTUAL_KEYBOARD);
-#endif
-
-	act = new Action(guiMap, "REMP", _("Remap keys"));
-	act->setEvent(EVENT_KEYMAPPER_REMAP);
-
-	act = new Action(guiMap, "FULS", _("Toggle fullscreen"));
-	act->setKeyEvent(KeyState(KEYCODE_RETURN, ASCII_RETURN, KBD_ALT));
-
 	mapper->addGlobalKeymap(guiMap);
 }
 


Commit: 576982bc33e5b106226c06bd74c747754e3c76e7
    https://github.com/scummvm/scummvm/commit/576982bc33e5b106226c06bd74c747754e3c76e7
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Use the default action bindings defined by the backends

Changed paths:
    backends/keymapper/keymap.cpp
    backends/keymapper/keymap.h
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    base/main.cpp


diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index f769077..2e99a44 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -29,6 +29,7 @@
 
 #include "backends/keymapper/action.h"
 #include "backends/keymapper/hardware-input.h"
+#include "backends/keymapper/keymapper-defaults.h"
 
 #define KEYMAP_KEY_PREFIX "keymap_"
 
@@ -39,7 +40,8 @@ Keymap::Keymap(KeymapType type, const String &name) :
 		_name(name),
 		_configDomain(nullptr),
 		_enabled(true),
-		_hardwareInputSet(nullptr) {
+		_hardwareInputSet(nullptr),
+		_backendDefaultBindings(nullptr) {
 
 }
 
@@ -123,6 +125,23 @@ void Keymap::setHardwareInputs(HardwareInputSet *hardwareInputSet) {
 	_hardwareInputSet = hardwareInputSet;
 }
 
+void Keymap::setBackendDefaultBindings(const Common::KeymapperDefaultBindings *backendDefaultBindings) {
+	_backendDefaultBindings = backendDefaultBindings;
+}
+
+void Keymap::registerBackendDefaultMappings() {
+	assert(_backendDefaultBindings);
+
+	for (ActionArray::const_iterator it = _actions.begin(); it != _actions.end(); ++it) {
+		Action *action = *it;
+		Common::String defaultHwId = _backendDefaultBindings->getDefaultBinding(_name, action->id);
+
+		if (!defaultHwId.empty()) {
+			action->addDefaultInputMapping(defaultHwId);
+		}
+	}
+}
+
 void Keymap::loadMappings() {
 	assert(_configDomain);
 	assert(_hardwareInputSet);
@@ -131,6 +150,10 @@ void Keymap::loadMappings() {
 		return;
 	}
 
+	if (_backendDefaultBindings) {
+		registerBackendDefaultMappings();
+	}
+
 	String prefix = KEYMAP_KEY_PREFIX + _name + "_";
 
 	_hwActionMap.clear();
diff --git a/backends/keymapper/keymap.h b/backends/keymapper/keymap.h
index 516a158..461b3a9 100644
--- a/backends/keymapper/keymap.h
+++ b/backends/keymapper/keymap.h
@@ -38,6 +38,7 @@ namespace Common {
 class Action;
 class HardwareInput;
 class HardwareInputSet;
+class KeymapperDefaultBindings;
 
 class Keymap {
 public:
@@ -53,6 +54,7 @@ public:
 	~Keymap();
 	void setConfigDomain(ConfigManager::Domain *configDomain);
 	void setHardwareInputs(HardwareInputSet *hardwareInputSet);
+	void setBackendDefaultBindings(const KeymapperDefaultBindings *backendDefaultBindings);
 
 	/**
 	* Registers a HardwareInput to the given Action
@@ -141,7 +143,9 @@ private:
 
 	ConfigManager::Domain *_configDomain;
 	HardwareInputSet *_hardwareInputSet;
+	const KeymapperDefaultBindings *_backendDefaultBindings;
 
+	void registerBackendDefaultMappings();
 };
 
 
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 569b4a3..20a8593 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -39,7 +39,8 @@ Keymapper::Keymapper(EventManager *evtMgr) :
 		_eventMan(evtMgr),
 		_enabled(true),
 		_enabledKeymapType(Keymap::kKeymapTypeGlobal),
-		_hardwareInputs(nullptr) {
+		_hardwareInputs(nullptr),
+		_backendDefaultBindings(nullptr) {
 }
 
 Keymapper::~Keymapper() {
@@ -61,6 +62,13 @@ void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) {
 	_hardwareInputs = inputs;
 }
 
+void Keymapper::registerBackendDefaultBindings(const Common::KeymapperDefaultBindings *backendDefaultBindings) {
+	if (!_keymaps.empty())
+		error("Backend default bindings must be defined before adding keymaps");
+
+	_backendDefaultBindings = backendDefaultBindings;
+}
+
 void Keymapper::addGlobalKeymap(Keymap *keymap) {
 	assert(keymap->getType() == Keymap::kKeymapTypeGlobal
 	       || keymap->getType() == Keymap::kKeymapTypeGui);
@@ -93,6 +101,7 @@ void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
 
 	keymap->setConfigDomain(domain);
 	keymap->setHardwareInputs(_hardwareInputs);
+	keymap->setBackendDefaultBindings(_backendDefaultBindings);
 	keymap->loadMappings();
 }
 
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index 8eac321..3289e7d 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -41,6 +41,7 @@ const char *const kGlobalKeymapName = "global";
 class Action;
 class HardwareInput;
 class HardwareInputSet;
+class KeymapperDefaultBindings;
 
 class Keymapper : public Common::DefaultEventMapper {
 public:
@@ -58,6 +59,11 @@ public:
 	void registerHardwareInputSet(HardwareInputSet *inputs);
 
 	/**
+	 * Registers platform-specific default mappings for keymap actions
+	 */
+	void registerBackendDefaultBindings(const KeymapperDefaultBindings *backendDefaultBindings);
+
+	/**
 	 * 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.
@@ -122,6 +128,7 @@ private:
 	void initKeymap(Keymap *keymap, ConfigManager::Domain *domain);
 
 	HardwareInputSet *_hardwareInputs;
+	const KeymapperDefaultBindings *_backendDefaultBindings;
 
 	Event executeAction(const Action *act, IncomingEventType incomingType);
 	EventType convertDownToUp(EventType eventType);
diff --git a/base/main.cpp b/base/main.cpp
index 83399dd..0c2f677 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -355,10 +355,12 @@ static void setupKeymapper(OSystem &system) {
 
 	Keymapper *mapper = system.getEventManager()->getKeymapper();
 
+	// Query the backend for hardware keys and default bindings and register them
 	HardwareInputSet *inputSet = system.getHardwareInputSet();
+	const Common::KeymapperDefaultBindings *backendDefaultBindings = system.getKeymapperDefaultBindings();
 
-	// Query backend for hardware keys and register them
 	mapper->registerHardwareInputSet(inputSet);
+	mapper->registerBackendDefaultBindings(backendDefaultBindings);
 
 	// Now create the global keymap
 	Keymap *primaryGlobalKeymap = new Keymap(Keymap::kKeymapTypeGlobal, kGlobalKeymapName);


Commit: d60190b12ec96df31a900e0432f03ab225dac26f
    https://github.com/scummvm/scummvm/commit/d60190b12ec96df31a900e0432f03ab225dac26f
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
ENGINES: Define default bindings for the existing engine keymaps

Changed paths:
    backends/keymapper/action.h
    engines/engine.cpp
    engines/kyra/engine/eobcommon.cpp
    engines/kyra/engine/lol.cpp
    engines/mohawk/riven.cpp
    engines/pegasus/pegasus.cpp


diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
index b0e96b3..00d162b 100644
--- a/backends/keymapper/action.h
+++ b/backends/keymapper/action.h
@@ -38,8 +38,9 @@ struct HardwareInput;
 class Keymap;
 
 struct KeyActionEntry {
-	const KeyState ks;
 	const char *id;
+	const KeyState ks;
+	const char *defaultHwId;
 	const char *description;
 };
 
diff --git a/engines/engine.cpp b/engines/engine.cpp
index dfc24f5..850ccf0 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -629,14 +629,15 @@ void Engine::initKeymap() {
 	// Since the game has multiple built-in keys for each of these anyway,
 	// this just attempts to remap one of them.
 	const Common::KeyActionEntry keyActionEntries[] = {
-		{ Common::KeyState(Common::KEYCODE_SPACE, ' ', 0),                   "PAUS",  _("Pause")     },
-		{ Common::KeyState(Common::KEYCODE_ESCAPE, Common::ASCII_ESCAPE, 0), "SKCT", _("Skip")      },
-		{ Common::KeyState(Common::KEYCODE_PERIOD, '.', 0),                  "SKLI", _("Skip line") }
+		{ "PAUS", Common::KeyState(Common::KEYCODE_SPACE, ' ', 0),                   "SPACE",  _("Pause")     },
+		{ "SKCT", Common::KeyState(Common::KEYCODE_ESCAPE, Common::ASCII_ESCAPE, 0), "ESCAPE", _("Skip")      },
+		{ "SKLI", Common::KeyState(Common::KEYCODE_PERIOD, '.', 0),                  "PERIOD", _("Skip line") }
 	};
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
 		act->setKeyEvent(keyActionEntries[i].ks);
+		act->addDefaultInputMapping(keyActionEntries[i].defaultHwId);
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/kyra/engine/eobcommon.cpp b/engines/kyra/engine/eobcommon.cpp
index c79f7a5..f552a7f 100644
--- a/engines/kyra/engine/eobcommon.cpp
+++ b/engines/kyra/engine/eobcommon.cpp
@@ -354,33 +354,35 @@ void EoBCoreEngine::initKeymap() {
 	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	const Common::KeyActionEntry keyActionEntries[] = {
-		{ Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward") },
-		{ Common::KeyState(Common::KEYCODE_DOWN), "MVB", _("Move Back") },
-		{ Common::KeyState(Common::KEYCODE_LEFT), "MVL", _("Move Left") },
-		{ Common::KeyState(Common::KEYCODE_RIGHT), "MVR", _("Move Right") },
-		{ Common::KeyState(Common::KEYCODE_HOME), "TL", _("Turn Left") },
-		{ Common::KeyState(Common::KEYCODE_PAGEUP), "TR", _("Turn Right") },
-		{ Common::KeyState(Common::KEYCODE_i), "INV", _("Open/Close Inventory") },
-		{ Common::KeyState(Common::KEYCODE_p), "SCE", _("Switch Inventory/Character screen") },
-		{ Common::KeyState(Common::KEYCODE_c), "CMP", _("Camp") },
-		{ Common::KeyState(Common::KEYCODE_SPACE), "CSP", _("Cast Spell") },
+		{ "MVF", Common::KEYCODE_UP,     "UP",     _("Move Forward")                      },
+		{ "MVB", Common::KEYCODE_DOWN,   "DOWN",   _("Move Back")                         },
+		{ "MVL", Common::KEYCODE_LEFT,   "LEFT",   _("Move Left")                         },
+		{ "MVR", Common::KEYCODE_RIGHT,  "RIGHT",  _("Move Right")                        },
+		{ "TL",  Common::KEYCODE_HOME,   "HOME",   _("Turn Left")                         },
+		{ "TR",  Common::KEYCODE_PAGEUP, "PAGEUP", _("Turn Right")                        },
+		{ "INV", Common::KEYCODE_i,      "i",      _("Open/Close Inventory")              },
+		{ "SCE", Common::KEYCODE_p,      "p",      _("Switch Inventory/Character screen") },
+		{ "CMP", Common::KEYCODE_c,      "c",      _("Camp")                              },
+		{ "CSP", Common::KEYCODE_SPACE,  "SPACE",  _("Cast Spell")                        },
 		// TODO: Spell cursor, but this needs more thought, since different
 		// game versions use different keycodes.
-		{ Common::KeyState(Common::KEYCODE_1), "SL1", _("Spell Level 1") },
-		{ Common::KeyState(Common::KEYCODE_2), "SL2", _("Spell Level 2") },
-		{ Common::KeyState(Common::KEYCODE_3), "SL3", _("Spell Level 3") },
-		{ Common::KeyState(Common::KEYCODE_4), "SL4", _("Spell Level 4") },
-		{ Common::KeyState(Common::KEYCODE_5), "SL5", _("Spell Level 5") }
+		{ "SL1", Common::KEYCODE_1,      "1",      _("Spell Level 1")                     },
+		{ "SL2", Common::KEYCODE_2,      "2",      _("Spell Level 2")                     },
+		{ "SL3", Common::KEYCODE_3,      "3",      _("Spell Level 3")                     },
+		{ "SL4", Common::KEYCODE_4,      "4",      _("Spell Level 4")                     },
+		{ "SL5", Common::KEYCODE_5,      "5",      _("Spell Level 5")                     }
 	};
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); ++i) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
 		act->setKeyEvent(keyActionEntries[i].ks);
+		act->addDefaultInputMapping(keyActionEntries[i].defaultHwId);
 	}
 
 	if (_flags.gameID == GI_EOB2) {
 		Common::Action *const act = new Common::Action(engineKeyMap, "SL6", _("Spell Level 6"));
 		act->setKeyEvent(Common::KeyState(Common::KEYCODE_6));
+		act->addDefaultInputMapping("6");
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/kyra/engine/lol.cpp b/engines/kyra/engine/lol.cpp
index 0d09f11..1397369 100644
--- a/engines/kyra/engine/lol.cpp
+++ b/engines/kyra/engine/lol.cpp
@@ -472,24 +472,25 @@ void LoLEngine::initKeymap() {
 	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	const Common::KeyActionEntry keyActionEntries[] = {
-		{Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1), "AT1", _("Attack 1")},
-		{Common::KeyState(Common::KEYCODE_F2, Common::ASCII_F2), "AT2", _("Attack 2")},
-		{Common::KeyState(Common::KEYCODE_F3, Common::ASCII_F3), "AT3", _("Attack 3")},
-		{Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward")},
-		{Common::KeyState(Common::KEYCODE_DOWN), "MVB", _("Move Back")},
-		{Common::KeyState(Common::KEYCODE_LEFT), "SLL", _("Slide Left")},
-		{Common::KeyState(Common::KEYCODE_RIGHT), "SLR", _("Slide Right")},
-		{Common::KeyState(Common::KEYCODE_HOME), "TL", _("Turn Left")},
-		{Common::KeyState(Common::KEYCODE_PAGEUP), "TR", _("Turn Right")},
-		{Common::KeyState(Common::KEYCODE_r), "RST", _("Rest")},
-		{Common::KeyState(Common::KEYCODE_o), "OPT", _("Options")},
-		{Common::KeyState(Common::KEYCODE_SLASH), "SPL", _("Choose Spell")},
-		{Common::KeyState(), 0, 0}
+		{ "AT1", Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1), "F1",     _("Attack 1")     },
+		{ "AT2", Common::KeyState(Common::KEYCODE_F2, Common::ASCII_F2), "F2",     _("Attack 2")     },
+		{ "AT3", Common::KeyState(Common::KEYCODE_F3, Common::ASCII_F3), "F3",     _("Attack 3")     },
+		{ "MVF", Common::KeyState(Common::KEYCODE_UP),                   "UP",     _("Move Forward") },
+		{ "MVB", Common::KeyState(Common::KEYCODE_DOWN),                 "DOWN",   _("Move Back")    },
+		{ "SLL", Common::KeyState(Common::KEYCODE_LEFT),                 "LEFT",   _("Slide Left")   },
+		{ "SLR", Common::KeyState(Common::KEYCODE_RIGHT),                "RIGHT",  _("Slide Right")  },
+		{ "TL",  Common::KeyState(Common::KEYCODE_HOME),                 "HOME",   _("Turn Left")    },
+		{ "TR",  Common::KeyState(Common::KEYCODE_PAGEUP),               "PAGEUP", _("Turn Right")   },
+		{ "RST", Common::KeyState(Common::KEYCODE_r),                    "r",      _("Rest")         },
+		{ "OPT", Common::KeyState(Common::KEYCODE_o),                    "o",      _("Options")      },
+		{ "SPL", Common::KeyState(Common::KEYCODE_SLASH),                "SLASH",  _("Choose Spell") },
+		{ 0,     Common::KeyState(),                                     0,        0                 }
 	};
 
 	for (const Common::KeyActionEntry *entry = keyActionEntries; entry->id; ++entry) {
 		Common::Action *const act = new Common::Action(engineKeyMap, entry->id, entry->description);
 		act->setKeyEvent(entry->ks);
+		act->addDefaultInputMapping(entry->defaultHwId);
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 1f3e6c4..a02f0da 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -879,47 +879,51 @@ void MohawkEngine_Riven::initKeymap() {
 	Common::Keymapper *const mapper = _eventMan->getKeymapper();
 
 	// Do not try to recreate same keymap over again
-	if (mapper->getKeymap(kKeymapName) != 0)
+	if (mapper->getKeymap(kKeymapName))
 		return;
 
 	Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
 
 	const Common::KeyActionEntry keyActionEntries[] = {
-		{ Common::KEYCODE_UP, "UP", _("Move Forward") },
-		{ Common::KEYCODE_DOWN, "DWN", _("Move Back") },
-		{ Common::KEYCODE_LEFT, "TL", _("Turn Left") },
-		{ Common::KEYCODE_RIGHT, "TR", _("Turn Right") },
-		{ Common::KEYCODE_PAGEUP, "LKUP", _("Look Up") },
-		{ Common::KEYCODE_PAGEDOWN, "LKDN", _("Look Down") },
-		{ Common::KEYCODE_F5, "OPTS", _("Show/Hide Options Menu") },
-		{ Common::KEYCODE_SPACE, "PAUS", _("Pause") },
-		{ Common::KeyState(Common::KEYCODE_o, 'o', Common::KBD_CTRL), "LOAD", _("Load Game State") },
-		{ Common::KeyState(Common::KEYCODE_s, 's', Common::KBD_CTRL), "SAVE", _("Save Game State") }
+		{ "UP",   Common::KEYCODE_UP,                                         "UP",       _("Move Forward")           },
+		{ "DWN",  Common::KEYCODE_DOWN,                                       "DOWN",     _("Move Back")              },
+		{ "TL",   Common::KEYCODE_LEFT,                                       "LEFT",     _("Turn Left")              },
+		{ "TR",   Common::KEYCODE_RIGHT,                                      "RIGHT",    _("Turn Right")             },
+		{ "LKUP", Common::KEYCODE_PAGEUP,                                     "PAGEUP",   _("Look Up")                },
+		{ "LKDN", Common::KEYCODE_PAGEDOWN,                                   "PAGEDOWN", _("Look Down")              },
+		{ "OPTS", Common::KEYCODE_F5,                                         "F5",       _("Show/Hide Options Menu") },
+		{ "PAUS", Common::KEYCODE_SPACE,                                      "SPACE",    _("Pause")                  },
+		{ "LOAD", Common::KeyState(Common::KEYCODE_o, 'o', Common::KBD_CTRL), "C+o",      _("Load Game State")        },
+		{ "SAVE", Common::KeyState(Common::KEYCODE_s, 's', Common::KBD_CTRL), "C+s",      _("Save Game State")        }
 	};
 
 	const Common::KeyActionEntry keyActionEntriesDemo[] = {
-		{ Common::KeyState(Common::KEYCODE_r, 'r', Common::KBD_CTRL), "RMM", _("Return To Main Menu") },
-		{ Common::KeyState(Common::KEYCODE_p, 'p', Common::KBD_CTRL), "INTV", _("Play Intro Videos") }
+		{ "RMM",  Common::KeyState(Common::KEYCODE_r, 'r', Common::KBD_CTRL), "C+r",      _("Return To Main Menu")    },
+		{ "INTV", Common::KeyState(Common::KEYCODE_p, 'p', Common::KBD_CTRL), "C+p",      _("Play Intro Videos")      }
 	};
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
 		act->setKeyEvent(keyActionEntries[i].ks);
+		act->addDefaultInputMapping(keyActionEntries[i].defaultHwId);
 	}
 
 	if (getFeatures() & GF_DEMO) {
 		for (uint i = 0; i < ARRAYSIZE(keyActionEntriesDemo); i++) {
 			Common::Action* const act = new Common::Action(engineKeyMap, keyActionEntriesDemo[i].id, keyActionEntriesDemo[i].description);
 			act->setKeyEvent(keyActionEntriesDemo[i].ks);
+			act->addDefaultInputMapping(keyActionEntriesDemo[i].defaultHwId);
 		}
 	}
 
 	if (getFeatures() & GF_25TH) {
 		Common::Action* const act = new Common::Action(engineKeyMap, "SMNU", _("Skip / Open main menu"));
 		act->setKeyEvent(Common::KEYCODE_ESCAPE);
+		act->addDefaultInputMapping("ESCAPE");
 	} else {
 		Common::Action* const act = new Common::Action(engineKeyMap, "SKIP", _("Skip"));
 		act->setKeyEvent(Common::KEYCODE_ESCAPE);
+		act->addDefaultInputMapping("ESCAPE");
 	}
 
 	mapper->addGameKeymap(engineKeyMap);
diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp
index e8ff92e..943ca26 100644
--- a/engines/pegasus/pegasus.cpp
+++ b/engines/pegasus/pegasus.cpp
@@ -2503,22 +2503,23 @@ void PegasusEngine::initKeymap() {
 	// Since the game has multiple built-in keys for each of these anyway,
 	// this just attempts to remap one of them.
 	const Common::KeyActionEntry keyActionEntries[] = {
-		{ Common::KEYCODE_UP, "UP", _("Up/Zoom In/Move Forward/Open Doors") },
-		{ Common::KEYCODE_DOWN, "DWN", _("Down/Zoom Out") },
-		{ Common::KEYCODE_LEFT, "TL", _("Turn Left") },
-		{ Common::KEYCODE_RIGHT, "TR", _("Turn Right") },
-		{ Common::KEYCODE_BACKQUOTE, "TIV", _("Display/Hide Inventory Tray") },
-		{ Common::KEYCODE_BACKSPACE, "TBI", _("Display/Hide Biochip Tray") },
-		{ Common::KEYCODE_RETURN, "ENT", _("Action/Select") },
-		{ Common::KEYCODE_t, "TMA", _("Toggle Center Data Display") },
-		{ Common::KEYCODE_i, "TIN", _("Display/Hide Info Screen") },
-		{ Common::KEYCODE_ESCAPE, "PM", _("Display/Hide Pause Menu") },
-		{ Common::KEYCODE_e, "WTF", "???" } // easter egg key (without being completely upfront about it)
+		{ "UP",  Common::KEYCODE_UP,        "UP",        _("Up/Zoom In/Move Forward/Open Doors") },
+		{ "DWN", Common::KEYCODE_DOWN,      "DOWN",      _("Down/Zoom Out")                      },
+		{ "TL",  Common::KEYCODE_LEFT,      "LEFT",      _("Turn Left")                          },
+		{ "TR",  Common::KEYCODE_RIGHT,     "RIGHT",     _("Turn Right")                         },
+		{ "TIV", Common::KEYCODE_BACKQUOTE, "BACKQUOTE", _("Display/Hide Inventory Tray")        },
+		{ "TBI", Common::KEYCODE_BACKSPACE, "BACKSPACE", _("Display/Hide Biochip Tray")          },
+		{ "ENT", Common::KEYCODE_RETURN,    "RETURN",    _("Action/Select")                      },
+		{ "TMA", Common::KEYCODE_t,         "t",         _("Toggle Center Data Display")         },
+		{ "TIN", Common::KEYCODE_i,         "i",         _("Display/Hide Info Screen")           },
+		{ "PM",  Common::KEYCODE_ESCAPE,    "ESCAPE",    _("Display/Hide Pause Menu")            },
+		{ "WTF", Common::KEYCODE_e,         "e",         "???" } // easter egg key (without being completely upfront about it)
 	};
 
 	for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) {
 		Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
 		act->setKeyEvent(keyActionEntries[i].ks);
+		act->addDefaultInputMapping(keyActionEntries[i].defaultHwId);
 	}
 
 	mapper->addGameKeymap(engineKeyMap);


Commit: 5a62837f04ff0034f4f751419c83e603ccd53ea4
    https://github.com/scummvm/scummvm/commit/5a62837f04ff0034f4f751419c83e603ccd53ea4
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
MAEMO: Adapt to the new keymapper API

Changed paths:
    backends/platform/maemo/maemo.cpp


diff --git a/backends/platform/maemo/maemo.cpp b/backends/platform/maemo/maemo.cpp
index 836102e..f297d5d 100644
--- a/backends/platform/maemo/maemo.cpp
+++ b/backends/platform/maemo/maemo.cpp
@@ -198,7 +198,7 @@ Common::HardwareInputSet *OSystem_SDL_Maemo::getHardwareInputSet() {
 
 Common::Keymap *OSystem_SDL_Maemo::getGlobalKeymap() {
 	using namespace Common;
-	Keymap *globalMap = new Keymap("maemo");
+	Keymap *globalMap = new Keymap(Keymap::kKeymapTypeGlobal, "maemo");
 
 	Action *act;
 
@@ -206,16 +206,16 @@ Common::Keymap *OSystem_SDL_Maemo::getGlobalKeymap() {
 	Event evt = Event();
 	evt.type = EVENT_CUSTOM_BACKEND_ACTION;
 	evt.customType = Maemo::kEventClickMode;
-	act->addEvent(evt);
+	act->setEvent(evt);
 
 	act = new Action(globalMap, "LCLK", _("Left Click"));
-	act->addLeftClickEvent();
+	act->setLeftClickEvent();
 
 	act = new Action(globalMap, "MCLK", _("Middle Click"));
-	act->addMiddleClickEvent();
+	act->setMiddleClickEvent();
 
 	act = new Action(globalMap, "RCLK", _("Right Click"));
-	act->addRightClickEvent();
+	act->setRightClickEvent();
 
 	return globalMap;
 }


Commit: 52be1c8c63a0fc6a3ed2f2a6c546cb2d1b98935f
    https://github.com/scummvm/scummvm/commit/52be1c8c63a0fc6a3ed2f2a6c546cb2d1b98935f
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
EVENTRECORDER: Register as an event observer rather than a mapper

Changed paths:
    gui/EventRecorder.cpp
    gui/EventRecorder.h


diff --git a/gui/EventRecorder.cpp b/gui/EventRecorder.cpp
index d0cf266..e5b1cb4 100644
--- a/gui/EventRecorder.cpp
+++ b/gui/EventRecorder.cpp
@@ -232,7 +232,7 @@ void EventRecorder::togglePause() {
 }
 
 void EventRecorder::RegisterEventSource() {
-	g_system->getEventManager()->getEventDispatcher()->registerMapper(this, false);
+	g_system->getEventManager()->getEventDispatcher()->registerObserver(this, Common::EventManager::kEventRecorderPriority, false);
 }
 
 uint32 EventRecorder::getRandomSeed(const Common::String &name) {
@@ -433,9 +433,9 @@ void EventRecorder::updateSubsystems() {
 	_recordMode = oldRecordMode;
 }
 
-Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Common::EventSource *source) {
+bool EventRecorder::notifyEvent(const Common::Event &ev) {
 	if ((!_initialized) && (_recordMode != kRecorderPlaybackPause)) {
-		return DefaultEventMapper::mapEvent(ev, source);
+		return false;
 	}
 
 	checkForKeyCode(ev);
@@ -444,23 +444,21 @@ Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Com
 	evt.mouse.y = evt.mouse.y * (g_system->getOverlayHeight() / g_system->getHeight());
 	switch (_recordMode) {
 	case kRecorderPlayback:
-		if (ev.kbdRepeat != true) {
-			return Common::List<Common::Event>();
+		if (!ev.kbdRepeat) {
+			return true;
 		}
-		return Common::DefaultEventMapper::mapEvent(ev, source);
-		break;
+		return false;
 	case kRecorderRecord:
 		g_gui.processEvent(evt, _controlPanel);
 		if (((evt.type == Common::EVENT_LBUTTONDOWN) || (evt.type == Common::EVENT_LBUTTONUP) || (evt.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) {
-			return Common::List<Common::Event>();
+			return true;
 		} else {
 			Common::RecorderEvent e(ev);
 			e.recordedtype = Common::kRecorderEventTypeNormal;
 			e.time = _fakeTimer;
 			_playbackFile->writeEvent(e);
-			return DefaultEventMapper::mapEvent(ev, source);
+			return false;
 		}
-		break;
 	case kRecorderPlaybackPause: {
 		Common::Event dialogEvent;
 		if (_controlPanel->isEditDlgVisible()) {
@@ -470,16 +468,13 @@ Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Com
 		}
 		g_gui.processEvent(dialogEvent, _controlPanel->getActiveDlg());
 		if (((dialogEvent.type == Common::EVENT_LBUTTONDOWN) || (dialogEvent.type == Common::EVENT_LBUTTONUP) || (dialogEvent.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) {
-			return Common::List<Common::Event>();
+			return true;
 		}
-		return Common::DefaultEventMapper::mapEvent(dialogEvent, source);
+		return false;
 	}
-		break;
 	default:
-		return Common::DefaultEventMapper::mapEvent(ev, source);
+		return false;
 	}
-
-	return Common::DefaultEventMapper::mapEvent(ev, source);
 }
 
 void EventRecorder::setGameMd5(const ADGameDescription *gameDesc) {
diff --git a/gui/EventRecorder.h b/gui/EventRecorder.h
index c2c4d6a..3aa4adf 100644
--- a/gui/EventRecorder.h
+++ b/gui/EventRecorder.h
@@ -64,7 +64,7 @@ class WriteStream;
  *
  * TODO: Add more documentation.
  */
-class EventRecorder : private Common::EventSource, public Common::Singleton<EventRecorder>, private Common::DefaultEventMapper {
+class EventRecorder : private Common::EventSource, public Common::Singleton<EventRecorder>, private Common::EventObserver {
 	friend class Common::Singleton<SingletonBaseType>;
 	EventRecorder();
 	~EventRecorder() override;
@@ -175,8 +175,8 @@ public:
 	void switchFastMode();
 
 private:
-	Common::List<Common::Event> mapEvent(const Common::Event &ev, Common::EventSource *source) override;
 	bool pollEvent(Common::Event &ev) override;
+	bool notifyEvent(const Common::Event &event) override;
 	bool _initialized;
 	volatile uint32 _fakeTimer;
 	bool _savedState;


Commit: 3d48b54288753f3383a6a0bae9a8f4a54da533ec
    https://github.com/scummvm/scummvm/commit/3d48b54288753f3383a6a0bae9a8f4a54da533ec
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Remove the ascii value from the hardware keys

The ascii value is for text input, which is not related to hotkeys.

Changed paths:
    backends/keymapper/hardware-input.cpp
    backends/keymapper/hardware-input.h
    backends/platform/maemo/maemo.cpp


diff --git a/backends/keymapper/hardware-input.cpp b/backends/keymapper/hardware-input.cpp
index 9798b76..94676c3 100644
--- a/backends/keymapper/hardware-input.cpp
+++ b/backends/keymapper/hardware-input.cpp
@@ -29,193 +29,193 @@
 namespace Common {
 
 static const KeyTableEntry defaultKeys[] = {
-	{"BACKSPACE", KEYCODE_BACKSPACE, ASCII_BACKSPACE, "Backspace", false},
-	{"TAB", KEYCODE_TAB, ASCII_TAB, "Tab", false},
-	{"CLEAR", KEYCODE_CLEAR, 0, "Clear", false},
-	{"RETURN", KEYCODE_RETURN, ASCII_RETURN, "Return", false},
-	{"PAUSE", KEYCODE_PAUSE, 0, "Pause", false},
-	{"ESCAPE", KEYCODE_ESCAPE, ASCII_ESCAPE, "Esc", false},
-	{"SPACE", KEYCODE_SPACE, ASCII_SPACE, "Space", false},
-	{"EXCLAIM", KEYCODE_EXCLAIM, '!', "!", false},
-	{"QUOTEDBL", KEYCODE_QUOTEDBL, '"', "\"", false},
-	{"HASH", KEYCODE_HASH, '#', "#", false},
-	{"DOLLAR", KEYCODE_DOLLAR, '$', "$", false},
-	{"PERCENT", KEYCODE_PERCENT, '%', "%", false},
-	{"AMPERSAND", KEYCODE_AMPERSAND, '&', "&", false},
-	{"QUOTE", KEYCODE_QUOTE, '\'', "'", false},
-	{"LEFTPAREN", KEYCODE_LEFTPAREN, '(', "(", false},
-	{"RIGHTPAREN", KEYCODE_RIGHTPAREN, ')', ")", false},
-	{"ASTERISK", KEYCODE_ASTERISK, '*', "*", false},
-	{"PLUS", KEYCODE_PLUS, '+', "+", false},
-	{"COMMA", KEYCODE_COMMA, ',', ",", false},
-	{"MINUS", KEYCODE_MINUS, '-', "-", false},
-	{"PERIOD", KEYCODE_PERIOD, '.', ".", false},
-	{"SLASH", KEYCODE_SLASH, '/', "/", false},
-	{"0", KEYCODE_0, '0', "0", false},
-	{"1", KEYCODE_1, '1', "1", false},
-	{"2", KEYCODE_2, '2', "2", false},
-	{"3", KEYCODE_3, '3', "3", false},
-	{"4", KEYCODE_4, '4', "4", false},
-	{"5", KEYCODE_5, '5', "5", false},
-	{"6", KEYCODE_6, '6', "6", false},
-	{"7", KEYCODE_7, '7', "7", false},
-	{"8", KEYCODE_8, '8', "8", false},
-	{"9", KEYCODE_9, '9', "9", false},
-	{"COLON", KEYCODE_COLON, ':', ":", false},
-	{"SEMICOLON", KEYCODE_SEMICOLON, ';', ";", false},
-	{"LESS", KEYCODE_LESS, '<', "<", false},
-	{"EQUALS", KEYCODE_EQUALS, '=', "=", false},
-	{"GREATER", KEYCODE_GREATER, '>', ">", false},
-	{"QUESTION", KEYCODE_QUESTION, '?', "?", false},
-	{"AT", KEYCODE_AT, '@', "@", false},
-
-	{"LEFTBRACKET", KEYCODE_LEFTBRACKET, '[', "[", false},
-	{"BACKSLASH", KEYCODE_BACKSLASH, '\\', "\\", false},
-	{"RIGHTBRACKET", KEYCODE_RIGHTBRACKET, ']', "]", false},
-	{"CARET", KEYCODE_CARET, '^', "^", false},
-	{"UNDERSCORE", KEYCODE_UNDERSCORE, '_', "_", false},
-	{"BACKQUOTE", KEYCODE_BACKQUOTE, '`', "`", false},
-	{"a", KEYCODE_a, 'a', "a", true},
-	{"b", KEYCODE_b, 'b', "b", true},
-	{"c", KEYCODE_c, 'c', "c", true},
-	{"d", KEYCODE_d, 'd', "d", true},
-	{"e", KEYCODE_e, 'e', "e", true},
-	{"f", KEYCODE_f, 'f', "f", true},
-	{"g", KEYCODE_g, 'g', "g", true},
-	{"h", KEYCODE_h, 'h', "h", true},
-	{"i", KEYCODE_i, 'i', "i", true},
-	{"j", KEYCODE_j, 'j', "j", true},
-	{"k", KEYCODE_k, 'k', "k", true},
-	{"l", KEYCODE_l, 'l', "l", true},
-	{"m", KEYCODE_m, 'm', "m", true},
-	{"n", KEYCODE_n, 'n', "n", true},
-	{"o", KEYCODE_o, 'o', "o", true},
-	{"p", KEYCODE_p, 'p', "p", true},
-	{"q", KEYCODE_q, 'q', "q", true},
-	{"r", KEYCODE_r, 'r', "r", true},
-	{"s", KEYCODE_s, 's', "s", true},
-	{"t", KEYCODE_t, 't', "t", true},
-	{"u", KEYCODE_u, 'u', "u", true},
-	{"v", KEYCODE_v, 'v', "v", true},
-	{"w", KEYCODE_w, 'w', "w", true},
-	{"x", KEYCODE_x, 'x', "x", true},
-	{"y", KEYCODE_y, 'y', "y", true},
-	{"z", KEYCODE_z, 'z', "z", true},
-	{"DELETE", KEYCODE_DELETE, 0, "Del", false},
+	{"BACKSPACE", KEYCODE_BACKSPACE, "Backspace"},
+	{"TAB", KEYCODE_TAB, "Tab"},
+	{"CLEAR", KEYCODE_CLEAR, "Clear"},
+	{"RETURN", KEYCODE_RETURN, "Return"},
+	{"PAUSE", KEYCODE_PAUSE, "Pause"},
+	{"ESCAPE", KEYCODE_ESCAPE, "Esc"},
+	{"SPACE", KEYCODE_SPACE, "Space"},
+	{"EXCLAIM", KEYCODE_EXCLAIM, "!"},
+	{"QUOTEDBL", KEYCODE_QUOTEDBL, "\""},
+	{"HASH", KEYCODE_HASH, "#"},
+	{"DOLLAR", KEYCODE_DOLLAR, "$"},
+	{"PERCENT", KEYCODE_PERCENT, "%"},
+	{"AMPERSAND", KEYCODE_AMPERSAND, "&"},
+	{"QUOTE", KEYCODE_QUOTE, "'"},
+	{"LEFTPAREN", KEYCODE_LEFTPAREN, "("},
+	{"RIGHTPAREN", KEYCODE_RIGHTPAREN, ")"},
+	{"ASTERISK", KEYCODE_ASTERISK, "*"},
+	{"PLUS", KEYCODE_PLUS, "+"},
+	{"COMMA", KEYCODE_COMMA, ","},
+	{"MINUS", KEYCODE_MINUS, "-"},
+	{"PERIOD", KEYCODE_PERIOD, "."},
+	{"SLASH", KEYCODE_SLASH, "/"},
+	{"0", KEYCODE_0, "0"},
+	{"1", KEYCODE_1, "1"},
+	{"2", KEYCODE_2, "2"},
+	{"3", KEYCODE_3, "3"},
+	{"4", KEYCODE_4, "4"},
+	{"5", KEYCODE_5, "5"},
+	{"6", KEYCODE_6, "6"},
+	{"7", KEYCODE_7, "7"},
+	{"8", KEYCODE_8, "8"},
+	{"9", KEYCODE_9, "9"},
+	{"COLON", KEYCODE_COLON, ":"},
+	{"SEMICOLON", KEYCODE_SEMICOLON, ";"},
+	{"LESS", KEYCODE_LESS, "<"},
+	{"EQUALS", KEYCODE_EQUALS, "="},
+	{"GREATER", KEYCODE_GREATER, ">"},
+	{"QUESTION", KEYCODE_QUESTION, "?"},
+	{"AT", KEYCODE_AT, "@"},
+
+	{"LEFTBRACKET", KEYCODE_LEFTBRACKET, "["},
+	{"BACKSLASH", KEYCODE_BACKSLASH, "\\"},
+	{"RIGHTBRACKET", KEYCODE_RIGHTBRACKET, "]"},
+	{"CARET", KEYCODE_CARET, "^"},
+	{"UNDERSCORE", KEYCODE_UNDERSCORE, "_"},
+	{"BACKQUOTE", KEYCODE_BACKQUOTE, "`"},
+	{"a", KEYCODE_a, "a"},
+	{"b", KEYCODE_b, "b"},
+	{"c", KEYCODE_c, "c"},
+	{"d", KEYCODE_d, "d"},
+	{"e", KEYCODE_e, "e"},
+	{"f", KEYCODE_f, "f"},
+	{"g", KEYCODE_g, "g"},
+	{"h", KEYCODE_h, "h"},
+	{"i", KEYCODE_i, "i"},
+	{"j", KEYCODE_j, "j"},
+	{"k", KEYCODE_k, "k"},
+	{"l", KEYCODE_l, "l"},
+	{"m", KEYCODE_m, "m"},
+	{"n", KEYCODE_n, "n"},
+	{"o", KEYCODE_o, "o"},
+	{"p", KEYCODE_p, "p"},
+	{"q", KEYCODE_q, "q"},
+	{"r", KEYCODE_r, "r"},
+	{"s", KEYCODE_s, "s"},
+	{"t", KEYCODE_t, "t"},
+	{"u", KEYCODE_u, "u"},
+	{"v", KEYCODE_v, "v"},
+	{"w", KEYCODE_w, "w"},
+	{"x", KEYCODE_x, "x"},
+	{"y", KEYCODE_y, "y"},
+	{"z", KEYCODE_z, "z"},
+	{"DELETE", KEYCODE_DELETE, "Del"},
 
 	// Numeric keypad
-	{"KP0", KEYCODE_KP0, 0, "KP0", false},
-	{"KP1", KEYCODE_KP1, 0, "KP1", false},
-	{"KP2", KEYCODE_KP2, 0, "KP2", false},
-	{"KP3", KEYCODE_KP3, 0, "KP3", false},
-	{"KP4", KEYCODE_KP4, 0, "KP4", false},
-	{"KP5", KEYCODE_KP5, 0, "KP5", false},
-	{"KP6", KEYCODE_KP6, 0, "KP6", false},
-	{"KP7", KEYCODE_KP7, 0, "KP7", false},
-	{"KP8", KEYCODE_KP8, 0, "KP8", false},
-	{"KP9", KEYCODE_KP9, 0, "KP9", false},
-	{"KP_PERIOD", KEYCODE_KP_PERIOD, 0, "KP.", false},
-	{"KP_DIVIDE", KEYCODE_KP_DIVIDE, 0, "KP/", false},
-	{"KP_MULTIPLY", KEYCODE_KP_MULTIPLY, 0, "KP*", false},
-	{"KP_MINUS", KEYCODE_KP_MINUS, 0, "KP-", false},
-	{"KP_PLUS", KEYCODE_KP_PLUS, 0, "KP+", false},
-	{"KP_ENTER", KEYCODE_KP_ENTER, 0, "KP Enter", false},
-	{"KP_EQUALS", KEYCODE_KP_EQUALS, 0, "KP=", false},
+	{"KP0", KEYCODE_KP0, "KP0"},
+	{"KP1", KEYCODE_KP1, "KP1"},
+	{"KP2", KEYCODE_KP2, "KP2"},
+	{"KP3", KEYCODE_KP3, "KP3"},
+	{"KP4", KEYCODE_KP4, "KP4"},
+	{"KP5", KEYCODE_KP5, "KP5"},
+	{"KP6", KEYCODE_KP6, "KP6"},
+	{"KP7", KEYCODE_KP7, "KP7"},
+	{"KP8", KEYCODE_KP8, "KP8"},
+	{"KP9", KEYCODE_KP9, "KP9"},
+	{"KP_PERIOD", KEYCODE_KP_PERIOD, "KP."},
+	{"KP_DIVIDE", KEYCODE_KP_DIVIDE, "KP/"},
+	{"KP_MULTIPLY", KEYCODE_KP_MULTIPLY, "KP*"},
+	{"KP_MINUS", KEYCODE_KP_MINUS, "KP-"},
+	{"KP_PLUS", KEYCODE_KP_PLUS, "KP+"},
+	{"KP_ENTER", KEYCODE_KP_ENTER, "KP Enter"},
+	{"KP_EQUALS", KEYCODE_KP_EQUALS, "KP="},
 
 	// Arrows + Home/End pad
-	{"UP", KEYCODE_UP, 0, "Up", false},
-	{"DOWN", KEYCODE_DOWN, 0, "Down", false},
-	{"RIGHT", KEYCODE_RIGHT, 0, "Right", false},
-	{"LEFT", KEYCODE_LEFT, 0, "Left", false},
-	{"INSERT", KEYCODE_INSERT, 0, "Insert", false},
-	{"HOME", KEYCODE_HOME, 0, "Home", false},
-	{"END", KEYCODE_END, 0, "End", false},
-	{"PAGEUP", KEYCODE_PAGEUP, 0, "PgUp", false},
-	{"PAGEDOWN", KEYCODE_PAGEDOWN, 0, "PgDn", false},
+	{"UP", KEYCODE_UP, "Up"},
+	{"DOWN", KEYCODE_DOWN, "Down"},
+	{"RIGHT", KEYCODE_RIGHT, "Right"},
+	{"LEFT", KEYCODE_LEFT, "Left"},
+	{"INSERT", KEYCODE_INSERT, "Insert"},
+	{"HOME", KEYCODE_HOME, "Home"},
+	{"END", KEYCODE_END, "End"},
+	{"PAGEUP", KEYCODE_PAGEUP, "PgUp"},
+	{"PAGEDOWN", KEYCODE_PAGEDOWN, "PgDn"},
 
 	// Function keys
-	{"F1", KEYCODE_F1, ASCII_F1, "F1", false},
-	{"F2", KEYCODE_F2, ASCII_F2, "F2", false},
-	{"F3", KEYCODE_F3, ASCII_F3, "F3", false},
-	{"F4", KEYCODE_F4, ASCII_F4, "F4", false},
-	{"F5", KEYCODE_F5, ASCII_F5, "F5", false},
-	{"F6", KEYCODE_F6, ASCII_F6, "F6", false},
-	{"F7", KEYCODE_F7, ASCII_F7, "F7", false},
-	{"F8", KEYCODE_F8, ASCII_F8, "F8", false},
-	{"F9", KEYCODE_F9, ASCII_F9, "F9", false},
-	{"F10", KEYCODE_F10, ASCII_F10, "F10", false},
-	{"F11", KEYCODE_F11, ASCII_F11, "F11", false},
-	{"F12", KEYCODE_F12, ASCII_F12, "F12", false},
-	{"F13", KEYCODE_F13, 0, "F13", false},
-	{"F14", KEYCODE_F14, 0, "F14", false},
-	{"F15", KEYCODE_F15, 0, "F15", false},
-	{"F16", KEYCODE_F16, 0, "F16", false},
-	{"F17", KEYCODE_F17, 0, "F17", false},
-	{"F18", KEYCODE_F18, 0, "F18", false},
+	{"F1", KEYCODE_F1, "F1"},
+	{"F2", KEYCODE_F2, "F2"},
+	{"F3", KEYCODE_F3, "F3"},
+	{"F4", KEYCODE_F4, "F4"},
+	{"F5", KEYCODE_F5, "F5"},
+	{"F6", KEYCODE_F6, "F6"},
+	{"F7", KEYCODE_F7, "F7"},
+	{"F8", KEYCODE_F8, "F8"},
+	{"F9", KEYCODE_F9, "F9"},
+	{"F10", KEYCODE_F10, "F10"},
+	{"F11", KEYCODE_F11, "F11"},
+	{"F12", KEYCODE_F12, "F12"},
+	{"F13", KEYCODE_F13, "F13"},
+	{"F14", KEYCODE_F14, "F14"},
+	{"F15", KEYCODE_F15, "F15"},
+	{"F16", KEYCODE_F16, "F16"},
+	{"F17", KEYCODE_F17, "F17"},
+	{"F18", KEYCODE_F18, "F18"},
 
 	// Miscellaneous function keys
-	{"HELP", KEYCODE_HELP, 0, "Help", false},
-	{"PRINT", KEYCODE_PRINT, 0, "Print", false},
-	{"SYSREQ", KEYCODE_SYSREQ, 0, "SysRq", false},
-	{"BREAK", KEYCODE_BREAK, 0, "Break", false},
-	{"MENU", KEYCODE_MENU, 0, "Menu", false},
+	{"HELP", KEYCODE_HELP, "Help"},
+	{"PRINT", KEYCODE_PRINT, "Print"},
+	{"SYSREQ", KEYCODE_SYSREQ, "SysRq"},
+	{"BREAK", KEYCODE_BREAK, "Break"},
+	{"MENU", KEYCODE_MENU, "Menu"},
 		// Power Macintosh power key
-	{"POWER", KEYCODE_POWER, 0, "Power", false},
+	{"POWER", KEYCODE_POWER, "Power"},
 		// Some european keyboards
-	{"EURO", KEYCODE_EURO, 0, "Euro", false},
+	{"EURO", KEYCODE_EURO, "Euro"},
 		// Atari keyboard has Undo
-	{"UNDO", KEYCODE_UNDO, 0, "Undo", false},
-	{"SLEEP", KEYCODE_SLEEP, 0, "Sleep", false},
-	{"MUTE", KEYCODE_MUTE, 0, "Mute", false},
-	{"EJECT", KEYCODE_EJECT, 0, "Eject", false},
-	{"VOLUMEUP", KEYCODE_VOLUMEUP, 0, "Volume Up", false},
-	{"VOLUMEDOWN", KEYCODE_VOLUMEDOWN, 0, "Volume Down", false},
-	{"LEFTSOFT", KEYCODE_LEFTSOFT, 0, "Left Soft", false},
-	{"RIGHTSOFT", KEYCODE_RIGHTSOFT, 0, "Right Soft", false},
-	{"CALL", KEYCODE_CALL, 0, "Call", false},
-	{"HANGUP", KEYCODE_HANGUP, 0, "Hang up", false},
-	{"CAMERA", KEYCODE_CAMERA, 0, "Camera", false},
-	{"WWW", KEYCODE_WWW, 0, "WWW", false},
-	{"MAIL", KEYCODE_MAIL, 0, "Mail", false},
-	{"CALCULATOR", KEYCODE_CALCULATOR, 0, "Calculator", false},
-	{"CUT", KEYCODE_CUT, 0, "Cut", false},
-	{"COPY", KEYCODE_COPY, 0, "Copy", false},
-	{"PASTE", KEYCODE_PASTE, 0, "Paste", false},
-	{"SELECT", KEYCODE_SELECT, 0, "Select", false},
-	{"CANCEL", KEYCODE_CANCEL, 0, "Cancel", false},
+	{"UNDO", KEYCODE_UNDO, "Undo"},
+	{"SLEEP", KEYCODE_SLEEP, "Sleep"},
+	{"MUTE", KEYCODE_MUTE, "Mute"},
+	{"EJECT", KEYCODE_EJECT, "Eject"},
+	{"VOLUMEUP", KEYCODE_VOLUMEUP, "Volume Up"},
+	{"VOLUMEDOWN", KEYCODE_VOLUMEDOWN, "Volume Down"},
+	{"LEFTSOFT", KEYCODE_LEFTSOFT, "Left Soft"},
+	{"RIGHTSOFT", KEYCODE_RIGHTSOFT, "Right Soft"},
+	{"CALL", KEYCODE_CALL, "Call"},
+	{"HANGUP", KEYCODE_HANGUP, "Hang up"},
+	{"CAMERA", KEYCODE_CAMERA, "Camera"},
+	{"WWW", KEYCODE_WWW, "WWW"},
+	{"MAIL", KEYCODE_MAIL, "Mail"},
+	{"CALCULATOR", KEYCODE_CALCULATOR, "Calculator"},
+	{"CUT", KEYCODE_CUT, "Cut"},
+	{"COPY", KEYCODE_COPY, "Copy"},
+	{"PASTE", KEYCODE_PASTE, "Paste"},
+	{"SELECT", KEYCODE_SELECT, "Select"},
+	{"CANCEL", KEYCODE_CANCEL, "Cancel"},
 
 	// Action keys
-	{"AC_SEARCH", KEYCODE_AC_SEARCH, 0, "AC Search", false},
-	{"AC_HOME", KEYCODE_AC_HOME, 0, "AC Home", false},
-	{"AC_BACK", KEYCODE_AC_BACK, 0, "AC Back", false},
-	{"AC_FORWARD", KEYCODE_AC_FORWARD, 0, "AC Forward", false},
-	{"AC_STOP", KEYCODE_AC_STOP, 0, "AC Stop", false},
-	{"AC_REFRESH", KEYCODE_AC_REFRESH, 0, "AC Refresh", false},
-	{"AC_BOOKMARKS", KEYCODE_AC_BOOKMARKS, 0, "AC Bookmarks", false},
+	{"AC_SEARCH", KEYCODE_AC_SEARCH, "AC Search"},
+	{"AC_HOME", KEYCODE_AC_HOME, "AC Home"},
+	{"AC_BACK", KEYCODE_AC_BACK, "AC Back"},
+	{"AC_FORWARD", KEYCODE_AC_FORWARD, "AC Forward"},
+	{"AC_STOP", KEYCODE_AC_STOP, "AC Stop"},
+	{"AC_REFRESH", KEYCODE_AC_REFRESH, "AC Refresh"},
+	{"AC_BOOKMARKS", KEYCODE_AC_BOOKMARKS, "AC Bookmarks"},
 
 	// Audio keys
-	{"AUDIONEXT", KEYCODE_AUDIONEXT, 0, "Audio Next", false},
-	{"AUDIOPREV", KEYCODE_AUDIOPREV, 0, "Audio Previous", false},
-	{"AUDIOSTOP", KEYCODE_AUDIOSTOP, 0, "Audio Stop", false},
-	{"AUDIOPLAY", KEYCODE_AUDIOPLAY, 0, "Audio Play", false},
-	{"AUDIOPAUSE", KEYCODE_AUDIOPAUSE, 0, "Audio Pause", false},
-	{"AUDIOPLAYPAUSE", KEYCODE_AUDIOPLAYPAUSE, 0, "Audio Play/Pause", false},
-	{"AUDIOMUTE", KEYCODE_AUDIOMUTE, 0, "Audio Mute", false},
-	{"AUDIOREWIND", KEYCODE_AUDIOREWIND, 0, "Audio Rewind", false},
-	{"AUDIOFASTFORWARD", KEYCODE_AUDIOFASTFORWARD, 0, "Audio Fast-Forward", false},
-
-	{0, KEYCODE_INVALID, 0, 0, false}
+	{"AUDIONEXT", KEYCODE_AUDIONEXT, "Audio Next"},
+	{"AUDIOPREV", KEYCODE_AUDIOPREV, "Audio Previous"},
+	{"AUDIOSTOP", KEYCODE_AUDIOSTOP, "Audio Stop"},
+	{"AUDIOPLAY", KEYCODE_AUDIOPLAY, "Audio Play"},
+	{"AUDIOPAUSE", KEYCODE_AUDIOPAUSE, "Audio Pause"},
+	{"AUDIOPLAYPAUSE", KEYCODE_AUDIOPLAYPAUSE, "Audio Play/Pause"},
+	{"AUDIOMUTE", KEYCODE_AUDIOMUTE, "Audio Mute"},
+	{"AUDIOREWIND", KEYCODE_AUDIOREWIND, "Audio Rewind"},
+	{"AUDIOFASTFORWARD", KEYCODE_AUDIOFASTFORWARD, "Audio Fast-Forward"},
+
+	{0, KEYCODE_INVALID, 0}
 };
 
 static const ModifierTableEntry defaultModifiers[] = {
-	{ 0, "", "", false },
-	{ KBD_CTRL, "C+", "Ctrl+", false },
-	{ KBD_ALT, "A+", "Alt+", false },
-	{ KBD_SHIFT, "", "", true },
-	{ KBD_CTRL | KBD_ALT, "C+A+", "Ctrl+Alt+", false },
-	{ KBD_SHIFT | KBD_CTRL, "S+C+", "Shift+Ctrl+", true },
-	{ KBD_SHIFT | KBD_CTRL | KBD_ALT, "C+A+", "Ctrl+Alt+", true },
-	{ 0, 0, 0, false }
+	{ 0, "", "" },
+	{ KBD_CTRL, "C+", "Ctrl+" },
+	{ KBD_ALT, "A+", "Alt+" },
+	{ KBD_SHIFT, "S+", "Shift+" },
+	{ KBD_CTRL | KBD_ALT, "C+A+", "Ctrl+Alt+" },
+	{ KBD_SHIFT | KBD_CTRL, "S+C+", "Shift+Ctrl+" },
+	{ KBD_SHIFT | KBD_CTRL | KBD_ALT, "S+C+A+", "Shift+Ctrl+Alt+" },
+	{ 0, 0, 0 }
 };
 
 HardwareInputSet::HardwareInputSet(bool useDefault, const KeyTableEntry *keys, const ModifierTableEntry *modifiers) {
@@ -226,7 +226,7 @@ HardwareInputSet::HardwareInputSet(bool useDefault, const KeyTableEntry *keys, c
 }
 
 HardwareInputSet::~HardwareInputSet() {
-	List<const HardwareInput *>::const_iterator it;
+	Array<const HardwareInput *>::const_iterator it;
 
 	for (it = _inputs.begin(); it != _inputs.end(); ++it)
 		delete *it;
@@ -243,7 +243,7 @@ void HardwareInputSet::addHardwareInput(const HardwareInput *input) {
 }
 
 const HardwareInput *HardwareInputSet::findHardwareInput(String id) const {
-	List<const HardwareInput *>::const_iterator it;
+	Array<const HardwareInput *>::const_iterator it;
 
 	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
 		if ((*it)->id == id)
@@ -253,7 +253,7 @@ const HardwareInput *HardwareInputSet::findHardwareInput(String id) const {
 }
 
 const HardwareInput *HardwareInputSet::findHardwareInput(const HardwareInputCode code) const {
-	List<const HardwareInput *>::const_iterator it;
+	Array<const HardwareInput *>::const_iterator it;
 
 	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
 		const HardwareInput *entry = *it;
@@ -263,8 +263,8 @@ const HardwareInput *HardwareInputSet::findHardwareInput(const HardwareInputCode
 	return 0;
 }
 
-const HardwareInput *HardwareInputSet::findHardwareInput(const KeyState& keystate) const {
-	List<const HardwareInput *>::const_iterator it;
+const HardwareInput *HardwareInputSet::findHardwareInput(const KeyState &keystate) const {
+	Array<const HardwareInput *>::const_iterator it;
 
 	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
 		const HardwareInput *entry = *it;
@@ -282,27 +282,13 @@ void HardwareInputSet::addHardwareInputs(const HardwareInputTableEntry inputs[])
 void HardwareInputSet::addHardwareInputs(const KeyTableEntry keys[], const ModifierTableEntry modifiers[]) {
 	const KeyTableEntry *key;
 	const ModifierTableEntry *mod;
-	char fullKeyId[50];
-	char fullKeyDesc[100];
-	uint16 ascii;
 
 	for (mod = modifiers; mod->id; mod++) {
 		for (key = keys; key->hwId; key++) {
-			ascii = key->ascii;
-
-			if (mod->shiftable && key->shiftable) {
-				snprintf(fullKeyId, 50, "%s%c", mod->id, toupper(key->hwId[0]));
-				snprintf(fullKeyDesc, 100, "%s%c", mod->desc, toupper(key->desc[0]));
-				ascii = toupper(key->ascii);
-			} else if (mod->shiftable) {
-				snprintf(fullKeyId, 50, "S+%s%s", mod->id, key->hwId);
-				snprintf(fullKeyDesc, 100, "Shift+%s%s", mod->desc, key->desc);
-			} else {
-				snprintf(fullKeyId, 50, "%s%s", mod->id, key->hwId);
-				snprintf(fullKeyDesc, 100, "%s%s", mod->desc, key->desc);
-			}
-
-			addHardwareInput(new HardwareInput(fullKeyId, KeyState(key->keycode, ascii, mod->flag), fullKeyDesc));
+			String fullKeyId = String::format("%s%s", mod->id, key->hwId);
+			String fullKeyDesc = String::format("%s%s", mod->desc, key->desc);
+
+			addHardwareInput(new HardwareInput(fullKeyId, KeyState(key->keycode, 0, mod->flag), fullKeyDesc));
 		}
 	}
 }
@@ -311,7 +297,7 @@ void HardwareInputSet::removeHardwareInput(const HardwareInput *input) {
 	if (!input)
 		return;
 
-	List<const HardwareInput *>::iterator it;
+	Array<const HardwareInput *>::iterator it;
 
 	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
 		const HardwareInput *entry = (*it);
diff --git a/backends/keymapper/hardware-input.h b/backends/keymapper/hardware-input.h
index 064d7e9..29baa2c 100644
--- a/backends/keymapper/hardware-input.h
+++ b/backends/keymapper/hardware-input.h
@@ -27,8 +27,8 @@
 
 #ifdef ENABLE_KEYMAPPER
 
+#include "common/array.h"
 #include "common/keyboard.h"
-#include "common/list.h"
 #include "common/str.h"
 #include "common/textconsole.h"
 
@@ -69,10 +69,10 @@ struct HardwareInput {
 	 */
 	KeyState key;
 
-	HardwareInput(String i, HardwareInputCode ic = 0, String desc = "")
+	HardwareInput(const String &i, HardwareInputCode ic = 0, const String &desc = "")
 		: id(i), inputCode(ic), description(desc), type(kHardwareInputTypeGeneric) { }
 
-	HardwareInput(String i, KeyState ky, String desc = "")
+	HardwareInput(const String &i, KeyState ky, const String &desc = "")
 		: id(i), key(ky), description(desc), type(kHardwareInputTypeKeyboard) { }
 };
 
@@ -88,9 +88,7 @@ struct HardwareInputTableEntry {
 struct KeyTableEntry {
 	const char *hwId;
 	KeyCode keycode;
-	uint16 ascii;
 	const char *desc;
-	bool shiftable;
 };
 
 /**
@@ -100,7 +98,6 @@ struct ModifierTableEntry {
 	byte flag;
 	const char *id;
 	const char *desc;
-	bool shiftable;
 };
 
 /**
@@ -127,9 +124,9 @@ public:
 
 	const HardwareInput *findHardwareInput(const HardwareInputCode code) const;
 
-	const HardwareInput *findHardwareInput(const KeyState& keystate) const;
+	const HardwareInput *findHardwareInput(const KeyState &keystate) const;
 
-	const List<const HardwareInput *> &getHardwareInputs() const { return _inputs; }
+	const Array<const HardwareInput *> &getHardwareInputs() const { return _inputs; }
 
 	uint size() const { return _inputs.size(); }
 
@@ -150,7 +147,7 @@ public:
 
 private:
 
-	List<const HardwareInput *> _inputs;
+	Array<const HardwareInput *> _inputs;
 };
 
 } // End of namespace Common
diff --git a/backends/platform/maemo/maemo.cpp b/backends/platform/maemo/maemo.cpp
index f297d5d..5beaa48 100644
--- a/backends/platform/maemo/maemo.cpp
+++ b/backends/platform/maemo/maemo.cpp
@@ -183,13 +183,13 @@ const Maemo::Model OSystem_SDL_Maemo::detectModel() {
 #ifdef ENABLE_KEYMAPPER
 static const Common::KeyTableEntry maemoKeys[] = {
 	// Function keys
-	{"MENU", Common::KEYCODE_F11, 0, "Menu", false},
-	{"HOME", Common::KEYCODE_F12, 0, "Home", false},
-	{"FULLSCREEN", Common::KEYCODE_F13, 0, "FullScreen", false},
-	{"ZOOMPLUS", Common::KEYCODE_F14, 0, "Zoom+", false},
-	{"ZOOMMINUS", Common::KEYCODE_F15, 0, "Zoom-", false},
+	{"MENU", Common::KEYCODE_F11, "Menu"},
+	{"HOME", Common::KEYCODE_F12, "Home"},
+	{"FULLSCREEN", Common::KEYCODE_F13, "FullScreen"},
+	{"ZOOMPLUS", Common::KEYCODE_F14, "Zoom+"},
+	{"ZOOMMINUS", Common::KEYCODE_F15, "Zoom-"},
 
-	{0, Common::KEYCODE_INVALID, 0, 0, false}
+	{0, Common::KEYCODE_INVALID, 0}
 };
 
 Common::HardwareInputSet *OSystem_SDL_Maemo::getHardwareInputSet() {


Commit: 285b10beef9c896ad38bf8e6e51ff815cee6127b
    https://github.com/scummvm/scummvm/commit/285b10beef9c896ad38bf8e6e51ff815cee6127b
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-01-26T19:07:53+01:00

Commit Message:
KEYMAPPER: Store hardware inputs into maps

Changed paths:
    backends/keymapper/hardware-input.cpp
    backends/keymapper/hardware-input.h
    backends/keymapper/keymapper.cpp


diff --git a/backends/keymapper/hardware-input.cpp b/backends/keymapper/hardware-input.cpp
index 94676c3..86d70a1 100644
--- a/backends/keymapper/hardware-input.cpp
+++ b/backends/keymapper/hardware-input.cpp
@@ -226,57 +226,51 @@ HardwareInputSet::HardwareInputSet(bool useDefault, const KeyTableEntry *keys, c
 }
 
 HardwareInputSet::~HardwareInputSet() {
-	Array<const HardwareInput *>::const_iterator it;
-
-	for (it = _inputs.begin(); it != _inputs.end(); ++it)
-		delete *it;
+	for (KeyInputMap::iterator it = _keyInput.begin(); it != _keyInput.end(); ++it)
+		delete it->_value;
+	for (CustomInputMap::iterator it = _customInput.begin(); it != _customInput.end(); ++it)
+		delete it->_value;
 }
 
-void HardwareInputSet::addHardwareInput(const HardwareInput *input) {
-	assert(input);
-
-	debug(8, "Adding hardware input [%s][%s]", input->id.c_str(), input->description.c_str());
-
-	removeHardwareInput(input);
-
-	_inputs.push_back(input);
-}
-
-const HardwareInput *HardwareInputSet::findHardwareInput(String id) const {
-	Array<const HardwareInput *>::const_iterator it;
-
-	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
-		if ((*it)->id == id)
-			return (*it);
+const HardwareInput *HardwareInputSet::findHardwareInput(const String &id) const {
+	for (KeyInputMap::const_iterator it = _keyInput.begin(); it != _keyInput.end(); ++it) {
+		if ((*it)._value->id == id)
+			return (*it)._value;
 	}
-	return 0;
+	for (CustomInputMap::const_iterator it = _customInput.begin(); it != _customInput.end(); ++it) {
+		if ((*it)._value->id == id)
+			return (*it)._value;
+	}
+
+	return nullptr;
 }
 
 const HardwareInput *HardwareInputSet::findHardwareInput(const HardwareInputCode code) const {
-	Array<const HardwareInput *>::const_iterator it;
-
-	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
-		const HardwareInput *entry = *it;
-		if (entry->type == kHardwareInputTypeGeneric && entry->inputCode == code)
-			return entry;
-	}
-	return 0;
+	return _customInput[code];
 }
 
 const HardwareInput *HardwareInputSet::findHardwareInput(const KeyState &keystate) const {
-	Array<const HardwareInput *>::const_iterator it;
-
-	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
-		const HardwareInput *entry = *it;
-		if (entry->type == kHardwareInputTypeKeyboard && entry->key == keystate)
-			return entry;
-	}
-	return 0;
+	return _keyInput[keystate];
 }
 
 void HardwareInputSet::addHardwareInputs(const HardwareInputTableEntry inputs[]) {
-	for (const HardwareInputTableEntry *entry = inputs; entry->hwId; ++entry)
-		addHardwareInput(new HardwareInput(entry->hwId, entry->code, entry->desc));
+	for (const HardwareInputTableEntry *entry = inputs; entry->hwId; ++entry) {
+		const HardwareInput *existingInput = findHardwareInput(entry->code);
+		if (existingInput) {
+			warning("Ignoring hardware input %s (code %d) because an input with the same code is already defined",
+			        entry->desc, entry->code);
+			continue;
+		}
+
+		existingInput = findHardwareInput(entry->hwId);
+		if (existingInput) {
+			warning("Ignoring hardware input %s (id %s) because an input with the same id is already defined",
+			        entry->desc, entry->hwId);
+			continue;
+		}
+
+		_customInput[entry->code] = new HardwareInput(entry->hwId, entry->code, entry->desc);
+	}
 }
 
 void HardwareInputSet::addHardwareInputs(const KeyTableEntry keys[], const ModifierTableEntry modifiers[]) {
@@ -285,35 +279,25 @@ void HardwareInputSet::addHardwareInputs(const KeyTableEntry keys[], const Modif
 
 	for (mod = modifiers; mod->id; mod++) {
 		for (key = keys; key->hwId; key++) {
-			String fullKeyId = String::format("%s%s", mod->id, key->hwId);
-			String fullKeyDesc = String::format("%s%s", mod->desc, key->desc);
+			String keyId = String::format("%s%s", mod->id, key->hwId);
+			KeyState keystate = KeyState(key->keycode, 0, mod->flag);
+
+			const HardwareInput *existingInput = findHardwareInput(keystate);
+			if (existingInput) {
+				warning("Ignoring hardware input %s%s (id %s) because an input with the same keystate is already defined",
+				        keys->desc, mod->desc, keyId.c_str());
+				continue;
+			}
+
+			existingInput = findHardwareInput(keyId);
+			if (existingInput) {
+				warning("Ignoring hardware input %s%s (id %s) because an input with the same id is already defined",
+				        keys->desc, mod->desc, keyId.c_str());
+				continue;
+			}
 
-			addHardwareInput(new HardwareInput(fullKeyId, KeyState(key->keycode, 0, mod->flag), fullKeyDesc));
-		}
-	}
-}
-
-void HardwareInputSet::removeHardwareInput(const HardwareInput *input) {
-	if (!input)
-		return;
-
-	Array<const HardwareInput *>::iterator it;
-
-	for (it = _inputs.begin(); it != _inputs.end(); ++it) {
-		const HardwareInput *entry = (*it);
-		bool match = false;
-		if (entry->id == input->id)
-			match = true;
-		else if (input->type == entry->type) {
-			if (input->type == kHardwareInputTypeGeneric && input->inputCode == entry->inputCode)
-				match = true;
-			else if (input->type == kHardwareInputTypeKeyboard && input->key == entry->key)
-				match = true;
-		}
-		if (match) {
-			debug(7, "Removing hardware input [%s] (%s) because it matches [%s] (%s)", entry->id.c_str(), entry->description.c_str(), input->id.c_str(), input->description.c_str());
-			delete entry;
-			_inputs.erase(it);
+			String fullKeyDesc = String::format("%s%s", mod->desc, key->desc);
+			_keyInput[keystate] = new HardwareInput(keyId, keystate, fullKeyDesc);
 		}
 	}
 }
diff --git a/backends/keymapper/hardware-input.h b/backends/keymapper/hardware-input.h
index 29baa2c..eda7661 100644
--- a/backends/keymapper/hardware-input.h
+++ b/backends/keymapper/hardware-input.h
@@ -28,6 +28,7 @@
 #ifdef ENABLE_KEYMAPPER
 
 #include "common/array.h"
+#include "common/hashmap.h"
 #include "common/keyboard.h"
 #include "common/str.h"
 #include "common/textconsole.h"
@@ -101,6 +102,17 @@ struct ModifierTableEntry {
 };
 
 /**
+ * Hash function for KeyState
+ */
+template<> struct Hash<KeyState>
+		: public UnaryFunction<KeyState, uint> {
+
+	uint operator()(const KeyState &val) const {
+		return (uint)val.keycode | ((uint)val.flags << 24);
+	}
+};
+
+/**
  * Simple class to encapsulate a device's set of HardwareInputs.
  * Each device should instantiate this and call addHardwareInput a number of times
  * in its constructor to define the device's available keys.
@@ -118,18 +130,12 @@ public:
 
 	virtual ~HardwareInputSet();
 
-	void addHardwareInput(const HardwareInput *input);
-
-	const HardwareInput *findHardwareInput(String id) const;
+	const HardwareInput *findHardwareInput(const String &id) const;
 
 	const HardwareInput *findHardwareInput(const HardwareInputCode code) const;
 
 	const HardwareInput *findHardwareInput(const KeyState &keystate) const;
 
-	const Array<const HardwareInput *> &getHardwareInputs() const { return _inputs; }
-
-	uint size() const { return _inputs.size(); }
-
 	/**
 	 * Add hardware inputs to the set out of a table.
 	 * @param inputs       table of available inputs
@@ -143,11 +149,13 @@ public:
 	 */
 	void addHardwareInputs(const KeyTableEntry keys[], const ModifierTableEntry modifiers[]);
 
-	void removeHardwareInput(const HardwareInput *input);
-
 private:
 
-	Array<const HardwareInput *> _inputs;
+	typedef HashMap<KeyState, const HardwareInput *> KeyInputMap;
+	typedef HashMap<HardwareInputCode, const HardwareInput *> CustomInputMap;
+
+	KeyInputMap _keyInput;
+	CustomInputMap _customInput;
 };
 
 } // End of namespace Common
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 20a8593..2de9c9b 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -239,7 +239,6 @@ EventType Keymapper::convertDownToUp(EventType type) {
 }
 
 const HardwareInput *Keymapper::findHardwareInput(const Event &event) {
-	// FIXME: Performance
 	switch (event.type) {
 		case EVENT_KEYDOWN:
 		case EVENT_KEYUP:




More information about the Scummvm-git-logs mailing list