Merge pull request #10 from advisoray/master

Extended functionality + fix Alt key under Windows
pull/389/head
Gergely Nagy 7 years ago committed by GitHub
commit ec35d638d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -121,6 +121,38 @@ properties:
> >
> Defaults to 1000. > Defaults to 1000.
### `.enable()`
> This method enables the SpaceCadet plugin. This is useful for interfacing
> with other plugins or macros, especially where SpaceCadet functionality isn't
> always desired.
>
> The default behavior is `enabled`.
### `.disable()`
> This method disables the SpaceCadet behavior. This is useful for interfacing
> with other plugins or macros, especially where SpaceCadet functionality isn't
> always desired.
### `.active()`
> This method returns `true` if SpaceCadet is enabled and `false` if SpaceCadet
> is disabled. This is useful for interfacing with other plugins or macros,
> especially where SpaceCadet functionality isn't always desired.
### `Key_SpaceCadetEnable`
> This provides a key for placing on a keymap for enabling the SpaceCadet
> behavior. This is only triggered on initial downpress, and does not
> trigger again if held down or when the key is released.
### `Key_SpaceCadetDisable`
> This provides a key for placing on a keymap for disabling the SpaceCadet
> behavior. This is only triggered on initial downpress, and does not
> trigger again if held down or when the key is released.
## Further reading ## Further reading
Starting from the [example][plugin:example] is the recommended way of getting Starting from the [example][plugin:example] is the recommended way of getting

