aboutsummaryrefslogtreecommitdiff
path: root/backends/keymapper/remap-dialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backends/keymapper/remap-dialog.cpp')
-rw-r--r--backends/keymapper/remap-dialog.cpp180
1 files changed, 100 insertions, 80 deletions
diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index b0f42fe426..009c2201a9 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -39,7 +39,7 @@ enum {
};
RemapDialog::RemapDialog()
- : Dialog("KeyMapper"), _keymapTable(0), _activeRemapAction(0), _topAction(0), _remapTimeout(0) {
+ : Dialog("KeyMapper"), _keymapTable(0), _topAction(0), _remapTimeout(0), _topKeymapIsGui(false) {
_keymapper = g_system->getEventManager()->getKeymapper();
assert(_keymapper);
@@ -57,12 +57,13 @@ RemapDialog::~RemapDialog() {
}
void RemapDialog::open() {
- bool divider = false;
const Stack<Keymapper::MapRecord> &activeKeymaps = _keymapper->getActiveStack();
if (activeKeymaps.size() > 0) {
- _kmPopUp->appendEntry(activeKeymaps.top().keymap->getName() + _(" (Active)"));
- divider = true;
+ 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)"));
}
Keymapper::Domain *_globalKeymaps = &_keymapper->getGlobalDomain();
@@ -84,27 +85,45 @@ void RemapDialog::open() {
keymapCount += _gameKeymaps->size();
}
+ if (activeKeymaps.size() > 1) {
+ keymapCount += activeKeymaps.size() - 1;
+ }
+
debug(3, "RemapDialog::open keymaps: %d", keymapCount);
- _keymapTable = (Keymap **)malloc(sizeof(Keymap*) * 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) {
- if (divider)
- _kmPopUp->appendEntry("");
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;
}
- divider = true;
}
if (_gameKeymaps) {
- if (divider)
- _kmPopUp->appendEntry("");
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;
}
@@ -138,18 +157,19 @@ void RemapDialog::reflowLayout() {
int16 areaX, areaY;
uint16 areaW, areaH;
+ g_gui.xmlEval()->getWidgetData((const String&)String("KeyMapper.KeymapArea"), areaX, areaY, areaW, areaH);
+
int spacing = g_gui.xmlEval()->getVar("Globals.KeyMapper.Spacing");
- int labelWidth = g_gui.xmlEval()->getVar("Globals.KeyMapper.LabelWidth");
int keyButtonWidth = g_gui.xmlEval()->getVar("Globals.KeyMapper.ButtonWidth");
int clearButtonWidth = g_gui.xmlEval()->getVar("Globals.Line.Height");
int clearButtonHeight = g_gui.xmlEval()->getVar("Globals.Line.Height");
- int colWidth = labelWidth + keyButtonWidth + clearButtonWidth + spacing;
- g_gui.xmlEval()->getWidgetData((const String&)String("KeyMapper.KeymapArea"), areaX, areaY, areaW, areaH);
+ int colWidth = areaW - scrollbarWidth;
+ int labelWidth = colWidth - (keyButtonWidth + spacing + clearButtonWidth + spacing);
- _colCount = (areaW - scrollbarWidth) / colWidth;
_rowCount = (areaH + spacing) / (buttonHeight + spacing);
- if (_colCount <= 0 || _rowCount <= 0)
+ debug(7, "rowCount = %d" , _rowCount);
+ if (colWidth <= 0 || _rowCount <= 0)
error("Remap dialog too small to display any keymaps");
_scrollBar->resize(areaX + areaW - scrollbarWidth, areaY, scrollbarWidth, areaH);
@@ -160,7 +180,7 @@ void RemapDialog::reflowLayout() {
uint textYOff = (buttonHeight - kLineHeight) / 2;
uint clearButtonYOff = (buttonHeight - clearButtonHeight) / 2;
uint oldSize = _keymapWidgets.size();
- uint newSize = _rowCount * _colCount;
+ uint newSize = _rowCount;
_keymapWidgets.reserve(newSize);
@@ -169,30 +189,22 @@ void RemapDialog::reflowLayout() {
if (i >= _keymapWidgets.size()) {
widg.actionText =
- new GUI::StaticTextWidget(this, 0, 0, 0, 0, "", Graphics::kTextAlignRight);
+ new GUI::StaticTextWidget(this, 0, 0, 0, 0, "", Graphics::kTextAlignLeft);
widg.keyButton =
new GUI::ButtonWidget(this, 0, 0, 0, 0, "", 0, kRemapCmd + i);
-#ifndef DISABLE_FANCY_THEMES
- if (g_gui.xmlEval()->getVar("Globals.ShowSearchPic") == 1 && g_gui.theme()->supportsImages()) {
- widg.clearButton = new GUI::PicButtonWidget(this, 0, 0, clearButtonWidth, clearButtonHeight, _("Clear value"), kClearCmd + i);
- ((GUI::PicButtonWidget *)widg.clearButton)->useThemeTransparency(true);
- ((GUI::PicButtonWidget *)widg.clearButton)->setGfx(g_gui.theme()->getImageSurface(GUI::ThemeEngine::kImageEraser));
- }
- else
-#endif
- widg.clearButton = new GUI::ButtonWidget(this, 0, 0, 0, 0, "C", _("Clear value"), kClearCmd + i);
-
+ widg.clearButton = addClearButton(this, "", kClearCmd + i, 0, 0, clearButtonWidth, clearButtonHeight);
_keymapWidgets.push_back(widg);
} else {
widg = _keymapWidgets[i];
}
- uint x = areaX + (i % _colCount) * colWidth;
- uint y = areaY + (i / _colCount) * (buttonHeight + spacing);
+ uint x = areaX;
+ uint y = areaY + (i) * (buttonHeight + spacing);
+
+ widg.keyButton->resize(x, y, keyButtonWidth, buttonHeight);
+ widg.clearButton->resize(x + keyButtonWidth + spacing, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
+ widg.actionText->resize(x + keyButtonWidth + spacing + clearButtonWidth + spacing, y + textYOff, labelWidth, kLineHeight);
- widg.actionText->resize(x, y + textYOff, labelWidth, kLineHeight);
- widg.keyButton->resize(x + labelWidth, y, keyButtonWidth, buttonHeight);
- widg.clearButton->resize(x + labelWidth + keyButtonWidth + spacing, y + clearButtonYOff, clearButtonWidth, clearButtonHeight);
}
while (oldSize > newSize) {
ActionWidgets widg = _keymapWidgets.remove_at(--oldSize);
@@ -231,16 +243,14 @@ void RemapDialog::clearMapping(uint i) {
return;
debug(3, "clear the mapping %u", i);
- _activeRemapAction = _currentActions[_topAction + i].action;
- _activeRemapAction->mapKey(0);
- _activeRemapAction->getParent()->saveMappings();
+ Action *activeRemapAction = _currentActions[_topAction + i].action;
+ activeRemapAction->mapInput(0);
+ activeRemapAction->getParent()->saveMappings();
_changes = true;
// force refresh
- _topAction = -1;
+ stopRemapping(true);
refreshKeymap();
-
- _activeRemapAction = 0;
}
void RemapDialog::startRemapping(uint i) {
@@ -248,57 +258,56 @@ void RemapDialog::startRemapping(uint i) {
return;
_remapTimeout = g_system->getMillis() + kRemapTimeoutDelay;
- _activeRemapAction = _currentActions[_topAction + i].action;
+ Action *activeRemapAction = _currentActions[_topAction + i].action;
_keymapWidgets[i].keyButton->setLabel("...");
_keymapWidgets[i].keyButton->draw();
- _keymapper->setEnabled(false);
+ _keymapper->startRemappingMode(activeRemapAction);
}
-void RemapDialog::stopRemapping() {
+void RemapDialog::stopRemapping(bool force) {
_topAction = -1;
refreshKeymap();
- _activeRemapAction = 0;
-
- _keymapper->setEnabled(true);
+ if (force)
+ _keymapper->stopRemappingMode();
}
void RemapDialog::handleKeyDown(Common::KeyState state) {
- if (_activeRemapAction)
+ if (_keymapper->isRemapping())
return;
GUI::Dialog::handleKeyDown(state);
}
void RemapDialog::handleKeyUp(Common::KeyState state) {
- if (_activeRemapAction) {
- const HardwareKey *hwkey = _keymapper->findHardwareKey(state);
+ if (_keymapper->isRemapping())
+ return;
- debug(4, "RemapDialog::handleKeyUp Key: %d, %d (%c), %x", state.keycode, state.ascii, (state.ascii ? state.ascii : ' '), state.flags);
+ GUI::Dialog::handleKeyUp(state);
+}
- if (hwkey) {
- _activeRemapAction->mapKey(hwkey);
- _activeRemapAction->getParent()->saveMappings();
- _changes = true;
- stopRemapping();
- }
+void RemapDialog::handleOtherEvent(Event ev) {
+ if (ev.type == EVENT_GUI_REMAP_COMPLETE_ACTION) {
+ // _keymapper is telling us that something changed
+ _changes = true;
+ stopRemapping();
} else {
- GUI::Dialog::handleKeyUp(state);
+ GUI::Dialog::handleOtherEvent(ev);
}
}
void RemapDialog::handleMouseDown(int x, int y, int button, int clickCount) {
- if (_activeRemapAction)
+ if (_keymapper->isRemapping())
stopRemapping();
else
Dialog::handleMouseDown(x, y, button, clickCount);
}
void RemapDialog::handleTickle() {
- if (_activeRemapAction && g_system->getMillis() > _remapTimeout)
- stopRemapping();
+ if (_keymapper->isRemapping() && g_system->getMillis() > _remapTimeout)
+ stopRemapping(true);
Dialog::handleTickle();
}
@@ -309,19 +318,22 @@ void RemapDialog::loadKeymap() {
debug(3, "RemapDialog::loadKeymap active keymaps: %u", activeKeymaps.size());
if (!activeKeymaps.empty() && _kmPopUp->getSelected() == 0) {
- // load active keymaps
+ // This is the "effective" view which shows all effective actions:
+ // - all of the topmost keymap action
+ // - all mapped actions that are reachable
- List<const HardwareKey*> freeKeys(_keymapper->getHardwareKeys());
+ List<const HardwareInput *> freeInputs(_keymapper->getHardwareInputs());
int topIndex = activeKeymaps.size() - 1;
- // skip the top gui keymap since it is for the keymapper itself
- // TODO: Don't use the keymap name as a way to discriminate GUI maps
- if (topIndex > 0 && activeKeymaps[topIndex].keymap->getName().equals(kGuiKeymapName))
+
+ // 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;
+ 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;
@@ -329,38 +341,46 @@ void RemapDialog::loadKeymap() {
_currentActions.push_back(info);
- if (act->getMappedKey())
- freeKeys.remove(act->getMappedKey());
+ if (act->getMappedInput())
+ freeInputs.remove(act->getMappedInput());
}
// loop through remaining finding mappings for unmapped keys
- if (top.inherit && topIndex >= 0) {
+ 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 HardwareKey*>::iterator keyIt = freeKeys.begin();
+ List<const HardwareInput *>::iterator inputIt = freeInputs.begin();
+ const HardwareInput *input = *inputIt;
+ while (inputIt != freeInputs.end()) {
- while (keyIt != freeKeys.end()) {
- Action *act = mr.keymap->getMappedAction((*keyIt)->key);
+ Action *act = 0;
+ if (input->type == kHardwareInputTypeKeyboard)
+ act = mr.keymap->getMappedAction(input->key);
+ else if (input->type == kHardwareInputTypeGeneric)
+ act = mr.keymap->getMappedAction(input->inputCode);
if (act) {
ActionInfo info = {act, true, act->description + " (" + mr.keymap->getName() + ")"};
_currentActions.push_back(info);
- freeKeys.erase(keyIt++);
+ freeInputs.erase(inputIt);
} else {
- ++keyIt;
+ ++inputIt;
}
}
- if (mr.inherit == false || freeKeys.empty())
+ if (mr.transparent == false || freeInputs.empty())
break;
}
}
} else 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
+
Keymap *km = _keymapTable[_kmPopUp->getSelectedTag()];
- List<Action*>::iterator it;
+ List<Action *>::iterator it;
for (it = km->getActions().begin(); it != km->getActions().end(); ++it) {
ActionInfo info = {*it, false, (*it)->description};
@@ -371,7 +391,7 @@ void RemapDialog::loadKeymap() {
// refresh scroll bar
_scrollBar->_currentPos = 0;
- _scrollBar->_numEntries = (_currentActions.size() + _colCount - 1) / _colCount;
+ _scrollBar->_numEntries = _currentActions.size();
_scrollBar->recalc();
// force refresh
@@ -380,7 +400,7 @@ void RemapDialog::loadKeymap() {
}
void RemapDialog::refreshKeymap() {
- int newTopAction = _scrollBar->_currentPos * _colCount;
+ int newTopAction = _scrollBar->_currentPos;
if (newTopAction == _topAction)
return;
@@ -399,13 +419,13 @@ void RemapDialog::refreshKeymap() {
debug(8, "RemapDialog::refreshKeymap actionI=%u", actionI);
ActionInfo& info = _currentActions[actionI];
- widg.actionText->setLabel(info.description + ": ");
+ widg.actionText->setLabel(info.description);
widg.actionText->setEnabled(!info.inherited);
- const HardwareKey *mappedKey = info.action->getMappedKey();
+ const HardwareInput *mappedInput = info.action->getMappedInput();
- if (mappedKey)
- widg.keyButton->setLabel(mappedKey->description);
+ if (mappedInput)
+ widg.keyButton->setLabel(mappedInput->description);
else
widg.keyButton->setLabel("-");