Skip to content

Commit

Permalink
Major redesign of the plugin and hooking interface
Browse files Browse the repository at this point in the history
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.

It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.

With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.

The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.

This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.

Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
  • Loading branch information
noseglasses authored and algernon committed May 11, 2018
1 parent bc76032 commit 08d91c2
Show file tree
Hide file tree
Showing 16 changed files with 813 additions and 158 deletions.
13 changes: 13 additions & 0 deletions doc/glossary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Glossary

This document is intended to name and describe the concepts, functions and data structures inside Kaleidoscope.

It is, as yet, incredibly incomplete.

Entries should be included in dictionary order. When describing an identifier of any kind from the codebase, it should be
written using identical capitalization to its use in the code and surrounded by backticks: `identifierName`


Event handler

: A function, usually provided by a `Plugin` that is run by a `Hook`
8 changes: 4 additions & 4 deletions examples/AppSwitcher/AppSwitcher.ino
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* -*- mode: c++ -*-
* AppSwitcher -- A Kaleidoscope Example
* Copyright (C) 2016, 2017 Gergely Nagy
* Copyright (C) 2016, 2017, 2018 Gergely Nagy
*
* 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
Expand Down Expand Up @@ -46,7 +46,6 @@ KEYMAPS(
)
/* *INDENT-ON* */


const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
switch (macroIndex) {
case M_APPSWITCH:
Expand All @@ -57,9 +56,10 @@ const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
return MACRO_NONE;
}

void setup() {
Kaleidoscope.use(&HostOS, &Macros);
KALEIDOSCOPE_INIT_PLUGINS(HostOS,
Macros);

void setup() {
Kaleidoscope.setup();
}

Expand Down
15 changes: 7 additions & 8 deletions examples/Kaleidoscope/Kaleidoscope.ino
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,16 @@ const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
return MACRO_NONE;
}

KALEIDOSCOPE_INIT_PLUGINS(TestMode,
LEDControl, LEDOff,
solidRed, solidOrange, solidYellow, solidGreen, solidBlue, solidIndigo, solidViolet,
LEDBreatheEffect, LEDRainbowEffect, LEDChaseEffect, NumLock,
Macros,
MouseKeys);

void setup() {
Kaleidoscope.setup();

Kaleidoscope.use(&TestMode,
&LEDControl, &LEDOff,
&solidRed, &solidOrange, &solidYellow, &solidGreen, &solidBlue, &solidIndigo, &solidViolet,
&LEDBreatheEffect, &LEDRainbowEffect, &LEDChaseEffect, &NumLock,

&Macros,
&MouseKeys,
NULL);
NumLock.numPadLayer = NUMPAD_KEYMAP;
LEDOff.activate();
}
Expand Down
134 changes: 87 additions & 47 deletions src/Kaleidoscope.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "Kaleidoscope.h"
#include <stdarg.h>

