Moved USB and Config functions to their own files
This commit is contained in:
parent
d9aae15559
commit
32267df99c
78
src/config_parsing.rs
Normal file
78
src/config_parsing.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
extern crate json;
|
||||||
|
extern crate colored;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyboardLighting {
|
||||||
|
pub lighting_type: String,
|
||||||
|
pub rows: u16,
|
||||||
|
pub cols: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct KeyboardLayout {
|
||||||
|
pub rows: u16,
|
||||||
|
pub cols: u16,
|
||||||
|
pub keys: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyboardConfig {
|
||||||
|
pub name: String,
|
||||||
|
pub vendor_id: u16,
|
||||||
|
pub product_id: u16,
|
||||||
|
pub layout: KeyboardLayout,
|
||||||
|
pub lighting: KeyboardLighting
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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;
|
||||||
|
}
|
||||||
143
src/main.rs
143
src/main.rs
@ -1,38 +1,16 @@
|
|||||||
extern crate libusb;
|
|
||||||
extern crate colored;
|
extern crate colored;
|
||||||
extern crate json;
|
|
||||||
|
|
||||||
|
// Config
|
||||||
|
mod config_parsing;
|
||||||
|
use config_parsing::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{cell::Cell, rc::Rc};
|
|
||||||
|
|
||||||
use colored::Colorize;
|
// USB
|
||||||
|
mod usb_communications;
|
||||||
|
use usb_communications::*;
|
||||||
|
|
||||||
use iced::{Sandbox, Settings, Vector};
|
use iced::{Sandbox, Settings, Vector};
|
||||||
use iced::widget::{Row, Column, Button, Text, Container, Slider};
|
use iced::widget::{Row, Column, Button, Text, Slider};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct KeyboardLighting {
|
|
||||||
lighting_type: String,
|
|
||||||
rows: u16,
|
|
||||||
cols: u16
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -64,63 +42,12 @@ enum MainPageMessages {
|
|||||||
row: u8,
|
row: u8,
|
||||||
col: u8
|
col: u8
|
||||||
},
|
},
|
||||||
UpdatedSlider_R(u8),
|
UpdatedSliderRed(u8),
|
||||||
UpdatedSlider_G(u8),
|
UpdatedSliderGreen(u8),
|
||||||
UpdatedSlider_B(u8)
|
UpdatedSliderBlue(u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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() -> Result<(), iced::Error> {
|
fn main() -> Result<(), iced::Error> {
|
||||||
// Printing the parsed config for debug purposes
|
// Printing the parsed config for debug purposes
|
||||||
@ -131,44 +58,6 @@ fn main() -> Result<(), iced::Error> {
|
|||||||
MainPage::run(Settings::default())
|
MainPage::run(Settings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
// USB Code
|
|
||||||
fn send_lighting_update(col: u8, row: u8, r: u8, g: u8, b: u8, _a: u8) {
|
|
||||||
println!("Sending lighting update!");
|
|
||||||
|
|
||||||
let config: KeyboardConfig = parse_config(&Path::new("numpad_config.json"));
|
|
||||||
|
|
||||||
let context = libusb::Context::new().unwrap(); // Get a new USB context
|
|
||||||
for device in context.devices().unwrap().iter() { // Iterate through all the devices
|
|
||||||
let device_desc = device.device_descriptor().unwrap(); // Get a descriptor for the device
|
|
||||||
|
|
||||||
if device_desc.vendor_id() == config.vendor_id && device_desc.product_id() == config.product_id { // Check if the devie is the device we are looking for
|
|
||||||
println!("Supported keyboard discovered, claiming it.");
|
|
||||||
|
|
||||||
let mut device_handle: libusb::DeviceHandle = device.open().unwrap(); // Get a handle for the device
|
|
||||||
|
|
||||||
if device_handle.kernel_driver_active(0).unwrap() { // If the device has an active kernel driver, detach it
|
|
||||||
println!("Interface has kernel driver, detaching...");
|
|
||||||
device_handle.detach_kernel_driver(0).unwrap();
|
|
||||||
}
|
|
||||||
device_handle.claim_interface(0).unwrap(); // Now that the device is free we claim it
|
|
||||||
|
|
||||||
match device_handle.write_control(
|
|
||||||
libusb::request_type(libusb::Direction::Out, libusb::RequestType::Class, libusb::Recipient::Interface), // The request is outband and uses HID specific features tergeting an interface
|
|
||||||
0x09, 0x0301, 0, // We want to send a SET_REPORT request, that is a custom feature, with the feature being lighting, we want to send it to endpoint 0
|
|
||||||
&[r, g, b, row, col], std::time::Duration::from_secs(1)) { // First we send the row, then the column, then the Red, Green, Blue, and lastly the brightness
|
|
||||||
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(); // Release the interface
|
|
||||||
device_handle.attach_kernel_driver(0).unwrap(); // Re-attach the kernel driver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI Code
|
// UI Code
|
||||||
impl Sandbox for MainPage {
|
impl Sandbox for MainPage {
|
||||||
@ -200,9 +89,9 @@ impl Sandbox for MainPage {
|
|||||||
|
|
||||||
fn update(&mut self, message: Self::Message) {
|
fn update(&mut self, message: Self::Message) {
|
||||||
match message {
|
match message {
|
||||||
MainPageMessages::UpdatedSlider_R(value) => { self.slider_values.slider_r = value; }
|
MainPageMessages::UpdatedSliderRed(value) => { self.slider_values.slider_r = value; }
|
||||||
MainPageMessages::UpdatedSlider_G(value) => { self.slider_values.slider_g = value; }
|
MainPageMessages::UpdatedSliderGreen(value) => { self.slider_values.slider_g = value; }
|
||||||
MainPageMessages::UpdatedSlider_B(value) => { self.slider_values.slider_b = value; }
|
MainPageMessages::UpdatedSliderBlue(value) => { self.slider_values.slider_b = value; }
|
||||||
MainPageMessages::UpdateColor { row, col } => {
|
MainPageMessages::UpdateColor { row, col } => {
|
||||||
println!("{:?}", message);
|
println!("{:?}", message);
|
||||||
send_lighting_update(col, row, self.slider_values.slider_r, self.slider_values.slider_g, self.slider_values.slider_b, 0x0);
|
send_lighting_update(col, row, self.slider_values.slider_r, self.slider_values.slider_g, self.slider_values.slider_b, 0x0);
|
||||||
@ -283,9 +172,9 @@ impl Sandbox for MainPage {
|
|||||||
|
|
||||||
// Create the color selector
|
// Create the color selector
|
||||||
|
|
||||||
let slider_r = Slider::new(0..=255, self.slider_values.slider_r, MainPageMessages::UpdatedSlider_R);
|
let slider_r = Slider::new(0..=255, self.slider_values.slider_r, MainPageMessages::UpdatedSliderRed);
|
||||||
let slider_g = Slider::new(0..=255, self.slider_values.slider_g, MainPageMessages::UpdatedSlider_G);
|
let slider_g = Slider::new(0..=255, self.slider_values.slider_g, MainPageMessages::UpdatedSliderGreen);
|
||||||
let slider_b = Slider::new(0..=255, self.slider_values.slider_b, MainPageMessages::UpdatedSlider_B);
|
let slider_b = Slider::new(0..=255, self.slider_values.slider_b, MainPageMessages::UpdatedSliderBlue);
|
||||||
let color_selector_col = Column::new()
|
let color_selector_col = Column::new()
|
||||||
.push(slider_r)
|
.push(slider_r)
|
||||||
.push(slider_g)
|
.push(slider_g)
|
||||||
|
|||||||
47
src/usb_communications.rs
Normal file
47
src/usb_communications.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
extern crate libusb;
|
||||||
|
extern crate colored;
|
||||||
|
|
||||||
|
use crate::config_parsing::*;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
|
|
||||||
|
// USB Code
|
||||||
|
pub fn send_lighting_update(col: u8, row: u8, r: u8, g: u8, b: u8, _a: u8) {
|
||||||
|
println!("Sending lighting update!");
|
||||||
|
|
||||||
|
let config: KeyboardConfig = parse_config(&Path::new("numpad_config.json"));
|
||||||
|
|
||||||
|
let context = libusb::Context::new().unwrap(); // Get a new USB context
|
||||||
|
for device in context.devices().unwrap().iter() { // Iterate through all the devices
|
||||||
|
let device_desc = device.device_descriptor().unwrap(); // Get a descriptor for the device
|
||||||
|
|
||||||
|
if device_desc.vendor_id() == config.vendor_id && device_desc.product_id() == config.product_id { // Check if the devie is the device we are looking for
|
||||||
|
println!("Supported keyboard discovered, claiming it.");
|
||||||
|
|
||||||
|
let mut device_handle: libusb::DeviceHandle = device.open().unwrap(); // Get a handle for the device
|
||||||
|
|
||||||
|
if device_handle.kernel_driver_active(0).unwrap() { // If the device has an active kernel driver, detach it
|
||||||
|
println!("Interface has kernel driver, detaching...");
|
||||||
|
device_handle.detach_kernel_driver(0).unwrap();
|
||||||
|
}
|
||||||
|
device_handle.claim_interface(0).unwrap(); // Now that the device is free we claim it
|
||||||
|
|
||||||
|
match device_handle.write_control(
|
||||||
|
libusb::request_type(libusb::Direction::Out, libusb::RequestType::Class, libusb::Recipient::Interface), // The request is outband and uses HID specific features tergeting an interface
|
||||||
|
0x09, 0x0301, 0, // We want to send a SET_REPORT request, that is a custom feature, with the feature being lighting, we want to send it to endpoint 0
|
||||||
|
&[r, g, b, row, col], std::time::Duration::from_secs(1)) { // First we send the row, then the column, then the Red, Green, Blue, and lastly the brightness
|
||||||
|
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(); // Release the interface
|
||||||
|
device_handle.attach_kernel_driver(0).unwrap(); // Re-attach the kernel driver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user