Files
basic1/lib/input_manager.cpp

210 lines
6.3 KiB
C++

// ============================================================================
// INPUT MANAGER IMPLEMENTATION
// ============================================================================
// Processes touch and button inputs into InputEvent objects
#include "input_manager.h"
#include "pico/stdlib.h"
#include "board_config.h"
#include <stdio.h>
// 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;
}