From 87f23765fd50a54a4d4bdfb9137cac2b1b562e51 Mon Sep 17 00:00:00 2001 From: Luke A Date: Sat, 25 Jan 2025 16:15:41 -0500 Subject: [PATCH] Keyboard Volume Dial - Rotary Encoder Extension (#1274) * Testing Volume Dial using GPEvents * Missed an include * Add volume up / down reset on usb report complete (this should be a built-in in input drivers). Also fixed a silly web config thing * Update Rotary.tsx * Update Rotary.jsx --- headers/drivers/keyboard/KeyboardDriver.h | 3 +++ proto/enums.proto | 1 + src/addons/rotaryencoder.cpp | 2 ++ src/drivers/keyboard/KeyboardDriver.cpp | 30 +++++++++++++++++++++++ www/src/Addons/Rotary.tsx | 5 ++-- www/src/Locales/en/Addons/Rotary.jsx | 1 + 6 files changed, 40 insertions(+), 2 deletions(-) diff --git a/headers/drivers/keyboard/KeyboardDriver.h b/headers/drivers/keyboard/KeyboardDriver.h index 11f5286b9..6f2212b8d 100644 --- a/headers/drivers/keyboard/KeyboardDriver.h +++ b/headers/drivers/keyboard/KeyboardDriver.h @@ -8,6 +8,7 @@ #include "gpdriver.h" #include "drivers/keyboard/KeyboardDescriptors.h" +#include "eventmanager.h" class KeyboardDriver : public GPDriver { public: @@ -25,6 +26,7 @@ class KeyboardDriver : public GPDriver { virtual const uint8_t * get_descriptor_device_qualifier_cb(); virtual uint16_t GetJoystickMidValue(); virtual USBListener * get_usb_auth_listener() { return nullptr; } + void handleEncoder(GPEvent* e); // for Volume - rotary encoder private: void releaseAllKeys(void); void pressKey(uint8_t code); @@ -33,6 +35,7 @@ class KeyboardDriver : public GPDriver { uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; uint16_t last_report_size; KeyboardReport keyboardReport; + int8_t volumeChange; }; #endif // _KEYBOARD_DRIVER_H_ diff --git a/proto/enums.proto b/proto/enums.proto index 86ff6c76a..ddaa2df83 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -450,6 +450,7 @@ enum RotaryEncoderPinMode ENCODER_MODE_RIGHT_TRIGGER = 6; ENCODER_MODE_DPAD_X = 7; ENCODER_MODE_DPAD_Y = 8; + ENCODER_MODE_VOLUME = 9; }; enum ReactiveLEDMode diff --git a/src/addons/rotaryencoder.cpp b/src/addons/rotaryencoder.cpp index 17fdc54a6..39c70bef2 100644 --- a/src/addons/rotaryencoder.cpp +++ b/src/addons/rotaryencoder.cpp @@ -124,6 +124,8 @@ void RotaryEncoderInput::process() int8_t axis = mapEncoderValueDPad(i, encoderValues[i], encoderMap[i].pulsesPerRevolution); dpadUp = (axis == 1); dpadDown = (axis == -1); + } else if (encoderMap[i].mode == ENCODER_MODE_VOLUME) { + // Prevents NONE kick-out, do nothing for now but rely on GP events } if ((encoderValues[i] - prevValues[i]) != 0) { diff --git a/src/drivers/keyboard/KeyboardDriver.cpp b/src/drivers/keyboard/KeyboardDriver.cpp index 2d94ac0a6..781591dd2 100644 --- a/src/drivers/keyboard/KeyboardDriver.cpp +++ b/src/drivers/keyboard/KeyboardDriver.cpp @@ -3,6 +3,8 @@ #include "drivers/shared/driverhelper.h" #include "drivers/hid/HIDDescriptors.h" +#include "eventmanager.h" + void KeyboardDriver::initialize() { keyboardReport = { .keycode = { 0 }, @@ -20,6 +22,10 @@ void KeyboardDriver::initialize() { .xfer_cb = hidd_xfer_cb, .sof = NULL }; + + // Handle Volume for Rotary Encoder + EventManager::getInstance().registerEventHandler(GP_EVENT_ENCODER_CHANGE, GPEVENT_CALLBACK(this->handleEncoder(event))); + volumeChange = 0; // no change } uint8_t KeyboardDriver::getModifier(uint8_t code) { @@ -87,6 +93,12 @@ void KeyboardDriver::process(Gamepad * gamepad) { if(gamepad->pressedE11()) { pressKey(keyboardMapping.keyButtonE11); } if(gamepad->pressedE12()) { pressKey(keyboardMapping.keyButtonE12); } + if( volumeChange > 0 ) { + pressKey(KEYBOARD_MULTIMEDIA_VOLUME_UP); + } else if ( volumeChange < 0 ) { + pressKey(KEYBOARD_MULTIMEDIA_VOLUME_DOWN); + } + // Wake up TinyUSB device if (tud_suspended()) tud_remote_wakeup(); @@ -109,6 +121,13 @@ void KeyboardDriver::process(Gamepad * gamepad) { if ( tud_hid_report(keyboardReport.reportId, keyboard_report_payload, keyboard_report_size) ) { memcpy(last_report, keyboard_report_payload, keyboard_report_size); last_report_size = keyboard_report_size; + + // Adjust volume on success + if( volumeChange > 0 ) { + volumeChange--; + } else if ( volumeChange < 0 ) { + volumeChange++; + } } } } @@ -174,3 +193,14 @@ const uint8_t * KeyboardDriver::get_descriptor_device_qualifier_cb() { uint16_t KeyboardDriver::GetJoystickMidValue() { return HID_JOYSTICK_MID << 8; } + +void KeyboardDriver::handleEncoder(GPEvent* e) { + GPEncoderChangeEvent * encoderEvent = (GPEncoderChangeEvent*)e; + if ( encoderEvent->direction == 1 ) { + // volume up + volumeChange++; + } else if ( encoderEvent->direction == -1 ) { + // volume down + volumeChange--; + } +} diff --git a/www/src/Addons/Rotary.tsx b/www/src/Addons/Rotary.tsx index 541af1229..9323ef705 100644 --- a/www/src/Addons/Rotary.tsx +++ b/www/src/Addons/Rotary.tsx @@ -17,6 +17,7 @@ const ENCODER_MODES = [ { label: 'encoder-mode-right-trigger', value: 6 }, { label: 'encoder-mode-dpad-x', value: 7 }, { label: 'encoder-mode-dpad-y', value: 8 }, + { label: 'encoder-mode-volume', value: 9 }, ]; const ENCODER_MULTIPLES = [ @@ -43,7 +44,7 @@ export const rotaryScheme = { .number() .required() .label('Rotary Encoder Add-On Enabled'), - encoderOneEnabled: yup.number().required().label('Encoder One Enabled'), + encoderOneEnabled: yup.boolean().required().label('Encoder One Enabled'), encoderOnePinA: yup .number() .label('Encoder One Pin A') @@ -65,7 +66,7 @@ export const rotaryScheme = { .required() .label('Encoder One Allow Wrap Around'), encoderOneMultiplier: yup.number().label('Encoder One Multiplier').required(), - encoderTwoEnabled: yup.number().required().label('Encoder Two Enabled'), + encoderTwoEnabled: yup.boolean().required().label('Encoder Two Enabled'), encoderTwoPinA: yup .number() .label('Encoder Two Pin A') diff --git a/www/src/Locales/en/Addons/Rotary.jsx b/www/src/Locales/en/Addons/Rotary.jsx index 83eb1244e..4755d67f2 100644 --- a/www/src/Locales/en/Addons/Rotary.jsx +++ b/www/src/Locales/en/Addons/Rotary.jsx @@ -18,4 +18,5 @@ export default { 'encoder-mode-right-trigger': 'Right Trigger', 'encoder-mode-dpad-x': 'D-Pad Left/Right', 'encoder-mode-dpad-y': 'D-Pad Up/Down', + 'encoder-mode-volume': 'Volume (Keyboard Only)', };