diff options
Diffstat (limited to 'backends/keymapper/keymapper.cpp')
-rw-r--r-- | backends/keymapper/keymapper.cpp | 264 |
1 files changed, 190 insertions, 74 deletions
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp index 29f495cd53..dcb021f2d8 100644 --- a/backends/keymapper/keymapper.cpp +++ b/backends/keymapper/keymapper.cpp @@ -25,9 +25,14 @@ #ifdef ENABLE_KEYMAPPER #include "common/config-manager.h" +#include "common/system.h" namespace Common { +// These magic numbers are provided by fuzzie and WebOS +static const uint32 kDelayKeyboardEventMillis = 250; +static const uint32 kDelayMouseEventMillis = 50; + void Keymapper::Domain::addKeymap(Keymap *map) { iterator it = find(map->getName()); @@ -54,26 +59,26 @@ Keymap *Keymapper::Domain::getKeymap(const String& name) { } Keymapper::Keymapper(EventManager *evtMgr) - : _eventMan(evtMgr), _enabled(true), _hardwareKeys(0) { + : _eventMan(evtMgr), _enabled(true), _remapping(false), _hardwareInputs(0), _actionToRemap(0) { ConfigManager::Domain *confDom = ConfMan.getDomain(ConfigManager::kKeymapperDomain); _globalDomain.setConfigDomain(confDom); } Keymapper::~Keymapper() { - delete _hardwareKeys; + delete _hardwareInputs; } -void Keymapper::registerHardwareKeySet(HardwareKeySet *keys) { - if (_hardwareKeys) - error("Hardware key set already registered"); +void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) { + if (_hardwareInputs) + error("Hardware input set already registered"); - if (!keys) { - warning("No hardware keys are supplied"); - return; + if (!inputs) { + warning("No hardware input were defined, using defaults"); + inputs = new HardwareInputSet(true); } - _hardwareKeys = keys; + _hardwareInputs = inputs; } void Keymapper::addGlobalKeymap(Keymap *keymap) { @@ -95,16 +100,15 @@ void Keymapper::addGameKeymap(Keymap *keymap) { } void Keymapper::initKeymap(Domain &domain, Keymap *map) { - if (!_hardwareKeys) { - warning("No hardware keys were registered yet (%s)", map->getName().c_str()); + if (!_hardwareInputs) { + warning("No hardware inputs were registered yet (%s)", map->getName().c_str()); return; } map->setConfigDomain(domain.getConfigDomain()); - map->loadMappings(_hardwareKeys); + map->loadMappings(_hardwareInputs); - if (map->isComplete(_hardwareKeys) == false) { - map->automaticMapping(_hardwareKeys); + if (map->isComplete(_hardwareInputs) == false) { map->saveMappings(); ConfMan.flushToDisk(); } @@ -120,7 +124,7 @@ void Keymapper::cleanupGameKeymaps() { // the game specific (=deleted) ones. Stack<MapRecord> newStack; - for (int i = 0; i < _activeMaps.size(); i++) { + for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) { if (_activeMaps[i].global) newStack.push(_activeMaps[i]); } @@ -128,63 +132,97 @@ void Keymapper::cleanupGameKeymaps() { _activeMaps = newStack; } -Keymap *Keymapper::getKeymap(const String& name, bool &global) { +Keymap *Keymapper::getKeymap(const String& name, bool *globalReturn) { Keymap *keymap = _gameDomain.getKeymap(name); - global = false; + bool global = false; if (!keymap) { keymap = _globalDomain.getKeymap(name); global = true; } + if (globalReturn) + *globalReturn = global; + return keymap; } -bool Keymapper::pushKeymap(const String& name, bool inherit) { +bool Keymapper::pushKeymap(const String& name, bool transparent) { bool global; - Keymap *newMap = getKeymap(name, global); + + assert(!name.empty()); + Keymap *newMap = getKeymap(name, &global); if (!newMap) { warning("Keymap '%s' not registered", name.c_str()); return false; } - pushKeymap(newMap, inherit, global); + pushKeymap(newMap, transparent, global); return true; } -void Keymapper::pushKeymap(Keymap *newMap, bool inherit, bool global) { - MapRecord mr = {newMap, inherit, global}; +void Keymapper::pushKeymap(Keymap *newMap, bool transparent, bool global) { + MapRecord mr = {newMap, transparent, global}; _activeMaps.push(mr); } -void Keymapper::popKeymap() { - if (!_activeMaps.empty()) - _activeMaps.pop(); +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(); + } + } + } -bool Keymapper::notifyEvent(const Common::Event &ev) { - if (ev.type == Common::EVENT_KEYDOWN) - return mapKeyDown(ev.kbd); +List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) { + if (source && !source->allowMapping()) { + return DefaultEventMapper::mapEvent(ev, source); + } + List<Event> mappedEvents; + + if (_remapping) + mappedEvents = remap(ev); + else if (ev.type == Common::EVENT_KEYDOWN) + mappedEvents = mapKeyDown(ev.kbd); else if (ev.type == Common::EVENT_KEYUP) - return mapKeyUp(ev.kbd); + mappedEvents = mapKeyUp(ev.kbd); + else if (ev.type == Common::EVENT_CUSTOM_BACKEND_HARDWARE) + mappedEvents = mapNonKey(ev.customType); + + if (!mappedEvents.empty()) + return mappedEvents; else - return false; + return DefaultEventMapper::mapEvent(ev, source); } -bool Keymapper::mapKeyDown(const KeyState& key) { +void Keymapper::startRemappingMode(Action *actionToRemap) { + assert(!_remapping); + + _remapping = true; + _actionToRemap = actionToRemap; +} + +List<Event> Keymapper::mapKeyDown(const KeyState& key) { return mapKey(key, true); } -bool Keymapper::mapKeyUp(const KeyState& key) { +List<Event> Keymapper::mapKeyUp(const KeyState& key) { return mapKey(key, false); } -bool Keymapper::mapKey(const KeyState& key, bool keyDown) { +List<Event> Keymapper::mapKey(const KeyState& key, bool keyDown) { if (!_enabled || _activeMaps.empty()) - return false; + return List<Event>(); Action *action = 0; @@ -195,14 +233,14 @@ bool Keymapper::mapKey(const KeyState& key, bool keyDown) { debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str()); action = mr.keymap->getMappedAction(key); - if (action || !mr.inherit) + if (action || !mr.transparent) break; } if (action) _keysDown[key] = action; } else { - HashMap<KeyState, Action*>::iterator it = _keysDown.find(key); + HashMap<KeyState, Action *>::iterator it = _keysDown.find(key); if (it != _keysDown.end()) { action = it->_value; @@ -211,11 +249,32 @@ bool Keymapper::mapKey(const KeyState& key, bool keyDown) { } if (!action) - return false; + return List<Event>(); - executeAction(action, keyDown); + return executeAction(action, keyDown ? kIncomingKeyDown : kIncomingKeyUp); +} - return true; + +List<Event> Keymapper::mapNonKey(const HardwareInputCode code) { + if (!_enabled || _activeMaps.empty()) + return List<Event>(); + + 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); + + if (action || !mr.transparent) + break; + } + + if (!action) + return List<Event>(); + + return executeAction(action); } Action *Keymapper::getAction(const KeyState& key) { @@ -224,49 +283,106 @@ Action *Keymapper::getAction(const KeyState& key) { return action; } -void Keymapper::executeAction(const Action *action, bool keyDown) { +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) { - Event evt = *it; - - switch (evt.type) { - case EVENT_KEYDOWN: - if (!keyDown) evt.type = EVENT_KEYUP; - break; - case EVENT_KEYUP: - if (keyDown) evt.type = EVENT_KEYDOWN; - break; - case EVENT_LBUTTONDOWN: - if (!keyDown) evt.type = EVENT_LBUTTONUP; - break; - case EVENT_LBUTTONUP: - if (keyDown) evt.type = EVENT_LBUTTONDOWN; - break; - case EVENT_RBUTTONDOWN: - if (!keyDown) evt.type = EVENT_RBUTTONUP; - break; - case EVENT_RBUTTONUP: - if (keyDown) evt.type = EVENT_RBUTTONDOWN; - break; - case EVENT_MBUTTONDOWN: - if (!keyDown) evt.type = EVENT_MBUTTONUP; - break; - case EVENT_MBUTTONUP: - if (keyDown) evt.type = EVENT_MBUTTONDOWN; - break; - default: - // don't deliver other events on key up - if (!keyDown) continue; + 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(); - addEvent(evt); + + // 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; +} + +EventType Keymapper::convertDownToUp(EventType type) { + EventType result = EVENT_INVALID; + switch (type) { + case EVENT_KEYDOWN: + result = EVENT_KEYUP; + break; + case EVENT_LBUTTONDOWN: + result = EVENT_LBUTTONUP; + break; + case EVENT_RBUTTONDOWN: + result = EVENT_RBUTTONUP; + break; + case EVENT_MBUTTONDOWN: + result = EVENT_MBUTTONUP; + break; + default: + break; } + return result; } -const HardwareKey *Keymapper::findHardwareKey(const KeyState& key) { - return (_hardwareKeys) ? _hardwareKeys->findHardwareKey(key) : 0; +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; +} + +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: + // eat the event by returning an event invalid + mappedEvent.type = EVENT_INVALID; + list.push_back(mappedEvent); + break; + case EVENT_KEYUP: + hwInput = findHardwareInput(ev.kbd); + break; + case EVENT_CUSTOM_BACKEND_HARDWARE: + hwInput = findHardwareInput(ev.customType); + break; + default: + break; + } + if (hwInput) { + _actionToRemap->mapInput(hwInput); + _actionToRemap->getParent()->saveMappings(); + _remapping = false; + _actionToRemap = 0; + mappedEvent.type = EVENT_GUI_REMAP_COMPLETE_ACTION; + list.push_back(mappedEvent); + } + return list; } } // End of namespace Common |