browser_input 0.2.0

Ergonomic input handling for WebAssembly applications in the browser with keyboard, mouse, and event processing
# 🎮 browser_input

> **Ergonomic input handling for WebAssembly applications in the browser**

A lightweight, efficient input handling library specifically designed for Rust WebAssembly applications. Provides a unified interface for capturing and processing keyboard, mouse, and other input events in web browsers.

## ✨ Features

### 🎯 **Input Types**
- **Keyboard Input** - Full keyboard event capture with modifier support
-**Mouse Buttons** - Left, right, middle mouse button handling
-**Mouse Movement** - Precise pointer position and movement tracking
-**Mouse Wheel** - Scroll events (planned)

### 🛠️ **Core Capabilities**
- **Event Queue System** - Buffered input events with modifier key states
- **State Tracking** - Real-time key and button state queries
- **Modifier Support** - Alt, Ctrl, Shift key combination detection
- **Browser Integration** - Direct DOM event binding with WebAssembly
- **Memory Efficient** - Minimal overhead for web deployment

## 🚀 Quick Start

### Add to Your Project
```toml
[dependencies]
browser_input = { workspace = true, features = ["enabled"] }
```

### Basic Input Loop
```rust
use browser_input::*;

let mut input = Input::new( None, CLIENT );

loop
{
  // Update input state from DOM events
  input.update_state();

  // Process event queue
  for Event { event_type, alt, ctrl, shift } in input.event_queue().as_slice()
  {
    match event_type
    {
      EventType::MouseButton( button, Action::Press ) =>
      {
        println!( "Mouse button {:?} pressed with modifiers: Alt={}, Ctrl={}, Shift={}", 
                 button, alt, ctrl, shift );
      }
      EventType::KeyBoard( key, Action::Press ) =>
      {
        println!( "Key {:?} pressed", key );
      }
      _ => {}
    }
  }

  // Direct state queries
  let pointer_pos = input.pointer_position();
  let is_w_down = input.is_key_down( keyboard::KeyboardKey::KeyW );
  let is_space_down = input.is_key_down( keyboard::KeyboardKey::Space );

  if is_w_down && ctrl {
    // Handle Ctrl+W combination
  }

  // CRITICAL: Clear events at end of frame
  input.clear_events();
}
```

### Game Input Example
```rust
use browser_input::*;

struct GameInput
{
  input: Input,
  player_speed: f32,
}

impl GameInput
{
  pub fn new() -> Self
  {
    Self
    {
      input: Input::new( None, CLIENT ),
      player_speed: 5.0,
    }
  }

  pub fn update( &mut self ) -> PlayerMovement
  {
    self.input.update_state();
    
    let mut movement = PlayerMovement::default();
    
    // WASD movement
    if self.input.is_key_down( keyboard::KeyboardKey::KeyW ) {
      movement.forward = self.player_speed;
    }
    if self.input.is_key_down( keyboard::KeyboardKey::KeyS ) {
      movement.backward = self.player_speed;
    }
    if self.input.is_key_down( keyboard::KeyboardKey::KeyA ) {
      movement.left = self.player_speed;
    }
    if self.input.is_key_down( keyboard::KeyboardKey::KeyD ) {
      movement.right = self.player_speed;
    }
    
    // Mouse look
    movement.mouse_pos = self.input.pointer_position();
    
    // Process discrete events
    for event in self.input.event_queue().as_slice()
    {
      if let EventType::MouseButton( MouseButton::Left, Action::Press ) = event.event_type
      {
        movement.shoot = true;
      }
    }
    
    self.input.clear_events();
    movement
  }
}

#[ derive( Default ) ]
struct PlayerMovement
{
  forward: f32,
  backward: f32,
  left: f32,
  right: f32,
  mouse_pos: ( f32, f32 ),
  shoot: bool,
}
```

## 📚 API Reference

### Core Types

