Add MacroSupport plugin

This plugin provides a shared virtual keys array used by Macros and
DynamicMacros, along with some functions to interact with it (`press()`,
`release()`, `tap()`, `clear()`).

Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
pull/1185/head
Michael Richters 3 years ago
parent cb9ad9f753
commit 3976e3dd5b
No known key found for this signature in database
GPG Key ID: 1288FD13E4EEF0C0

@ -0,0 +1,51 @@
# MacroSupport
This plugin provides the supplemental key array used by the Macros and DynamicMacros plugins, and is necessary for the proper functioning of those plugins.
## Using the plugin
Any firmware sketch that uses either Macros or DynamicMacros automatically includes this plugin, so there's no need to add it explicitly. If your sketch doesn't require either type of Macros key, however, you can still make use of the MacroSupport plugin's helper methods (`tap()`, `press()`, _et al_). In that case, you should include the MacroSupport header file, and include it in `KALEIDOSCOPE_INIT_PLUGINS()`:
```c++
#include <Kaleidoscope.h>
#include <Kaleidoscope-MacroSupport.h>
// Other plugin code that calls `MacroSupport.press()` (for example)
KALEIDOSCOPE_INIT_PLUGINS(
MacroSupport,
// Other plugin(s) that make use of MacroSupport
);
void setup() {
Kaleidoscope.setup ();
}
```
## Plugin methods
The plugin provides a `MacroSupport` object, which contains a supplemental array of virtual keys that it adds to USB Keyboard reports. Other plugins and user code can interact with it via the following methods:
### `.press(key)`
> Sends a key press event for `key`, and will keep that virtual key active in
> the supplemental virtual keys array.
### `.release(key)`
> Sends a key release event for `key`, and removes it from the supplemental
> virtual keys array.
### `.clear()`
> Releases all active virtual keys held by MacroSupport. This both empties the
> supplemental keys array (see above) and sends a release event for each key
> stored there.
### `.tap(key)`
> Sends an immediate press and release event for `key` with no delay, using an
> invalid key address. This method doesn't actually use the supplemental keys
> array, but is provided here for convenience and simplicity.
It is not necessary to use either the Macros (or DynamicMacros) to make use of MacroSupport. When using it with custom code, however, please remember that the supplemental active keys array it provides will be shared by all clients (e.g. Macros, user-defined Leader or TapDance functions), so if you want more than one of those clients to be active simultaneously, be aware that calles to `MacroSupport.clear()` will affect all of them, not just the caller.

@ -0,0 +1,7 @@
name=Kaleidoscope-MacroSupport
version=0.0.0
sentence=Macro keys for Kaleidoscope
maintainer=Kaleidoscope's Developers <jesse@keyboard.io>
url=https://github.com/keyboardio/Kaleidoscope
author=Gergely Nagy, Jesse Vincent, Michael Richters
paragraph=

