Move fast, break things

This commit is contained in:
Luke D Jones
2020-08-01 23:06:36 +12:00
parent 4c32901467
commit a879907bc3
9 changed files with 5 additions and 591 deletions

110
Cargo.lock generated
View File

@@ -26,26 +26,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "bindgen"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66c0bb6167449588ff70803f4127f0684f9063097eca5016f37eb52b92c2cf36"
dependencies = [
"bitflags",
"cexpr",
"cfg-if",
"clang-sys",
"lazy_static",
"lazycell",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
]
[[package]]
name = "bit-set"
version = "0.5.2"
@@ -82,31 +62,12 @@ version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c1f1d60091c1b73e2b1f4560ab419204b178e625fa945ded7b660becd2bd46"
[[package]]
name = "cexpr"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "clang-sys"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
dependencies = [
"glob",
"libc",
]
[[package]]
name = "crc32fast"
version = "1.2.0"
@@ -138,26 +99,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "enumflags2"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83c8d82922337cd23a15f88b70d8e4ef5f11da38dd7cdb55e84dd5de99695da0"
dependencies = [
"enumflags2_derive",
]
[[package]]
name = "enumflags2_derive"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@@ -327,12 +268,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "gumdrop"
version = "0.8.0"
@@ -412,12 +347,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
[[package]]
name = "libc"
version = "0.2.71"
@@ -559,12 +488,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "pin-project"
version = "0.4.22"
@@ -725,7 +648,6 @@ dependencies = [
"serde_json",
"sysfs-class",
"tokio",
"uhid-virt",
]
[[package]]
@@ -739,12 +661,6 @@ dependencies = [
"libusb1-sys",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc_version"
version = "0.2.3"
@@ -820,12 +736,6 @@ dependencies = [
"serde",
]
[[package]]
name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "slab"
version = "0.4.2"
@@ -959,26 +869,6 @@ dependencies = [
"syn",
]
[[package]]
name = "uhid-virt"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e317bfbb0281bb799f4802d62261a798443a88df4352f302269ad32b4cfc822"
dependencies = [
"enumflags2",
"libc",
"uhidrs-sys",
]
[[package]]
name = "uhidrs-sys"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfcc3b1a199338bcfe0e64b3c427ffab84514e7b23f9402d7fef9b38c0a9916e"
dependencies = [
"bindgen",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"

View File

@@ -39,7 +39,4 @@ serde_json = "^1.0"
# Device control
sysfs-class = "^0.1.2" # used for backlight control and baord ID
# cpu power management
intel-pstate = "^0.2.1"
# virtualisation of HID, mainly for outputting consumer key codes
uhid-virt = "^0.0.5"
#keycode = "^0.3"
intel-pstate = "^0.2.1"

View File

@@ -1,4 +1,3 @@
use crate::virt_device::ConsumerKeys;
use rog_client::aura_modes::AuraModes;
use serde_derive::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
@@ -8,7 +7,6 @@ pub static CONFIG_PATH: &str = "/etc/rogcore.conf";
#[derive(Default, Deserialize, Serialize)]
pub struct Config {
pub rog_key: ConsumerKeys,
pub fan_mode: u8,
pub bat_charge_limit: u8,
pub brightness: u8,

View File

@@ -64,12 +64,6 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
laptop.supported_modes().to_owned(),
);
let keyboard_reader = KeyboardReader::new(
rogcore.get_raw_device_handle(),
laptop.key_endpoint(),
laptop.key_filter().to_owned(),
);
led_writer
.reload_last_builtin(&mut config)
.await
@@ -89,7 +83,6 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
let (
tree,
aura_command_sender,
mut aura_command_recv,
mut animatrix_recv,
fan_mode,
@@ -161,14 +154,7 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
.unwrap_or_else(|err| warn!("{:?}", err));
}
}
// Keyboard reads
let data = keyboard_reader.poll_keyboard().await;
if let Some(bytes) = data {
laptop
.do_keyboard_command(&mut rogcore, &config1, bytes, aura_command_sender.clone())
.await
.unwrap_or_else(|err| warn!("{}", err));
}
}
});
@@ -277,48 +263,3 @@ async fn send_boot_signals(
Ok(())
}
// fn start_keyboard_task(
// fan_mode: Arc<Mutex<Option<u8>>>,
// charge_limit: Arc<Mutex<Option<u8>>>,
// config: Arc<Mutex<Config>>,
// aura_command_sender: mpsc::Sender<AuraModes>,
// mut rogcore: RogCore,
// laptop: LaptopBase,
// ) -> tokio::task::JoinHandle<()> {
// let keyboard_reader = KeyboardReader::new(
// rogcore.get_raw_device_handle(),
// laptop.key_endpoint(),
// laptop.key_filter().to_owned(),
// );
//
// tokio::spawn(async move {
// loop {
// // Fan mode
// if let Ok(mut lock) = fan_mode.try_lock() {
// if let Some(n) = lock.take() {
// let mut config = config.lock().await;
// rogcore
// .set_fan_mode(n, &mut config)
// .unwrap_or_else(|err| warn!("{:?}", err));
// }
// }
// // Charge limit
// if let Ok(mut lock) = charge_limit.try_lock() {
// if let Some(n) = lock.take() {
// let mut config = config.lock().await;
// rogcore
// .set_charge_limit(n, &mut config)
// .unwrap_or_else(|err| warn!("{:?}", err));
// }
// }
// // Keyboard reads
// let data = keyboard_reader.poll_keyboard().await;
// if let Some(bytes) = data {
// laptop
// .run(&mut rogcore, &config, bytes, aura_command_sender.clone())
// .await
// .unwrap_or_else(|err| warn!("{}", err));
// }
// }
// })
// }

