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/keymapper.h"
24 
25 #include "backends/keymapper/action.h"
26 #include "backends/keymapper/hardware-input.h"
27 #include "backends/keymapper/keymapper-defaults.h"
28 
29 #include "common/system.h"
30 
31 namespace Common {
32 
33 // These magic numbers are provided by fuzzie and WebOS
34 static const uint32 kDelayKeyboardEventMillis = 250;
35 static const uint32 kDelayMouseEventMillis = 50;
36 
Keymapper(EventManager * eventMan)37 Keymapper::Keymapper(EventManager *eventMan) :
38 		_eventMan(eventMan),
39 		_hardwareInputs(nullptr),
40 		_backendDefaultBindings(nullptr),
41 		_delayedEventSource(new DelayedEventSource()),
42 		_enabled(true),
43 		_enabledKeymapType(Keymap::kKeymapTypeGame) {
44 	_eventMan->getEventDispatcher()->registerSource(_delayedEventSource, true);
45 	resetInputState();
46 }
47 
~Keymapper()48 Keymapper::~Keymapper() {
49 	clear();
50 }
51 
clear()52 void Keymapper::clear() {
53 	for (KeymapArray::iterator it = _keymaps.begin(); it != _keymaps.end(); it++) {
54 		delete *it;
55 	}
56 	_keymaps.clear();
57 
58 	delete _backendDefaultBindings;
59 	_backendDefaultBindings = nullptr;
60 
61 	delete _hardwareInputs;
62 	_hardwareInputs = nullptr;
63 }
64 
registerHardwareInputSet(HardwareInputSet * inputs,KeymapperDefaultBindings * backendDefaultBindings)65 void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs, KeymapperDefaultBindings *backendDefaultBindings) {
66 	bool reloadMappings = false;
67 	if (_hardwareInputs) {
68 		reloadMappings = true;
69 		delete _hardwareInputs;
70 	}
71 	if (_backendDefaultBindings) {
72 		reloadMappings = true;
73 		delete _backendDefaultBindings;
74 	}
75 
76 	if (!inputs) {
77 		warning("No hardware input were defined, using defaults");
78 		CompositeHardwareInputSet *compositeInputs = new CompositeHardwareInputSet();
79 		compositeInputs->addHardwareInputSet(new MouseHardwareInputSet(defaultMouseButtons));
80 		compositeInputs->addHardwareInputSet(new KeyboardHardwareInputSet(defaultKeys, defaultModifiers));
81 		inputs = compositeInputs;
82 	}
83 
84 	_hardwareInputs = inputs;
85 	_backendDefaultBindings = backendDefaultBindings;
86 
87 	if (reloadMappings) {
88 		reloadAllMappings();
89 	}
90 }
91 
addGlobalKeymap(Keymap * keymap)92 void Keymapper::addGlobalKeymap(Keymap *keymap) {
93 	assert(keymap->getType() == Keymap::kKeymapTypeGlobal
94 	       || keymap->getType() == Keymap::kKeymapTypeGui);
95 
96 	ConfigManager::Domain *keymapperDomain = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
97 	initKeymap(keymap, keymapperDomain);
98 	_keymaps.push_back(keymap);
99 }
100 
addGameKeymap(Keymap * keymap)101 void Keymapper::addGameKeymap(Keymap *keymap) {
102 	assert(keymap->getType() == Keymap::kKeymapTypeGame);
103 
104 	ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain();
105 
106 	if (!gameDomain) {
107 		error("Call to Keymapper::addGameKeymap when no game loaded");
108 	}
109 
110 	initKeymap(keymap, gameDomain);
111 	_keymaps.push_back(keymap);
112 }
113 
initKeymap(Keymap * keymap,ConfigManager::Domain * domain)114 void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
115 	if (!_hardwareInputs) {
116 		warning("No hardware inputs were registered yet (%s)", keymap->getId().c_str());
117 		return;
118 	}
119 
120 	keymap->setConfigDomain(domain);
121 	reloadKeymapMappings(keymap);
122 }
123 
reloadKeymapMappings(Keymap * keymap)124 void Keymapper::reloadKeymapMappings(Keymap *keymap) {
125 	keymap->setHardwareInputs(_hardwareInputs);
126 	keymap->setBackendDefaultBindings(_backendDefaultBindings);
127 	keymap->loadMappings();
128 }
129 
cleanupGameKeymaps()130 void Keymapper::cleanupGameKeymaps() {
131 	// Flush all game specific keymaps
132 	KeymapArray::iterator it = _keymaps.begin();
133 	while (it != _keymaps.end()) {
134 		if ((*it)->getType() == Keymap::kKeymapTypeGame) {
135 			delete *it;
136 			it = _keymaps.erase(it);
137 		} else {
138 			it++;
139 		}
140 	}
141 }
142 
getKeymap(const String & id) const143 Keymap *Keymapper::getKeymap(const String &id) const {
144 	for (KeymapArray::const_iterator it = _keymaps.begin(); it != _keymaps.end(); it++) {
145 		if ((*it)->getId() == id) {
146 			return *it;
147 		}
148 	}
149 
150 	return nullptr;
151 }
152 
reloadAllMappings()153 void Keymapper::reloadAllMappings() {
154 	for (uint i = 0; i < _keymaps.size(); i++) {
155 		reloadKeymapMappings(_keymaps[i]);
156 	}
157 }
158 
setEnabledKeymapType(Keymap::KeymapType type)159 void Keymapper::setEnabledKeymapType(Keymap::KeymapType type) {
160 	assert(type == Keymap::kKeymapTypeGui || type == Keymap::kKeymapTypeGame);
161 	_enabledKeymapType = type;
162 }
163 
mapEvent(const Event & ev)164 List<Event> Keymapper::mapEvent(const Event &ev) {
165 	if (!_enabled) {
166 		List<Event> originalEvent;
167 		originalEvent.push_back(ev);
168 		return originalEvent;
169 	}
170 
171 	hardcodedEventMapping(ev);
172 
173 	Keymap::ActionArray actions;
174 	Keymap::KeymapMatch match = getMappedActions(ev, actions, _enabledKeymapType);
175 	if (match != Keymap::kKeymapMatchExact) {
176 		// If we found exact matching actions this input in the game / gui keymaps,
177 		// no need to look at the global keymaps. An input resulting in actions
178 		// from system and game keymaps would lead to unexpected user experience.
179 		Keymap::ActionArray globalActions;
180 		match = getMappedActions(ev, globalActions, Keymap::kKeymapTypeGlobal);
181 		if (match == Keymap::kKeymapMatchExact || actions.empty()) {
182 			actions = globalActions;
183 		}
184 	}
185 
186 	bool matchedAction = !actions.empty();
187 	List<Event> mappedEvents;
188 	for (Keymap::ActionArray::const_iterator it = actions.begin(); it != actions.end(); it++) {
189 		Event mappedEvent = executeAction(*it, ev);
190 		if (mappedEvent.type == EVENT_INVALID) {
191 			continue;
192 		}
193 
194 		// In case we mapped a mouse event to something else, we need to generate an artificial
195 		// mouse move event so event observers can keep track of the mouse position.
196 		// Makes it possible to reliably use the mouse position from EventManager when consuming
197 		// custom action events.
198 		if (isMouseEvent(ev) && !isMouseEvent(mappedEvent)) {
199 			Event fakeMouseEvent;
200 			fakeMouseEvent.type  = EVENT_MOUSEMOVE;
201 			fakeMouseEvent.mouse = ev.mouse;
202 
203 			mappedEvents.push_back(fakeMouseEvent);
204 		}
205 
206 		mappedEvents.push_back(mappedEvent);
207 	}
208 
209 	if (ev.type == EVENT_JOYAXIS_MOTION && ev.joystick.axis < ARRAYSIZE(_joystickAxisPreviouslyPressed)) {
210 		if (ABS<int32>(ev.joystick.position) >= kJoyAxisPressedTreshold) {
211 			_joystickAxisPreviouslyPressed[ev.joystick.axis] = true;
212 		} else if (ABS<int32>(ev.joystick.position) < kJoyAxisUnpressedTreshold) {
213 			_joystickAxisPreviouslyPressed[ev.joystick.axis] = false;
214 		}
215 	}
216 
217 	if (!matchedAction) {
218 		// if it didn't get mapped, just pass it through
219 		mappedEvents.push_back(ev);
220 	}
221 
222 	return mappedEvents;
223 }
224 
getMappedActions(const Event & event,Keymap::ActionArray & actions,Keymap::KeymapType keymapType) const225 Keymap::KeymapMatch Keymapper::getMappedActions(const Event &event, Keymap::ActionArray &actions, Keymap::KeymapType keymapType) const {
226 	Keymap::KeymapMatch match = Keymap::kKeymapMatchNone;
227 
228 	for (uint i = 0; i < _keymaps.size(); i++) {
229 		if (!_keymaps[i]->isEnabled() || _keymaps[i]->getType() != keymapType) {
230 			continue;
231 		}
232 
233 		Keymap::ActionArray array;
234 		Keymap::KeymapMatch match2 = _keymaps[i]->getMappedActions(event, array);
235 		if (match2 == match) {
236 			actions.push_back(array);
237 		} else if (match2 > match) {
238 			match = match2;
239 			actions.clear();
240 			actions.push_back(array);
241 		}
242 	}
243 	return match;
244 }
245 
convertToIncomingEventType(const Event & ev) const246 Keymapper::IncomingEventType Keymapper::convertToIncomingEventType(const Event &ev) const {
247 	if (ev.type == EVENT_CUSTOM_BACKEND_HARDWARE
248 	           || ev.type == EVENT_WHEELDOWN
249 	           || ev.type == EVENT_WHEELUP) {
250 		return kIncomingEventInstant;
251 	} else if (ev.type == EVENT_JOYAXIS_MOTION) {
252 		if (ev.joystick.axis >= ARRAYSIZE(_joystickAxisPreviouslyPressed)) {
253 			return kIncomingEventIgnored;
254 		}
255 
256 		if (!_joystickAxisPreviouslyPressed[ev.joystick.axis] && ABS<int32>(ev.joystick.position) >= kJoyAxisPressedTreshold) {
257 			return kIncomingEventStart;
258 		} else if (_joystickAxisPreviouslyPressed[ev.joystick.axis] && ABS<int32>(ev.joystick.position) < kJoyAxisUnpressedTreshold) {
259 			return kIncomingEventEnd;
260 		} else {
261 			return kIncomingEventIgnored;
262 		}
263 	} else if (ev.type == EVENT_KEYDOWN
264 	           || ev.type == EVENT_LBUTTONDOWN
265 	           || ev.type == EVENT_RBUTTONDOWN
266 	           || ev.type == EVENT_MBUTTONDOWN
267 	           || ev.type == EVENT_X1BUTTONDOWN
268 	           || ev.type == EVENT_X2BUTTONDOWN
269 	           || ev.type == EVENT_JOYBUTTON_DOWN) {
270 		return kIncomingEventStart;
271 	} else {
272 		return kIncomingEventEnd;
273 	}
274 }
275 
executeAction(const Action * action,const Event & incomingEvent)276 Event Keymapper::executeAction(const Action *action, const Event &incomingEvent) {
277 	Event outgoingEvent = Event(action->event);
278 
279 	IncomingEventType incomingType = convertToIncomingEventType(incomingEvent);
280 
281 	if (outgoingEvent.type == EVENT_JOYAXIS_MOTION
282 	        || outgoingEvent.type == EVENT_CUSTOM_BACKEND_ACTION_AXIS) {
283 		if (incomingEvent.type == EVENT_JOYAXIS_MOTION) {
284 			// At the moment only half-axes can be bound to actions, hence taking
285 			//  the absolute value. If full axes were to be mappable, the action
286 			//  could carry the information allowing to distinguish cases here.
287 			outgoingEvent.joystick.position = ABS(incomingEvent.joystick.position);
288 		} else if (incomingType == kIncomingEventStart) {
289 			outgoingEvent.joystick.position = JOYAXIS_MAX;
290 		} else if (incomingType == kIncomingEventEnd) {
291 			outgoingEvent.joystick.position = 0;
292 		}
293 
294 		return outgoingEvent;
295 	}
296 
297 	if (incomingType == kIncomingEventIgnored) {
298 		outgoingEvent.type = EVENT_INVALID;
299 		return outgoingEvent;
300 	}
301 
302 	if (incomingEvent.type == EVENT_KEYDOWN && incomingEvent.kbdRepeat && !action->shouldTriggerOnKbdRepeats()) {
303 		outgoingEvent.type = EVENT_INVALID;
304 		return outgoingEvent;
305 	}
306 
307 	EventType convertedType = convertStartToEnd(outgoingEvent.type);
308 
309 	// hardware keys need to send up instead when they are up
310 	if (incomingType == kIncomingEventEnd) {
311 		outgoingEvent.type = convertedType;
312 	}
313 
314 	if (outgoingEvent.type == EVENT_KEYDOWN && incomingEvent.type == EVENT_KEYDOWN) {
315 		outgoingEvent.kbdRepeat = incomingEvent.kbdRepeat;
316 	}
317 
318 	if (isMouseEvent(outgoingEvent)) {
319 		if (isMouseEvent(incomingEvent)) {
320 			outgoingEvent.mouse = incomingEvent.mouse;
321 		} else {
322 			outgoingEvent.mouse = _eventMan->getMousePos();
323 		}
324 	}
325 
326 	// Check if the event is coming from a non-key hardware event
327 	// that is mapped to a key event
328 	if (incomingType == kIncomingEventInstant && convertedType != EVENT_INVALID) {
329 		// WORKAROUND: Delay the down events coming from non-key hardware events
330 		// with a zero delay. This is to prevent DOWN1 DOWN2 UP1 UP2.
331 		_delayedEventSource->scheduleEvent(outgoingEvent, 0);
332 
333 		// non-keys need to send up as well
334 		// WORKAROUND: Delay the up events coming from non-key hardware events
335 		// This is for engines that run scripts that check on key being down
336 		outgoingEvent.type = convertedType;
337 		const uint32 delay = (convertedType == EVENT_KEYUP ? kDelayKeyboardEventMillis : kDelayMouseEventMillis);
338 		_delayedEventSource->scheduleEvent(outgoingEvent, delay);
339 	}
340 
341 	return outgoingEvent;
342 }
343 
convertStartToEnd(EventType type)344 EventType Keymapper::convertStartToEnd(EventType type) {
345 	EventType result = EVENT_INVALID;
346 	switch (type) {
347 	case EVENT_KEYDOWN:
348 		result = EVENT_KEYUP;
349 		break;
350 	case EVENT_LBUTTONDOWN:
351 		result = EVENT_LBUTTONUP;
352 		break;
353 	case EVENT_RBUTTONDOWN:
354 		result = EVENT_RBUTTONUP;
355 		break;
356 	case EVENT_MBUTTONDOWN:
357 		result = EVENT_MBUTTONUP;
358 		break;
359 	case EVENT_X1BUTTONDOWN:
360 		result = EVENT_X1BUTTONUP;
361 		break;
362 	case EVENT_X2BUTTONDOWN:
363 		result = EVENT_X2BUTTONUP;
364 		break;
365 	case EVENT_JOYBUTTON_DOWN:
366 		result = EVENT_JOYBUTTON_UP;
367 		break;
368 	case EVENT_CUSTOM_BACKEND_ACTION_START:
369 		result = EVENT_CUSTOM_BACKEND_ACTION_END;
370 		break;
371 	case EVENT_CUSTOM_ENGINE_ACTION_START:
372 		result = EVENT_CUSTOM_ENGINE_ACTION_END;
373 		break;
374 	default:
375 		break;
376 	}
377 	return result;
378 }
379 
findHardwareInput(const Event & event)380 HardwareInput Keymapper::findHardwareInput(const Event &event) {
381 	return _hardwareInputs->findHardwareInput(event);
382 }
383 
hardcodedEventMapping(Event ev)384 void Keymapper::hardcodedEventMapping(Event ev) {
385 	// TODO: Either add support for long presses to the keymapper
386 	// or move this elsewhere as an event observer + source
387 #ifdef ENABLE_VKEYBD
388 	// Trigger virtual keyboard on long press of more than 1 second
389 	// of middle mouse button.
390 	const uint32 vkeybdTime = 1000;
391 
392 	static uint32 vkeybdThen = 0;
393 
394 	if (ev.type == EVENT_MBUTTONDOWN) {
395 		vkeybdThen = g_system->getMillis();
396 	}
397 
398 	if (ev.type == EVENT_MBUTTONUP) {
399 		if ((g_system->getMillis() - vkeybdThen) >= vkeybdTime) {
400 			Event vkeybdEvent;
401 			vkeybdEvent.type = EVENT_VIRTUAL_KEYBOARD;
402 
403 			// Avoid blocking event from engine.
404 			_delayedEventSource->scheduleEvent(vkeybdEvent, 100);
405 		}
406 	}
407 #endif
408 }
409 
resetInputState()410 void Keymapper::resetInputState() {
411 	for (uint i = 0; i < ARRAYSIZE(_joystickAxisPreviouslyPressed); i++) {
412 		_joystickAxisPreviouslyPressed[i] = false;
413 	}
414 }
415 
scheduleEvent(const Event & ev,uint32 delayMillis)416 void DelayedEventSource::scheduleEvent(const Event &ev, uint32 delayMillis) {
417 	if (_delayedEvents.empty()) {
418 		_delayedEffectiveTime = g_system->getMillis() + delayMillis;
419 		delayMillis = 0;
420 	}
421 	DelayedEventsEntry entry = DelayedEventsEntry(delayMillis, ev);
422 	_delayedEvents.push(entry);
423 }
424 
pollEvent(Event & event)425 bool DelayedEventSource::pollEvent(Event &event) {
426 	if (_delayedEvents.empty()) {
427 		return false;
428 	}
429 
430 	uint32 now = g_system->getMillis(true);
431 
432 	if (now >= _delayedEffectiveTime) {
433 		event = _delayedEvents.pop().event;
434 
435 		if (!_delayedEvents.empty()) {
436 			_delayedEffectiveTime += _delayedEvents.front().timerOffset;
437 		}
438 
439 		return true;
440 	}
441 
442 	return false;
443 }
444 
allowMapping() const445 bool DelayedEventSource::allowMapping() const {
446 	return false; // Events from this source have already been mapped, and should not be mapped again
447 }
448 
449 } // End of namespace Common
450