input manager provides ground of truth on device input choise

This commit is contained in:
Adolfo Reyna
2026-01-30 22:07:31 -05:00
parent 436245a7a2
commit f860d4f5e6
10 changed files with 97 additions and 44 deletions

View File

@@ -321,17 +321,17 @@ int main()
InputManager input_manager(touch, &config);
// Create GameLauncher
GameLauncher launcher(V_WIDTH, V_HEIGHT, &renderer, &gui);
GameLauncher launcher(V_WIDTH, V_HEIGHT, &renderer, &gui, &input_manager);
// Register available games
launcher.register_game("Tic-Tac-Toe", "Classic 2-player game",
[](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g) -> Game* {
return new TicTacToeGame(w, h, r, g);
[](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g, InputManager* im) -> Game* {
return new TicTacToeGame(w, h, r, g, im);
});
launcher.register_game("Demo Game", "Simple test game",
[](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g) -> Game* {
return new DemoGame(w, h, r, g);
[](uint16_t w, uint16_t h, LowLevelRenderer* r, LowLevelGUI* g, InputManager* im) -> Game* {
return new DemoGame(w, h, r, g, im);
});
// Draw launcher menu
@@ -443,6 +443,13 @@ int main()
current_game = launcher.get_selected_game();
needs_refresh = current_game->update(input);
// Check if game wants to exit
if (current_game->wants_to_exit()) {
printf("Game requested exit - returning to launcher\n");
launcher.reset();
needs_refresh = true;
}
// Check if player wants to exit (hold for 2+ seconds or special gesture)
// For now, we'll add a simple long-press detection
if (input.type == INPUT_TOUCH_DOWN) {

View File

@@ -4,14 +4,14 @@
// Simple demo game to test the launcher
#include "demo_game.h"
#include "board_config.h"
#include "input_manager.h"
#include <stdio.h>
#include <string.h>
extern Font font_5x5_obj;
DemoGame::DemoGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
: Game(width, height, renderer, gui), tap_count(0), exit_requested(false) {
DemoGame::DemoGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
: Game(width, height, renderer, gui, input_manager), tap_count(0), exit_requested(false) {
}
void DemoGame::init() {
@@ -54,11 +54,11 @@ void DemoGame::draw() {
// Instructions
if (tap_count < 3) {
#ifdef BUTTON_KEY0_PIN
renderer->draw_string(width/2 - 80, y + 80, "Tap or press 3 times", true);
#else
renderer->draw_string(width/2 - 80, y + 80, "Tap 3 times to exit", true);
#endif
if (input_manager->has_buttons()) {
renderer->draw_string(width/2 - 80, y + 80, "Tap or press 3 times", true);
} else {
renderer->draw_string(width/2 - 80, y + 80, "Tap 3 times to exit", true);
}
} else {
renderer->draw_string(width/2 - 70, y + 80, "Exiting to menu...", true);
}

View File

@@ -16,11 +16,12 @@
*/
class DemoGame : public Game {
public:
DemoGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui);
DemoGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager);
void init() override;
bool update(const InputEvent& event) override;
void draw() override;
bool wants_to_exit() const override { return exit_requested; }
private:
int tap_count;

View File

@@ -4,15 +4,15 @@
// Game logic, input handling, and rendering for Tic-Tac-Toe
#include "tic_tac_toe.h"
#include "board_config.h"
#include "input_manager.h"
#include <stdio.h>
#include <string.h>
// Font reference from display system
extern Font font_5x5_obj;
TicTacToeGame::TicTacToeGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
: Game(width, height, renderer, gui) {
TicTacToeGame::TicTacToeGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
: Game(width, height, renderer, gui, input_manager) {
// Initialize statistics to zero
state.x_wins = 0;
state.o_wins = 0;
@@ -220,20 +220,20 @@ void TicTacToeGame::draw() {
} else {
renderer->draw_string(20, 40, "TIE GAME!", true);
}
#ifdef BUTTON_KEY0_PIN
renderer->draw_string(20, 55, "Touch or KEY0 to restart", true);
#else
renderer->draw_string(20, 55, "Touch to restart", true);
#endif
if (input_manager->has_buttons()) {
renderer->draw_string(20, 55, "Touch or KEY0 to restart", true);
} else {
renderer->draw_string(20, 55, "Touch to restart", true);
}
} else {
char turn_text[30];
snprintf(turn_text, sizeof(turn_text), "Turn: %s", state.current_player == 1 ? "X" : "O");
renderer->draw_string(20, 40, turn_text, true);
#ifdef BUTTON_KEY0_PIN
renderer->draw_string(20, 55, "Touch cell or use keys", true);
#else
renderer->draw_string(20, 55, "Touch cell to play", true);
#endif
if (input_manager->has_buttons()) {
renderer->draw_string(20, 55, "Touch cell or use keys", true);
} else {
renderer->draw_string(20, 55, "Touch cell to play", true);
}
}
// Draw game board (use same layout as touch detection!)

View File

@@ -26,8 +26,9 @@ public:
* @param height Display height in pixels
* @param renderer Pointer to low-level rendering interface
* @param gui Pointer to GUI drawing primitives
* @param input_manager Pointer to input manager for capability queries
*/
TicTacToeGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui);
TicTacToeGame(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager);
/**
* @brief Initialize game state (reset board, keep statistics)

View File

@@ -12,6 +12,9 @@
#include "display/low_level_render.h"
#include "display/low_level_gui.h"
// Forward declaration
class InputManager;
/**
* @brief Abstract base class for all games
*
@@ -31,9 +34,10 @@ public:
* @param height Display height in pixels
* @param renderer Pointer to low-level rendering interface
* @param gui Pointer to GUI drawing primitives
* @param input_manager Pointer to input manager for capability queries
*/
Game(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui)
: width(width), height(height), renderer(renderer), gui(gui) {
Game(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
: width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager) {
}
/**
@@ -68,6 +72,16 @@ public:
* The actual screen refresh happens in the main loop on Core 1.
*/
virtual void draw() = 0;
/**
* @brief Check if game wants to exit back to launcher
*
* Games can override this to signal they want to return to the menu.
* Default implementation returns false.
*
* @return true if game wants to exit, false to continue playing
*/
virtual bool wants_to_exit() const { return false; }
protected:
// Display dimensions
@@ -77,6 +91,9 @@ protected:
// Rendering interfaces (provided by basic1.cpp)
LowLevelRenderer* renderer;
LowLevelGUI* gui;
// Input manager for capability queries
InputManager* input_manager;
};
#endif // GAME_H

View File

@@ -4,19 +4,19 @@
// Menu system for selecting and launching games
#include "game_launcher.h"
#include "board_config.h"
#include "input_manager.h"
#include "display/low_level_render.h"
#include "display/low_level_gui.h"
#include <stdio.h>
GameLauncher::GameLauncher(uint16_t width, uint16_t height,
LowLevelRenderer* renderer, LowLevelGUI* gui)
: width(width), height(height), renderer(renderer), gui(gui),
LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
: width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager),
selected_index(0), selected_game(nullptr) {
}
void GameLauncher::register_game(const char* name, const char* description,
Game* (*factory)(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*)) {
Game* (*factory)(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*, InputManager*)) {
GameEntry entry;
entry.name = name;
entry.description = description;
@@ -51,11 +51,11 @@ void GameLauncher::draw() {
// Draw instructions at bottom
const char* instructions;
#ifdef BUTTON_KEY0_PIN
instructions = "Touch game or use KEY0/KEY1";
#else
instructions = "Touch game to play";
#endif
if (input_manager->has_buttons()) {
instructions = "Touch game or use KEY0/KEY1";
} else {
instructions = "Touch game to play";
}
renderer->set_font(&font_5x5_obj);
renderer->draw_string_scaled(30, height - 35, instructions, 2);
}
@@ -75,7 +75,7 @@ bool GameLauncher::update(const InputEvent& event) {
if (event.y >= y - 5 && event.y < y + MENU_ITEM_HEIGHT - 5) {
// Game selected - create instance
printf("Selected game: %s\n", games[i].name);
selected_game = games[i].factory(width, height, renderer, gui);
selected_game = games[i].factory(width, height, renderer, gui, input_manager);
if (selected_game) {
selected_game->init();
return true; // Signal game selected
@@ -100,7 +100,7 @@ bool GameLauncher::update(const InputEvent& event) {
// Select current game
if (selected_index >= 0 && selected_index < (int)games.size()) {
printf("Selected game: %s\n", games[selected_index].name);
selected_game = games[selected_index].factory(width, height, renderer, gui);
selected_game = games[selected_index].factory(width, height, renderer, gui, input_manager);
if (selected_game) {
selected_game->init();
return true; // Signal game selected

View File

@@ -14,6 +14,7 @@
// Forward declarations
class LowLevelRenderer;
class LowLevelGUI;
class InputManager;
/**
* @brief Game entry in launcher menu
@@ -22,7 +23,7 @@ struct GameEntry {
const char* name; // Display name
const char* description; // Short description
Game* (*factory)(uint16_t width, uint16_t height,
LowLevelRenderer* renderer, LowLevelGUI* gui); // Factory function
LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager); // Factory function
};
/**
@@ -42,8 +43,9 @@ public:
* @param height Display height in pixels
* @param renderer Pointer to low-level rendering interface
* @param gui Pointer to GUI drawing primitives
* @param input_manager Pointer to input manager for capability queries
*/
GameLauncher(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui);
GameLauncher(uint16_t width, uint16_t height, LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager);
/**
* @brief Register a game in the launcher
@@ -52,7 +54,7 @@ public:
* @param factory Function pointer to create game instance
*/
void register_game(const char* name, const char* description,
Game* (*factory)(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*));
Game* (*factory)(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*, InputManager*));
/**
* @brief Draw the launcher menu
@@ -88,6 +90,7 @@ private:
uint16_t height;
LowLevelRenderer* renderer;
LowLevelGUI* gui;
InputManager* input_manager;
std::vector<GameEntry> games;
int selected_index; // Currently highlighted game

View File

@@ -27,6 +27,18 @@ InputManager::InputManager(LowLevelTouch* touch, const GameConfig* config)
: touch(touch), config(config) {
}
bool InputManager::has_touch() const {
return touch != nullptr;
}
bool InputManager::has_buttons() const {
#ifdef BUTTON_KEY0_PIN
return true;
#else
return false;
#endif
}
InputEvent InputManager::process_touch_input(uint32_t* last_time) {
InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false};

View File

@@ -55,6 +55,18 @@ public:
* @return Constant string with gesture name
*/
static const char* get_gesture_name(uint8_t gesture_code);
/**
* @brief Check if touch input is available
* @return true if touch controller is present, false otherwise
*/
bool has_touch() const;
/**
* @brief Check if hardware buttons are available
* @return true if physical buttons are present, false otherwise
*/
bool has_buttons() const;
private:
LowLevelTouch* touch;