Macros: Add a way to have more control over when reports are sent

Sometimes we'd like to be in control of when reports are sent during macro
playback. This implements a way to achieve that.

Fixes #368.

Signed-off-by: Gergely Nagy <algernon@keyboard.io>
pull/466/head
Gergely Nagy 6 years ago
parent 6d41c79a5b
commit 41abaaff3e
No known key found for this signature in database
GPG Key ID: AC1E90BAC433F68F

@ -75,6 +75,10 @@ In certain cases we need to delay the unicode input sequence, otherwise the host
The [Cycle](doc/plugin/Cycle.md) plugin has much better support for cycling through keys with modifiers applied to them, such as `LSHIFT(Key_A)`. Please see the documentation and the updated example for more information. The [Cycle](doc/plugin/Cycle.md) plugin has much better support for cycling through keys with modifiers applied to them, such as `LSHIFT(Key_A)`. Please see the documentation and the updated example for more information.
### More control over when to send reports during Macro playback
There are situations where one would like to disable sending a report after each and every step of a macro, and rather have direct control over when reports are sent. The new `WITH_EXPLICIT_REPORT`, `WITH_IMPLICIT_REPORT` and `SEND_REPORT` steps help with that. Please see the [Macros](doc/plugin/Macros.md) documentation for more information.
## New hardware support ## New hardware support
Kaleidoscope has been ported to the following devices: Kaleidoscope has been ported to the following devices:

@ -142,7 +142,7 @@ need to define them in a special way, using the `MACRO` helper (or its
## `MACRO` steps ## `MACRO` steps
Macro steps can be divided into two groups: Macro steps can be divided into the following groups:
### Delays ### Delays
@ -171,6 +171,23 @@ not supported by this compact representation.
* `U(key)`, `Ur(key)`, `Uc(key)`: Simulates a key being released (going up). * `U(key)`, `Ur(key)`, `Uc(key)`: Simulates a key being released (going up).
* `T(key)`, `Tr(key)`, `Tc(key)`: Simulates a key being tapped (pressed first, then released). * `T(key)`, `Tr(key)`, `Tc(key)`: Simulates a key being tapped (pressed first, then released).
### Controlling when to send reports
While the plugin will - by default - send a report after every step, that is not
always desirable. For this reason, we allow turning this implicit reporting off,
and switching to explicit reporting instead. Note that the tap steps (`T()`,
`Tr()`, and `Tc()`) will always send an implicit report, and so will
`Macros.type()`.
To control when to send reports, the following steps can be used:
* `WITH_EXPLICIT_REPORT`: Prevents the plugin from sending an implicit report
after every step. To send a report, one needs to have a `SEND_REPORT` step
too.
* `WITH_IMPLICIT_REPORT`: Enables sending an implicit report after every step
(the default).
* `SEND_REPORT`: Send a report.
## Overrideable methods ## Overrideable methods
### `macroAction(macroIndex, keyState)` ### `macroAction(macroIndex, keyState)`

@ -29,23 +29,26 @@ MacroKeyEvent Macros_::active_macros[];
byte Macros_::active_macro_count; byte Macros_::active_macro_count;
byte Macros_::row, Macros_::col; byte Macros_::row, Macros_::col;
void playMacroKeyswitchEvent(Key key, uint8_t keyswitch_state) { void playMacroKeyswitchEvent(Key key, uint8_t keyswitch_state, bool explicit_report) {
handleKeyswitchEvent(key, UNKNOWN_KEYSWITCH_LOCATION, keyswitch_state | INJECTED); handleKeyswitchEvent(key, UNKNOWN_KEYSWITCH_LOCATION, keyswitch_state | INJECTED);
if (explicit_report)
return;
kaleidoscope::hid::sendKeyboardReport(); kaleidoscope::hid::sendKeyboardReport();
kaleidoscope::hid::sendMouseReport(); kaleidoscope::hid::sendMouseReport();
} }
static void readKeyCodeAndPlay(const macro_t *macro_p, uint8_t flags, uint8_t keyStates) { static void readKeyCodeAndPlay(const macro_t *macro_p, uint8_t flags, uint8_t keyStates, bool explicit_report) {
Key key; Key key;
key.flags = flags; key.flags = flags;
key.keyCode = pgm_read_byte(macro_p++); key.keyCode = pgm_read_byte(macro_p++);
if (keyIsPressed(keyStates)) { if (keyIsPressed(keyStates)) {
playMacroKeyswitchEvent(key, IS_PRESSED); playMacroKeyswitchEvent(key, IS_PRESSED, explicit_report);
} }
if (keyWasPressed(keyStates)) { if (keyWasPressed(keyStates)) {
playMacroKeyswitchEvent(key, WAS_PRESSED); playMacroKeyswitchEvent(key, WAS_PRESSED, explicit_report);
} }
} }
@ -53,12 +56,23 @@ void Macros_::play(const macro_t *macro_p) {
macro_t macro = MACRO_ACTION_END; macro_t macro = MACRO_ACTION_END;
uint8_t interval = 0; uint8_t interval = 0;
uint8_t flags; uint8_t flags;
bool explicit_report = false;
if (!macro_p) if (!macro_p)
return; return;
while (true) { while (true) {
switch (macro = pgm_read_byte(macro_p++)) { switch (macro = pgm_read_byte(macro_p++)) {
case MACRO_ACTION_STEP_EXPLICIT_REPORT:
explicit_report = true;
break;
case MACRO_ACTION_STEP_IMPLICIT_REPORT:
explicit_report = false;
break;
case MACRO_ACTION_STEP_SEND_REPORT:
kaleidoscope::hid::sendKeyboardReport();
kaleidoscope::hid::sendMouseReport();
break;
case MACRO_ACTION_STEP_INTERVAL: case MACRO_ACTION_STEP_INTERVAL:
interval = pgm_read_byte(macro_p++); interval = pgm_read_byte(macro_p++);
break; break;
@ -69,25 +83,25 @@ void Macros_::play(const macro_t *macro_p) {
} }
case MACRO_ACTION_STEP_KEYDOWN: case MACRO_ACTION_STEP_KEYDOWN:
flags = pgm_read_byte(macro_p++); flags = pgm_read_byte(macro_p++);
readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED); readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED, explicit_report);
break; break;
case MACRO_ACTION_STEP_KEYUP: case MACRO_ACTION_STEP_KEYUP:
flags = pgm_read_byte(macro_p++); flags = pgm_read_byte(macro_p++);
readKeyCodeAndPlay(macro_p++, flags, WAS_PRESSED); readKeyCodeAndPlay(macro_p++, flags, WAS_PRESSED, explicit_report);
break; break;
case MACRO_ACTION_STEP_TAP: case MACRO_ACTION_STEP_TAP:
flags = pgm_read_byte(macro_p++); flags = pgm_read_byte(macro_p++);
readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED | WAS_PRESSED); readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED | WAS_PRESSED, false);
break; break;
case MACRO_ACTION_STEP_KEYCODEDOWN: case MACRO_ACTION_STEP_KEYCODEDOWN:
readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED); readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED, explicit_report);
break; break;
case MACRO_ACTION_STEP_KEYCODEUP: case MACRO_ACTION_STEP_KEYCODEUP:
readKeyCodeAndPlay(macro_p++, 0, WAS_PRESSED); readKeyCodeAndPlay(macro_p++, 0, WAS_PRESSED, explicit_report);
break; break;
case MACRO_ACTION_STEP_TAPCODE: case MACRO_ACTION_STEP_TAPCODE:
readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED | WAS_PRESSED); readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED | WAS_PRESSED, false);
break; break;
case MACRO_ACTION_END: case MACRO_ACTION_END:
@ -197,8 +211,8 @@ const macro_t *Macros_::type(const char *string) {
if (key.raw == Key_NoKey.raw) if (key.raw == Key_NoKey.raw)
continue; continue;
playMacroKeyswitchEvent(key, IS_PRESSED); playMacroKeyswitchEvent(key, IS_PRESSED, false);
playMacroKeyswitchEvent(key, WAS_PRESSED); playMacroKeyswitchEvent(key, WAS_PRESSED, false);
} }

