// ============================================================================ // INPUT MANAGER IMPLEMENTATION // ============================================================================ // Processes touch and button inputs into InputEvent objects #include "input_manager.h" #include "pico/stdlib.h" #include "board_config.h" #include // External interrupt flags from basic1.cpp extern volatile bool touch_interrupt_flag; extern volatile bool touch_event_down; extern volatile bool button_key0_pressed; extern volatile bool button_key1_pressed; // GameConfig struct definition (matches basic1.cpp) struct GameConfig { uint32_t touch_debounce_ms; uint32_t button_debounce_ms; bool enable_gestures; bool enable_continuous_draw; bool debug_verbose; }; 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}; // Check if touch interrupt flag is set if (!touch_interrupt_flag) { return event; // No touch event } printf("Processing touch: flag=%d, event_down=%d\n", touch_interrupt_flag, touch_event_down); // Don't clear the flag yet - we may still be processing continuous touch // Check if touch is active if (!touch_event_down) { // Touch released - reset timing for next touch touch_interrupt_flag = false; *last_time = 0; // Reset so next touch is treated as new touch-down event.type = INPUT_TOUCH_UP; event.valid = true; printf("Touch UP\n"); return event; } // Touch is down - check debounce timing uint32_t now = to_ms_since_boot(get_absolute_time()); if (now - *last_time < config->touch_debounce_ms) { return event; // Too soon, skip } // Read touch data TouchData touch_data; if (!touch || !touch->read_touch(&touch_data)) { // Clear flag even if read failed to prevent getting stuck touch_interrupt_flag = false; printf("Touch read FAILED\n"); return event; // Read failed } // Clear the interrupt flag after successfully reading touch data // This allows the next touch interrupt to be detected touch_interrupt_flag = false; printf("Touch DOWN at (%d,%d)\n", touch_data.points[0].x, touch_data.points[0].y); // Populate event structure event.x = touch_data.points[0].x; event.y = touch_data.points[0].y; event.pressure = touch_data.points[0].pressure; event.gesture_code = touch_data.gesture; event.valid = true; // Determine event type if (*last_time == 0) { event.type = INPUT_TOUCH_DOWN; // Check for virtual buttons InputType virtual_type; if (check_virtual_buttons(event.x, event.y, virtual_type)) { event.type = virtual_type; event.button_id = (virtual_type == INPUT_BUTTON_0) ? 0 : 1; printf("Virtual button %d pressed via touch\n", event.button_id); } } else { event.type = INPUT_TOUCH_MOVE; } // Handle gesture events if (config->enable_gestures && touch_data.gesture != 0) { event.type = INPUT_GESTURE; if (config->debug_verbose) { printf("Gesture: 0x%02X (%s)\n", event.gesture_code, get_gesture_name(event.gesture_code)); } } *last_time = now; return event; } InputEvent InputManager::process_button_input() { InputEvent event = {INPUT_NONE, 0, 0, 0, 0, 0, false}; #ifdef BUTTON_KEY0_PIN // Check KEY0 if (button_key0_pressed) { button_key0_pressed = false; sleep_ms(config->button_debounce_ms); if (gpio_get(BUTTON_KEY0_PIN) == 0) { // Verify still pressed event.type = INPUT_BUTTON_0; event.button_id = 0; event.valid = true; if (config->debug_verbose) { printf("Button KEY0 action triggered\n"); } return event; } } #ifdef BUTTON_KEY1_PIN // Check KEY1 if (button_key1_pressed) { button_key1_pressed = false; sleep_ms(config->button_debounce_ms); if (gpio_get(BUTTON_KEY1_PIN) == 0) { // Verify still pressed event.type = INPUT_BUTTON_1; event.button_id = 1; event.valid = true; if (config->debug_verbose) { printf("Button KEY1 action triggered\n"); } return event; } } #endif #endif return event; } const char* InputManager::get_gesture_name(uint8_t gesture_code) { switch(gesture_code) { case 0x10: return "Move Up"; case 0x14: return "Move Right"; case 0x18: return "Move Down"; case 0x1C: return "Move Left"; case 0x48: return "Zoom In"; case 0x49: return "Zoom Out"; default: return "Unknown"; } } void InputManager::get_virtual_button_regions(int* a_rect, int* b_rect) const { for (int i = 0; i < 4; i++) { a_rect[i] = v_button_a[i]; b_rect[i] = v_button_b[i]; } } void InputManager::set_virtual_button_regions(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) { v_button_a[0] = ax; v_button_a[1] = ay; v_button_a[2] = aw; v_button_a[3] = ah; v_button_b[0] = bx; v_button_b[1] = by; v_button_b[2] = bw; v_button_b[3] = bh; v_buttons_active = true; } void InputManager::clear_virtual_button_regions() { v_buttons_active = false; } bool InputManager::check_virtual_buttons(int16_t x, int16_t y, InputType& out_type) const { if (!v_buttons_active) return false; if (x >= v_button_a[0] && x <= v_button_a[0] + v_button_a[2] && y >= v_button_a[1] && y <= v_button_a[1] + v_button_a[3]) { out_type = INPUT_BUTTON_0; return true; } if (x >= v_button_b[0] && x <= v_button_b[0] + v_button_b[2] && y >= v_button_b[1] && y <= v_button_b[1] + v_button_b[3]) { out_type = INPUT_BUTTON_1; return true; } return false; }