aboutsummaryrefslogtreecommitdiff
path: root/backends/keymapper/keymapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backends/keymapper/keymapper.cpp')
-rw-r--r--backends/keymapper/keymapper.cpp264
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