Fix up to work better with timers

Also introduces an explicit `pressTime` and `delay`.

Fixes #1.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
pull/389/head
Gergely Nagy 8 years ago
parent ff2ef71db1
commit 128d0f4bda

@ -12,14 +12,16 @@ plugin allows one to inject events at various delays, by telling it which keys
to press. Unlike macros, these press keys at given positions, as if they were
pressed by someone typing on it - the firmware will not see the difference.
Given a sequence (with delays), the plugin will walk through it once activated,
and hold the key for about a third of the delay amount, then release it.
Given a sequence (with press- and delay times), the plugin will walk through it
once activated, and hold the key for the specified amount, release it, and move
on to the next after the delay time.
## Using the plugin
To use the plugin, one needs to include the header, and configure it with a list
of key coordinates and a delay triplet. One also needs a way to trigger starting
the sequence, and a macro is the most convenient way for that.
of key coordinates, a press time, and a delay time quartett. One also needs a
way to trigger starting the sequence, and a macro is the most convenient way for
that.
```c++
#include <Akela-GhostInTheFirmware.h>
@ -33,7 +35,7 @@ const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
}
static const Akela::GhostInTheFirmware::GhostKey ghostKeys[] PROGMEM = {
{0, 0, 10},
{0, 0, 200, 50},
{0, 0, 0}
};
@ -55,9 +57,13 @@ method:
### `.configure(sequence)`
> Set the sequence of keys to press. Each element is a triplet of `row`,
> `column`, and a `delay`. Each of these will be pressed in different cycles,
> unlike macros which play back within a single cycle.
> Set the sequence of keys to press. Each element is a quartett of `row`,
> `column`, a `pressTime`, and a `delay`. Each of these will be pressed in
> different cycles, unlike macros which play back within a single cycle.
>
> The key at `row`, `column` will be held for `pressTime` milliseconds, and
> after an additional `delay` milliseconds, the plugin will move on to the next
> entry in the sequence.
>
> The sequence *MUST* reside in `PROGMEM`.

@ -24,24 +24,28 @@
const Key keymaps[][ROWS][COLS] PROGMEM = {
[0] = KEYMAP_STACKED
(
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, M(0),
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
___, ___, ___, ___, ___, ___, M(0),
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey,
___, ___, ___, ___,
___,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
Key_NoKey, Key_NoKey, Key_NoKey, Key_NoKey,
Key_NoKey
___, ___, ___, ___,
___
),
};
static Key eventDropper (Key mappedKey, byte row, byte col, uint8_t keyState) {
return Key_NoKey;
}
const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
if (macroIndex == 0 && key_toggled_on (keyState))
GhostInTheFirmware.activate ();
@ -50,75 +54,77 @@ const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
}
static const Akela::GhostInTheFirmware::GhostKey ghostKeys[] PROGMEM = {
{0, 6, 5},
{0, 5, 5},
{0, 4, 5},
{0, 3, 5},
{0, 2, 5},
{0, 1, 5},
{0, 0, 5},
{1, 0, 5},
{1, 1, 5},
{1, 2, 5},
{1, 3, 5},
{1, 4, 5},
{1, 5, 5},
{1, 6, 5},
{2, 6, 5},
{2, 5, 5},
{2, 4, 5},
{2, 3, 5},
{2, 2, 5},
{2, 1, 5},
{2, 0, 5},
{3, 0, 5},
{3, 1, 5},
{3, 3, 5},
{3, 4, 5},
{3, 5, 5},
{0, 7, 5},
{1, 7, 5},
{2, 7, 5},
{3, 7, 5},
{3, 6, 5},
{3, 9, 5},
{3, 8, 5},
{2, 8, 5},
{1, 8, 5},
{0, 8, 5},
{3, 10, 5},
{3, 11, 5},
{3, 12, 5},
{3, 13, 5},
{3, 14, 5},
{3, 15, 5},
{2, 15, 5},
{2, 14, 5},
{2, 13, 5},
{2, 12, 5},
{2, 11, 5},
{2, 10, 5},
{2, 9, 5},
{1, 9, 5},
{1, 10, 5},
{1, 11, 5},
{1, 12, 5},
{1, 13, 5},
{1, 14, 5},
{1, 15, 5},
{0, 15, 5},
{0, 14, 5},
{0, 13, 5},
{0, 12, 5},
{0, 11, 5},
{0, 10, 5},
{0, 9, 5},
{0, 0, 0}
{0, 6, 200, 50},
{0, 5, 200, 50},
{0, 4, 200, 50},
{0, 3, 200, 50},
{0, 2, 200, 50},
{0, 1, 200, 50},
{0, 0, 200, 50},
{1, 0, 200, 50},
{1, 1, 200, 50},
{1, 2, 200, 50},
{1, 3, 200, 50},
{1, 4, 200, 50},
{1, 5, 200, 50},
{1, 6, 200, 50},
{2, 6, 200, 50},
{2, 5, 200, 50},
{2, 4, 200, 50},
{2, 3, 200, 50},
{2, 2, 200, 50},
{2, 1, 200, 50},
{2, 0, 200, 50},
{3, 0, 200, 50},
{3, 1, 200, 50},
{3, 3, 200, 50},
{3, 4, 200, 50},
{3, 5, 200, 50},
{0, 7, 200, 50},
{1, 7, 200, 50},
{2, 7, 200, 50},
{3, 7, 200, 50},
{3, 6, 200, 50},
{3, 9, 200, 50},
{3, 8, 200, 50},
{2, 8, 200, 50},
{1, 8, 200, 50},
{0, 8, 200, 50},
{3, 10, 200, 50},
{3, 11, 200, 50},
{3, 12, 200, 50},
{3, 13, 200, 50},
{3, 14, 200, 50},
{3, 15, 200, 50},
{2, 15, 200, 50},
{2, 14, 200, 50},
{2, 13, 200, 50},
{2, 12, 200, 50},
{2, 11, 200, 50},
{2, 10, 200, 50},
{2, 9, 200, 50},
{1, 9, 200, 50},
{1, 10, 200, 50},
{1, 11, 200, 50},
{1, 12, 200, 50},
{1, 13, 200, 50},
{1, 14, 200, 50},
{1, 15, 200, 50},
{0, 15, 200, 50},
{0, 14, 200, 50},
{0, 13, 200, 50},
{0, 12, 200, 50},
{0, 11, 200, 50},
{0, 10, 200, 50},
{0, 9, 200, 50},
{0, 0, 0, 0}
};
void setup () {
Serial.begin (9600);
Keyboardio.setup (KEYMAP_SIZE);
GhostInTheFirmware.configure (ghostKeys);
@ -126,7 +132,7 @@ void setup () {
Keyboardio.use (&LEDControl, &GhostInTheFirmware, &StalkerEffect, &Macros,
NULL);
event_handler_hook_use (eventDropper);
}
void loop () {

@ -21,9 +21,11 @@
namespace Akela {
GhostInTheFirmware::GhostKey *GhostInTheFirmware::ghostKeys;
bool GhostInTheFirmware::isActive;
bool GhostInTheFirmware::isPressed;
uint16_t GhostInTheFirmware::currentPos;
uint32_t GhostInTheFirmware::startTime;
uint16_t GhostInTheFirmware::timeOut;
uint16_t GhostInTheFirmware::pressTimeOut;
uint16_t GhostInTheFirmware::delayTimeOut;
GhostInTheFirmware::GhostInTheFirmware (void) {
}
@ -48,32 +50,35 @@ namespace Akela {
if (postClear || !isActive)
return;
if (timeOut == 0) {
timeOut = pgm_read_word (&(ghostKeys[currentPos].delay));
if (pressTimeOut == 0) {
pressTimeOut = pgm_read_word (&(ghostKeys[currentPos].pressTime));
delayTimeOut = pgm_read_word (&(ghostKeys[currentPos].delay));
if (timeOut == 0) {
if (pressTimeOut == 0) {
currentPos = 0;
isActive = false;
return;
}
} else if ((millis () - startTime) == timeOut / 3) {
byte row = pgm_read_byte (&(ghostKeys[currentPos].row));
byte col = pgm_read_byte (&(ghostKeys[currentPos].col));
handle_key_event (Key_NoKey, row, col, WAS_PRESSED);
}
isPressed = true;
startTime = millis ();
} else {
if (isPressed && ((millis () - startTime) > pressTimeOut)) {
isPressed = false;
startTime = millis ();
if ((millis () - startTime) < timeOut / 3) {
byte row = pgm_read_byte (&(ghostKeys[currentPos].row));
byte col = pgm_read_byte (&(ghostKeys[currentPos].col));
byte row = pgm_read_byte (&(ghostKeys[currentPos].row));
byte col = pgm_read_byte (&(ghostKeys[currentPos].col));
handle_key_event (Key_NoKey, row, col, IS_PRESSED);
}
handle_key_event (Key_NoKey, row, col, WAS_PRESSED);
} else if (isPressed) {
byte row = pgm_read_byte (&(ghostKeys[currentPos].row));
byte col = pgm_read_byte (&(ghostKeys[currentPos].col));
if ((millis () - startTime) > timeOut) {
currentPos++;
timeOut = 0;
startTime = millis ();
handle_key_event (Key_NoKey, row, col, IS_PRESSED);
} else if ((millis () - startTime) > delayTimeOut) {
currentPos++;
pressTimeOut = 0;
}
}
}

@ -26,6 +26,7 @@ namespace Akela {
typedef struct {
byte row;
byte col;
uint16_t pressTime;
uint16_t delay;
} GhostKey;
@ -38,9 +39,11 @@ namespace Akela {
private:
static GhostKey *ghostKeys;
static bool isActive;
static bool isPressed;
static uint16_t currentPos;
static uint32_t startTime;
static uint16_t timeOut;
static uint16_t pressTimeOut;
static uint16_t delayTimeOut;
static void loopHook (bool postClear);
};

Loading…
Cancel
Save