|
|
|
#include "key_events.h"
|
|
|
|
|
|
|
|
static void handle_keymap_key_event(Key keymapEntry, uint8_t keyState) {
|
|
|
|
if (keymapEntry.flags & SWITCH_TO_KEYMAP_MOMENTARY ) {
|
|
|
|
if (key_toggled_on(keyState)) {
|
|
|
|
if ( keymapEntry.rawKey == KEYMAP_NEXT) {
|
|
|
|
temporary_keymap++;
|
|
|
|
} else if ( keymapEntry.rawKey == KEYMAP_PREVIOUS) {
|
|
|
|
temporary_keymap--;
|
|
|
|
} else {
|
|
|
|
temporary_keymap = keymapEntry.rawKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (key_toggled_off(keyState)) {
|
|
|
|
temporary_keymap = primary_keymap;
|
|
|
|
}
|
|
|
|
|
|
|
|
// switch keymap and stay there
|
|
|
|
} else if (key_toggled_on(keyState)) {
|
|
|
|
temporary_keymap = primary_keymap = keymapEntry.rawKey;
|
|
|
|
Storage.save_primary_keymap(primary_keymap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool handle_synthetic_key_event(Key mappedKey, uint8_t keyState) {
|
|
|
|
if (mappedKey.flags & RESERVED)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(mappedKey.flags & SYNTHETIC))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!key_toggled_on(keyState))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (mappedKey.flags & IS_INTERNAL) {
|
|
|
|
if (mappedKey.flags & LED_TOGGLE) {
|
|
|
|
LEDControl.next_mode();
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (mappedKey.flags & IS_CONSUMER) {
|
|
|
|
ConsumerControl.press(mappedKey.rawKey);
|
|
|
|
} else if (mappedKey.flags & IS_SYSCTL) {
|
|
|
|
SystemControl.press(mappedKey.rawKey);
|
|
|
|
} else if (mappedKey.flags & SWITCH_TO_KEYMAP ||
|
|
|
|
mappedKey.flags & SWITCH_TO_KEYMAP_MOMENTARY) {
|
|
|
|
// Should not happen, handled elsewhere.
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
key_events: A way to hook into the event handling
This adds a new `handle_user_key_event` function, that will get called
before anything else, and can override what happens. If it returns true,
the event will not be processed further by the firmware. By default,
this function returns false, and is a no-op.
It is defined with a `weak` attribute, to let the linker know that any
other function with the same name should override his one. This makes it
possible to have another version of this function in a firmware Sketch,
and override the behaviour, to extend the event handling.
This is the foundation that allows it to use external libraries, and tap
into the firmware's event handler, to add new stuff. (We can already
hook into the main loop by changing the top `loop` function in the
Sketch)
This addresses #21 for the most part.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
|
hooks: Add a way to replace hooks
To make replacing work sanely, we first NULL out both the eventHandlers
and loopHooks arrays in the Keyboardio_ constructor. This allows the
replace functions to just run through the whole array, and either see
hook pointers there, or NULL. So they don't need to be afraid of garbage
being there.
This makes the replacing very easy: run through the array, and replace
the first occurrence of the old hook with the new. This further
simplifies addition: the old hook we pass in, will be NULL. If we run
out of space, it silently fails, like before.
Replacing hooks is important for cases where one wants to build features
that can be toggled off, or their behaviour otherwise changed at
run-time. In this case, the most efficent way is to replace the hook,
which is what these new helpers allow us to do.
This closes #36.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
custom_handler_t eventHandlers[HOOK_MAX];
|
|
|
|
|
|
|
|
Key lookup_key(byte keymap, byte row, byte col) {
|
|
|
|
Key mappedKey;
|
|
|
|
|
|
|
|
mappedKey.raw = pgm_read_word(&(keymaps[keymap][row][col]));
|
|
|
|
|
|
|
|
return mappedKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool handle_key_event_default(Key mappedKey, byte row, byte col, uint8_t keyState) {
|
|
|
|
//for every newly pressed button, figure out what logical key it is and send a key down event
|
|
|
|
// for every newly released button, figure out what logical key it is and send a key up event
|
|
|
|
|
key_events: look up mappedKey earlier
Do the mappedKey lookup earlier, in handle_key_event, so that if any of
our handlers need to look at the mapped key, they do not have to look it
up themselves. This simplifies plugged hooks considerably, as they can
always assume that the mapped key they receive is correct. They still
receive enough information to do the lookup themselves, though, if they
ever need that.
Additionally, in handle_key_event_default, baseKey is only looked up if
mappedKey was NoKey. This is so that hooks can defer to this function,
via handle_key_event, setting their own mappedKey, without having to
worry about setting a row/col that would map to a special key on the
base layer.
Fixes #39.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
Key baseKey = Key_NoKey;
|
|
|
|
if (!(keyState & INJECTED)) {
|
key_events: look up mappedKey earlier
Do the mappedKey lookup earlier, in handle_key_event, so that if any of
our handlers need to look at the mapped key, they do not have to look it
up themselves. This simplifies plugged hooks considerably, as they can
always assume that the mapped key they receive is correct. They still
receive enough information to do the lookup themselves, though, if they
ever need that.
Additionally, in handle_key_event_default, baseKey is only looked up if
mappedKey was NoKey. This is so that hooks can defer to this function,
via handle_key_event, setting their own mappedKey, without having to
worry about setting a row/col that would map to a special key on the
base layer.
Fixes #39.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
baseKey = lookup_key(primary_keymap, row, col);
|
A way to restart the event handler with a different code
There are scenarios where one would want to inject a keycode into the
event handler chain, restart the processing from scratch, but with a
keycode different than what the lookup would normally yield. For
example, with one-shot modifiers, a feature one may wish is to be able
to turn the one-shotness off, and have them act as normal modifiers.
This is easily done, if we can remove the one-shot markup, and let the
event handler process the resulting code as-is.
This makes that possible: in a custom event handler, just call
handle_key_event() with the first argument set to the desired code, and
the rest left unchanged. This makes it possible to inject events: not
just register keycodes with the HID, but inject synthetic events,
something much more powerful.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
}
|
|
|
|
|
|
|
|
if ((baseKey.flags & SWITCH_TO_KEYMAP
|
|
|
|
|| baseKey.flags & SWITCH_TO_KEYMAP_MOMENTARY)) {
|
|
|
|
handle_keymap_key_event(baseKey, keyState);
|
|
|
|
} else if (mappedKey.flags & SYNTHETIC) {
|
|
|
|
handle_synthetic_key_event( mappedKey, keyState);
|
|
|
|
} else if (key_is_pressed(keyState)) {
|
|
|
|
press_key(mappedKey);
|
|
|
|
} else if (key_toggled_off(keyState) && (keyState & INJECTED)) {
|
|
|
|
release_key(mappedKey);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void press_key(Key mappedKey) {
|
|
|
|
if (mappedKey.flags & SHIFT_HELD) {
|
|
|
|
Keyboard.press(Key_LShift.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & CTRL_HELD) {
|
|
|
|
Keyboard.press(Key_LCtrl.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & LALT_HELD) {
|
|
|
|
Keyboard.press(Key_LAlt.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & RALT_HELD) {
|
|
|
|
Keyboard.press(Key_RAlt.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & GUI_HELD) {
|
|
|
|
Keyboard.press(Key_LGUI.rawKey);
|
|
|
|
}
|
|
|
|
Keyboard.press(mappedKey.rawKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void release_key(Key mappedKey) {
|
|
|
|
if (mappedKey.flags & SHIFT_HELD) {
|
|
|
|
Keyboard.release(Key_LShift.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & CTRL_HELD) {
|
|
|
|
Keyboard.release(Key_LCtrl.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & LALT_HELD) {
|
|
|
|
Keyboard.release(Key_LAlt.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & RALT_HELD) {
|
|
|
|
Keyboard.release(Key_RAlt.rawKey);
|
|
|
|
}
|
|
|
|
if (mappedKey.flags & GUI_HELD) {
|
|
|
|
Keyboard.release(Key_LGUI.rawKey);
|
|
|
|
}
|
|
|
|
Keyboard.release(mappedKey.rawKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handle_key_event(Key mappedKey, byte row, byte col, uint8_t keyState) {
|
|
|
|
if (!(keyState & INJECTED)) {
|
|
|
|
mappedKey = lookup_key(temporary_keymap, row, col);
|
|
|
|
}
|
|
|
|
for (byte i = 0; eventHandlers[i] != NULL && i < HOOK_MAX; i++) {
|
|
|
|
custom_handler_t handler = eventHandlers[i];
|
|
|
|
if ((*handler)(mappedKey, row, col, keyState))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
handle_key_event_default(mappedKey, row, col, keyState);
|
|
|
|
}
|