Aplicación del Principio de Responsabilidad Única (SRP) - Fase 1/6
## Cambios realizados
### Nuevos archivos
- source/input/input_handler.h - Declaración clase InputHandler
- source/input/input_handler.cpp - Procesamiento eventos SDL (~180 líneas)
- REFACTOR_PLAN.md - Documento de seguimiento del refactor
### Modificaciones en Engine
- **engine.h**: Agregados 24 métodos públicos para InputHandler
- **engine.cpp**:
- Eliminado handleEvents() (420 líneas)
- Implementados métodos públicos wrapper (~180 líneas)
- Renombrados métodos internos con sufijo `Internal`:
* toggleShapeMode → toggleShapeModeInternal
* activateShape → activateShapeInternal
* switchTexture → switchTextureInternal
- Bucle run() simplificado (5 → 12 líneas)
### Actualización build
- CMakeLists.txt: Agregado source/input/*.cpp a archivos fuente
## Impacto
- **Líneas extraídas**: ~430 del switch gigante de handleEvents()
- **Compilación**: ✅ Exitosa sin errores
- **Funcionalidad**: ✅ 100% preservada
## Beneficios
- ✅ Engine desacoplado de eventos SDL
- ✅ InputHandler stateless (fácilmente testeable)
- ✅ Clara separación detección input vs ejecución lógica
- ✅ Preparado para testing unitario de inputs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
267 lines
8.6 KiB
C++
267 lines
8.6 KiB
C++
#include "input_handler.h"
|
|
|
|
#include <SDL3/SDL_keycode.h> // for SDL_Keycode
|
|
#include <string> // for std::string, std::to_string
|
|
|
|
#include "../engine.h" // for Engine
|
|
#include "../external/mouse.h" // for Mouse namespace
|
|
|
|
bool InputHandler::processEvents(Engine& engine) {
|
|
SDL_Event event;
|
|
while (SDL_PollEvent(&event)) {
|
|
// Procesar eventos de ratón (auto-ocultar cursor)
|
|
Mouse::handleEvent(event);
|
|
|
|
// Salir del bucle si se detecta una petición de cierre
|
|
if (event.type == SDL_EVENT_QUIT) {
|
|
return true; // Solicitar salida
|
|
}
|
|
|
|
// Procesar eventos de teclado
|
|
if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) {
|
|
switch (event.key.key) {
|
|
case SDLK_ESCAPE:
|
|
return true; // Solicitar salida
|
|
|
|
case SDLK_SPACE:
|
|
engine.pushBallsAwayFromGravity();
|
|
break;
|
|
|
|
case SDLK_G:
|
|
engine.handleGravityToggle();
|
|
break;
|
|
|
|
// Controles de dirección de gravedad con teclas de cursor
|
|
case SDLK_UP:
|
|
engine.handleGravityDirectionChange(GravityDirection::UP, "Gravedad Arriba");
|
|
break;
|
|
|
|
case SDLK_DOWN:
|
|
engine.handleGravityDirectionChange(GravityDirection::DOWN, "Gravedad Abajo");
|
|
break;
|
|
|
|
case SDLK_LEFT:
|
|
engine.handleGravityDirectionChange(GravityDirection::LEFT, "Gravedad Izquierda");
|
|
break;
|
|
|
|
case SDLK_RIGHT:
|
|
engine.handleGravityDirectionChange(GravityDirection::RIGHT, "Gravedad Derecha");
|
|
break;
|
|
|
|
case SDLK_V:
|
|
engine.toggleVSync();
|
|
break;
|
|
|
|
case SDLK_H:
|
|
engine.toggleDebug();
|
|
break;
|
|
|
|
// Toggle Física ↔ Última Figura (antes era C)
|
|
case SDLK_F:
|
|
engine.toggleShapeMode();
|
|
break;
|
|
|
|
// Selección directa de figuras 3D
|
|
case SDLK_Q:
|
|
engine.activateShape(ShapeType::SPHERE, "Esfera");
|
|
break;
|
|
|
|
case SDLK_W:
|
|
engine.activateShape(ShapeType::LISSAJOUS, "Lissajous");
|
|
break;
|
|
|
|
case SDLK_E:
|
|
engine.activateShape(ShapeType::HELIX, "Hélice");
|
|
break;
|
|
|
|
case SDLK_R:
|
|
engine.activateShape(ShapeType::TORUS, "Toroide");
|
|
break;
|
|
|
|
case SDLK_T:
|
|
engine.activateShape(ShapeType::CUBE, "Cubo");
|
|
break;
|
|
|
|
case SDLK_Y:
|
|
engine.activateShape(ShapeType::CYLINDER, "Cilindro");
|
|
break;
|
|
|
|
case SDLK_U:
|
|
engine.activateShape(ShapeType::ICOSAHEDRON, "Icosaedro");
|
|
break;
|
|
|
|
case SDLK_I:
|
|
engine.activateShape(ShapeType::ATOM, "Átomo");
|
|
break;
|
|
|
|
case SDLK_O:
|
|
engine.activateShape(ShapeType::PNG_SHAPE, "Forma PNG");
|
|
break;
|
|
|
|
// Ciclar temas de color (movido de T a B)
|
|
case SDLK_B:
|
|
{
|
|
// Detectar si Shift está presionado
|
|
SDL_Keymod modstate = SDL_GetModState();
|
|
if (modstate & SDL_KMOD_SHIFT) {
|
|
// Shift+B: Ciclar hacia atrás (tema anterior)
|
|
engine.cycleTheme(false);
|
|
} else {
|
|
// B solo: Ciclar hacia adelante (tema siguiente)
|
|
engine.cycleTheme(true);
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Temas de colores con teclado numérico (con transición suave)
|
|
case SDLK_KP_1:
|
|
engine.switchThemeByNumpad(1);
|
|
break;
|
|
|
|
case SDLK_KP_2:
|
|
engine.switchThemeByNumpad(2);
|
|
break;
|
|
|
|
case SDLK_KP_3:
|
|
engine.switchThemeByNumpad(3);
|
|
break;
|
|
|
|
case SDLK_KP_4:
|
|
engine.switchThemeByNumpad(4);
|
|
break;
|
|
|
|
case SDLK_KP_5:
|
|
engine.switchThemeByNumpad(5);
|
|
break;
|
|
|
|
case SDLK_KP_6:
|
|
engine.switchThemeByNumpad(6);
|
|
break;
|
|
|
|
case SDLK_KP_7:
|
|
engine.switchThemeByNumpad(7);
|
|
break;
|
|
|
|
case SDLK_KP_8:
|
|
engine.switchThemeByNumpad(8);
|
|
break;
|
|
|
|
case SDLK_KP_9:
|
|
engine.switchThemeByNumpad(9);
|
|
break;
|
|
|
|
case SDLK_KP_0:
|
|
engine.switchThemeByNumpad(0);
|
|
break;
|
|
|
|
// Toggle de página de temas (Numpad Enter)
|
|
case SDLK_KP_ENTER:
|
|
engine.toggleThemePage();
|
|
break;
|
|
|
|
// Cambio de sprite/textura dinámico
|
|
case SDLK_N:
|
|
engine.switchTexture();
|
|
break;
|
|
|
|
// Control de escala de figura (solo en modo SHAPE)
|
|
case SDLK_KP_PLUS:
|
|
engine.handleShapeScaleChange(true); // Aumentar
|
|
break;
|
|
|
|
case SDLK_KP_MINUS:
|
|
engine.handleShapeScaleChange(false); // Disminuir
|
|
break;
|
|
|
|
case SDLK_KP_MULTIPLY:
|
|
engine.resetShapeScale();
|
|
break;
|
|
|
|
case SDLK_KP_DIVIDE:
|
|
engine.toggleDepthZoom();
|
|
break;
|
|
|
|
// Cambio de número de pelotas (escenarios 1-8)
|
|
case SDLK_1:
|
|
engine.changeScenario(0, "10 Pelotas");
|
|
break;
|
|
|
|
case SDLK_2:
|
|
engine.changeScenario(1, "50 Pelotas");
|
|
break;
|
|
|
|
case SDLK_3:
|
|
engine.changeScenario(2, "100 Pelotas");
|
|
break;
|
|
|
|
case SDLK_4:
|
|
engine.changeScenario(3, "500 Pelotas");
|
|
break;
|
|
|
|
case SDLK_5:
|
|
engine.changeScenario(4, "1,000 Pelotas");
|
|
break;
|
|
|
|
case SDLK_6:
|
|
engine.changeScenario(5, "5,000 Pelotas");
|
|
break;
|
|
|
|
case SDLK_7:
|
|
engine.changeScenario(6, "10,000 Pelotas");
|
|
break;
|
|
|
|
case SDLK_8:
|
|
engine.changeScenario(7, "50,000 Pelotas");
|
|
break;
|
|
|
|
// Controles de zoom dinámico (solo si no estamos en fullscreen)
|
|
case SDLK_F1:
|
|
engine.handleZoomOut();
|
|
break;
|
|
|
|
case SDLK_F2:
|
|
engine.handleZoomIn();
|
|
break;
|
|
|
|
// Control de pantalla completa
|
|
case SDLK_F3:
|
|
engine.toggleFullscreen();
|
|
break;
|
|
|
|
// Modo real fullscreen (cambia resolución interna)
|
|
case SDLK_F4:
|
|
engine.toggleRealFullscreen();
|
|
break;
|
|
|
|
// Toggle escalado entero/estirado (solo en fullscreen F3)
|
|
case SDLK_F5:
|
|
engine.toggleIntegerScaling();
|
|
break;
|
|
|
|
// Toggle Modo DEMO COMPLETO (auto-play) o Pausar tema dinámico (Shift+D)
|
|
case SDLK_D:
|
|
// Shift+D = Pausar tema dinámico
|
|
if (event.key.mod & SDL_KMOD_SHIFT) {
|
|
engine.pauseDynamicTheme();
|
|
} else {
|
|
// D sin Shift = Toggle DEMO ↔ SANDBOX
|
|
engine.toggleDemoMode();
|
|
}
|
|
break;
|
|
|
|
// Toggle Modo DEMO LITE (solo física/figuras)
|
|
case SDLK_L:
|
|
engine.toggleDemoLiteMode();
|
|
break;
|
|
|
|
// Toggle Modo LOGO (easter egg - marca de agua)
|
|
case SDLK_K:
|
|
engine.toggleLogoMode();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false; // No se solicitó salida
|
|
}
|