ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

keymapper.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "backends/keymapper/keymapper.h"
00024 
00025 #ifdef ENABLE_KEYMAPPER
00026 
00027 #include "common/config-manager.h"
00028 #include "common/system.h"
00029 
00030 namespace Common {
00031 
00032 // These magic numbers are provided by fuzzie and WebOS
00033 static const uint32 kDelayKeyboardEventMillis = 250;
00034 static const uint32 kDelayMouseEventMillis = 50;
00035 
00036 void Keymapper::Domain::addKeymap(Keymap *map) {
00037     iterator it = find(map->getName());
00038 
00039     if (it != end())
00040         delete it->_value;
00041 
00042     setVal(map->getName(), map);
00043 }
00044 
00045 void Keymapper::Domain::deleteAllKeyMaps() {
00046     for (iterator it = begin(); it != end(); ++it)
00047         delete it->_value;
00048 
00049     clear();
00050 }
00051 
00052 Keymap *Keymapper::Domain::getKeymap(const String& name) {
00053     iterator it = find(name);
00054 
00055     if (it != end())
00056         return it->_value;
00057     else
00058         return 0;
00059 }
00060 
00061 Keymapper::Keymapper(EventManager *evtMgr)
00062     : _eventMan(evtMgr), _enabled(true), _remapping(false), _hardwareInputs(0), _actionToRemap(0) {
00063     ConfigManager::Domain *confDom = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
00064 
00065     _globalDomain.setConfigDomain(confDom);
00066 }
00067 
00068 Keymapper::~Keymapper() {
00069     delete _hardwareInputs;
00070 }
00071 
00072 void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) {
00073     if (_hardwareInputs)
00074         error("Hardware input set already registered");
00075 
00076     if (!inputs) {
00077         warning("No hardware input were defined, using defaults");
00078         inputs = new HardwareInputSet(true);
00079     }
00080 
00081     _hardwareInputs = inputs;
00082 }
00083 
00084 void Keymapper::addGlobalKeymap(Keymap *keymap) {
00085     initKeymap(_globalDomain, keymap);
00086 }
00087 
00088 void Keymapper::addGameKeymap(Keymap *keymap) {
00089     if (ConfMan.getActiveDomain() == 0)
00090         error("Call to Keymapper::addGameKeymap when no game loaded");
00091 
00092     // Detect whether the active game changed since last call.
00093     // If so, flush the game key configuration.
00094     if (_gameDomain.getConfigDomain() != ConfMan.getActiveDomain()) {
00095         cleanupGameKeymaps();
00096         _gameDomain.setConfigDomain(ConfMan.getActiveDomain());
00097     }
00098 
00099     initKeymap(_gameDomain, keymap);
00100 }
00101 
00102 void Keymapper::initKeymap(Domain &domain, Keymap *map) {
00103     if (!_hardwareInputs) {
00104         warning("No hardware inputs were registered yet (%s)", map->getName().c_str());
00105         return;
00106     }
00107 
00108     map->setConfigDomain(domain.getConfigDomain());
00109     map->loadMappings(_hardwareInputs);
00110 
00111     if (map->isComplete(_hardwareInputs) == false) {
00112         map->saveMappings();
00113         ConfMan.flushToDisk();
00114     }
00115 
00116     domain.addKeymap(map);
00117 }
00118 
00119 void Keymapper::cleanupGameKeymaps() {
00120     // Flush all game specific keymaps
00121     _gameDomain.deleteAllKeyMaps();
00122 
00123     // Now restore the stack of active maps. Re-add all global keymaps, drop
00124     // the game specific (=deleted) ones.
00125     Stack<MapRecord> newStack;
00126 
00127     for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) {
00128         if (_activeMaps[i].global)
00129             newStack.push(_activeMaps[i]);
00130     }
00131 
00132     _activeMaps = newStack;
00133 }
00134 
00135 Keymap *Keymapper::getKeymap(const String& name, bool *globalReturn) {
00136     Keymap *keymap = _gameDomain.getKeymap(name);
00137     bool global = false;
00138 
00139     if (!keymap) {
00140         keymap = _globalDomain.getKeymap(name);
00141         global = true;
00142     }
00143 
00144     if (globalReturn)
00145         *globalReturn = global;
00146 
00147     return keymap;
00148 }
00149 
00150 bool Keymapper::pushKeymap(const String& name, bool transparent) {
00151     bool global;
00152 
00153     assert(!name.empty());
00154     Keymap *newMap = getKeymap(name, &global);
00155 
00156     if (!newMap) {
00157         warning("Keymap '%s' not registered", name.c_str());
00158         return false;
00159     }
00160 
00161     pushKeymap(newMap, transparent, global);
00162 
00163     return true;
00164 }
00165 
00166 void Keymapper::pushKeymap(Keymap *newMap, bool transparent, bool global) {
00167     MapRecord mr = {newMap, transparent, global};
00168 
00169     _activeMaps.push(mr);
00170 }
00171 
00172 void Keymapper::popKeymap(const char *name) {
00173     if (!_activeMaps.empty()) {
00174         if (name) {
00175             String topKeymapName = _activeMaps.top().keymap->getName();
00176             if (topKeymapName.equals(name))
00177                 _activeMaps.pop();
00178             else
00179                 warning("An attempt to pop wrong keymap was blocked (expected %s but was %s)", name, topKeymapName.c_str());
00180         } else {
00181             _activeMaps.pop();
00182         }
00183     }
00184 
00185 }
00186 
00187 List<Event> Keymapper::mapEvent(const Event &ev, EventSource *source) {
00188     if (source && !source->allowMapping()) {
00189         return DefaultEventMapper::mapEvent(ev, source);
00190     }
00191     List<Event> mappedEvents;
00192 
00193     if (_remapping)
00194         mappedEvents = remap(ev);
00195     else if (ev.type == Common::EVENT_KEYDOWN)
00196         mappedEvents = mapKeyDown(ev.kbd);
00197     else if (ev.type == Common::EVENT_KEYUP)
00198         mappedEvents = mapKeyUp(ev.kbd);
00199     else if (ev.type == Common::EVENT_CUSTOM_BACKEND_HARDWARE)
00200         mappedEvents = mapNonKey(ev.customType);
00201 
00202     if (!mappedEvents.empty())
00203         return mappedEvents;
00204     else
00205         return DefaultEventMapper::mapEvent(ev, source);
00206 }
00207 
00208 void Keymapper::startRemappingMode(Action *actionToRemap) {
00209     assert(!_remapping);
00210 
00211     _remapping = true;
00212     _actionToRemap = actionToRemap;
00213 }
00214 
00215 List<Event> Keymapper::mapKeyDown(const KeyState& key) {
00216     return mapKey(key, true);
00217 }
00218 
00219 List<Event> Keymapper::mapKeyUp(const KeyState& key) {
00220     return mapKey(key, false);
00221 }
00222 
00223 List<Event> Keymapper::mapKey(const KeyState& key, bool keyDown) {
00224     if (!_enabled || _activeMaps.empty())
00225         return List<Event>();
00226 
00227     Action *action = 0;
00228 
00229     if (keyDown) {
00230         // Search for key in active keymap stack
00231         for (int i = _activeMaps.size() - 1; i >= 0; --i) {
00232             MapRecord mr = _activeMaps[i];
00233             debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
00234             action = mr.keymap->getMappedAction(key);
00235 
00236             if (action || !mr.transparent)
00237                 break;
00238         }
00239 
00240         if (action)
00241             _keysDown[key] = action;
00242     } else {
00243         HashMap<KeyState, Action *>::iterator it = _keysDown.find(key);
00244 
00245         if (it != _keysDown.end()) {
00246             action = it->_value;
00247             _keysDown.erase(key);
00248         }
00249     }
00250 
00251     if (!action)
00252         return List<Event>();
00253 
00254     return executeAction(action, keyDown ? kIncomingKeyDown : kIncomingKeyUp);
00255 }
00256 
00257 
00258 List<Event> Keymapper::mapNonKey(const HardwareInputCode code) {
00259     if (!_enabled || _activeMaps.empty())
00260         return List<Event>();
00261 
00262     Action *action = 0;
00263 
00264     // Search for nonkey in active keymap stack
00265     for (int i = _activeMaps.size() - 1; i >= 0; --i) {
00266         MapRecord mr = _activeMaps[i];
00267         debug(5, "Keymapper::mapKey keymap: %s", mr.keymap->getName().c_str());
00268         action = mr.keymap->getMappedAction(code);
00269 
00270         if (action || !mr.transparent)
00271             break;
00272     }
00273 
00274     if (!action)
00275         return List<Event>();
00276 
00277     return executeAction(action);
00278 }
00279 
00280 Action *Keymapper::getAction(const KeyState& key) {
00281     Action *action = 0;
00282 
00283     return action;
00284 }
00285 
00286 List<Event> Keymapper::executeAction(const Action *action, IncomingEventType incomingType) {
00287     List<Event> mappedEvents;
00288     List<Event>::const_iterator it;
00289     Event evt;
00290     for (it = action->events.begin(); it != action->events.end(); ++it) {
00291         evt = Event(*it);
00292         EventType convertedType = convertDownToUp(evt.type);
00293 
00294         // hardware keys need to send up instead when they are up
00295         if (incomingType == kIncomingKeyUp) {
00296             if (convertedType == EVENT_INVALID)
00297                 continue; // don't send any non-down-converted events on up they were already sent on down
00298             evt.type = convertedType;
00299         }
00300 
00301         evt.mouse = _eventMan->getMousePos();
00302 
00303         // Check if the event is coming from a non-key hardware event
00304         // that is mapped to a key event
00305         if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID)
00306             // WORKAROUND: Delay the down events coming from non-key hardware events
00307             // with a zero delay. This is to prevent DOWN1 DOWN2 UP1 UP2.
00308             addDelayedEvent(0, evt);
00309         else
00310             mappedEvents.push_back(evt);
00311 
00312         // non-keys need to send up as well
00313         if (incomingType == kIncomingNonKey && convertedType != EVENT_INVALID) {
00314             // WORKAROUND: Delay the up events coming from non-key hardware events
00315             // This is for engines that run scripts that check on key being down
00316             evt.type = convertedType;
00317             const uint32 delay = (convertedType == EVENT_KEYUP ? kDelayKeyboardEventMillis : kDelayMouseEventMillis);
00318             addDelayedEvent(delay, evt);
00319         }
00320     }
00321     return mappedEvents;
00322 }
00323 
00324 EventType Keymapper::convertDownToUp(EventType type) {
00325     EventType result = EVENT_INVALID;
00326     switch (type) {
00327     case EVENT_KEYDOWN:
00328         result = EVENT_KEYUP;
00329         break;
00330     case EVENT_LBUTTONDOWN:
00331         result = EVENT_LBUTTONUP;
00332         break;
00333     case EVENT_RBUTTONDOWN:
00334         result = EVENT_RBUTTONUP;
00335         break;
00336     case EVENT_MBUTTONDOWN:
00337         result = EVENT_MBUTTONUP;
00338         break;
00339     default:
00340         break;
00341     }
00342     return result;
00343 }
00344 
00345 const HardwareInput *Keymapper::findHardwareInput(const KeyState& key) {
00346     return (_hardwareInputs) ? _hardwareInputs->findHardwareInput(key) : 0;
00347 }
00348 
00349 const HardwareInput *Keymapper::findHardwareInput(const HardwareInputCode code) {
00350     return (_hardwareInputs) ? _hardwareInputs->findHardwareInput(code) : 0;
00351 }
00352 
00353 List<Event> Keymapper::remap(const Event &ev) {
00354     assert(_remapping);
00355     assert(_actionToRemap);
00356 
00357     List<Event> list;
00358 
00359     const HardwareInput *hwInput = 0;
00360     Event mappedEvent;
00361 
00362     switch (ev.type) {
00363     case EVENT_KEYDOWN:
00364         // eat the event by returning an event invalid
00365         mappedEvent.type = EVENT_INVALID;
00366         list.push_back(mappedEvent);
00367         break;
00368     case EVENT_KEYUP:
00369         hwInput = findHardwareInput(ev.kbd);
00370         break;
00371     case EVENT_CUSTOM_BACKEND_HARDWARE:
00372         hwInput = findHardwareInput(ev.customType);
00373         break;
00374     default:
00375         break;
00376     }
00377     if (hwInput) {
00378         _actionToRemap->mapInput(hwInput);
00379         _actionToRemap->getParent()->saveMappings();
00380         _remapping = false;
00381         _actionToRemap = 0;
00382         mappedEvent.type = EVENT_GUI_REMAP_COMPLETE_ACTION;
00383         list.push_back(mappedEvent);
00384     }
00385     return list;
00386 }
00387 
00388 } // End of namespace Common
00389 
00390 #endif // #ifdef ENABLE_KEYMAPPER


Generated on Sat Feb 9 2019 05:00:34 for ResidualVM by doxygen 1.7.1
curved edge   curved edge