@ -0,0 +1,19 @@
/* Kaleidoscope-MacroSupport -- Macro keys for Kaleidoscope
* Copyright (C) 2022 Keyboard.io, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "kaleidoscope/plugin/MacroSupport.h" // IWYU pragma: export

@ -0,0 +1,105 @@
/* Kaleidoscope-MacroSupport - Macros support functions for Kaleidoscope
* Copyright (C) 2022 Keyboard.io, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "kaleidoscope/plugin/MacroSupport.h"
#include <Arduino.h> // for pgm_read_byte, delay, F, PROGMEM, __F...
#include <Kaleidoscope-FocusSerial.h> // for Focus, FocusSerial
#include <stdint.h> // for uint8_t
#include "kaleidoscope/KeyAddr.h" // for KeyAddr
#include "kaleidoscope/KeyEvent.h" // for KeyEvent
#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResul...
#include "kaleidoscope/key_defs.h" // for Key, LSHIFT, Key_NoKey, Key_0, Key_1
#include "kaleidoscope/keyswitch_state.h" // for INJECTED, IS_PRESSED, WAS_PRESSED
// =============================================================================
// `Macros` plugin code
namespace kaleidoscope {
namespace plugin {
constexpr uint8_t press_state = IS_PRESSED | INJECTED;
constexpr uint8_t release_state = WAS_PRESSED | INJECTED;
// -----------------------------------------------------------------------------
// Public helper functions
void MacroSupport::press(Key key) {
Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), press_state, key});
// This key may remain active for several subsequent events, so we need to
// store it in the active macro keys array.
for (Key &macro_key : active_macro_keys_) {
if (macro_key == Key_NoKey) {
macro_key = key;
break;
}
}
}
void MacroSupport::release(Key key) {
// Before sending the release event, we need to remove the key from the active
// macro keys array, or it will get inserted into the report anyway.
for (Key &macro_key : active_macro_keys_) {
if (macro_key == key) {
macro_key = Key_NoKey;
}
}
Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), release_state, key});
}
void MacroSupport::clear() {
// Clear the active macro keys array.
for (Key &macro_key : active_macro_keys_) {
if (macro_key == Key_NoKey)
continue;
Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), release_state, macro_key});
macro_key = Key_NoKey;
}
}
void MacroSupport::tap(Key key) const {
// No need to call `press()` & `release()`, because we're immediately
// releasing the key after pressing it. It is possible for some other plugin
// to insert an event in between, but very unlikely.
Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), press_state, key});
Runtime.handleKeyEvent(KeyEvent{KeyAddr::none(), release_state, key});
}
// -----------------------------------------------------------------------------
// Event handlers
EventHandlerResult MacroSupport::beforeReportingState(const KeyEvent &event) {
// Do this in beforeReportingState(), instead of `onAddToReport()` because
// `live_keys` won't get updated until after the macro sequence is played from
// the keypress. This could be changed by either updating `live_keys` manually
// ahead of time, or by executing the macro sequence on key release instead of
// key press. This is probably the simplest solution.
for (Key key : active_macro_keys_) {
if (key != Key_NoKey)
Runtime.addToReport(key);
}
return EventHandlerResult::OK;
}
EventHandlerResult MacroSupport::onNameQuery() {
return ::Focus.sendName(F("MacroSupport"));
}
} // namespace plugin
} // namespace kaleidoscope
kaleidoscope::plugin::MacroSupport MacroSupport;

@ -0,0 +1,78 @@
/* Kaleidoscope-MacroSupport - Macros support functions for Kaleidoscope
* Copyright (C) 2022 Keyboard.io, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "kaleidoscope/KeyEvent.h" // for KeyEvent
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult
#include "kaleidoscope/key_defs.h" // for Key
#include "kaleidoscope/plugin.h" // for Plugin
// =============================================================================
// The number of simultaneously-active `Key` values that a macro can have
// running during a call to `Macros.play()`. I don't know if it's actually
// possible to override this by defining it in a sketch before including
// "Kaleidoscope-Macros.h", but probably not.
#if !defined(MAX_CONCURRENT_MACRO_KEYS)
#define MAX_CONCURRENT_MACRO_KEYS 8
#endif
namespace kaleidoscope {
namespace plugin {
class MacroSupport : public Plugin {
public:
/// Send a key press event from a Macro
///
/// Generates a new `KeyEvent` and calls `Runtime.handleKeyEvent()` with the
/// specified `key`, then stores that `key` in an array of active macro key
/// values. This allows the macro to press one key and keep it active when a
/// subsequent key event is sent as part of the same macro sequence.
void press(Key key);
/// Send a key release event from a Macro
///
/// Generates a new `KeyEvent` and calls `Runtime.handleKeyEvent()` with the
/// specified `key`, then removes that key from the array of active macro
/// keys (see `Macros.press()`).
void release(Key key);
/// Clear all virtual keys held by Macros
///
/// This function clears the active macro keys array, sending a release event
/// for each key stored there.
void clear();
/// Send a key "tap event" from a Macro
///
/// Generates two new `KeyEvent` objects, one each to press and release the
/// specified `key`, passing both in sequence to `Runtime.handleKeyEvent()`.
void tap(Key key) const;
// ---------------------------------------------------------------------------
// Event handlers
EventHandlerResult onNameQuery();
EventHandlerResult beforeReportingState(const KeyEvent &event);
private:
// An array of key values that are active while a macro sequence is playing
Key active_macro_keys_[MAX_CONCURRENT_MACRO_KEYS];
};
} // namespace plugin
} // namespace kaleidoscope
extern kaleidoscope::plugin::MacroSupport MacroSupport;
Loading…
Cancel
Save