Xteink-X4-crosspoint-reader/src/activities/util/KeyboardEntryActivity.h
Dave Allie 77c655fcf5
Some checks are pending
CI / build (push) Waiting to run
Give activities names and log when entering and exiting them (#92)
## Summary

* Give activities name and log when entering and exiting them
* Clearer logs when attempting to debug, knowing where users are coming
from/going to helps
2025-12-21 21:17:00 +11:00

132 lines
3.7 KiB
C++

#pragma once
#include <GfxRenderer.h>
#include <InputManager.h>
#include <functional>
#include <string>
#include "../Activity.h"
/**
* Reusable keyboard entry activity for text input.
* Can be started from any activity that needs text entry.
*
* Usage:
* 1. Create a KeyboardEntryActivity instance
* 2. Set callbacks with setOnComplete() and setOnCancel()
* 3. Call onEnter() to start the activity
* 4. Call loop() in your main loop
* 5. When complete or cancelled, callbacks will be invoked
*/
class KeyboardEntryActivity : public Activity {
public:
// Callback types
using OnCompleteCallback = std::function<void(const std::string&)>;
using OnCancelCallback = std::function<void()>;
/**
* Constructor
* @param renderer Reference to the GfxRenderer for drawing
* @param inputManager Reference to InputManager for handling input
* @param title Title to display above the keyboard
* @param initialText Initial text to show in the input field
* @param maxLength Maximum length of input text (0 for unlimited)
* @param isPassword If true, display asterisks instead of actual characters
*/
KeyboardEntryActivity(GfxRenderer& renderer, InputManager& inputManager, const std::string& title = "Enter Text",
const std::string& initialText = "", const size_t maxLength = 0, const bool isPassword = false)
: Activity("KeyboardEntry", renderer, inputManager),
title(title),
text(initialText),
maxLength(maxLength),
isPassword(isPassword) {}
/**
* Handle button input. Call this in your main loop.
* @return true if input was handled, false otherwise
*/
bool handleInput();
/**
* Render the keyboard at the specified Y position.
* @param startY Y-coordinate where keyboard rendering starts (default 10)
*/
void render(int startY = 10) const;
/**
* Get the current text entered by the user.
*/
const std::string& getText() const { return text; }
/**
* Set the current text.
*/
void setText(const std::string& newText);
/**
* Check if the user has completed text entry (pressed OK on Done).
*/
bool isComplete() const { return complete; }
/**
* Check if the user has cancelled text entry.
*/
bool isCancelled() const { return cancelled; }
/**
* Reset the keyboard state for reuse.
*/
void reset(const std::string& newTitle = "", const std::string& newInitialText = "");
/**
* Set callback for when input is complete.
*/
void setOnComplete(OnCompleteCallback callback) { onComplete = callback; }
/**
* Set callback for when input is cancelled.
*/
void setOnCancel(OnCancelCallback callback) { onCancel = callback; }
// Activity overrides
void onEnter() override;
void loop() override;
private:
std::string title;
std::string text;
size_t maxLength;
bool isPassword;
// Keyboard state
int selectedRow = 0;
int selectedCol = 0;
bool shiftActive = false;
bool complete = false;
bool cancelled = false;
// Callbacks
OnCompleteCallback onComplete;
OnCancelCallback onCancel;
// Keyboard layout
static constexpr int NUM_ROWS = 5;
static constexpr int KEYS_PER_ROW = 13; // Max keys per row (rows 0 and 1 have 13 keys)
static const char* const keyboard[NUM_ROWS];
static const char* const keyboardShift[NUM_ROWS];
// Special key positions (bottom row)
static constexpr int SHIFT_ROW = 4;
static constexpr int SHIFT_COL = 0;
static constexpr int SPACE_ROW = 4;
static constexpr int SPACE_COL = 2;
static constexpr int BACKSPACE_ROW = 4;
static constexpr int BACKSPACE_COL = 7;
static constexpr int DONE_ROW = 4;
static constexpr int DONE_COL = 9;
char getSelectedChar() const;
void handleKeyPress();
int getRowLength(int row) const;
};