From 41abaaff3ede53c49b405e50e5ec3a0d7bfda289 Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sat, 17 Nov 2018 12:45:53 +0100 Subject: [PATCH] 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 --- NEWS.md | 4 +++ doc/plugin/Macros.md | 19 ++++++++++- src/kaleidoscope/plugin/Macros.cpp | 38 ++++++++++++++------- src/kaleidoscope/plugin/Macros/MacroSteps.h | 8 +++++ 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/NEWS.md b/NEWS.md index 683e6426..6c90cd11 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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. +### 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 Kaleidoscope has been ported to the following devices: diff --git a/doc/plugin/Macros.md b/doc/plugin/Macros.md index 0fdd07b3..79c79ead 100644 --- a/doc/plugin/Macros.md +++ b/doc/plugin/Macros.md @@ -142,7 +142,7 @@ need to define them in a special way, using the `MACRO` helper (or its ## `MACRO` steps -Macro steps can be divided into two groups: +Macro steps can be divided into the following groups: ### Delays @@ -171,6 +171,23 @@ not supported by this compact representation. * `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). +### 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 ### `macroAction(macroIndex, keyState)` diff --git a/src/kaleidoscope/plugin/Macros.cpp b/src/kaleidoscope/plugin/Macros.cpp index de67e540..52b398cc 100644 --- a/src/kaleidoscope/plugin/Macros.cpp +++ b/src/kaleidoscope/plugin/Macros.cpp @@ -29,23 +29,26 @@ MacroKeyEvent Macros_::active_macros[]; byte Macros_::active_macro_count; 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); + if (explicit_report) + return; + kaleidoscope::hid::sendKeyboardReport(); 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.flags = flags; key.keyCode = pgm_read_byte(macro_p++); if (keyIsPressed(keyStates)) { - playMacroKeyswitchEvent(key, IS_PRESSED); + playMacroKeyswitchEvent(key, IS_PRESSED, explicit_report); } 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; uint8_t interval = 0; uint8_t flags; + bool explicit_report = false; if (!macro_p) return; while (true) { 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: interval = pgm_read_byte(macro_p++); break; @@ -69,25 +83,25 @@ void Macros_::play(const macro_t *macro_p) { } case MACRO_ACTION_STEP_KEYDOWN: flags = pgm_read_byte(macro_p++); - readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED); + readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED, explicit_report); break; case MACRO_ACTION_STEP_KEYUP: flags = pgm_read_byte(macro_p++); - readKeyCodeAndPlay(macro_p++, flags, WAS_PRESSED); + readKeyCodeAndPlay(macro_p++, flags, WAS_PRESSED, explicit_report); break; case MACRO_ACTION_STEP_TAP: flags = pgm_read_byte(macro_p++); - readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED | WAS_PRESSED); + readKeyCodeAndPlay(macro_p++, flags, IS_PRESSED | WAS_PRESSED, false); break; case MACRO_ACTION_STEP_KEYCODEDOWN: - readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED); + readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED, explicit_report); break; case MACRO_ACTION_STEP_KEYCODEUP: - readKeyCodeAndPlay(macro_p++, 0, WAS_PRESSED); + readKeyCodeAndPlay(macro_p++, 0, WAS_PRESSED, explicit_report); break; case MACRO_ACTION_STEP_TAPCODE: - readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED | WAS_PRESSED); + readKeyCodeAndPlay(macro_p++, 0, IS_PRESSED | WAS_PRESSED, false); break; case MACRO_ACTION_END: @@ -197,8 +211,8 @@ const macro_t *Macros_::type(const char *string) { if (key.raw == Key_NoKey.raw) continue; - playMacroKeyswitchEvent(key, IS_PRESSED); - playMacroKeyswitchEvent(key, WAS_PRESSED); + playMacroKeyswitchEvent(key, IS_PRESSED, false); + playMacroKeyswitchEvent(key, WAS_PRESSED, false); } diff --git a/src/kaleidoscope/plugin/Macros/MacroSteps.h b/src/kaleidoscope/plugin/Macros/MacroSteps.h index 39bf2a64..1d4b77a7 100644 --- a/src/kaleidoscope/plugin/Macros/MacroSteps.h +++ b/src/kaleidoscope/plugin/Macros/MacroSteps.h @@ -29,6 +29,10 @@ typedef enum { MACRO_ACTION_STEP_KEYCODEDOWN, MACRO_ACTION_STEP_KEYCODEUP, MACRO_ACTION_STEP_TAPCODE, + + MACRO_ACTION_STEP_EXPLICIT_REPORT, + MACRO_ACTION_STEP_IMPLICIT_REPORT, + MACRO_ACTION_STEP_SEND_REPORT, } MacroActionStepType; 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 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;