#### `Input`
Main input manager struct:
```rust
impl Input
{
  // Create new input handler
  pub fn new( canvas: Option< web_sys::HtmlCanvasElement >, client: ClientType ) -> Self;
  
  // Update state from DOM events (call once per frame)
  pub fn update_state( &mut self );
  
  // Get current event queue
  pub fn event_queue( &self ) -> &Vec< Event >;
  
  // Clear event queue (call at end of frame)
  pub fn clear_events( &mut self );
  
  // Query key state
  pub fn is_key_down( &self, key: keyboard::KeyboardKey ) -> bool;
  
  // Get current pointer position
  pub fn pointer_position( &self ) -> ( f32, f32 );
}
```

#### `Event`
Input event with modifier keys:
```rust
pub struct Event
{
  pub event_type: EventType,
  pub alt: bool,
  pub ctrl: bool,
  pub shift: bool,
}
```

#### `EventType`
Different types of input events:
```rust
pub enum EventType
{
  MouseButton( MouseButton, Action ),
  KeyBoard( keyboard::KeyboardKey, Action ),
  MouseMove( f32, f32 ), // x, y coordinates
}
```

### Key Constants

#### Keyboard Keys
```rust
use browser_input::keyboard::KeyboardKey;

// Movement keys
KeyboardKey::KeyW
KeyboardKey::KeyA
KeyboardKey::KeyS
KeyboardKey::KeyD

// Arrow keys
KeyboardKey::ArrowUp
KeyboardKey::ArrowDown
KeyboardKey::ArrowLeft
KeyboardKey::ArrowRight

// Action keys
KeyboardKey::Space
KeyboardKey::Enter
KeyboardKey::Escape
KeyboardKey::Tab

// Number keys
KeyboardKey::Digit1
KeyboardKey::Digit2
// ... etc
```

#### Mouse Buttons
```rust
use browser_input::MouseButton;

MouseButton::Left
MouseButton::Right
MouseButton::Middle
```

## 🎯 Usage Patterns

### Real-Time Controls
For games and interactive applications requiring immediate response:
```rust
// Query current state directly
let move_up = input.is_key_down( KeyboardKey::KeyW );
let move_down = input.is_key_down( KeyboardKey::KeyS );
let shooting = input.is_key_down( KeyboardKey::Space );
```

### Event-Driven Actions  
For UI interactions and discrete actions:
```rust
for event in input.event_queue().as_slice()
{
  match event.event_type
  {
    EventType::KeyBoard( KeyboardKey::Enter, Action::Press ) => {
      // Handle menu selection
    }
    EventType::MouseButton( MouseButton::Left, Action::Release ) => {
      // Handle button click
    }
    _ => {}
  }
}
```

### Modifier Key Combinations
```rust
for Event { event_type, ctrl, alt, shift } in input.event_queue().as_slice()
{
  if let EventType::KeyBoard( KeyboardKey::KeyS, Action::Press ) = event_type
  {
    if *ctrl {
      save_file(); // Ctrl+S
    } else if *alt {
      save_as(); // Alt+S
    } else {
      // Regular 'S' press
    }
  }
}
```

## ⚠️ Important Notes

### Frame Management
- **Always call `update_state()`** at the beginning of your main loop
- **Always call `clear_events()`** at the end of your main loop
- Failure to clear events will cause the event queue to grow indefinitely

### Canvas Binding
```rust
// Bind to specific canvas
let canvas = document.get_element_by_id( "game-canvas" )
  .unwrap()
  .dyn_into::< web_sys::HtmlCanvasElement >()
  .unwrap();
let input = Input::new( Some( canvas ), CLIENT );

// Bind to entire document (default)
let input = Input::new( None, CLIENT );
```

### Performance
- Event processing is O(n) where n is the number of events per frame
- State queries (`is_key_down`) are O(1) constant time
- Memory usage scales with the number of simultaneous key presses

## 🤝 Contributing

This crate is part of the CGTools workspace. Feel free to submit issues and pull requests on GitHub.

## 📄 License

MIT