From f860d4f5e62bdc8c2d0dd089b05c2919cc397414 Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Fri, 30 Jan 2026 22:07:31 -0500 Subject: [PATCH] input manager provides ground of truth on device input choise --- basic1.cpp | 17 ++++++++++++----- games/demo_game.cpp | 16 ++++++++-------- games/demo_game.h | 3 ++- games/tic_tac_toe.cpp | 26 +++++++++++++------------- games/tic_tac_toe.h | 3 ++- lib/game.h | 21 +++++++++++++++++++-- lib/game_launcher.cpp | 22 +++++++++++----------- lib/game_launcher.h | 9 ++++++--- lib/input_manager.cpp | 12 ++++++++++++ lib/input_manager.h | 12 ++++++++++++ 10 files changed, 97 insertions(+), 44 deletions(-) diff --git a/basic1.cpp b/basic1.cpp index 3e91c86..871da05 100644 --- a/basic1.cpp +++ b/basic1.cpp @@ -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) { diff --git a/games/demo_game.cpp b/games/demo_game.cpp index 55a3912..8bf8edc 100644 --- a/games/demo_game.cpp +++ b/games/demo_game.cpp @@ -4,14 +4,14 @@ // Simple demo game to test the launcher #include "demo_game.h" -#include "board_config.h" +#include "input_manager.h" #include #include 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); } diff --git a/games/demo_game.h b/games/demo_game.h index d91f9e2..5e329a3 100644 --- a/games/demo_game.h +++ b/games/demo_game.h @@ -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; diff --git a/games/tic_tac_toe.cpp b/games/tic_tac_toe.cpp index b47bc3b..6dcb61f 100644 --- a/games/tic_tac_toe.cpp +++ b/games/tic_tac_toe.cpp @@ -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 #include // 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!) diff --git a/games/tic_tac_toe.h b/games/tic_tac_toe.h index 866dece..289f9cc 100644 --- a/games/tic_tac_toe.h +++ b/games/tic_tac_toe.h @@ -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) diff --git a/lib/game.h b/lib/game.h index 4fcbf53..a4ea069 100644 --- a/lib/game.h +++ b/lib/game.h @@ -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 diff --git a/lib/game_launcher.cpp b/lib/game_launcher.cpp index f49cac1..02daece 100644 --- a/lib/game_launcher.cpp +++ b/lib/game_launcher.cpp @@ -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 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 diff --git a/lib/game_launcher.h b/lib/game_launcher.h index 196c9f1..99818a0 100644 --- a/lib/game_launcher.h +++ b/lib/game_launcher.h @@ -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 games; int selected_index; // Currently highlighted game diff --git a/lib/input_manager.cpp b/lib/input_manager.cpp index c3de55d..e023629 100644 --- a/lib/input_manager.cpp +++ b/lib/input_manager.cpp @@ -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}; diff --git a/lib/input_manager.h b/lib/input_manager.h index 4d7bfb5..ae65c11 100644 --- a/lib/input_manager.h +++ b/lib/input_manager.h @@ -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;