Skip to content

[Feature] Input Action/Axis Mapping and Mouse Press Coordinates #84

@vmarcella

Description

@vmarcella

Overview

Implement an input mapping system with action/axis bindings and button state tracking. Also fix mouse press/release events to include cursor coordinates instead of hard-coded zeros.

Current State

Mouse events use placeholder coordinates:

// crates/lambda-rs/src/runtimes/application.rs:286-296
let event = match state {
  ElementState::Pressed => Mouse::Pressed {
    button,
    x: 0.0,  // FIXME: should be cursor position
    y: 0.0,
    device_id: 0,
  },
  ElementState::Released => Mouse::Released {
    button,
    x: 0.0,  // FIXME: should be cursor position
    y: 0.0,
    device_id: 0,
  },
};

Cursor position is tracked in CursorMoved events but not propagated to press/release events.

No input abstraction layer

  • Raw keyboard and mouse events are exposed directly
  • Applications must implement their own state tracking and action mapping
  • No concept of "actions" (jump, shoot) or "axes" (move horizontal, look vertical)

Scope

Bug Fix: Mouse Coordinates

  • Track last known cursor position in the event loop
  • Populate x and y fields in MousePressed and Mouse::Released events

Input Mapping System

Input Mapping System

  • InputAction: named action bound to one or more keys/buttons
  • InputAxis: named axis bound to keys (digital) or mouse/gamepad axes (analog)
  • InputState: tracks current button states and state transitions (just pressed, just released)
  • InputMap: configuration object mapping names to bindings

Proposed API

pub struct InputAction {
  name: String,
  bindings: Vec<InputBinding>,
}

/// A named axis with a value in [-1.0, 1.0] or [0.0, 1.0].
pub struct InputAxis {
  name: String,
  positive: Vec<InputBinding>,
  negative: Vec<InputBinding>,
}

pub enum InputBinding {
  Key(VirtualKey),
  MouseButton(Button),
  // Future: GamepadButton, GamepadAxis
}

/// Tracks input state for a frame.
pub struct InputState {
  // ...internal state...
}

impl InputState {
  /// Update state from an event. Call once per event.
  pub fn process_event(&mut self, event: &Events);
  
  /// Returns true if the action is currently held.
  pub fn is_action_held(&self, action: &str) -> bool;
  
  /// Returns true only on the frame the action was first pressed.
  pub fn is_action_just_pressed(&self, action: &str) -> bool;
  
  /// Returns true only on the frame the action was released.
  pub fn is_action_just_released(&self, action: &str) -> bool;
  
  /// Returns the current axis value in [-1.0, 1.0].
  pub fn get_axis(&self, axis: &str) -> f32;
  
  /// Call at end of frame to reset transition states.
  pub fn end_frame(&mut self);
}

pub struct InputMap {
  actions: HashMap<String, InputAction>,
  axes: HashMap<String, InputAxis>,
}

impl InputMap {
  pub fn new() -> Self;
  pub fn add_action(&mut self, name: &str, bindings: &[InputBinding]) -> &mut Self;
  pub fn add_axis(&mut self, name: &str, positive: &[InputBinding], negative: &[InputBinding]) -> &mut Self;
}

Example Usage

// Configure input map
let mut input_map = InputMap::new();
input_map
  .add_action("jump", &[InputBinding::Key(VirtualKey::Space)])
  .add_action("fire", &[InputBinding::MouseButton(Button::Left)])
  .add_axis("horizontal", 
    &[InputBinding::Key(VirtualKey::D), InputBinding::Key(VirtualKey::Right)],
    &[InputBinding::Key(VirtualKey::A), InputBinding::Key(VirtualKey::Left)],
  );

// In update loop
input_state.process_event(&event);

if input_state.is_action_just_pressed("jump") {
  player.jump();
}

let move_x = input_state.get_axis("horizontal");
player.velocity.x = move_x * speed;

// End of frame
input_state.end_frame();

Acceptance Criteria

  • Mouse press/release events include actual cursor coordinates
  • InputAction struct with multiple bindings
  • InputAxis struct with positive/negative bindings
  • InputState with held, just_pressed, just_released queries
  • InputMap for declarative input configuration
  • Digital-to-axis conversion for keyboard axes
  • end_frame() to reset transition states
  • Example demonstrating input mapping
  • Documentation for input system usage

Notes

  • Gamepad support is out of scope for initial implementation
  • Mouse delta (relative motion) MAY be added as a built-in axis
  • Considering serialization support for InputMap (e.g. from config file)
  • This specification is subject to change due to a personal desire to improve the ApplicationRuntime event loop and to also improve how components process events.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions