The English used in this library is based on machine translations from Japanese.
This is a library for controlling a macro pad (keyboard) using Arduino.
This library only handles key input processing and macro management, so you will need a separate HID library to use it as an HID device (e.g., Keyboard library).
This README assumes the use of Keyboard.h, so for detailed information about keyboard functionality, please refer to Keyboard.
This library uses STL, so it only works in environments where STL is supported. For platforms like AVR microcontrollers that do not support STL by default, additional library installation may be required.
- Reads key inputs from a key matrix, directly connected buttons, or custom wiring and manages events.
- Each key can be assigned a macro, and custom macros can also be defined.
- Layers enable seamless switching of key mappings.
- Profiles allow easy switching between sets of layers.
- A macro that enables concise definition of custom macros.
- Accepts a
Key-type argument namedkey. - Example:
Do { Keyboard.print("Hello, world!"); }
- A macro for easily defining actions to execute after a delay set with the
macroDelay()function. - Captures the
keyvariable from the outer scope. - Example:
macroDelay(1000, After { Keyboard.print("Hello, world!"); });
- Simply an alias for
nullptr. - Used to indicate an invalid key assignment.
- Returns a macro that sends a key's character to the PC while the key is held down, like a standard keyboard.
- Works only with supported HID libraries (currently
Keyboard.h).
- Returns a macro that sends the first argument's keycode when tapped and the second argument's keycode when held.
- Works only with supported HID libraries (currently
Keyboard.h).
- Simple wrappers for the
pressTo()function.
- The central class of this library.
init(LayeredKeymap)- Registers a keymap with the MacroPad.
- Must be called during initialization.
KEYS- An array of
Keyobjects corresponding to all keys.
- An array of
LAYERS- Manages layers via the
Layerclass.
- Manages layers via the
- Each key in the library is assigned a
Keyobject, which manages its state. - A selection of the interface is described below:
-
Represents events occurring on each key:
Event Name Condition SINGLE Single short press (exclusive) LONG Long press (exclusive) DOUBLE Double press in quick succession (exclusive) TAP Single short press HOLD Long press RISING_EDGE When the key is pressed FALLING_EDGE When the key is released CHANGE_INPUT When the input state changes PRESSED While the key is pressed RELEASED While the key is released -
SINGLE,DOUBLE, andLONGare mutually exclusive (only one occurs at a time).- For instance,
SINGLEoccurs after waiting to confirm no double press, whileTAPoccurs immediately upon release.
- For instance,
init(longThreshold, doubleThreshold, holdThreshold, debounceTime)- Defines thresholds for detecting long presses, double presses, hold actions, and debounce intervals.
- Example:
Key::init(1000, 500, 10);
bool hasOccurred(Key::Event)- Checks if the specified event has occurred for the key.
- Example:
key.hasOccurred(Key::Event::SINGLE)
uint32_t getStateDuration()- Returns the time in milliseconds since the last input state change.
- Example:
key.getStateDuration()
uint8_t getCountOfClick()- Returns the number of times the key has been clicked.
- Resets if the interval exceeds
doubleThreshold. - Allows events for up to 255 clicks.
bool isPressed()- Returns whether the key is pressed.
- Equivalent to
hasOccurred(Key::Event::PRESSED).
uint32_t getPressTime()- Returns the duration the key has been pressed.
- Returns
0if the key is not pressed.
uint16_t getIndex()- Returns the key's index.
Note: The term "macro" in "
Domacro" refers to syntax replaced by the#definedirective. Below, "macro" refers to the program executed in response to key events unless stated otherwise.
-
Define custom macros using the
Domacro.- Macros receive the
Keyobject reference as thekeyargument when executed.
- Macros receive the
-
Macros can perform any desired processing, but since execution is synchronous, they should be implemented for quick processing.
-
Macros execute in order of ascending index.
-
To define macros that take parameters, define them as functions that return a macro (closures).
// A macro that types "Hello, world!" when the key is released
auto greet = Do {
if (key.hasOccurred(Key::Event::FALLING_EDGE)) {
Keyboard.println("Hello, world!");
}
};
// Alternatively, use a regular function
void greet(Key key) {
if (key.hasOccurred(Key::Event::FALLING_EDGE)) {
Keyboard.println("Hello, world!");
}
}// A macro that types a specified character while the key is pressed
inline Macro pressTo(uint8_t pressKey) {
return [pressKey](Key key) {
if (key.hasOccurred(Key::Event::RISING_EDGE)) {
Keyboard.press(pressKey);
} else if (key.hasOccurred(Key::Event::FALLING_EDGE)) {
Keyboard.release(pressKey);
}
};
}- Use this function to introduce delays within macros.
- Takes two arguments: wait time (in milliseconds) and the function to execute.
- Use the
Aftermacro to define the second argument concisely. - Avoid using
delay()in macros, as it halts all processing. UsemacroDelay()instead unless absolutely necessary. - Time is determined via polling, so precision is limited.
- Example:
macroDelay(1000, After { Keyboard.print("Hello, world!"); });
-
MacroPadsupports up to 255 layers. -
When passing a keymap to
MacroPad::init(), provide an array of keymaps for the desired number of layers. -
Layerclass manages layers:set(layer)- Switches to the specified layer.
- Does nothing if the layer does not exist.
- Example:
macroPad.LAYERS.set(1)
reset()- Reverts to the previous layer.
- May behave unexpectedly if a layer is revisited multiple times.
uint8_t get()- Returns the current layer's index.
-
The
LayerUtilclass simplifies layer-switching macro creation:Macro to(layer)- Returns a macro to switch to the specified layer when pressed.
- Example:
layer.to(1)
Macro back(layer)- Returns a macro to switch to the specified layer when released.
- Example:
layer.back(0)
Macro reset()- Returns a macro to revert to the previous layer.
- Example:
layer.reset()
- Usage is similar to layers.
- Access profiles through
MacroPad::PROFILES.
- Access profiles through
-
The library uses a plugin-based system for key input. You can define custom input algorithms by inheriting from the
KeyReaderclass.- Pass the custom instance to the
MacroPadconstructor for custom key input processing.
- Pass the custom instance to the
-
Key states are stored as an array of unsigned 32-bit integers, with each bit representing a key's input state (up to 32 keys per array element).
- The bit index corresponds to the keymap index.
- For example, the 0th key in the keymap corresponds to the 0th bit of the 0th array element.
- The bit index corresponds to the keymap index.
- Abstract class for managing key input.
uint32_t (&getStateData())[KEYBOARD_SIZE]- Returns a reference to the array storing key input data.
void read()- Updates key states.
- Called each time the
update()method of theMacroPadinstance is invoked. - The
MacroPadinstance verifies the key events after executing this method and checks the array returned bygetStateData().