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