1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
//! Query the player's input and turn it into controls.
//!
//! This module defines two main structs: `PollingInputHandler` and `EventInputHandler`.
//!
//! `PollingInputHandler` is used when your game engine provides player input by polling for it. The GGEZ library
//! uses this method; you can call `keyboard::get_keyboard_input` and get what keys are pressed that way.
//!
//! `EventInputHandler` is used when your game engine provides player input by producing Input events. SDL2 and
//! browsers with WASM work this way. I believe Piston also works this way, but I've never worked with Piston.
//!
//! # API
//!
//! Both styles of input handling implement the same trait, `InputHandler`. It has functions for querying the state of the
//! controls, but not for updating them.
//! This lets you write your main loop function generic over the kind of input handler you have, in case you want
//! to port your game to platforms with different input styles.
//!
//! # Updating the Inputs
//!
//! It is VERY IMPORTANT that before you do *any* processing in your main loop you call `InputHandler::update`.
//! This tells the input handler that the next frame has elapsed.
//!
//! For `PollingInputHandler`, you must pass in a `&HashSet` containing all the pressed keys to `update`.
//!
//! `EventInputHandler` also exposes `input_down` and `input_up`, which you must call upon getting an input event.
//!
//! # Generics
//!
//! To work with all the ways game libraries deal with input handling, the Input Handlers are generic over
//! the inputs `I` that the game engine gives you, and the controls `C` that your game uses.
//!
//! Inputs must be hashable (so, `Hash + Eq + PartialEq`).
//!
//! Controls must be useable with the EnumMap crate. You can do that easily enough with `#[derive(Enum)]`. (Internally,
//! the handlers use EnumMap to map each control to how long it has been held down.).
//!
//! Both of them must impl Clone (or Copy).
//!
//! It will probably be useful to define some type aliases to prevent having to type out your generics over and over
//! again. For example:
//!
// we ignore this block of code because i really don't want to bother with importing
// all those game libraries...
//! ```ignore
//! ##[derive(Enum)]
//! enum MyControls {
//!     Up,
//!     Down,
//!     Left,
//!     Right,
//!     Jump,
//!     Pause,
//! }
//!
//! /// When you're writing a game with GGEZ
//! mod ggez_game {
//!     type InputHandler = PollingInputHandler<ggez::input::keyboard::KeyCode, super::MyControls>;
//! }
//!
//! /// When you're writing a game with Piston
//! mod piston_game {
//!     type InputHandler = EventInputHandler<piston::input::keyboard::Key, super::MyControls>;
//! }
//!
//! /// When you're writing a game for the browser with wasm-pack or similar
//! mod browser_wasm_js_something {
//!     type InputHandler = EventInputHandler<String, super::MyControls>;
//! }
//!
//! ```
//!
//! # Changing Controls on the Fly
//!
//! Both input handlers support changing controls on the fly (perhaps through some sort of menu).
//! Call `listen_for_control_change` with the control you want to update the input for, and the next time an input
//! is received, that control will be associated with that input.
//!
//! If multiple controls are pressed at the same time during a frame where the input handler is
//! listening for a control change, it's undefined which one the control will be set to.
//! It will be set to one of them, however.

mod polling;
pub use polling::PollingInputHandler;
mod event;
pub use event::EventInputHandler;

use std::hash::Hash;

use enum_map::Enum;

/// The InputHandler trait, makng sure that both styles of input handling
/// expose the same API.
pub trait InputHandler<I: Hash + Eq + PartialEq + Clone, C: Enum<u32> + Clone> {
    /// Is this input pressed down?
    /// i.e. is the player pressing the button?
    fn pressed(&self, control: C) -> bool;

    /// Is this input released?
    /// i.e. is the player *not* pressing the button?
    fn released(&self, control: C) -> bool;

    /// Is this input being clicked down?
    /// i.e. was it up last frame, but down this frame?
    fn clicked_down(&self, control: C) -> bool;
}