# key-input

A `no_std` library for high-level key input handling in embedded systems.

Provides debouncing, multi-click detection, hold detection, and long press support through a state machine approach.

## Features

- **Debounce** — Filters out mechanical key bounce noise
- **Multi-click** — Detects single, double, and triple clicks
- **Hold** — Detects when a key is held down beyond a threshold
- **Long press** (feature: `long-press`) — Detects long press events, with single-trigger or repeat modes
- **Long press repeat** (feature: `long-press-repeat`) — Repeatedly triggers at a set interval while the key is held

## Usage

### Implement the `KeyDriver` trait

Provide hardware access by implementing `KeyDriver`:

```rust
use key_input::{KeyDriver, TU};

struct MyDriver;

impl KeyDriver<u32> for MyDriver {
    fn now(&self) -> u32 {
        // Return current time (e.g., from a timer peripheral)
        timer_now()
    }

    fn elapsed(&self, last: u32) -> TU {
        // Return milliseconds elapsed since `last`
        (self.now().wrapping_sub(last)) as TU
    }

    fn scan(&mut self) -> Option<u8> {
        // Return Some(key_code) if a key is pressed, None otherwise
        if key_is_pressed() {
            Some(1)
        } else {
            None
        }
    }
}
```

### Optionally customize `KeyConfig`

Override timing constants by implementing `KeyConfig`:

```rust
use key_input::config::KeyConfig;
use key_input::TU;

struct MyConfig;

impl KeyConfig for MyConfig {
    const DEBOUNCE: TU = 15;   // debounce duration (ms)
    const RELEASE: TU = 300;   // release timeout for multi-click (ms)
    const HOLD: TU = 500;      // hold threshold (ms)
}
```

Default values:

| Constant | Default (ms) |
|----------|-------------|
| `DEBOUNCE` | 10 |
| `RELEASE` | 250 |
| `HOLD` | 600 |

### Create `KeyInput` and poll

```rust
use key_input::{KeyInput, config::DefaultConfig};

let mut key = KeyInput::<_, _, DefaultConfig>::new(MyDriver);

loop {
    key.poll();

    if key.is_clicked() {
        // Single click detected
    }

    if key.is_double_clicked() {
        // Double click detected
    }

    #[cfg(feature = "long-press")]
    if key.is_long_pressed() {
        // Long press detected
    }

    if let Some(duration) = key.holding_time() {
        // Key is being held for `duration` ms
    }

    key.reset();
}
```

## Feature Flags

| Feature | Description |
|---------|-------------|
| `long-press` | Enables long press detection (`is_long_pressed`, `LongPress` config) |
| `long-press-repeat` | Enables repeat mode for long press (implies `long-press`) |

### Long press modes

With `long-press` enabled, configure the mode via `KeyConfig`:

```rust
use key_input::config::{KeyConfig, LongPress};
use key_input::TU;

struct MyConfig;

impl KeyConfig for MyConfig {
    const DEBOUNCE: TU = 10;
    const RELEASE: TU = 250;
    const HOLD: TU = 600;
    const LONG_PRESS: LongPress = LongPress::Single(2000); // trigger once after 2s
}
```

With `long-press-repeat` enabled:

```rust
const LONG_PRESS: LongPress = LongPress::Repeat(2000, 500); // first trigger at 2s, then every 500ms
```

## License

MIT
