mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-25 05:34:27 +00:00
KEYMAPPER: Allow mapped actions without modifier keys when no mapped actions exist for current modifier keys
This commit is contained in:
parent
bc3a642cb7
commit
b4083476d5
@ -124,74 +124,108 @@ const Action *Keymap::findAction(const char *id) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Keymap::ActionArray Keymap::getMappedActions(const Event &event) const {
|
||||
Keymap::KeymapMatch Keymap::getMappedActions(const Event &event, ActionArray &actions) const {
|
||||
switch (event.type) {
|
||||
case EVENT_KEYDOWN:
|
||||
case EVENT_KEYUP: {
|
||||
KeyState normalizedKeystate = KeyboardHardwareInputSet::normalizeKeyState(event.kbd);
|
||||
HardwareInput hardwareInput = HardwareInput::createKeyboard("", normalizedKeystate, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
if (!actions.empty()) {
|
||||
return kKeymapMatchExact;
|
||||
}
|
||||
|
||||
if (normalizedKeystate.flags & KBD_NON_STICKY) {
|
||||
// If no matching actions and non-sticky keyboard modifiers are down,
|
||||
// check again for matches without the exact keyboard modifiers
|
||||
for (HardwareActionMap::const_iterator itInput = _hwActionMap.begin(); itInput != _hwActionMap.end(); ++itInput) {
|
||||
if (itInput->_key.type == kHardwareInputTypeKeyboard && itInput->_key.key.keycode == normalizedKeystate.keycode) {
|
||||
int flags = itInput->_key.key.flags;
|
||||
if (flags & KBD_NON_STICKY && (flags & normalizedKeystate.flags) == flags) {
|
||||
actions.push_back(itInput->_value);
|
||||
return kKeymapMatchPartial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly check again for matches no non-sticky keyboard modifiers
|
||||
normalizedKeystate.flags &= ~KBD_NON_STICKY;
|
||||
hardwareInput = HardwareInput::createKeyboard("", normalizedKeystate, "");
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
return actions.empty() ? kKeymapMatchNone : kKeymapMatchPartial;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_LBUTTONDOWN:
|
||||
case EVENT_LBUTTONUP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_LEFT, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case EVENT_RBUTTONDOWN:
|
||||
case EVENT_RBUTTONUP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_RIGHT, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case EVENT_MBUTTONDOWN:
|
||||
case EVENT_MBUTTONUP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_MIDDLE, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case Common::EVENT_WHEELUP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_WHEEL_UP, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case Common::EVENT_WHEELDOWN: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_WHEEL_DOWN, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case EVENT_X1BUTTONDOWN:
|
||||
case EVENT_X1BUTTONUP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_X1, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case EVENT_X2BUTTONDOWN:
|
||||
case EVENT_X2BUTTONUP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createMouse("", MOUSE_BUTTON_X2, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case EVENT_JOYBUTTON_DOWN:
|
||||
case EVENT_JOYBUTTON_UP: {
|
||||
HardwareInput hardwareInput = HardwareInput::createJoystickButton("", event.joystick.button, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
case EVENT_JOYAXIS_MOTION: {
|
||||
if (event.joystick.position != 0) {
|
||||
bool positiveHalf = event.joystick.position >= 0;
|
||||
HardwareInput hardwareInput = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, positiveHalf, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
} else {
|
||||
// Axis position zero is part of both half axes, and triggers actions bound to both
|
||||
Keymap::ActionArray actions;
|
||||
HardwareInput hardwareInputPos = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, true, "");
|
||||
HardwareInput hardwareInputNeg = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, false, "");
|
||||
actions.push_back(_hwActionMap[hardwareInputPos]);
|
||||
actions.push_back(_hwActionMap[hardwareInputNeg]);
|
||||
return actions;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_CUSTOM_BACKEND_HARDWARE: {
|
||||
HardwareInput hardwareInput = HardwareInput::createCustom("", event.customType, "");
|
||||
return _hwActionMap[hardwareInput];
|
||||
actions.push_back(_hwActionMap[hardwareInput]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return ActionArray();
|
||||
break;
|
||||
}
|
||||
|
||||
return actions.empty() ? kKeymapMatchNone : kKeymapMatchExact;
|
||||
}
|
||||
|
||||
void Keymap::setConfigDomain(ConfigManager::Domain *configDomain) {
|
||||
|
@ -72,6 +72,12 @@ public:
|
||||
kKeymapTypeGame
|
||||
};
|
||||
|
||||
enum KeymapMatch {
|
||||
kKeymapMatchNone,
|
||||
kKeymapMatchPartial,
|
||||
kKeymapMatchExact
|
||||
};
|
||||
|
||||
typedef Array<Action *> ActionArray;
|
||||
|
||||
Keymap(KeymapType type, const String &id, const String &description);
|
||||
@ -109,9 +115,10 @@ public:
|
||||
/**
|
||||
* Find the Actions that a hardware input is mapped to
|
||||
* @param hardwareInput the input that is mapped to the required Action
|
||||
* @return an array containing pointers to the actions
|
||||
* @param actions an array containing pointers to the actions
|
||||
* @return the matching status for the retieved actions
|
||||
*/
|
||||
ActionArray getMappedActions(const Event &event) const;
|
||||
KeymapMatch getMappedActions(const Event &event, ActionArray &actions) const;
|
||||
|
||||
/**
|
||||
* Adds a new Action to this Map
|
||||
|
@ -170,13 +170,40 @@ List<Event> Keymapper::mapEvent(const Event &ev) {
|
||||
|
||||
hardcodedEventMapping(ev);
|
||||
|
||||
List<Event> mappedEvents;
|
||||
bool matchedAction = mapEvent(ev, _enabledKeymapType, mappedEvents);
|
||||
if (!matchedAction) {
|
||||
// If we found actions matching this input in the game / gui keymaps,
|
||||
Keymap::ActionArray actions;
|
||||
Keymap::KeymapMatch match = getMappedActions(ev, actions, _enabledKeymapType);
|
||||
if (match != Keymap::kKeymapMatchExact) {
|
||||
// If we found exact matching actions this input in the game / gui keymaps,
|
||||
// no need to look at the global keymaps. An input resulting in actions
|
||||
// from system and game keymaps would lead to unexpected user experience.
|
||||
matchedAction = mapEvent(ev, Keymap::kKeymapTypeGlobal, mappedEvents);
|
||||
Keymap::ActionArray globalActions;
|
||||
match = getMappedActions(ev, globalActions, Keymap::kKeymapTypeGlobal);
|
||||
if (match == Keymap::kKeymapMatchExact || actions.empty()) {
|
||||
actions = globalActions;
|
||||
}
|
||||
}
|
||||
|
||||
bool matchedAction = !actions.empty();
|
||||
List<Event> mappedEvents;
|
||||
for (Keymap::ActionArray::const_iterator it = actions.begin(); it != actions.end(); it++) {
|
||||
Event mappedEvent = executeAction(*it, ev);
|
||||
if (mappedEvent.type == EVENT_INVALID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// In case we mapped a mouse event to something else, we need to generate an artificial
|
||||
// mouse move event so event observers can keep track of the mouse position.
|
||||
// Makes it possible to reliably use the mouse position from EventManager when consuming
|
||||
// custom action events.
|
||||
if (isMouseEvent(ev) && !isMouseEvent(mappedEvent)) {
|
||||
Event fakeMouseEvent;
|
||||
fakeMouseEvent.type = EVENT_MOUSEMOVE;
|
||||
fakeMouseEvent.mouse = ev.mouse;
|
||||
|
||||
mappedEvents.push_back(fakeMouseEvent);
|
||||
}
|
||||
|
||||
mappedEvents.push_back(mappedEvent);
|
||||
}
|
||||
|
||||
if (ev.type == EVENT_JOYAXIS_MOTION && ev.joystick.axis < ARRAYSIZE(_joystickAxisPreviouslyPressed)) {
|
||||
@ -195,42 +222,25 @@ List<Event> Keymapper::mapEvent(const Event &ev) {
|
||||
return mappedEvents;
|
||||
}
|
||||
|
||||
bool Keymapper::mapEvent(const Event &ev, Keymap::KeymapType keymapType, List<Event> &mappedEvents) {
|
||||
bool matchedAction = false;
|
||||
Keymap::KeymapMatch Keymapper::getMappedActions(const Event &event, Keymap::ActionArray &actions, Keymap::KeymapType keymapType) const {
|
||||
Keymap::KeymapMatch match = Keymap::kKeymapMatchNone;
|
||||
|
||||
for (uint i = 0; i < _keymaps.size(); i++) {
|
||||
if (!_keymaps[i]->isEnabled() || _keymaps[i]->getType() != keymapType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Keymap::ActionArray actions = _keymaps[i]->getMappedActions(ev);
|
||||
if (!actions.empty()) {
|
||||
matchedAction = true;
|
||||
}
|
||||
|
||||
for (Keymap::ActionArray::const_iterator it = actions.begin(); it != actions.end(); it++) {
|
||||
Event mappedEvent = executeAction(*it, ev);
|
||||
if (mappedEvent.type == EVENT_INVALID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// In case we mapped a mouse event to something else, we need to generate an artificial
|
||||
// mouse move event so event observers can keep track of the mouse position.
|
||||
// Makes it possible to reliably use the mouse position from EventManager when consuming
|
||||
// custom action events.
|
||||
if (isMouseEvent(ev) && !isMouseEvent(mappedEvent)) {
|
||||
Event fakeMouseEvent;
|
||||
fakeMouseEvent.type = EVENT_MOUSEMOVE;
|
||||
fakeMouseEvent.mouse = ev.mouse;
|
||||
|
||||
mappedEvents.push_back(fakeMouseEvent);
|
||||
}
|
||||
|
||||
mappedEvents.push_back(mappedEvent);
|
||||
Keymap::ActionArray array;
|
||||
Keymap::KeymapMatch match2 = _keymaps[i]->getMappedActions(event, array);
|
||||
if (match2 == match) {
|
||||
actions.push_back(array);
|
||||
} else if (match2 > match) {
|
||||
match = match2;
|
||||
actions.clear();
|
||||
actions.push_back(array);
|
||||
}
|
||||
}
|
||||
|
||||
return matchedAction;
|
||||
return match;
|
||||
}
|
||||
|
||||
Keymapper::IncomingEventType Keymapper::convertToIncomingEventType(const Event &ev) const {
|
||||
|
@ -150,7 +150,7 @@ private:
|
||||
|
||||
bool _joystickAxisPreviouslyPressed[6];
|
||||
|
||||
bool mapEvent(const Event &ev, Keymap::KeymapType keymapType, List<Event> &mappedEvents);
|
||||
Keymap::KeymapMatch getMappedActions(const Event &event, Keymap::ActionArray &actions, Keymap::KeymapType keymapType) const;
|
||||
Event executeAction(const Action *act, const Event &incomingEvent);
|
||||
EventType convertStartToEnd(EventType eventType);
|
||||
IncomingEventType convertToIncomingEventType(const Event &ev) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user