Skip to main content

Crate cruil

Crate cruil 

Source
Expand description

§cruil: Charlotte’s Raw USB Input Library

(Pronounced “cru-ill” or “cruel”)

cruil is a library that uses raw USB HID under the hood to be able to distinguish between and read input from input devices that are usually combined by the operating system (keyboards, mice)

On supported operating systems, this also includes Bluetooth HID devices.

[!WARNING]

cruil is still really early in development.

The entire API may change in the future.

See “Currently broken/WIP/unimplemented” for a list of current limitations.

§Why is this useful?

Some ideas:

  • Local multi-player video games that use keyboards and mice
  • Simulation software that uses multiple keyboards to create large control panels
  • Software to create a large emoji keyboard, à la Tom Scott, but without the bodge
  • Multi-seat software that uses multiple mice to create multiple pointers on one screen

§What cruil does NOT do

  • Handle keyboard layouts (as of now, this may change in the future if necessary)
  • Map keys or key combinations to typed characters (out of scope)

§Currently broken/WIP/unimplemented

  • Report descriptor parsing, which breaks:
    • Linux, BSD, and other Unix support
    • A lot of keyboards and mice
      • Turns out that more advanced devices don’t allow you to get off the hook easily anymore
  • Linux, BSD, and other Unix: Bluetooth
    • dependency limitation, will look into solving this in the future

§Operating system quirks

Cruil uses hidapi under the hood, so it inherits a lot of the same limitations:

  • Windows: everything should just work
  • macOS: requires input monitoring permissions
  • Linux, BSD, and other Unix: uses the libusb backend, so Bluetooth is unsupported

§Example

From examples/player_one.rs:

use cruil::keyboard::*;
use cruil::*;

fn main() -> CruilResult<()> {
    let cruil = Cruil::new()?;

    let mut devices: Vec<KeyboardDevice> = cruil
        .open_all_with(|info| matches!(DeviceKind::from_info(info), Ok(DeviceKind::Keyboard)))
        .into_iter()
        .map(|device| device.keyboard())
        .collect::<Option<Vec<_>>>()
        .unwrap();

    // The first keyboard to press a key becomes player one!
    println!("Press any key to join!");
    let player_one = 'player_select: loop {
        for (index, device) in devices.iter_mut().enumerate() {
            if let Some(report) = device.try_read()?
                && report.just_pressed.any()
            {
                // First key press!
                break 'player_select index;
            }
        }
    };

    // Let's drop all other devices and get ownership over the player
    let player_one = devices.into_iter().nth(player_one).unwrap();

    // Let's start reading player one's input in the background
    let player_one = ThreadedReader::start(player_one);

    // Game loop...
    loop {
        let events: Vec<KeyboardInputState> = player_one.iter().collect::<CruilResult<_>>()?;
        for event in events {
            // Process game input...
            if event.currently_pressed.any() {
                println!("Player 1 is pressing {}", event.currently_pressed);
            }
        }

        // Process the game...
    }
}

Modules§

keyboard
mouse

Structs§

Cruil
Cruil’s main struct. Get started here!
OwnedReadableDeviceIter
A ReadableDeviceIter that owns the ReadableDevice, obtained through ReadableDevice::owned_iter, or an IntoIterator::into_iter implementation.
OwnedThreadedReaderIter
A ThreadedReaderIter that owns the ThreadedReader, obtained through ThreadedReader::into_iter.
ReadableDeviceIter
ReadableDeviceIter implements Iterator by calling try_read in the next function.
ThreadedReader
A threaded reader that can be asynchronously polled for events.
ThreadedReaderIter
ThreadedReaderIter implements Iterator by calling poll_event in the next function.
ThreadedReaderTryIter
An iterator that takes ownership of a ThreadedReader and iterates over it while also catching a possible internal thread panic.
UnrecognizedKey
An error that indicates that the given key code sent by the device is unknown and could not be parsed.

Enums§

CruilError
Cruil’s all-encompassing error type.
DeviceKind
An enum containing cruil’s built-in supported device kinds, Keyboard and Mouse.
InputDevice
An opened input device, which is either a Keyboard or a Mouse. (The two types of devices Cruil has built-in support for)
InputState
An input state obtained by reading an InputDevice.
KeyboardError
An error that indicates that something went wrong with the keyboard device, presumably a hardware fault.
ProtocolViolation
An error that indicates that the device sent an invalid response.

Constants§

MAX_HID_PACKET_SIZE
The maximum size of a HID packet.

Traits§

ReadableDevice
A device which HID reports (aka “events” or “frames”) can be read from.

Type Aliases§

CruilResult
Cruil’s Result type.