View File

@@ -1,58 +1,13 @@
use crate::{config::Config, rogcore::RogCore};
use rog_client::{
aura_modes::{
AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, MULTISTATIC, PULSE, RAIN, RAINBOW,
RGB, RIPPLE, SINGLE, STAR, STROBE,
},
error::AuraError,
};
//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState};
use crate::virt_device::{ConsumerKeys, KeyboardKeys};
use log::{info, warn};
static HELP_ADDRESS: &str = "https://github.com/flukejones/rog-core";
/// The map of bytes which each fn+key combo emits (0x1866 device only)
pub enum FnKeys {
Rog = 0x38,
MicToggle = 0x7C,
Fan = 0xAE,
ScreenToggle = 0x35,
ScreenBrightDn = 0x10,
ScreenBrightUp = 0x20,
TouchPadToggle = 0x6b,
Sleep = 0x6C,
AirplaneMode = 0x88,
LedBrightUp = 0xC4,
LedBrightDown = 0xC5,
AuraPrevious = 0xB2,
AuraNext = 0xB3,
Calc = 0x92,
None,
}
impl From<u8> for FnKeys {
fn from(byte: u8) -> Self {
match byte {
0x38 => FnKeys::Rog,
0x7C => FnKeys::MicToggle,
0xAE => FnKeys::Fan,
0x35 => FnKeys::ScreenToggle,
0x10 => FnKeys::ScreenBrightDn,
0x20 => FnKeys::ScreenBrightUp,
0x6b => FnKeys::TouchPadToggle,
0x6C => FnKeys::Sleep,
0x88 => FnKeys::AirplaneMode,
0xC4 => FnKeys::LedBrightUp,
0xC5 => FnKeys::LedBrightDown,
0xB2 => FnKeys::AuraPrevious,
0xB3 => FnKeys::AuraNext,
0x90 => FnKeys::Calc,
_ => FnKeys::None,
}
}
}
pub(crate) fn match_laptop() -> LaptopBase {
for device in rusb::devices().unwrap().iter() {
let device_desc = device.device_descriptor().unwrap();
@@ -64,9 +19,6 @@ pub(crate) fn match_laptop() -> LaptopBase {
return LaptopBase {
usb_vendor: 0x0B05,
usb_product: 0x1854,
report_filter_bytes: vec![0x5a, 0x02],
min_led_bright: 0x00,
max_led_bright: 0x03,
//from `lsusb -vd 0b05:1866`
led_endpoint: 0x04,
//from `lsusb -vd 0b05:1866`
@@ -93,9 +45,6 @@ fn select_1866_device(prod: u16) -> LaptopBase {
let mut laptop = LaptopBase {
usb_vendor: 0x0B05,
usb_product: prod,
report_filter_bytes: vec![0x5a, 0x02],
min_led_bright: 0x00,
max_led_bright: 0x03,
//from `lsusb -vd 0b05:1866`
led_endpoint: 0x04,
//from `lsusb -vd 0b05:1866`
@@ -166,117 +115,19 @@ fn select_1866_device(prod: u16) -> LaptopBase {
pub(super) struct LaptopBase {
usb_vendor: u16,
usb_product: u16,
report_filter_bytes: Vec<u8>,
min_led_bright: u8,
max_led_bright: u8,
led_endpoint: u8,
key_endpoint: u8,
supported_modes: Vec<u8>,
support_animatrix: bool,
}
use tokio::sync::{mpsc, Mutex};
impl LaptopBase {
// Pass in LedWriter as Mutex so it is only locked when required
/// Determines what action each fn+key combo should have
pub(super) async fn do_keyboard_command(
&self,
rogcore: &mut RogCore,
config: &Mutex<Config>,
key_buf: [u8; 32],
mut aura_command: mpsc::Sender<AuraModes>,
) -> Result<(), AuraError> {
let mut config = config.lock().await;
match FnKeys::from(key_buf[1]) {
FnKeys::LedBrightUp => {
let mut bright = config.brightness;
if bright < self.max_led_bright {
bright += 1;
info!("Increased LED brightness to {:#?}", bright);
}
aura_command
.send(AuraModes::LedBrightness(bright))
.await
.unwrap_or_else(|err| warn!("LedBrightUp: {}", err));
}
FnKeys::LedBrightDown => {
let mut bright = config.brightness;
if bright > self.min_led_bright {
bright -= 1;
}
aura_command
.send(AuraModes::LedBrightness(bright))
.await
.unwrap_or_else(|err| warn!("LedBrightDown: {}", err));
}
FnKeys::AuraNext => {
if let Ok(idx) = self.supported_modes.binary_search(&config.current_mode) {
let idx_next = if idx < self.supported_modes.len() - 1 {
idx + 1
} else {
0
};
config.read();
if let Some(data) = config.get_led_mode_data(self.supported_modes[idx_next]) {
aura_command.send(data.clone()).await.unwrap_or_else(|_| {});
}
} else {
warn!("Tried to step to next LED mode while in non-supported mode");
}
}
FnKeys::AuraPrevious => {
if let Ok(idx) = self.supported_modes.binary_search(&config.current_mode) {
let idx_next = if idx > 0 {
idx - 1
} else {
self.supported_modes.len() - 1
};
config.read();
if let Some(data) = config.get_led_mode_data(self.supported_modes[idx_next]) {
aura_command.send(data.clone()).await.unwrap_or_else(|_| {});
}
} else {
warn!("Tried to step to next LED mode while in non-supported mode");
}
}
FnKeys::ScreenBrightUp => rogcore.virt_keys().press(ConsumerKeys::BacklightInc.into()), //self.backlight.step_up(),
FnKeys::ScreenBrightDn => rogcore.virt_keys().press(ConsumerKeys::BacklightDec.into()),
FnKeys::ScreenToggle => {}
FnKeys::Sleep => rogcore.suspend_with_systemd(),
FnKeys::AirplaneMode => rogcore.toggle_airplane_mode(),
FnKeys::MicToggle => rogcore.virt_keys().press(KeyboardKeys::MicToggle.into()),
FnKeys::Fan => {
rogcore.fan_mode_step(&mut config).unwrap_or_else(|err| {
warn!("Couldn't toggle fan mode: {:?}", err);
});
}
FnKeys::TouchPadToggle => rogcore
.virt_keys()
.press(KeyboardKeys::TouchpadToggle.into()),
FnKeys::Rog => rogcore.virt_keys().press(config.rog_key.into()),
FnKeys::Calc => rogcore
.virt_keys()
.press(ConsumerKeys::LaunchCalculator.into()),
FnKeys::None => {
if key_buf[0] != 0x5A {
info!("Unmapped key, attempt passthrough: {:X?}", &key_buf[1]);
rogcore.virt_keys().press(key_buf);
}
}
}
Ok(())
}
pub(super) fn led_endpoint(&self) -> u8 {
self.led_endpoint
}
pub(super) fn key_endpoint(&self) -> u8 {
self.key_endpoint
}
pub(super) fn key_filter(&self) -> &[u8] {
&self.report_filter_bytes
}
pub(super) fn usb_vendor(&self) -> u16 {
self.usb_vendor
}

View File

@@ -14,7 +14,5 @@ mod rog_dbus;
/// The core module which allows writing to LEDs or polling the
/// laptop keyboard attached devices
pub mod rogcore;
/// A virtual "consumer device" to help emit the correct key codes
mod virt_device;
mod error;

View File

@@ -176,7 +176,6 @@ pub(super) fn dbus_create_tree(
config: Arc<Mutex<Config>>,
) -> (
Tree<MTSync, ()>,
Sender<AuraModes>,
Receiver<AuraModes>,
Receiver<Vec<Vec<u8>>>,
DbusU8Type,
@@ -210,9 +209,7 @@ pub(super) fn dbus_create_tree(
factory.object_path(DBUS_PATH, ()).introspectable().add(
factory
.interface(DBUS_IFACE, ())
.add_m(set_keyboard_backlight(Mutex::new(
aura_command_send.clone(),
)))
.add_m(set_keyboard_backlight(Mutex::new(aura_command_send)))
.add_m(set_animatrix(Mutex::new(animatrix_send)))
.add_m(set_fan_mode(fan_mode.clone()))
.add_m(set_charge_limit(charge_limit.clone()))
@@ -228,7 +225,6 @@ pub(super) fn dbus_create_tree(
.add(factory.object_path("/", ()).introspectable());
(
tree,
aura_command_send,
aura_command_recv,
animatrix_recv,
fan_mode,

View File

@@ -1,17 +1,16 @@
// Return show-stopping errors, otherwise map error to a log level
use crate::{config::Config, error::RogError, virt_device::VirtKeys};
use crate::{config::Config, error::RogError};
use log::{error, info, warn};
use rusb::{Device, DeviceHandle};
use std::error::Error;
use std::fs::OpenOptions;
use std::io::Write;
use std::marker::{PhantomData, PhantomPinned};
use std::marker::{PhantomPinned};
use std::path::Path;
use std::process::Command;
use std::ptr::NonNull;
use std::str::FromStr;
use std::time::Duration;
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
@@ -29,7 +28,6 @@ static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_
/// - `LED_INIT4`
pub struct RogCore {
handle: DeviceHandle<rusb::GlobalContext>,
virt_keys: VirtKeys,
_pin: PhantomPinned,
}
@@ -79,25 +77,13 @@ impl RogCore {
device.set_auto_detach_kernel_driver(true)?;
}
if let Err(err) = device.claim_interface(interface) {
warn!("Could not claim keyboard device interface: {:?}", err);
warn!("Sleeping 5 seconds");
std::thread::sleep(std::time::Duration::from_millis(5000));
device.claim_interface(interface)?;
}
// std::thread::sleep(std::time::Duration::from_millis(500));
Ok(RogCore {
handle: device,
virt_keys: VirtKeys::new(),
_pin: PhantomPinned,
})
}
pub fn virt_keys(&mut self) -> &mut VirtKeys {
&mut self.virt_keys
}
fn get_device(vendor: u16, product: u16) -> Result<Device<rusb::GlobalContext>, rusb::Error> {
for device in rusb::devices()?.iter() {
let device_desc = device.device_descriptor()?;
@@ -330,70 +316,8 @@ impl RogCore {
}
}
}
pub fn get_raw_device_handle(&mut self) -> NonNull<DeviceHandle<rusb::GlobalContext>> {
// Breaking every damn lifetime guarantee rust gives us
unsafe {
NonNull::new_unchecked(&mut self.handle as *mut DeviceHandle<rusb::GlobalContext>)
}
}
}
/// Lifetime is tied to `DeviceHandle` from `RogCore`
pub struct KeyboardReader<'d, C: 'd>
where
C: rusb::UsbContext,
{
handle: NonNull<DeviceHandle<C>>,
endpoint: u8,
filter: Vec<u8>,
_phantom: PhantomData<&'d DeviceHandle<C>>,
}
/// UNSAFE
unsafe impl<'d, C> Send for KeyboardReader<'d, C> where C: rusb::UsbContext {}
unsafe impl<'d, C> Sync for KeyboardReader<'d, C> where C: rusb::UsbContext {}
impl<'d, C> KeyboardReader<'d, C>
where
C: rusb::UsbContext,
{
pub fn new(device_handle: NonNull<DeviceHandle<C>>, key_endpoint: u8, filter: Vec<u8>) -> Self {
KeyboardReader {
handle: device_handle,
endpoint: key_endpoint,
filter,
_phantom: PhantomData,
}
}
/// Write the bytes read from the device interrupt to the buffer arg, and returns the
/// count of bytes written
///
/// `report_filter_bytes` is used to filter the data read from the interupt so
/// only the relevant byte array is returned.
pub async fn poll_keyboard(&self) -> Option<[u8; 32]> {
let mut buf = [0u8; 32];
match unsafe { self.handle.as_ref() }.read_interrupt(
self.endpoint,
&mut buf,
Duration::from_millis(200),
) {
Ok(_) => {
if self.filter.contains(&buf[0])
&& (buf[1] != 0 || buf[2] != 0 || buf[3] != 0 || buf[4] != 0)
{
return Some(buf);
}
}
Err(err) => match err {
rusb::Error::Timeout => {}
_ => error!("Failed to read keyboard interrupt: {:?}", err),
},
}
None
}
}
#[derive(Debug)]
pub enum FanLevel {

View File

@@ -1,181 +0,0 @@
use log::error;
use serde_derive::{Deserialize, Serialize};
use uhid_virt::{Bus, CreateParams, UHIDDevice};
/// Create a virtual device to emit key-presses
///
/// This is required in some instances because either the USB device that
/// an interface for a working set of buttons is also captured, or because
/// there is no equivalent "system" action to take for a key function and
/// a key-press is required to emit a particular key code.
///
/// The two devices set up mirror that of the GX502GW and can accept the same
/// original byte arrays to emit.
/// - "Consumer Device" generally has all device type controls like media, backlight, power
/// - "Keyboard Device" is a full featured keyboard including special keys like F13-F24
///
/// # Some example uses:
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x68, 0, 0, 0, 0]); // F13, Config/Control Panel`
///
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x70, 0, 0, 0, 0]); // F21, Touchpad toggle, XF86/Gnome`
///
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x71, 0, 0, 0, 0]); // F22, Touchpad on, XF86/Gnome`
///
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x72, 0, 0, 0, 0]); // F23, Touchpad off, XF86/Gnome`
///
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]); // Sleep`
///
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]); // Power (menu)`
pub struct VirtKeys {
device: UHIDDevice<std::fs::File>,
}
impl Default for VirtKeys {
fn default() -> Self {
Self::new()
}
}
impl VirtKeys {
pub fn new() -> Self {
VirtKeys {
device: UHIDDevice::create(CreateParams {
name: String::from("Virtual ROG buttons"),
phys: String::from(""),
uniq: String::from(""),
bus: Bus::USB,
vendor: 0x0b05,
product: 0x1866,
version: 0,
country: 0,
// This is a device which emits the usage code as a whole, rather than as bits
rd_data: [
// Consumer Device TLC
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)
0x19, 0x00, // Usage Minimum (Unassigned)
0x2A, 0x3C, 0x02, // Usage Maximum (AC Format)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x3C, 0x02, // Logical Maximum (572)
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State)
0xC0, //
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State)
0x95, 0x1E, // Report Count (30)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State)
0xC0, // End Collection
]
.to_vec(),
})
.map_err(|err| error!("Could not create virtual device: {:?}", err))
.expect("Could not create virtual device"),
}
}
/// A single on/off key press
pub fn press(&mut self, input: [u8; 32]) {
self.device.write(&input).unwrap();
let mut reset = [0u8; 32];
reset[0] = input[0];
self.device.write(&reset).unwrap();
}
}
#[allow(dead_code)]
#[derive(Copy, Clone, Deserialize, Serialize)]
pub enum ConsumerKeys {
Power = 0x30,
Sleep = 0x32,
// Menu = 0x40,
MediaRecord = 0xB2,
MediaFastFwd = 0xB3,
MediaRewind = 0xB4,
MediaNext = 0xB5,
MediaPrev = 0xB6,
MediaStop = 0xB7,
MediaPlayPause = 0xCD,
MediaVolMute = 0xE2,
MediaVolUp = 0xE9,
MediaVolDown = 0xEA,
BacklightInc = 0x6F,
BacklightDec = 0x70,
// BacklightTog = 0x72, // USAGE (Backlight toggle? display toggle?)
ControlConfig = 0x183,
LaunchTextEditor = 0x185,
LaunchEmailApp = 0x18A,
LaunchNewsReader = 0x18B,
LaunchCalendar = 0x018E,
LaunchCalculator = 0x192,
LaunchWebBrowser = 0x196,
// VideoOutStep = 0x82,
FileBrowser = 0x1B4,
}
impl From<ConsumerKeys> for [u8; 32] {
fn from(key: ConsumerKeys) -> Self {
let mut bytes = [0u8; 32];
bytes[0] = 0x02; // report ID for consumer
bytes[1] = key as u8;
bytes[2] = (key as u16 >> 8) as u8;
bytes
}
}
impl Default for ConsumerKeys {
fn default() -> Self {
ConsumerKeys::ControlConfig
}
}
/// Implements only a small subset of useful keys
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum KeyboardKeys {
Config = 0x68, // Desktop configuration, F13
MicToggle = 0x6f, // Microphone toggle, F20
TouchpadToggle = 0x70, // Touchpad toggle, F21
WWW = 0xf0, // Web browser
Sleep = 0xf8, // Sleep
Coffee = 0xf9, // lockscreen
}
impl From<KeyboardKeys> for [u8; 32] {
fn from(key: KeyboardKeys) -> Self {
let mut bytes = [0u8; 32];
bytes[0] = 0x01; // report ID for keyboard
bytes[3] = key as u8;
bytes
}
}