KEYMAPPER: Remove the domain class

This commit is contained in:
Bastien Bouclet 2017-08-13 16:35:58 +02:00
parent ada44ca760
commit ac44469558
12 changed files with 87 additions and 260 deletions

View file

@ -33,7 +33,11 @@
namespace Common {
Keymap::Keymap(const Keymap& km) : _actions(km._actions), _hwActionMap(), _configDomain(0) {
Keymap::Keymap(KeymapType type, const String &name) :
_type(type),
_name(name),
_configDomain(nullptr) {
}
Keymap::~Keymap() {

View file

@ -41,11 +41,15 @@ class HardwareInputSet;
class Keymap {
public:
Keymap(const String& name) : _name(name) {}
Keymap(const Keymap& km);
enum KeymapType {
kKeymapTypeGlobal,
kKeymapTypeGui,
kKeymapTypeGame
};
Keymap(KeymapType type, const String &name);
~Keymap();
public:
/**
* Registers a HardwareInput to the given Action
* @param action Action in this Keymap
@ -95,6 +99,8 @@ public:
const String& getName() { return _name; }
KeymapType getType() const { return _type; }
private:
friend struct Action;
@ -110,6 +116,7 @@ private:
typedef List<Action *> ActionList;
typedef HashMap<const HardwareInput *, Action *> HardwareActionMap;
KeymapType _type;
String _name;
ActionList _actions;
HardwareActionMap _hwActionMap;

View file

@ -35,36 +35,8 @@ namespace Common {
static const uint32 kDelayKeyboardEventMillis = 250;
static const uint32 kDelayMouseEventMillis = 50;
void Keymapper::Domain::addKeymap(Keymap *map) {
iterator it = find(map->getName());
if (it != end())
delete it->_value;
setVal(map->getName(), map);
}
void Keymapper::Domain::deleteAllKeyMaps() {
for (iterator it = begin(); it != end(); ++it)
delete it->_value;
clear();
}
Keymap *Keymapper::Domain::getKeymap(const String& name) {
iterator it = find(name);
if (it != end())
return it->_value;
else
return 0;
}
Keymapper::Keymapper(EventManager *evtMgr)
: _eventMan(evtMgr), _enabled(true), _hardwareInputs(0) {
ConfigManager::Domain *confDom = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
_globalDomain.setConfigDomain(confDom);
}
Keymapper::~Keymapper() {
@ -84,84 +56,89 @@ void Keymapper::registerHardwareInputSet(HardwareInputSet *inputs) {
}
void Keymapper::addGlobalKeymap(Keymap *keymap) {
initKeymap(_globalDomain, keymap);
assert(keymap->getType() == Keymap::kKeymapTypeGlobal
|| keymap->getType() == Keymap::kKeymapTypeGui);
ConfigManager::Domain *keymapperDomain = ConfMan.getDomain(ConfigManager::kKeymapperDomain);
initKeymap(keymap, keymapperDomain);
}
void Keymapper::addGameKeymap(Keymap *keymap) {
if (ConfMan.getActiveDomain() == 0)
error("Call to Keymapper::addGameKeymap when no game loaded");
assert(keymap->getType() == Keymap::kKeymapTypeGame);
// Detect whether the active game changed since last call.
// If so, flush the game key configuration.
if (_gameDomain.getConfigDomain() != ConfMan.getActiveDomain()) {
cleanupGameKeymaps();
_gameDomain.setConfigDomain(ConfMan.getActiveDomain());
ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain();
if (!gameDomain) {
error("Call to Keymapper::addGameKeymap when no game loaded");
}
initKeymap(_gameDomain, keymap);
cleanupGameKeymaps();
initKeymap(keymap, gameDomain);
}
void Keymapper::initKeymap(Domain &domain, Keymap *map) {
void Keymapper::initKeymap(Keymap *keymap, ConfigManager::Domain *domain) {
if (!_hardwareInputs) {
warning("No hardware inputs were registered yet (%s)", map->getName().c_str());
warning("No hardware inputs were registered yet (%s)", keymap->getName().c_str());
return;
}
map->setConfigDomain(domain.getConfigDomain());
map->loadMappings(_hardwareInputs);
keymap->setConfigDomain(domain);
keymap->loadMappings(_hardwareInputs);
domain.addKeymap(map);
_keymaps.push_back(keymap);
}
void Keymapper::cleanupGameKeymaps() {
// Flush all game specific keymaps
_gameDomain.deleteAllKeyMaps();
KeymapArray::iterator it = _keymaps.begin();
while (it != _keymaps.end()) {
if ((*it)->getType() == Keymap::kKeymapTypeGame) {
delete *it;
it = _keymaps.erase(it);
} else {
it++;
}
}
// Now restore the stack of active maps. Re-add all global keymaps, drop
// the game specific (=deleted) ones.
Stack<MapRecord> newStack;
for (Stack<MapRecord>::size_type i = 0; i < _activeMaps.size(); i++) {
if (_activeMaps[i].global)
if (_activeMaps[i].keymap->getType() == Keymap::kKeymapTypeGlobal)
newStack.push(_activeMaps[i]);
}
_activeMaps = newStack;
}
Keymap *Keymapper::getKeymap(const String& name, bool *globalReturn) {
Keymap *keymap = _gameDomain.getKeymap(name);
bool global = false;
if (!keymap) {
keymap = _globalDomain.getKeymap(name);
global = true;
Keymap *Keymapper::getKeymap(const String &name) {
for (KeymapArray::const_iterator it = _keymaps.begin(); it != _keymaps.end(); it++) {
if ((*it)->getName() == name) {
return *it;
}
}
if (globalReturn)
*globalReturn = global;
return keymap;
return nullptr;
}
bool Keymapper::pushKeymap(const String& name, bool transparent) {
bool global;
bool Keymapper::pushKeymap(const String &name, bool transparent) {
assert(!name.empty());
Keymap *newMap = getKeymap(name, &global);
Keymap *newMap = getKeymap(name);
if (!newMap) {
warning("Keymap '%s' not registered", name.c_str());
return false;
}
pushKeymap(newMap, transparent, global);
pushKeymap(newMap, transparent);
return true;
}
void Keymapper::pushKeymap(Keymap *newMap, bool transparent, bool global) {
MapRecord mr = {newMap, transparent, global};
void Keymapper::pushKeymap(Keymap *newMap, bool transparent) {
MapRecord mr = {newMap, transparent};
_activeMaps.push(mr);
}

View file

@ -56,33 +56,6 @@ public:
struct MapRecord {
Keymap* keymap;
bool transparent;
bool global;
};
/* Nested class that represents a set of keymaps */
class Domain : public HashMap<String, Keymap*,
IgnoreCase_Hash, IgnoreCase_EqualTo> {
public:
Domain() : _configDomain(0) {}
~Domain() {
deleteAllKeyMaps();
}
void setConfigDomain(ConfigManager::Domain *confDom) {
_configDomain = confDom;
}
ConfigManager::Domain *getConfigDomain() {
return _configDomain;
}
void addKeymap(Keymap *map);
void deleteAllKeyMaps();
Keymap *getKeymap(const String& name);
private:
ConfigManager::Domain *_configDomain;
};
Keymapper(EventManager *eventMan);
@ -129,9 +102,10 @@ public:
* Obtain a keymap of the given name from the keymapper.
* Game keymaps have priority over global keymaps
* @param name name of the keymap to return
* @param global set to true if returned keymap is global, false if game
*/
Keymap *getKeymap(const String& name, bool *global = 0);
Keymap *getKeymap(const String &name);
const Array<Keymap *> &getKeymaps() const { return _keymaps; }
/**
* Push a new keymap to the top of the active stack, activating
@ -161,8 +135,6 @@ public:
*/
const HardwareInput *findHardwareInput(const Event &event);
Domain& getGlobalDomain() { return _globalDomain; }
Domain& getGameDomain() { return _gameDomain; }
const Stack<MapRecord>& getActiveStack() const { return _activeMaps; }
/**
@ -183,14 +155,11 @@ private:
kIncomingNonKey
};
void initKeymap(Domain &domain, Keymap *keymap);
Domain _globalDomain;
Domain _gameDomain;
void initKeymap(Keymap *keymap, ConfigManager::Domain *domain);
HardwareInputSet *_hardwareInputs;
void pushKeymap(Keymap *newMap, bool transparent, bool global);
void pushKeymap(Keymap *newMap, bool transparent);
Event executeAction(const Action *act, IncomingEventType incomingType);
EventType convertDownToUp(EventType eventType);
@ -200,6 +169,9 @@ private:
bool _enabled;
typedef Array<Keymap *> KeymapArray;
KeymapArray _keymaps;
Stack<MapRecord> _activeMaps;
};

View file

@ -44,7 +44,7 @@ enum {
};
RemapDialog::RemapDialog()
: Dialog("KeyMapper"), _keymapTable(0), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false), _remapAction(nullptr) {
: Dialog("KeyMapper"), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false), _remapAction(nullptr) {
_keymapper = g_system->getEventManager()->getKeymapper();
assert(_keymapper);
@ -64,81 +64,17 @@ RemapDialog::RemapDialog()
}
RemapDialog::~RemapDialog() {
free(_keymapTable);
delete _remapInputWatcher;
}
void RemapDialog::open() {
const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack();
_keymapTable = _keymapper->getKeymaps();
if (activeKeymaps.size() > 0) {
if (activeKeymaps.top().keymap->getName() == Common::kGuiKeymapName)
_topKeymapIsGui = true;
// Add the entry for the "effective" special view. See RemapDialog::loadKeymap()
_kmPopUp->appendEntry(activeKeymaps.top().keymap->getName() + _(" (Effective)"));
}
debug(3, "RemapDialog::open keymaps: %d", _keymapTable.size());
Keymapper::Domain *_globalKeymaps = &_keymapper->getGlobalDomain();
Keymapper::Domain *_gameKeymaps = 0;
int keymapCount = 0;
if (_globalKeymaps->empty())
_globalKeymaps = 0;
else
keymapCount += _globalKeymaps->size();
if (ConfMan.getActiveDomain() != 0) {
_gameKeymaps = &_keymapper->getGameDomain();
if (_gameKeymaps->empty())
_gameKeymaps = 0;
else
keymapCount += _gameKeymaps->size();
}
if (activeKeymaps.size() > 1) {
keymapCount += activeKeymaps.size() - 1;
}
debug(3, "RemapDialog::open keymaps: %d", keymapCount);
_keymapTable = (Keymap **)malloc(sizeof(Keymap *) * keymapCount);
Keymapper::Domain::iterator it;
uint32 idx = 0;
if (activeKeymaps.size() > 1) {
int topIndex = activeKeymaps.size() - 1;
bool active = activeKeymaps[topIndex].transparent;
for (int i = topIndex - 1; i >= 0; --i) {
Keymapper::MapRecord mr = activeKeymaps[i];
// Add an entry for each keymap in the stack after the top keymap. Mark it Active if it is
// reachable or Blocked if an opaque keymap is on top of it thus blocking access to it.
_kmPopUp->appendEntry(mr.keymap->getName() + (active ? _(" (Active)") : _(" (Blocked)")), idx);
_keymapTable[idx++] = mr.keymap;
active &= mr.transparent;
}
}
_kmPopUp->appendEntry("");
// Now add entries for all known keymaps. Note that there will be duplicates with the stack entries.
if (_globalKeymaps) {
for (it = _globalKeymaps->begin(); it != _globalKeymaps->end(); ++it) {
// "global" means its keybindings apply to all games; saved in a global conf domain
_kmPopUp->appendEntry(it->_value->getName() + _(" (Global)"), idx);
_keymapTable[idx++] = it->_value;
}
}
if (_gameKeymaps) {
for (it = _gameKeymaps->begin(); it != _gameKeymaps->end(); ++it) {
// "game" means its keybindings are saved per-target
_kmPopUp->appendEntry(it->_value->getName() + _(" (Game)"), idx);
_keymapTable[idx++] = it->_value;
}
// Show the keymaps by order of priority (game keymaps first)
for (int i = _keymapTable.size() - 1; i >= 0; i--) {
_kmPopUp->appendEntry(_keymapTable[i]->getName(), i);
}
_changes = false;
@ -152,9 +88,6 @@ void RemapDialog::open() {
void RemapDialog::close() {
_kmPopUp->clearEntries();
free(_keymapTable);
_keymapTable = 0;
if (_changes)
ConfMan.flushToDisk();
@ -255,7 +188,7 @@ void RemapDialog::clearMapping(uint i) {
return;
debug(3, "clear the mapping %u", i);
Action *activeRemapAction = _currentActions[_topAction + i].action;
Action *activeRemapAction = _currentActions[_topAction + i];
_keymapper->clearMapping(activeRemapAction);
_changes = true;
@ -273,7 +206,7 @@ void RemapDialog::startRemapping(uint i) {
return;
}
_remapAction = _currentActions[_topAction + i].action;
_remapAction = _currentActions[_topAction + i];
_remapTimeout = g_system->getMillis() + kRemapTimeoutDelay;
_remapInputWatcher->startWatching();
@ -313,64 +246,8 @@ void RemapDialog::handleTickle() {
void RemapDialog::loadKeymap() {
_currentActions.clear();
const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack();
debug(3, "RemapDialog::loadKeymap active keymaps: %u", activeKeymaps.size());
if (!activeKeymaps.empty() && _kmPopUp->getSelected() == 0) {
// This is the "effective" view which shows all effective actions:
// - all of the topmost keymap action
// - all mapped actions that are reachable
List<const HardwareInput *> freeInputs(_keymapper->getHardwareInputs());
int topIndex = activeKeymaps.size() - 1;
// This is a WORKAROUND for changing the popup list selected item and changing it back
// to the top entry. Upon changing it back, the top keymap is always "gui".
if (!_topKeymapIsGui && activeKeymaps[topIndex].keymap->getName() == kGuiKeymapName)
--topIndex;
// add most active keymap's keys
Keymapper::MapRecord top = activeKeymaps[topIndex];
List<Action *>::iterator actIt;
debug(3, "RemapDialog::loadKeymap top keymap: %s", top.keymap->getName().c_str());
for (actIt = top.keymap->getActions().begin(); actIt != top.keymap->getActions().end(); ++actIt) {
Action *act = *actIt;
ActionInfo info = {act, false, act->description};
_currentActions.push_back(info);
const HardwareInput *mappedInput = top.keymap->getActionMapping(act);
if (mappedInput)
freeInputs.remove(mappedInput);
}
// loop through remaining finding mappings for unmapped keys
if (top.transparent && topIndex >= 0) {
for (int i = topIndex - 1; i >= 0; --i) {
Keymapper::MapRecord mr = activeKeymaps[i];
debug(3, "RemapDialog::loadKeymap keymap: %s", mr.keymap->getName().c_str());
List<const HardwareInput *>::iterator inputIt = freeInputs.begin();
const HardwareInput *input = *inputIt;
while (inputIt != freeInputs.end()) {
Action *act = mr.keymap->getMappedAction(input);
if (act) {
ActionInfo info = {act, true, act->description + " (" + mr.keymap->getName() + ")"};
_currentActions.push_back(info);
freeInputs.erase(inputIt);
} else {
++inputIt;
}
}
if (mr.transparent == false || freeInputs.empty())
break;
}
}
} else if (_kmPopUp->getSelected() != -1) {
if (_kmPopUp->getSelected() != -1) {
// This is the regular view of a keymap that isn't the topmost one.
// It shows all of that keymap's actions
@ -379,9 +256,7 @@ void RemapDialog::loadKeymap() {
List<Action *>::iterator it;
for (it = km->getActions().begin(); it != km->getActions().end(); ++it) {
ActionInfo info = {*it, false, (*it)->description};
_currentActions.push_back(info);
_currentActions.push_back(*it);
}
}
@ -409,18 +284,17 @@ void RemapDialog::refreshKeymap() {
uint actionI = _topAction;
for (uint widgetI = 0; widgetI < _keymapWidgets.size(); widgetI++) {
ActionWidgets& widg = _keymapWidgets[widgetI];
ActionWidgets &widg = _keymapWidgets[widgetI];
if (actionI < _currentActions.size()) {
debug(8, "RemapDialog::refreshKeymap actionI=%u", actionI);
ActionInfo& info = _currentActions[actionI];
Action *action = _currentActions[actionI];
widg.actionText->setLabel(info.description);
widg.actionText->setEnabled(!info.inherited);
widg.actionText->setLabel(action->description);
Keymap *keymap = info.action->getParent();
Keymap *keymap = action->getParent();
const HardwareInput *mappedInput = keymap->getActionMapping(info.action);
const HardwareInput *mappedInput = keymap->getActionMapping(action);
if (mappedInput)
widg.keyButton->setLabel(mappedInput->description);
else
@ -436,11 +310,9 @@ void RemapDialog::refreshKeymap() {
widg.keyButton->setVisible(false);
widg.clearButton->setVisible(false);
}
//widg.actionText->markAsDirty();
//widg.keyButton->markAsDirty();
}
// need to redraw entire Dialog so that invisible
// widgets disappear
// need to redraw entire Dialog so that invisible widgets disappear
g_gui.scheduleTopDialogRedraw();
}

View file

@ -60,11 +60,6 @@ protected:
GUI::ButtonWidget *keyButton;
GUI::ButtonWidget *clearButton;
};
struct ActionInfo {
Action *action;
bool inherited;
String description;
};
void loadKeymap();
void refreshKeymap();
@ -73,13 +68,13 @@ protected:
void stopRemapping();
Keymapper *_keymapper;
Keymap** _keymapTable;
Common::Array<Keymap *> _keymapTable;
InputWatcher *_remapInputWatcher;
Action *_remapAction;
uint32 _remapTimeout;
Array<ActionInfo> _currentActions;
Array<Action *> _currentActions;
int _topAction;
GUI::StaticTextWidget *_kmPopUpDesc;

View file

@ -360,7 +360,7 @@ static void setupKeymapper(OSystem &system) {
mapper->registerHardwareInputSet(inputSet);
// Now create the global keymap
Keymap *primaryGlobalKeymap = new Keymap(kGlobalKeymapName);
Keymap *primaryGlobalKeymap = new Keymap(Keymap::kKeymapTypeGlobal, kGlobalKeymapName);
Action *act;
act = new Action(primaryGlobalKeymap, "MENU", _("Menu"));
act->setEvent(EVENT_MAINMENU);

View file

@ -351,7 +351,7 @@ void EoBCoreEngine::initKeymap() {
if (mapper->getKeymap(kKeymapName) != 0)
return;
Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
const Common::KeyActionEntry keyActionEntries[] = {
{ Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward") },

View file

@ -473,7 +473,7 @@ void LoLEngine::initKeymap() {
if (mapper->getKeymap(kKeymapName) != 0)
return;
Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
const Common::KeyActionEntry keyActionEntries[] = {
{Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1), "AT1", _("Attack 1")},

View file

@ -882,7 +882,7 @@ void MohawkEngine_Riven::initKeymap() {
if (mapper->getKeymap(kKeymapName) != 0)
return;
Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
const Common::KeyActionEntry keyActionEntries[] = {
{ Common::KEYCODE_UP, "UP", _("Move Forward") },

View file

@ -2498,7 +2498,7 @@ void PegasusEngine::initKeymap() {
if (mapper->getKeymap(kKeymapName) != 0)
return;
Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
Common::Keymap *const engineKeyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, kKeymapName);
// Since the game has multiple built-in keys for each of these anyway,
// this just attempts to remap one of them.

View file

@ -119,7 +119,7 @@ void GuiManager::initKeymap() {
return;
Action *act;
Keymap *guiMap = new Keymap(kGuiKeymapName);
Keymap *guiMap = new Keymap(Keymap::kKeymapTypeGui, kGuiKeymapName);
act = new Action(guiMap, "CLOS", _("Close"));
act->setKeyEvent(KeyState(KEYCODE_ESCAPE, ASCII_ESCAPE, 0));