hid-api-rs 3.0.1

Hardware proxy for injecting & intercepting keyboard/mouse inputs
Documentation
use std::ops::Deref;
use std::{
    fs::{File, OpenOptions},
    io::{BufWriter, Write},
};
use std::io::{Error, ErrorKind};

use bitvec::prelude::Lsb0;
use bitvec::view::BitView;

use crate::gadgets::keyboard::KeyboardState;
use crate::gadgets::mouse::MouseRaw;

static mut GADGET_DEVICE_FILE: Option<File> = None;

pub fn open_gadget_device(gadget_device_path: String) -> Result<&'static mut File, Error> {
    unsafe {
        GADGET_DEVICE_FILE = match OpenOptions::new()
            .write(true)
            .append(true)
            .open(gadget_device_path)
        {
            Ok(result) => Some(result),
            Err(error) => return Err(error),
        };

        match &mut GADGET_DEVICE_FILE {
            Some(ref mut gadget) => Ok(gadget),
            None => Err(Error::new(
                ErrorKind::NotFound,
                String::from("Hid gadget device file not found."),
            ))
        }
    }
}

pub fn write_mouse(raw: &MouseRaw, gadget_writer: &mut BufWriter<&mut File>) -> Result<(), Error> {
    const ID: [u8; 1] = [1u8];

    let mut buttons = 0u8;
    let bits = buttons.view_bits_mut::<Lsb0>();
    bits.set(0, raw.left_button);
    bits.set(1, raw.right_button);
    bits.set(2, raw.middle_button);
    bits.set(3, raw.four_button);
    bits.set(4, raw.five_button);

    let x_bytes = u16_to_u8s(raw.relative_x as u16);
    let y_bytes = u16_to_u8s(raw.relative_y as u16);
    let wheel_bytes = u16_to_u8s(raw.relative_wheel as u16);

    let formatted_event = [
        &ID[..],
        &mut buttons.to_le_bytes(),
        &[x_bytes[0]], &[x_bytes[1]],
        &[y_bytes[0]], &[y_bytes[1]],
        &[wheel_bytes[0]], &[wheel_bytes[1]]
    ].concat();

    gadget_writer.write(&formatted_event)?;
    gadget_writer.flush()?;

    Ok(())
}

pub fn write_keyboard(
    keyboard_state: &KeyboardState,
    gadget_writer: &mut BufWriter<&mut File>,
) -> Result<(), Error> {
    const ID: u8 = 2;

    let mut modifiers_down: Vec<i32> = Vec::new();
    if let Ok(modifiers_down_rwl) = keyboard_state.modifiers_down.read() {
        modifiers_down = modifiers_down_rwl.deref().clone();
    }

    let mut modifier = 0u8;
    let bits = modifier.view_bits_mut::<Lsb0>();
    for modifier in &modifiers_down {
        bits.set(*modifier as usize, true);
    }

    let mut keys_down: Vec<i32> = Vec::new();
    if let Ok(keys_down_rwl) = keyboard_state.keys_down.read() {
        keys_down = keys_down_rwl.deref().clone();
    }

    let mut formatted_event: Vec<u8> = vec![ID];

    match modifiers_down.is_empty() {
        true => formatted_event.push(0),
        false => formatted_event.push(modifier),
    }
    formatted_event.push(0);

    for key_down_index in 1..7 {
        if key_down_index - 1 < keys_down.len() {
            let key_down: i32 = keys_down[key_down_index - 1];
            formatted_event.push(key_down as u8);
        } else {
            formatted_event.push(0);
        }
    }

    gadget_writer.write(&formatted_event)?;
    gadget_writer.flush()?;

    Ok(())
}

fn u16_to_u8s(value: u16) -> [u8; 2] {
    let low_byte = (value >> 8) as u8;
    let high_byte = value as u8;

    [high_byte, low_byte]
}