reaction 0.2.0

Universal low-latency input handling for game engines
Documentation
use crate::error::Result;
use crate::raw_input::common::{RawInputData, RawInputProvider};
use crate::state::advanced::AdvancedInputState;
// use crate::types::*; // KeyCode and MouseButton should be in prelude or types

/// Integrates raw input provider with AdvancedInputState.
pub struct InputSystemManager {
    raw_input_provider: Box<dyn RawInputProvider>,
    input_state: AdvancedInputState,
}

impl InputSystemManager {
    pub fn new(raw_input_provider: Box<dyn RawInputProvider>) -> Result<Self> {
        let mut provider = raw_input_provider;
        provider.initialize()?;

        Ok(Self {
            raw_input_provider: provider,
            input_state: AdvancedInputState::new(),
        })
    }

    /// Pulls all pending events from the raw provider and feeds them into the internal state.
    pub fn poll_and_update(&mut self, frame: u32) -> Result<()> {
        while let Some(raw_data) = self.raw_input_provider.poll()? {
            self.feed_raw_input(&raw_data, frame);
        }
        Ok(())
    }

    fn feed_raw_input(&mut self, raw_data: &RawInputData, frame: u32) {
        let timestamp = self.input_state.time;

        for (key, &is_pressed) in &raw_data.keys {
            if is_pressed {
                self.input_state.keyboard.press(*key, timestamp, frame);
            } else {
                self.input_state.keyboard.release(*key, frame);
            }
        }

        for (button, &is_pressed) in &raw_data.mouse_buttons {
            if is_pressed {
                self.input_state.mouse.button_press(*button, frame);
            } else {
                self.input_state.mouse.button_release(*button, frame);
            }
        }

        let (dx, dy) = raw_data.mouse_delta;
        self.input_state.mouse.move_rel(dx as f32, dy as f32);
    }

    /// Advance frame, clearing transient input state.
    pub fn end_frame(&mut self, delta_time_ms: f32) {
        self.input_state.end_frame(delta_time_ms);
    }

    /// Get reference to current input state.
    pub fn state(&self) -> &AdvancedInputState {
        &self.input_state
    }

    /// Get mutable reference (dangerous, use sparingly).
    pub fn state_mut(&mut self) -> &mut AdvancedInputState {
        &mut self.input_state
    }

    /// Shutdown and release resources.
    pub fn shutdown(mut self) -> Result<()> {
        self.raw_input_provider.shutdown()
    }
}

pub struct ReactionPlugin;

impl ReactionPlugin {
    // Note: World is from archetype_ecs, which is a dependency
    // We assume the user wants this integration
    /*
    pub fn setup(world: &mut World) {
        // Initialize system manager (requires raw input provider)
        // For now, just register empty AdvancedInputState
        world.insert_resource(AdvancedInputState::new());
    }
    */
}

// ECS system to update input each frame.
// pub fn poll_input_system(manager: &mut InputSystemManager, dt: f32) -> Result<()> {
//     manager.poll_and_update(manager.state().frame)?;
//     manager.end_frame(dt);
//     Ok(())
// }