@ -22,7 +22,7 @@
const Key keymaps[][ROWS][COLS] PROGMEM = { const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED [0] = KEYMAP_STACKED
( (
Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_NoKey, Key_NoKey, Key_1, Key_2, Key_3, Key_4, Key_5, Key_SpaceCadetEnable,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab, Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G, Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape, Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
@ -30,7 +30,7 @@ const Key keymaps[][ROWS][COLS] PROGMEM = {
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift, Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
Key_skip, Key_skip,
Key_skip, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip, Key_SpaceCadetDisable, Key_6, Key_7, Key_8, Key_9, Key_0, Key_skip,
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals, Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote, Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus, Key_skip, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,

@ -37,6 +37,7 @@ SpaceCadet::KeyBinding::KeyBinding(Key input_, Key output_, uint16_t timeout_) {
//Space Cadet //Space Cadet
SpaceCadet::KeyBinding * SpaceCadet::map; SpaceCadet::KeyBinding * SpaceCadet::map;
uint16_t SpaceCadet::time_out = 1000; uint16_t SpaceCadet::time_out = 1000;
bool SpaceCadet::disabled = false;
//Empty Constructor //Empty Constructor
SpaceCadet::SpaceCadet() { SpaceCadet::SpaceCadet() {
@ -55,23 +56,61 @@ SpaceCadet::SpaceCadet() {
map = initialmap; map = initialmap;
} }
//Function to enable SpaceCadet behavior
void SpaceCadet::enable() {
disabled = false;
}
//Function to disable SpaceCadet behavior
void SpaceCadet::disable() {
disabled = true;
}
//Function to determine whether SpaceCadet is active (useful for Macros and other plugins)
bool SpaceCadet::active() {
return !disabled;
}
void SpaceCadet::begin() { void SpaceCadet::begin() {
Kaleidoscope.useEventHandlerHook(eventHandlerHook); Kaleidoscope.useEventHandlerHook(eventHandlerHook);
} }
Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key_state) { Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key_state) {
//Handle our synthetic keys for enabling and disabling functionality
if (mapped_key.flags == (SYNTHETIC | IS_INTERNAL | SPACECADET_TOGGLE)) {
//Only fire the activate / deactivate on the initial press (not held or release)
if (keyToggledOn(key_state)) {
if (mapped_key == Key_SpaceCadetEnable) {
enable();
} else if (mapped_key == Key_SpaceCadetDisable) {
disable();
}
}
//in any case, return NoKey (these don't do anything else)
return Key_NoKey;
}
// If nothing happened, bail out fast. //if SpaceCadet is disabled, this was an injected key, it was NoKey,
if (!keyIsPressed(key_state) && !keyWasPressed(key_state)) { //or if they key somehow came here without being either pressed or released,
//return the mapped key and just get out of here.
if (
disabled
|| (key_state & INJECTED)
|| mapped_key == Key_NoKey
|| (!keyIsPressed(key_state) && !keyWasPressed(key_state))
) {
return mapped_key; return mapped_key;
} }
// If a key has been just toggled on... // If a key has been just toggled on...
if (keyToggledOn(key_state)) { if (keyToggledOn(key_state)) {
//This will only set one key, and if it isn't in our map it clears everything //check to see if we found a valid key. Assume not valid.
//for the non-pressed key bool valid_key = false;
//Exit condition is if we reach the sentinal
//This will only set one key, and, if it isn't in our map, it clears everything for the non-pressed key
//Exit condition is if we reach the special SPACECADET_MAP_END sentinel
for ( for (
uint8_t i = 0 ; uint8_t i = 0 ;
!( !(
@ -83,28 +122,52 @@ Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key
) { ) {
if (mapped_key.raw == map[i].input.raw) { if (mapped_key.raw == map[i].input.raw) {
//The keypress was valid and a match. //The keypress was valid and a match. Mark it as flagged and reset the counter
map[i].flagged = true; map[i].flagged = true;
map[i].start_time = millis(); map[i].start_time = millis();
//yes, we found a valid key
valid_key = true;
} else { } else {
//The keypress wasn't a match. //If the key entry we're looking at was flagged previously, add it to the
//report before we do anything else (this handles the situation where we
//hit another key after this -- if it's a modifier, we want the modifier
//key to be added to the report, for things like ctrl, alt, shift, etc)
if (map[i].flagged) {
handleKeyswitchEvent(map[i].input, row, col, IS_PRESSED | INJECTED);
}
//The keypress wasn't a match, so we need to mark it as not flagged and
//reset the timer for it to disable everything.
map[i].flagged = false; map[i].flagged = false;
map[i].start_time = 0; map[i].start_time = 0;
} }
} }
//If we found a valid key in our map, we don't actually want to send anything.
//This gets around an issue in Windows if we map a SpaceCadet function on top
//of Alt -- sending Alt by itself activates the menubar. We don't want to send
//anything until we know that we're either sending the alternate key or we
//know for sure that we want to send the originally pressed key.
if (valid_key) {
return Key_NoKey;
}
//this is all we need to do on keypress, let the next handler do its thing too. //this is all we need to do on keypress, let the next handler do its thing too.
//This case assumes we weren't a valid key that we were watching, so we don't
//need to do anything else.
return mapped_key; return mapped_key;
} }
// if the state is empty, that means that either the shifts weren't pressed, // if the state is empty, that means that either an activating key wasn't pressed,
// or we used another key in the interim. in both cases, nothing special to do. // or we used another key in the interim. in both cases, nothing special to do.
bool valid_key = false; bool valid_key = false;
bool pressed_key_was_valid = false; bool pressed_key_was_valid = false;
uint8_t index = 0; uint8_t index = 0;
//Look to see if any keys in our map are flagged. //Look to see if any keys in our map are currently flagged.
//Exit condition is if we reach the sentinal //Exit condition is if we reach the special SPACECADET_MAP_END sentinel
for ( for (
uint8_t i = 0 ; uint8_t i = 0 ;
!( !(
@ -115,17 +178,20 @@ Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key
++i ++i
) { ) {
//The key we're looking at was previously flagged (so perform action)
if (map[i].flagged) { if (map[i].flagged) {
valid_key = true; valid_key = true;
index = i; index = i;
} }
//the key we're looking at was valid (in the map)
if (map[i].input.raw == mapped_key.raw) { if (map[i].input.raw == mapped_key.raw) {
pressed_key_was_valid = true; pressed_key_was_valid = true;
} }
} }
//If no valid mapped keys were pressed, simply return the key that
//If no valid mapped keys were pressed, simply return the keycode //was originally passed in.
if (!valid_key) { if (!valid_key) {
return mapped_key; return mapped_key;
} }
@ -137,18 +203,20 @@ Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key
current_timeout = time_out; current_timeout = time_out;
} }
//Check to determine if we have surpassed our timeout for holding this key
if ((millis() - map[index].start_time) >= current_timeout) { if ((millis() - map[index].start_time) >= current_timeout) {
// if we timed out, that means we need to keep pressing the mapped // if we timed out, that means we need to keep pressing the mapped
// key, but we won't need to send the alternative key in the end // key, but we won't need to send the alternative key in the end
map[index].flagged = false; map[index].flagged = false;
map[index].start_time = 0; map[index].start_time = 0;
//Just return this key itself (we won't run alternative keys check)
return mapped_key; return mapped_key;
} }
// If the key that was pressed isn't one of our mapped keys, just // If the key that was pressed isn't one of our mapped keys, just
// return. This can happen when another key is released, and that should not // return. This can happen when another key is released, and that should not
// interrupt us. // interrupt us.
if (!pressed_key_was_valid) { if (!pressed_key_was_valid) {
return mapped_key; return mapped_key;
} }
@ -159,10 +227,9 @@ Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key
Key alternate_key = map[index].output; Key alternate_key = map[index].output;
//Since we are sending the actual key (no need for shift, etc), //Since we are sending the actual key (no need for shift, etc),
//only need to send that key and not the original key. In fact, we //only need to send that key and not the original key.
//may want to even UNSET the originally pressed key (future
//enhanacement?). This might also mean we don't need to return the //inject our new key
//key that was pressed, though I haven't confirmed that.
handleKeyswitchEvent(alternate_key, row, col, IS_PRESSED | INJECTED); handleKeyswitchEvent(alternate_key, row, col, IS_PRESSED | INJECTED);
//Unflag the key so we don't try this again. //Unflag the key so we don't try this again.
@ -170,6 +237,15 @@ Key SpaceCadet::eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key
map[index].start_time = 0; map[index].start_time = 0;
} }
//Special case here for if we had a valid key that's continuing to be held.
//If it's a valid key, and it's continuing to be held, return NoKey.
//This prevents us from accidentally triggering a keypress that we didn't
//mean to handle.
if (valid_key) {
return Key_NoKey;
}
//Finally, as a final sanity check, simply return the passed-in key as-is.
return mapped_key; return mapped_key;
} }

@ -24,6 +24,12 @@
#define SPACECADET_MAP_END (kaleidoscope::SpaceCadet::KeyBinding) { Key_NoKey, Key_NoKey, 0 } #define SPACECADET_MAP_END (kaleidoscope::SpaceCadet::KeyBinding) { Key_NoKey, Key_NoKey, 0 }
#endif #endif
#ifndef SPACECADET_TOGGLE
#define SPACECADET_TOGGLE B00000011 // Synthetic, internal
#define Key_SpaceCadetEnable (Key) { 0, KEY_FLAGS | SYNTHETIC | IS_INTERNAL | SPACECADET_TOGGLE }
#define Key_SpaceCadetDisable (Key) { 1, KEY_FLAGS | SYNTHETIC | IS_INTERNAL | SPACECADET_TOGGLE }
#endif
namespace kaleidoscope { namespace kaleidoscope {
//Declaration for the method (implementing KaleidoscopePlugin) //Declaration for the method (implementing KaleidoscopePlugin)
class SpaceCadet : public KaleidoscopePlugin { class SpaceCadet : public KaleidoscopePlugin {
@ -55,6 +61,9 @@ class SpaceCadet : public KaleidoscopePlugin {
//Methods //Methods
void begin(void) final; void begin(void) final;
static void enable(void);
static void disable(void);
static bool active(void);
//Publically accessible variables //Publically accessible variables
static uint16_t time_out; // The global timeout in milliseconds static uint16_t time_out; // The global timeout in milliseconds
@ -62,6 +71,7 @@ class SpaceCadet : public KaleidoscopePlugin {
private: private:
static Key eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key_state); static Key eventHandlerHook(Key mapped_key, byte row, byte col, uint8_t key_state);
static bool disabled;
}; };
}; };

Loading…
Cancel
Save