1 /* ScummVM - Graphic Adventure Engine
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.
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.
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.
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.
26 #include "backends/keymapper/keymap.h"
28 #ifdef ENABLE_KEYMAPPER
30 #include "backends/keymapper/hardware-key.h"
32 #define KEYMAP_KEY_PREFIX "keymap_"
36 Keymap::Keymap(const Keymap
& km
) : _actions(km
._actions
), _keymap(), _configDomain(0) {
37 List
<Action
*>::iterator it
;
39 for (it
= _actions
.begin(); it
!= _actions
.end(); it
++) {
40 const HardwareKey
*hwKey
= (*it
)->getMappedKey();
43 _keymap
[hwKey
->key
] = *it
;
49 List
<Action
*>::iterator it
;
51 for (it
= _actions
.begin(); it
!= _actions
.end(); it
++)
55 void Keymap::addAction(Action
*action
) {
56 if (findAction(action
->id
))
57 error("Action with id %s already in KeyMap", action
->id
);
59 _actions
.push_back(action
);
62 void Keymap::registerMapping(Action
*action
, const HardwareKey
*hwKey
) {
63 HashMap
<KeyState
, Action
*>::iterator it
;
65 it
= _keymap
.find(hwKey
->key
);
67 // if key is already mapped to a different action then un-map it
68 if (it
!= _keymap
.end() && action
!= it
->_value
) {
69 it
->_value
->mapKey(0);
72 _keymap
[hwKey
->key
] = action
;
75 void Keymap::unregisterMapping(Action
*action
) {
76 const HardwareKey
*hwKey
= action
->getMappedKey();
79 _keymap
.erase(hwKey
->key
);
83 Action
*Keymap::getAction(const char *id
) {
84 return findAction(id
);
87 Action
*Keymap::findAction(const char *id
) {
88 List
<Action
*>::iterator it
;
90 for (it
= _actions
.begin(); it
!= _actions
.end(); it
++) {
91 if (strncmp((*it
)->id
, id
, ACTION_ID_SIZE
) == 0)
97 const Action
*Keymap::findAction(const char *id
) const {
98 List
<Action
*>::const_iterator it
;
100 for (it
= _actions
.begin(); it
!= _actions
.end(); it
++) {
101 if (strncmp((*it
)->id
, id
, ACTION_ID_SIZE
) == 0)
108 Action
*Keymap::getMappedAction(const KeyState
& ks
) const {
109 HashMap
<KeyState
, Action
*>::iterator it
;
111 it
= _keymap
.find(ks
);
113 if (it
== _keymap
.end())
119 void Keymap::setConfigDomain(ConfigManager::Domain
*dom
) {
123 void Keymap::loadMappings(const HardwareKeySet
*hwKeys
) {
127 ConfigManager::Domain::iterator it
;
128 String prefix
= KEYMAP_KEY_PREFIX
+ _name
+ "_";
130 for (it
= _configDomain
->begin(); it
!= _configDomain
->end(); it
++) {
131 const String
& key
= it
->_key
;
133 if (!key
.hasPrefix(prefix
.c_str()))
137 const char *actionId
= key
.c_str() + prefix
.size();
138 Action
*ua
= getAction(actionId
);
141 warning("'%s' keymap does not contain Action with ID %s",
142 _name
.c_str(), actionId
);
143 _configDomain
->erase(key
);
148 const HardwareKey
*hwKey
= hwKeys
->findHardwareKey(it
->_value
.c_str());
151 warning("HardwareKey with ID %s not known", it
->_value
.c_str());
152 _configDomain
->erase(key
);
160 void Keymap::saveMappings() {
164 List
<Action
*>::const_iterator it
;
165 String prefix
= KEYMAP_KEY_PREFIX
+ _name
+ "_";
167 for (it
= _actions
.begin(); it
!= _actions
.end(); it
++) {
168 uint actIdLen
= strlen((*it
)->id
);
170 actIdLen
= (actIdLen
> ACTION_ID_SIZE
) ? ACTION_ID_SIZE
: actIdLen
;
172 String
actId((*it
)->id
, (*it
)->id
+ actIdLen
);
173 char hwId
[HWKEY_ID_SIZE
+1];
175 memset(hwId
, 0, HWKEY_ID_SIZE
+1);
177 if ((*it
)->getMappedKey()) {
178 memcpy(hwId
, (*it
)->getMappedKey()->hwKeyId
, HWKEY_ID_SIZE
);
180 _configDomain
->setVal(prefix
+ actId
, hwId
);
184 bool Keymap::isComplete(const HardwareKeySet
*hwKeys
) {
185 List
<Action
*>::iterator it
;
186 bool allMapped
= true;
187 uint numberMapped
= 0;
189 for (it
= _actions
.begin(); it
!= _actions
.end(); it
++) {
190 if ((*it
)->getMappedKey()) {
197 return allMapped
|| (numberMapped
== hwKeys
->size());
201 // - current weakness:
202 // - if an action finds a key with required type but a parent action with
203 // higher priority is using it, that key is never used
204 void Keymap::automaticMapping(HardwareKeySet
*hwKeys
) {
205 // Create copies of action and key lists.
206 List
<Action
*> actions(_actions
);
207 List
<const HardwareKey
*> keys(hwKeys
->getHardwareKeys());
209 List
<Action
*>::iterator actIt
;
210 List
<const HardwareKey
*>::iterator keyIt
, selectedKey
;
212 // Remove actions and keys from local lists that have already been mapped.
213 actIt
= actions
.begin();
215 while (actIt
!= actions
.end()) {
216 Action
*act
= *actIt
;
217 const HardwareKey
*key
= act
->getMappedKey();
221 actIt
= actions
.erase(actIt
);
227 // Sort remaining actions by priority.
228 ActionPriorityComp priorityComp
;
229 sort(actions
.begin(), actions
.end(), priorityComp
);
231 // First mapping pass:
232 // - Match if a key's preferred action type is the same as the action's
233 // type, or vice versa.
234 // - Priority is given to:
235 // - keys that match action types over key types.
236 // - keys that have not been used by parent maps.
237 // - If a key has been used by a parent map the new action must have a
238 // higher priority than the parent action.
239 // - As soon as the number of skipped actions equals the number of keys
240 // remaining we stop matching. This means that the second pass will assign keys
241 // to these higher priority skipped actions.
243 actIt
= actions
.begin();
245 while (actIt
!= actions
.end() && skipped
< keys
.size()) {
246 selectedKey
= keys
.end();
248 Action
*act
= *actIt
;
250 for (keyIt
= keys
.begin(); keyIt
!= keys
.end(); ++keyIt
) {
251 if ((*keyIt
)->preferredAction
== act
->type
&& act
->type
!= kGenericActionType
) {
252 Action
*parentAct
= getParentMappedAction((*keyIt
)->key
);
257 } else if (parentAct
->priority
<= act
->priority
&& matchRank
< 3) {
261 } else if ((*keyIt
)->type
== act
->preferredKey
&& act
->preferredKey
!= kGenericKeyType
&& matchRank
< 2) {
262 Action
*parentAct
= getParentMappedAction((*keyIt
)->key
);
267 } else if (parentAct
->priority
<= act
->priority
&& matchRank
< 1) {
273 if (selectedKey
!= keys
.end()) {
274 // Map action and delete action & key from local lists.
275 act
->mapKey(*selectedKey
);
276 keys
.erase(selectedKey
);
277 actIt
= actions
.erase(actIt
);
279 // Skip action (will be mapped in next pass).
285 // Second mapping pass:
286 // - Maps any remaining actions to keys
287 // - priority given to:
288 // - keys that have no parent action
289 // - keys whose parent action has lower priority than the new action
290 // - keys whose parent action has the lowest priority
291 // - is guaranteed to match a key if they are not all used up
292 for (actIt
= actions
.begin(); actIt
!= actions
.end(); ++actIt
) {
293 selectedKey
= keys
.end();
296 int lowestPriority
= 0;
297 Action
*act
= *actIt
;
299 for (keyIt
= keys
.begin(); keyIt
!= keys
.end(); ++keyIt
) {
300 Action
*parentAct
= getParentMappedAction((*keyIt
)->key
);
305 } else if (matchRank
< 2) {
306 if (parentAct
->priority
<= act
->priority
) {
309 } else if (parentAct
->priority
< lowestPriority
|| matchRank
== 0) {
311 lowestPriority
= parentAct
->priority
;
317 if (selectedKey
!= keys
.end()) {
318 act
->mapKey(*selectedKey
);
319 keys
.erase(selectedKey
);
320 } else {// no match = no keys left
326 Action
*Keymap::getParentMappedAction(KeyState key
) {
328 Action
*act
= _parent
->getMappedAction(key
);
333 return _parent
->getParentMappedAction(key
);
339 } // end of namespace Common
341 #endif // #ifdef ENABLE_KEYMAPPER