diff --git a/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeys.h b/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeys.h
index 496d56a6..3dee363d 100644
--- a/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeys.h
+++ b/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeys.h
@@ -148,6 +148,11 @@ class MouseKeys : public kaleidoscope::Plugin {
uint16_t cursor_accel_duration = 1000;
};
+ // ---------------------------------------------------------------------------
+ // This lets the MouseKeysConfig plugin access the internal config variables
+ // directly. Mainly useful for calls to `Runtime.storage.get()`/`.put()`.
+ friend class MouseKeysConfig;
+
private:
static constexpr uint8_t cursor_update_interval_ = 4;
@@ -183,7 +188,21 @@ class MouseKeys : public kaleidoscope::Plugin {
uint8_t cursorDelta() const;
};
-} // namespace plugin
-} // namespace kaleidoscope
+// =============================================================================
+// Plugin for configuration of MouseKeys via Focus and persistent storage of
+// settins in EEPROM (i.e. Chrysalis).
+class MouseKeysConfig : public Plugin {
+ public:
+ EventHandlerResult onSetup();
+ EventHandlerResult onFocusEvent(const char *command);
+
+ private:
+ // The base address in persistent storage for configuration data:
+ uint16_t settings_addr_;
+};
+
+} // namespace plugin
+} // namespace kaleidoscope
extern kaleidoscope::plugin::MouseKeys MouseKeys;
+extern kaleidoscope::plugin::MouseKeysConfig MouseKeysConfig;
diff --git a/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeysConfig.cpp b/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeysConfig.cpp
new file mode 100644
index 00000000..eb2caa3b
--- /dev/null
+++ b/plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeysConfig.cpp
@@ -0,0 +1,144 @@
+/* -*- mode: c++ -*-
+ * Kaleidoscope-MouseKeys -- Mouse 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 .
+ */
+
+#include "kaleidoscope/plugin/MouseKeys.h" // IWYU pragma: associated
+
+#include // for PSTR, strcmp_P, strncmp_P
+#include // for EEPROMSettings
+#include // for Focus, FocusSerial
+#include // for uint16_t, uint32_t, uint8_t
+
+#include "kaleidoscope/Runtime.h" // for Runtime, Runtime_
+#include "kaleidoscope/device/device.h" // for VirtualProps::Storage, Base<>::Storage
+#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult, EventHandlerResult::OK
+
+namespace kaleidoscope {
+namespace plugin {
+
+// =============================================================================
+// MouseKeys configurator
+
+EventHandlerResult MouseKeysConfig::onSetup() {
+ settings_addr_ = ::EEPROMSettings.requestSlice(sizeof(MouseKeys::Settings));
+ uint32_t checker;
+
+ Runtime.storage().get(settings_addr_, checker);
+
+ // If the EEPROM is empty, storre the default settings.
+ if (checker == 0xffffffff) {
+ Runtime.storage().put(settings_addr_, ::MouseKeys.settings_);
+ Runtime.storage().commit();
+ }
+
+ Runtime.storage().get(settings_addr_, ::MouseKeys.settings_);
+ return EventHandlerResult::OK;
+}
+
+// -----------------------------------------------------------------------------
+EventHandlerResult MouseKeysConfig::onFocusEvent(const char *command) {
+ // If the focus command is a request for help, provide the list of valid
+ // commands.
+ if (::Focus.handleHelp(command, PSTR("mousekeys.scroll_interval\n"
+ "mousekeys.init_speed\n"
+ "mousekeys.base_speed\n"
+ "mousekeys.accel_duration")))
+ return EventHandlerResult::OK;
+
+ // The length of the string `mousekeys.`:
+ constexpr uint8_t base_cmd_len = 10;
+
+ // If this is not a MouseKeys command, do nothing.
+ if (strncmp_P(command, PSTR("mousekeys."), base_cmd_len) != 0)
+ return EventHandlerResult::OK;
+ // Otherwise, advance the pointer to the subcommand.
+ command += base_cmd_len;
+
+ enum Command : uint8_t {
+ SCROLL_INTERVAL,
+ INIT_SPEED,
+ BASE_SPEED,
+ ACCEL_DURATION,
+ };
+ Command cmd;
+
+ // Parse the (sub)command. If it's not a valid command, abort.
+ if (strcmp_P(command, PSTR("scroll_interval")) == 0)
+ cmd = Command::SCROLL_INTERVAL;
+ else if (strcmp_P(command, PSTR("init_speed")) == 0)
+ cmd = Command::INIT_SPEED;
+ else if (strcmp_P(command, PSTR("base_speed")) == 0)
+ cmd = Command::BASE_SPEED;
+ else if (strcmp_P(command, PSTR("accel_duration")) == 0)
+ cmd = Command::ACCEL_DURATION;
+ else
+ return EventHandlerResult::ABORT;
+
+ if (::Focus.isEOL()) {
+ // If there is no argument given, we send back the current value of the
+ // setting that was requested.
+ uint16_t val;
+ switch (cmd) {
+ case Command::SCROLL_INTERVAL:
+ val = ::MouseKeys.getScrollInterval();
+ break;
+ case Command::INIT_SPEED:
+ val = ::MouseKeys.getCursorInitSpeed();
+ break;
+ case Command::BASE_SPEED:
+ val = ::MouseKeys.getCursorBaseSpeed();
+ break;
+ case Command::ACCEL_DURATION:
+ val = ::MouseKeys.getCursorAccelDuration();
+ break;
+ default:
+ return EventHandlerResult::ABORT;
+ }
+ ::Focus.send(val);
+ return EventHandlerResult::EVENT_CONSUMED;
+ } else {
+ // If there is an argument, we read it, then pass it to the corresponding
+ // setter method of MouseKeys.
+ uint16_t arg;
+ ::Focus.read(arg);
+
+ switch (cmd) {
+ case Command::SCROLL_INTERVAL:
+ ::MouseKeys.setScrollInterval(arg);
+ break;
+ case Command::INIT_SPEED:
+ ::MouseKeys.setCursorInitSpeed(arg);
+ break;
+ case Command::BASE_SPEED:
+ ::MouseKeys.setCursorBaseSpeed(arg);
+ break;
+ case Command::ACCEL_DURATION:
+ ::MouseKeys.setCursorAccelDuration(arg);
+ break;
+ }
+ }
+
+ // Update settings stored in EEPROM, and indicate that this Focus event has
+ // been handled successfully.
+ Runtime.storage().put(settings_addr_, ::MouseKeys.settings_);
+ Runtime.storage().commit();
+ return EventHandlerResult::EVENT_CONSUMED;
+}
+
+} // namespace plugin
+} // namespace kaleidoscope
+
+kaleidoscope::plugin::MouseKeysConfig MouseKeysConfig;