KEYMAPPER: Enable remapping the keyboard modifier keys

This commit is contained in:
Bastien Bouclet 2020-02-13 07:25:01 +01:00
parent 73bc139811
commit 29dd15af0c
5 changed files with 74 additions and 10 deletions

View File

@ -205,6 +205,19 @@ const KeyTableEntry defaultKeys[] = {
{"AUDIOREWIND", KEYCODE_AUDIOREWIND, "Audio Rewind"},
{"AUDIOFASTFORWARD", KEYCODE_AUDIOFASTFORWARD, "Audio Fast-Forward"},
// Modifier keys
{"SCROLLOCK", KEYCODE_SCROLLOCK, "Scroll Lock" },
{"CAPSLOCK", KEYCODE_CAPSLOCK, "Caps Lock" },
{"NUMLOCK", KEYCODE_NUMLOCK, "Num Lock" },
{"LSHIFT", KEYCODE_LSHIFT, "Left Shift" },
{"RSHIFT", KEYCODE_RSHIFT, "Right Shift" },
{"LALT", KEYCODE_LALT, "Left Alt" },
{"RALT", KEYCODE_RALT, "Right Alt" },
{"LCTRL", KEYCODE_LCTRL, "Left Control" },
{"RCTRL", KEYCODE_RCTRL, "Right Control" },
{"LMETA", KEYCODE_LMETA, "Left Meta" },
{"RMETA", KEYCODE_RMETA, "Right Meta" },
{0, KEYCODE_INVALID, 0}
};
@ -314,9 +327,11 @@ HardwareInput KeyboardHardwareInputSet::findHardwareInput(const Event &event) co
switch (event.type) {
case EVENT_KEYDOWN:
case EVENT_KEYUP: {
KeyState normalizedKeystate = normalizeKeyState(event.kbd);
const KeyTableEntry *key = nullptr;
for (key = _keys; key->hwId; key++) {
if (event.kbd.keycode == key->keycode) {
if (normalizedKeystate.keycode == key->keycode) {
break;
}
}
@ -330,7 +345,7 @@ HardwareInput KeyboardHardwareInputSet::findHardwareInput(const Event &event) co
byte modifierFlags = 0;
for (const ModifierTableEntry *modifier = _modifiers; modifier->id; modifier++) {
if (event.kbd.flags & modifier->flag) {
if (normalizedKeystate.flags & modifier->flag) {
id += modifier->id;
id += "+";
fullKeyDesc += modifier->desc;
@ -346,6 +361,50 @@ HardwareInput KeyboardHardwareInputSet::findHardwareInput(const Event &event) co
}
}
KeyState KeyboardHardwareInputSet::normalizeKeyState(const KeyState &keystate) {
KeyState normalizedKeystate = keystate;
// We ignore the sticky modifiers as they traditionally
// have no impact on the outcome of key presses.
// TODO: Maybe Num Lock should act as a modifier for the keypad.
normalizedKeystate.flags &= ~KBD_STICKY;
// Modifier keypresses ignore the corresponding modifier flag.
// That way, for example, `Left Shift` is not identified
// as `Shift+Left Shift` by the keymapper.
switch (normalizedKeystate.keycode) {
case KEYCODE_LSHIFT:
case KEYCODE_RSHIFT:
normalizedKeystate.flags &= ~KBD_SHIFT;
break;
case KEYCODE_LCTRL:
case KEYCODE_RCTRL:
normalizedKeystate.flags &= ~KBD_CTRL;
break;
case KEYCODE_LALT:
case KEYCODE_RALT:
normalizedKeystate.flags &= ~KBD_ALT;
break;
case KEYCODE_LMETA:
case KEYCODE_RMETA:
normalizedKeystate.flags &= ~KBD_META;
break;
case KEYCODE_SCROLLOCK:
normalizedKeystate.flags &= ~KBD_SCRL;
break;
case KEYCODE_CAPSLOCK:
normalizedKeystate.flags &= ~KBD_CAPS;
break;
case KEYCODE_NUMLOCK:
normalizedKeystate.flags &= ~KBD_NUM;
break;
default:
break;
}
return normalizedKeystate;
}
MouseHardwareInputSet::MouseHardwareInputSet(const HardwareInputTableEntry *buttonEntries) :
_buttonEntries(buttonEntries) {
assert(_buttonEntries);

View File

@ -234,6 +234,9 @@ public:
HardwareInput findHardwareInput(const String &id) const override;
HardwareInput findHardwareInput(const Event &event) const override;
/** Transform a keystate into a canonical form that can be used to unambiguously identify the keypress */
static KeyState normalizeKeyState(const KeyState &keystate);
private:
const KeyTableEntry *_keys;
const ModifierTableEntry *_modifiers;

View File

@ -128,7 +128,8 @@ Keymap::ActionArray Keymap::getMappedActions(const Event &event) const {
switch (event.type) {
case EVENT_KEYDOWN:
case EVENT_KEYUP: {
HardwareInput hardwareInput = HardwareInput::createKeyboard("", event.kbd, "");
KeyState normalizedKeystate = KeyboardHardwareInputSet::normalizeKeyState(event.kbd);
HardwareInput hardwareInput = HardwareInput::createKeyboard("", normalizedKeystate, "");
return _hwActionMap[hardwareInput];
}
case EVENT_LBUTTONDOWN:

View File

@ -44,20 +44,21 @@ struct HardwareInput;
class HardwareInputSet;
class KeymapperDefaultBindings;
struct Event_EqualTo {
struct HardwareInput_EqualTo {
bool operator()(const HardwareInput& x, const HardwareInput& y) const {
return (x.type == y.type)
&& (x.key == y.key) // TODO: Remove the equality operator from KeyState
&& (x.key.keycode == y.key.keycode)
&& (x.key.flags == y.key.flags)
&& (x.inputCode == y.inputCode);
}
};
struct Event_Hash {
struct HardwareInput_Hash {
uint operator()(const HardwareInput& x) const {
uint hash = 7;
hash = 31 * hash + x.type;
hash = 31 * hash + x.key.keycode;
hash = 31 * hash + (x.key.flags & ~KBD_STICKY);
hash = 31 * hash + x.key.flags;
hash = 31 * hash + x.inputCode;
return hash;
}
@ -169,7 +170,7 @@ private:
void registerMappings(Action *action, const StringArray &hwInputIds);
bool areMappingsIdentical(const Array<HardwareInput> &inputs, const StringArray &mapping);
typedef HashMap<HardwareInput, ActionArray, Event_Hash, Event_EqualTo> HardwareActionMap;
typedef HashMap<HardwareInput, ActionArray, HardwareInput_Hash, HardwareInput_EqualTo> HardwareActionMap;
KeymapType _type;
String _id;

View File

@ -346,8 +346,8 @@ struct KeyState {
/**
* Check if two key states are equal. This implementation ignores the state
* of the sticky flags (caps lock, num lock, scroll lock) completely. This
* functionality is currently only used by the keymapper.
* of the sticky flags (caps lock, num lock, scroll lock) completely.
* @todo is this still being used?
*/
bool operator==(const KeyState &x) const {
// Intentionally ignore ASCII, as the keycode and non-sticky flag