132 lines
4.8 KiB
Rust
132 lines
4.8 KiB
Rust
extern crate libusb;
|
|
extern crate colored;
|
|
extern crate json;
|
|
|
|
use colored::Colorize;
|
|
use std::path::Path;
|
|
|
|
#[derive(Debug)]
|
|
struct KeyboardLighting {
|
|
lighting_type: String,
|
|
rows: u16,
|
|
cols: u16
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct KeyboardLayout {
|
|
rows: u16,
|
|
cols: u16,
|
|
keys: Vec<String>
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct KeyboardConfig {
|
|
name: String,
|
|
vendor_id: u16,
|
|
product_id: u16,
|
|
layout: KeyboardLayout,
|
|
lighting: KeyboardLighting
|
|
}
|
|
|
|
fn parse_config(config_path: &Path) -> KeyboardConfig{
|
|
let mut parsed_json = json::parse(&std::fs::read_to_string(config_path).unwrap()).unwrap();
|
|
|
|
// General info
|
|
let extracted_name: String = parsed_json["name"].as_str().expect("ERROR: Failed to parse name").to_string();
|
|
let extracted_vendor_id: u16 = u16::from_str_radix(parsed_json["vendor_id"].as_str().expect("ERROR: Failed to parse name"), 16).unwrap();
|
|
let extracted_product_id: u16 = u16::from_str_radix(parsed_json["product_id"].as_str().expect("ERROR: Failed to parse name"), 16).unwrap();
|
|
|
|
// Layout
|
|
let extracted_layout_rows: u16 = parsed_json["layout"]["rows"].as_u16().expect("ERROR: Failed to parse layout rows");
|
|
let extracted_layout_cols: u16 = parsed_json["layout"]["cols"].as_u16().expect("ERROR: Failed to parse layout cols");
|
|
let mut extracted_layout_keys: Vec<String> = Vec::new();
|
|
let mut keys: std::collections::VecDeque<String> = std::collections::VecDeque::new();
|
|
for i in 0..extracted_layout_rows {
|
|
let mut row: json::JsonValue = parsed_json["layout"]["keys"].pop();
|
|
for j in 0..extracted_layout_cols {
|
|
keys.push_front(row.pop().as_str().expect("ERROR: Failed to extract key names").to_string());
|
|
}
|
|
}
|
|
for i in 0..keys.len() {
|
|
extracted_layout_keys.push(keys.pop_front().expect("ERROR: Empty key value"));
|
|
}
|
|
|
|
let keyboard_layout = KeyboardLayout {
|
|
rows: extracted_layout_rows,
|
|
cols: extracted_layout_cols,
|
|
keys: extracted_layout_keys
|
|
};
|
|
|
|
// Lighting
|
|
let extracted_lighting_type: String = parsed_json["lighting"]["type"].as_str().expect("ERROR: Failed to parse lighting type").to_string();
|
|
let extracted_lighting_rows: u16 = parsed_json["lighting"]["layout"]["rows"].as_u16().expect("ERROR: Failed to parse lighting rows");
|
|
let extracted_lighting_cols: u16 = parsed_json["lighting"]["layout"]["cols"].as_u16().expect("ERROR: Failed to parse lighting cols");
|
|
|
|
let keyboard_lighting = KeyboardLighting {
|
|
lighting_type: extracted_lighting_type,
|
|
rows: extracted_lighting_rows,
|
|
cols: extracted_lighting_cols
|
|
};
|
|
|
|
|
|
let keyboard_config = KeyboardConfig {
|
|
name: extracted_name,
|
|
vendor_id: extracted_vendor_id,
|
|
product_id: extracted_product_id,
|
|
layout: keyboard_layout,
|
|
lighting: keyboard_lighting
|
|
};
|
|
|
|
return keyboard_config;
|
|
}
|
|
|
|
fn main() {
|
|
let config: KeyboardConfig = parse_config(&Path::new("numpad_config.json"));
|
|
|
|
println!("{:#?}", config);
|
|
|
|
let context = libusb::Context::new().unwrap();
|
|
|
|
for device in context.devices().unwrap().iter() {
|
|
let device_desc = device.device_descriptor().unwrap();
|
|
|
|
println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
|
|
device.bus_number(),
|
|
device.address(),
|
|
device_desc.vendor_id(),
|
|
device_desc.product_id());
|
|
|
|
|
|
if device_desc.vendor_id() == config.vendor_id && device_desc.product_id() == config.product_id {
|
|
println!("Woah, this is my device! I'm going to open it!");
|
|
let config_desc = device.active_config_descriptor().unwrap();
|
|
|
|
let mut device_handle: libusb::DeviceHandle = device.open().unwrap();
|
|
println!("Number of interfaces: {}", config_desc.num_interfaces());
|
|
//println!("The device supports these languages: {:?}", &device_handle.read_languages(std::time::Duration::from_millis(100)));
|
|
|
|
if device_handle.kernel_driver_active(0).unwrap() {
|
|
println!("Interface has kernel driver, detaching...");
|
|
device_handle.detach_kernel_driver(0).unwrap();
|
|
}
|
|
device_handle.claim_interface(0).unwrap();
|
|
|
|
match device_handle.write_control(libusb::request_type(libusb::Direction::Out, libusb::RequestType::Class, libusb::Recipient::Interface), 0x09, 0x0300, 0, &[0x00], std::time::Duration::from_secs(1)) {
|
|
Ok(n) => {
|
|
println!("{}", format!("Successfully wrote {} bytes!", n).green());
|
|
},
|
|
Err(e) => {
|
|
eprintln!("{}{:?}", format!("Failed to write with error: ").red().bold(), e);
|
|
}
|
|
}
|
|
|
|
device_handle.release_interface(0).unwrap();
|
|
device_handle.attach_kernel_driver(0).unwrap();
|
|
|
|
println!("Goodbye!");
|
|
std::process::exit(0);
|
|
}
|
|
}
|
|
|
|
}
|