namespace kaleidoscope {

Kaleidoscope_::eventHandlerHook Kaleidoscope_::eventHandlers[HOOK_MAX];
Kaleidoscope_::loopHook Kaleidoscope_::loopHooks[HOOK_MAX];

Expand All @@ -9,6 +11,8 @@ Kaleidoscope_::Kaleidoscope_(void) {

void
Kaleidoscope_::setup(void) {
kaleidoscope::Hooks::onSetup();

KeyboardHardware.setup();

kaleidoscope::hid::initializeKeyboard();
Expand All @@ -31,115 +35,144 @@ Kaleidoscope_::setup(void) {

void
Kaleidoscope_::loop(void) {
kaleidoscope::Hooks::beforeEachCycle();

KeyboardHardware.scanMatrix();

kaleidoscope::Hooks::beforeReportingState();

#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
for (byte i = 0; loopHooks[i] != NULL && i < HOOK_MAX; i++) {
loopHook hook = loopHooks[i];
(*hook)(false);
}
#endif

kaleidoscope::hid::sendKeyboardReport();
kaleidoscope::hid::releaseAllKeys();

#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
for (byte i = 0; loopHooks[i] != NULL && i < HOOK_MAX; i++) {
loopHook hook = loopHooks[i];
(*hook)(true);
}
#endif

kaleidoscope::Hooks::afterEachCycle();
}

bool
Kaleidoscope_::focusHook(const char *command) {
enum {
ON,
OFF,
GETSTATE,
} subCommand;

if (strncmp_P(command, PSTR("layer."), 6) != 0)
return false;

if (strcmp_P(command + 6, PSTR("on")) == 0)
subCommand = ON;
else if (strcmp_P(command + 6, PSTR("off")) == 0)
subCommand = OFF;
else if (strcmp_P(command + 6, PSTR("getState")) == 0)
subCommand = GETSTATE;
else
return false;

switch (subCommand) {
case ON: {
uint8_t layer = Serial.parseInt();
Layer.on(layer);
break;
}

case OFF: {
uint8_t layer = Serial.parseInt();
Layer.off(layer);
break;
}

case GETSTATE:
Serial.println(Layer.getLayerState(), BIN);
break;
}

return true;
}

Kaleidoscope_ Kaleidoscope;

/* Deprecated functions */

/* Disable deprecation warnings for these, we only want to have those at
* non-internal call sites. */

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

void
Kaleidoscope_::replaceEventHandlerHook(eventHandlerHook oldHook, eventHandlerHook newHook) {
#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
for (byte i = 0; i < HOOK_MAX; i++) {
if (eventHandlers[i] == oldHook) {
eventHandlers[i] = newHook;
return;
}
}
#endif
}

void
Kaleidoscope_::appendEventHandlerHook(eventHandlerHook hook) {
#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
replaceEventHandlerHook((eventHandlerHook)NULL, hook);
#endif
}

void
Kaleidoscope_::useEventHandlerHook(eventHandlerHook hook) {
#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
for (byte i = 0; i < HOOK_MAX; i++) {
if (eventHandlers[i] == hook)
return;
}
appendEventHandlerHook(hook);
#endif
}

void
Kaleidoscope_::replaceLoopHook(loopHook oldHook, loopHook newHook) {
#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
for (byte i = 0; i < HOOK_MAX; i++) {
if (loopHooks[i] == oldHook) {
loopHooks[i] = newHook;
return;
}
}
#endif
}

void
Kaleidoscope_::appendLoopHook(loopHook hook) {
#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
replaceLoopHook((loopHook)NULL, hook);
#endif
}

void
Kaleidoscope_::useLoopHook(loopHook hook) {
#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
for (byte i = 0; i < HOOK_MAX; i++) {
if (loopHooks[i] == hook)
return;
}
appendLoopHook(hook);
#endif
}

bool
Kaleidoscope_::focusHook(const char *command) {
enum {
ON,
OFF,
GETSTATE,
} subCommand;

if (strncmp_P(command, PSTR("layer."), 6) != 0)
return false;

if (strcmp_P(command + 6, PSTR("on")) == 0)
subCommand = ON;
else if (strcmp_P(command + 6, PSTR("off")) == 0)
subCommand = OFF;
else if (strcmp_P(command + 6, PSTR("getState")) == 0)
subCommand = GETSTATE;
else
return false;

switch (subCommand) {
case ON: {
uint8_t layer = Serial.parseInt();
Layer.on(layer);
break;
}

case OFF: {
uint8_t layer = Serial.parseInt();
Layer.off(layer);
break;
}

case GETSTATE:
Serial.println(Layer.getLayerState(), BIN);
break;
}

return true;
}

Kaleidoscope_ Kaleidoscope;

/* Deprecated functions */

#if KALEIDOSCOPE_ENABLE_V1_PLUGIN_API
void event_handler_hook_use(Kaleidoscope_::eventHandlerHook hook) {
Kaleidoscope.useEventHandlerHook(hook);
}
Expand All @@ -148,13 +181,20 @@ void loop_hook_use(Kaleidoscope_::loopHook hook) {
Kaleidoscope.useLoopHook(hook);
}

void __USE_PLUGINS(KaleidoscopePlugin *plugin, ...) {
void __USE_PLUGINS(kaleidoscope::Plugin *plugin, ...) {
va_list ap;

Kaleidoscope.use(plugin);

va_start(ap, plugin);
while ((plugin = (KaleidoscopePlugin *)va_arg(ap, KaleidoscopePlugin *)) != NULL)
while ((plugin = (kaleidoscope::Plugin *)va_arg(ap, kaleidoscope::Plugin *)) != NULL)
Kaleidoscope.use(plugin);
va_end(ap);
}
#endif

#pragma GCC diagnostic pop // restore diagnostic options

} // namespace kaleidoscope

Kaleidoscope_ Kaleidoscope;

0 comments on commit 08d91c2

Please sign in to comment.