Skip to content

Commit

Permalink
Replace RotaryNavConfig with RotaryInputAdapter (#204)
Browse files Browse the repository at this point in the history
Replaced the RotaryNavConfig struct with a new RotaryInputAdapter class to handle rotary input for LCD menus efficiently. The adapter manages user input through a rotary encoder, recognizing short, long, and double presses for menu navigation and selection.
  • Loading branch information
forntoh authored Sep 17, 2024
1 parent f593af6 commit 78b85eb
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 91 deletions.
18 changes: 5 additions & 13 deletions examples/InputRotary/InputRotary.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include <ItemSubMenu.h>
#include <LcdMenu.h>
#include <SimpleRotary.h>
#include <input/RotaryInputAdapter.h>
#include <interface/LiquidCrystalI2CAdapter.h>
#include <utils/RotaryNavConfig.h>

#define LCD_ROWS 2
#define LCD_COLS 16
Expand All @@ -31,26 +31,18 @@ SUB_MENU(
ITEM_INPUT_CHARSET("User", charset, inputCallback),
ITEM_COMMAND("Clear", clearInput));

LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);

SimpleRotary encoder(2, 3, 4);

RotaryNavConfig menuConfig = {
.encoder = &encoder,
.menu = &menu,
.longPressDuration = 1000,
};
LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);
RotaryInputAdapter rotaryInput(&menu, &encoder);

void setup() {
Serial.begin(9600);
menu.initialize(mainMenu);
}

void loop() {
// Call the handleRotaryMenu function, passing the menuConfig instance
processWithRotaryEncoder(&menuConfig);
}
void loop() { rotaryInput.observe(); }

// Define the callbacks
void inputCallback(char* value) {
Expand Down
18 changes: 5 additions & 13 deletions examples/SimpleRotary/SimpleRotary.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <ItemToggle.h>
#include <LcdMenu.h>
#include <SimpleRotary.h>
#include <input/RotaryInputAdapter.h>
#include <interface/LiquidCrystalI2CAdapter.h>
#include <utils/RotaryNavConfig.h>

Expand Down Expand Up @@ -32,27 +33,18 @@ MAIN_MENU(
ITEM_TOGGLE("Backlight", toggleBacklight),
ITEM_BASIC("Blink random"));

LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);

SimpleRotary encoder(2, 3, 4);

RotaryNavConfig menuConfig = {
.encoder = &encoder,
.menu = &menu,
.longPressDuration = 1000,
.doublePressThreshold = 500,
};
LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);
RotaryInputAdapter rotaryInput(&menu, &encoder);

void setup() {
Serial.begin(9600);
menu.initialize(mainMenu);
}

void loop() {
// Call the handleRotaryMenu function, passing the menuConfig instance
processWithRotaryEncoder(&menuConfig);
}
void loop() { rotaryInput.observe(); }

// Define the callbacks
void toggleBacklight(uint16_t isOn) {
Expand Down
72 changes: 72 additions & 0 deletions src/input/RotaryInputAdapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#pragma once

#include "InputInterface.h"
#include <SimpleRotary.h>

class RotaryInputAdapter : public InputInterface {
private:
uint16_t longPressDuration; // Duration to consider a long press
uint16_t doublePressThreshold; // Duration to consider a double press
unsigned long lastPressTime = 0; // Last time the button was pressed
bool pendingEnter = false; // Flag to indicate if an enter action is pending

public:
SimpleRotary* encoder;

/**
* @brief Adapter for handling rotary input for an LCD menu.
*
* This class interfaces with a rotary encoder to manage user input
* for navigating and selecting options in an LCD menu.
*
* @param menu Pointer to the LcdMenu instance that this adapter will control.
* @param encoder Pointer to the SimpleRotary instance representing the rotary encoder.
* @param longPressDuration Duration in milliseconds to recognize a long press (default is 1000 ms).
* @param doublePressThreshold Duration in milliseconds to recognize a double press (default is 300 ms).
*/
RotaryInputAdapter(
LcdMenu* menu,
SimpleRotary* encoder,
uint16_t longPressDuration = 1000,
uint16_t doublePressThreshold = 300) : InputInterface(menu),
encoder(encoder),
longPressDuration(longPressDuration),
doublePressThreshold(doublePressThreshold) {};

void observe() override {
// Handle rotary encoder rotation
uint8_t rotation = encoder->rotate();
if (rotation == 1) {
menu->process(DOWN); // Call DOWN action
} else if (rotation == 2) {
menu->process(UP); // Call UP action
}

// Handle button press (short, long, and double press)
uint8_t pressType = encoder->pushType(longPressDuration);
unsigned long currentTime = millis();

if (pressType == 1) {
if (pendingEnter) {
if (doublePressThreshold > 0 &&
currentTime - lastPressTime < doublePressThreshold) {
menu->process(BACKSPACE); // Call BACKSPACE action (double press)
pendingEnter = false;
}
} else {
pendingEnter = true;
lastPressTime = currentTime;
}
} else if (pressType == 2) {
menu->process(BACK); // Call BACK action (long press)
pendingEnter = false;
}

// Check if the doublePressThreshold has elapsed for pending enter action
if ((!menu->lcd.getEditModeEnabled() && pendingEnter) ||
(pendingEnter && (currentTime - lastPressTime >= doublePressThreshold))) {
menu->process(ENTER); // Call ENTER action (short press)
pendingEnter = false;
}
}
};
65 changes: 0 additions & 65 deletions src/utils/RotaryNavConfig.h

This file was deleted.

0 comments on commit 78b85eb

Please sign in to comment.