1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "backends/keymapper/keymap.h"
24 
25 #ifdef ENABLE_KEYMAPPER
26 
27 #include "common/system.h"
28 
29 #include "backends/keymapper/hardware-input.h"
30 #include "backends/keymapper/keymapper-defaults.h"
31 
32 #define KEYMAP_KEY_PREFIX "keymap_"
33 
34 namespace Common {
35 
Keymap(const Keymap & km)36 Keymap::Keymap(const Keymap& km) : _actions(km._actions), _keymap(), _nonkeymap(), _configDomain(0) {
37 	List<Action *>::iterator it;
38 
39 	for (it = _actions.begin(); it != _actions.end(); ++it) {
40 		const HardwareInput *hwInput = (*it)->getMappedInput();
41 
42 		if (hwInput) {
43 			if (hwInput->type == kHardwareInputTypeKeyboard)
44 				_keymap[hwInput->key] = *it;
45 			else if (hwInput->type == kHardwareInputTypeGeneric)
46 				_nonkeymap[hwInput->inputCode] = *it;
47 		}
48 	}
49 }
50 
~Keymap()51 Keymap::~Keymap() {
52 	List<Action *>::iterator it;
53 
54 	for (it = _actions.begin(); it != _actions.end(); ++it)
55 		delete *it;
56 }
57 
addAction(Action * action)58 void Keymap::addAction(Action *action) {
59 	if (findAction(action->id))
60 		error("Action with id %s already in KeyMap", action->id);
61 
62 	_actions.push_back(action);
63 }
64 
registerMapping(Action * action,const HardwareInput * hwInput)65 void Keymap::registerMapping(Action *action, const HardwareInput *hwInput) {
66 	if (hwInput->type == kHardwareInputTypeKeyboard) {
67 		HashMap<KeyState, Action *>::iterator it = _keymap.find(hwInput->key);
68 		// if input is already mapped to a different action then unmap it from there
69 		if (it != _keymap.end() && action != it->_value)
70 			it->_value->mapInput(0);
71 		// now map it
72 		_keymap[hwInput->key] = action;
73 	} else if (hwInput->type == kHardwareInputTypeGeneric) {
74 		HashMap<HardwareInputCode, Action *>::iterator it = _nonkeymap.find(hwInput->inputCode);
75 		// if input is already mapped to a different action then unmap it from there
76 		if (it != _nonkeymap.end() && action != it->_value)
77 			it->_value->mapInput(0);
78 		// now map it
79 		_nonkeymap[hwInput->inputCode] = action;
80 	}
81 }
82 
unregisterMapping(Action * action)83 void Keymap::unregisterMapping(Action *action) {
84 	const HardwareInput *hwInput = action->getMappedInput();
85 
86 	if (hwInput) {
87 		if (hwInput->type == kHardwareInputTypeKeyboard)
88 			_keymap.erase(hwInput->key);
89 		else if (hwInput->type == kHardwareInputTypeGeneric)
90 			_nonkeymap.erase(hwInput->inputCode);
91 	}
92 }
93 
getAction(const char * id)94 Action *Keymap::getAction(const char *id) {
95 	return findAction(id);
96 }
97 
findAction(const char * id)98 Action *Keymap::findAction(const char *id) {
99 	List<Action *>::iterator it;
100 
101 	for (it = _actions.begin(); it != _actions.end(); ++it) {
102 		if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0)
103 			return *it;
104 	}
105 	return 0;
106 }
107 
findAction(const char * id) const108 const Action *Keymap::findAction(const char *id) const {
109 	List<Action *>::const_iterator it;
110 
111 	for (it = _actions.begin(); it != _actions.end(); ++it) {
112 		if (strncmp((*it)->id, id, ACTION_ID_SIZE) == 0)
113 			return *it;
114 	}
115 
116 	return 0;
117 }
118 
getMappedAction(const KeyState & ks) const119 Action *Keymap::getMappedAction(const KeyState& ks) const {
120 	HashMap<KeyState, Action *>::iterator it;
121 
122 	it = _keymap.find(ks);
123 
124 	if (it == _keymap.end())
125 		return 0;
126 	else
127 		return it->_value;
128 }
129 
getMappedAction(const HardwareInputCode code) const130 Action *Keymap::getMappedAction(const HardwareInputCode code) const {
131 	HashMap<HardwareInputCode, Action *>::iterator it;
132 
133 	it = _nonkeymap.find(code);
134 
135 	if (it == _nonkeymap.end())
136 		return 0;
137 	else
138 		return it->_value;
139 }
140 
setConfigDomain(ConfigManager::Domain * dom)141 void Keymap::setConfigDomain(ConfigManager::Domain *dom) {
142 	_configDomain = dom;
143 }
144 
loadMappings(const HardwareInputSet * hwKeys)145 void Keymap::loadMappings(const HardwareInputSet *hwKeys) {
146 	if (!_configDomain)
147 		return;
148 
149 	if (_actions.empty())
150 		return;
151 
152 	Common::KeymapperDefaultBindings *defaults = g_system->getKeymapperDefaultBindings();
153 
154 	HashMap<String, const HardwareInput *> mappedInputs;
155 	List<Action*>::iterator it;
156 	String prefix = KEYMAP_KEY_PREFIX + _name + "_";
157 
158 	for (it = _actions.begin(); it != _actions.end(); ++it) {
159 		Action* ua = *it;
160 		String actionId(ua->id);
161 		String confKey = prefix + actionId;
162 
163 		String hwInputId = _configDomain->getVal(confKey);
164 
165 		bool defaulted = false;
166 		// fall back to the platform-specific defaults
167 		if (hwInputId.empty() && defaults) {
168 			hwInputId = defaults->getDefaultBinding(_name, actionId);
169 			if (!hwInputId.empty())
170 				defaulted = true;
171 		}
172 		// there's no mapping
173 		if (hwInputId.empty())
174 			continue;
175 
176 		const HardwareInput *hwInput = hwKeys->findHardwareInput(hwInputId.c_str());
177 
178 		if (!hwInput) {
179 			warning("HardwareInput with ID '%s' not known", hwInputId.c_str());
180 			continue;
181 		}
182 
183 		if (defaulted) {
184 			if (mappedInputs.contains(hwInputId)) {
185 				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());
186 				continue;
187 			}
188 			warning("Action [%s] fell back to hardcoded default value [%s]", confKey.c_str(), hwInputId.c_str());
189 		}
190 
191 		mappedInputs.setVal(hwInputId, hwInput);
192 		// map the key
193 		ua->mapInput(hwInput);
194 	}
195 }
196 
saveMappings()197 void Keymap::saveMappings() {
198 	if (!_configDomain)
199 		return;
200 
201 	List<Action *>::const_iterator it;
202 	String prefix = KEYMAP_KEY_PREFIX + _name + "_";
203 
204 	for (it = _actions.begin(); it != _actions.end(); ++it) {
205 		uint actIdLen = strlen((*it)->id);
206 
207 		actIdLen = (actIdLen > ACTION_ID_SIZE) ? ACTION_ID_SIZE : actIdLen;
208 
209 		String actId((*it)->id, (*it)->id + actIdLen);
210 		String hwId = "";
211 
212 		if ((*it)->getMappedInput()) {
213 			hwId = (*it)->getMappedInput()->id;
214 		}
215 		_configDomain->setVal(prefix + actId, hwId);
216 	}
217 }
218 
isComplete(const HardwareInputSet * hwInputs)219 bool Keymap::isComplete(const HardwareInputSet *hwInputs) {
220 	List<Action *>::iterator it;
221 	bool allMapped = true;
222 	uint numberMapped = 0;
223 
224 	for (it = _actions.begin(); it != _actions.end(); ++it) {
225 		if ((*it)->getMappedInput()) {
226 			++numberMapped;
227 		} else {
228 			allMapped = false;
229 		}
230 	}
231 
232 	return allMapped || (numberMapped == hwInputs->size());
233 }
234 
235 } // End of namespace Common
236 
237 #endif // #ifdef ENABLE_KEYMAPPER
238