@ -29,6 +29,10 @@ typedef enum {
MACRO_ACTION_STEP_KEYCODEDOWN, MACRO_ACTION_STEP_KEYCODEDOWN,
MACRO_ACTION_STEP_KEYCODEUP, MACRO_ACTION_STEP_KEYCODEUP,
MACRO_ACTION_STEP_TAPCODE, MACRO_ACTION_STEP_TAPCODE,
MACRO_ACTION_STEP_EXPLICIT_REPORT,
MACRO_ACTION_STEP_IMPLICIT_REPORT,
MACRO_ACTION_STEP_SEND_REPORT,
} MacroActionStepType; } MacroActionStepType;
typedef uint8_t macro_t; typedef uint8_t macro_t;
@ -51,4 +55,8 @@ typedef uint8_t macro_t;
#define Uc(k) MACRO_ACTION_STEP_KEYCODEUP, (Key_ ## k).keyCode #define Uc(k) MACRO_ACTION_STEP_KEYCODEUP, (Key_ ## k).keyCode
#define Tc(k) MACRO_ACTION_STEP_TAPCODE, (Key_ ## k).keyCode #define Tc(k) MACRO_ACTION_STEP_TAPCODE, (Key_ ## k).keyCode
#define WITH_EXPLICIT_REPORT MACRO_ACTION_STEP_EXPLICIT_REPORT
#define WITH_IMPLICIT_REPORT MACRO_ACTION_STEP_IMPLICIT_REPORT
#define SEND_REPORT MACRO_ACTION_STEP_SEND_REPORT
__attribute__((deprecated("END is no longer required to end macros"))) const MacroActionStepType END = MACRO_ACTION_END; __attribute__((deprecated("END is no longer required to end macros"))) const MacroActionStepType END = MACRO_ACTION_END;

Loading…
Cancel
Save