Initial commit

This commit is contained in:
Sebastian H. Gabrielli 2022-06-16 00:10:16 +02:00
commit 023283b807
5 changed files with 293 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

125
Cargo.lock generated Normal file
View File

@ -0,0 +1,125 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bit-set"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e1e6fb1c9e3d6fcdec57216a74eaa03e41f52a22f13a16438251d8e88b89da"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "json"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
[[package]]
name = "keyboard_control_software"
version = "0.1.0"
dependencies = [
"colored",
"json",
"libusb",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libusb"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f990ddd929cbe53de4ecd6cf26e1f4e0c5b9796e4c629d9046570b03738aa53"
dependencies = [
"bit-set",
"libc",
"libusb-sys",
]
[[package]]
name = "libusb-sys"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c53b6582563d64ad3e692f54ef95239c3ea8069e82c9eb70ca948869a7ad767"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

11
Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "keyboard_control_software"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libusb = "0.3.0"
colored = "2.0.0"
json = "0.12.4"

25
numpad_config.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "Sebaweb numpad",
"vendor_id": "CAFE",
"product_id": "53BA",
"layout": {
"rows": 5,
"cols": 4,
"keys": [
["NumLk", "/", "*", "-"],
["7", "8", "9", "+"],
["4", "5", "6", "&+"],
["1", "2", "3", "Enter"],
["0", "&0", ",", "&Enter"]
]
},
"lighting": {
"type": "RGB",
"layout": {
"rows": 1,
"cols": 4
}
}
}

131
src/main.rs Normal file
View File

@ -0,0 +1,131 @@
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);
}
}
}