From 5f5b715f8eaefec985e0d6ad8cdd2ece8a8ca29e Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Tue, 15 Mar 2022 21:47:56 -0500 Subject: [PATCH] Add MouseKeysConfig plugin This new plugin will allow MouseKeys to be configured via Focus, and store and retrieve its config parameters from EEPROM, enabling Chrysalis to control it. Signed-off-by: Michael Richters --- .../src/kaleidoscope/plugin/MouseKeys.h | 23 ++- .../kaleidoscope/plugin/MouseKeysConfig.cpp | 144 ++++++++++++++++++ 2 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 plugins/Kaleidoscope-MouseKeys/src/kaleidoscope/plugin/MouseKeysConfig.cpp 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;