diff --git a/Cargo.toml b/Cargo.toml index dcb2269..6c2d2ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "footswitch-rs" version = "0.1.0" -authors = ["Dennis "] +authors = ["Dennis Potter "] [dependencies] -structopt = "0.2.10" +structopt = "0.2.13" hidapi = "0.5.0" -users = "0.7" +users = "0.8" colored = "1.6.1" diff --git a/src/main.rs b/src/main.rs index db85836..3c42f9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,32 +20,43 @@ use colored::*; #[derive(StructOpt, Debug)] #[structopt(name = "rust-footswitch")] struct Opt { - /// Prints a table of all keys with rows - #[structopt(short = "l", long = "listkeys")] - listkeys: Option, - #[structopt(subcommand)] cmd: Option, } #[derive(StructOpt, Debug)] enum Command { - /// Write to the footpedal - #[structopt(name = "write")] - Write { - /// Specify pedal to modify with following command. Possible values: [0 | 1 | 2] - #[structopt(short = "p", long = "pedal")] - pedal: Vec, - - /// Command to apply. Possible values: [set_key | set_mousebutton | del_key | app_key | app_str | app_mod] - #[structopt(short = "c", long = "command")] - command: Vec, - - /// Input values to apply - #[structopt(short = "i", long = "input")] - input: Vec, + /// Prints a table of all possible keys + #[structopt(name = "list")] + ListKeys { + /// Specify the number of columns of the table + #[structopt(short = "c", long = "columns")] + columns: usize, }, + /// Set a key or a mousebutton to one or more pedals + #[structopt(name = "set")] + Set { + #[structopt(subcommand)] + cmd: Set + }, + + /// Append a key, a modifier, or a string to one or more pedals + #[structopt(name = "append")] + Append { + #[structopt(subcommand)] + cmd: Append + }, + + /// Clear the value of one or more pedals + #[structopt(name = "clear")] + Clear { + /// Specify pedal(s) to clear: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + }, + + /// Read from the footpedal #[structopt(name = "read")] Read { /// Read all pedals @@ -58,76 +69,180 @@ enum Command { } } +#[derive(StructOpt, Debug)] +enum Set { +/// Set a key value to one or more pedals + #[structopt(name = "key")] + SetKey { + /// Specify pedal(s) to modify: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + + /// Value(s) to apply + #[structopt(short = "i", long = "input")] + input: Vec, + }, + + /// Set a mousebutton to one or more pedals + #[structopt(name = "mousebutton")] + SetMousebutton { + /// Specify pedal(s) to modify: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + + /// Value(s) to apply + #[structopt(short = "i", long = "input")] + input: Vec, + }, + + /// Set X, Y, and W movement of the mouse pointer for one or more pedals + #[structopt(name = "mousemovement")] + SetMousemovement { + /// Specify pedal(s) to modify: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + + /// X value(s): [-128,127] + #[structopt(short = "x")] + x: Vec, + + /// Y value(s): [-128,127] + #[structopt(short = "y")] + y: Vec, + + /// W value(s): [-128,127] + #[structopt(short = "w")] + w: Vec, + } +} + +#[derive(StructOpt, Debug)] +enum Append { + /// Append a key value to one or more pedals + #[structopt(name = "key")] + AppendKey { + /// Specify pedal(s) to modify: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + + /// Value(s) to apply + #[structopt(short = "i", long = "input")] + input: Vec, + }, + + /// Append a string to one or more pedals + #[structopt(name = "string")] + AppendString { + /// Specify pedal(s) to modify: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + + /// Value(s) to apply + #[structopt(short = "i", long = "input")] + input: Vec, + }, + + /// Append a modifier to one or more pedals + #[structopt(name = "modifier")] + AppendModifier { + /// Specify pedal(s) to modify: [0 | 1 | 2] + #[structopt(short = "p", long = "pedal")] + pedal: Vec, + + /// Value(s) to apply + #[structopt(short = "i", long = "input")] + input: Vec, + } +} + fn main() { let opt = Opt::from_args(); - welcome("footswitch-rs, Dennis Potter "); + welcome(); check_sudo(); - - + // All options that don't need the device to be open // Print all keys and exit application - if let Some(x) = opt.listkeys { - key_operations::print_key_map(x); - goodbye(); + match opt.cmd { + Some(Command::ListKeys { columns }) => { + key_operations::print_key_map(columns); + goodbye(); + }, + _ => { /* Do nothing, there are still lots of other options further below */ } } let mut pedals = pedal_operations::Pedals::new(); - - // All options that need the device to be open match opt.cmd { - Some(Command::Write {pedal: ped_list, command: cmd_list, input: val_list}) => { - if ped_list.len() != cmd_list.len() && ped_list.len() != val_list.len() { - error!("You must define as much pedals as you define commands and as you define input values!"); - } + Some(Command::Append { cmd }) => { + match cmd { + Append::AppendKey { pedal, input } => + { - for (i, cmd) in cmd_list.iter().enumerate() { - match cmd as &str { - "set_key" => { - pedals.set_key(ped_list[i] as usize, val_list[i].as_str()); + }, + Append::AppendString { pedal, input } => + { + check_length(&pedal, &input); + + for (i, pedal) in pedal.iter().enumerate() { + pedals.set_string(*pedal as usize, input[i].as_str()); } - "set_mousebutton" => { - pedals.set_mousebutton(ped_list[i] as usize, val_list[i].as_str()); - } - "del_key" => { - } - "app_key" => { - } - "app_str" => { - pedals.set_string(ped_list[i] as usize, val_list[i].as_str()); - } - "app_mod" => { - pedals.set_modifier(ped_list[i] as usize, val_list[i].as_str()); - } - "set_x" => { - pedals.set_mouse_xyw(ped_list[i] as usize, val_list[i].as_str(), 5) - } - "set_y" => { - pedals.set_mouse_xyw(ped_list[i] as usize, val_list[i].as_str(), 6) - } - "set_w" => { - pedals.set_mouse_xyw(ped_list[i] as usize, val_list[i].as_str(), 7) - } - _ => { - error!("Unknown command!"); + }, + Append::AppendModifier { pedal, input } => + { + check_length(&pedal, &input); + + for (i, pedal) in pedal.iter().enumerate() { + pedals.set_modifier(*pedal as usize, input[i].as_str()); } } } - // Since we ran the Write command without any errors, we are now writing everything - pedals.write_pedals(); + pedals.update_and_close(); + }, - info!("Successfully wrote everything to footpedal!"); - info!("The current state of the device is shown below."); + Some(Command::Set { cmd }) => { + match cmd { + Set::SetKey { pedal, input } => + { + check_length(&pedal, &input); - // Show user current state of pedal - pedals.read_pedals(vec![0,1,2]); + for (i, pedal) in pedal.iter().enumerate() { + pedals.set_key(*pedal as usize, input[i].as_str()); + } + }, + Set::SetMousebutton { pedal, input } => + { + check_length(&pedal, &input); - goodbye(); + for (i, pedal) in pedal.iter().enumerate() { + pedals.set_mousebutton(*pedal as usize, input[i].as_str()); + } + } + + Set::SetMousemovement { pedal, x, y, w } => + { + + if pedal.len() != x.len() || x.len() != y.len() || y.len() != w.len() { + error!("You must define X, Y, and W for every pedal. If a direction is not needed, set it to 0!"); + } + + for (i, pedal) in pedal.iter().enumerate() { + pedals.set_mouse_xyw(*pedal as usize, x[i], 5); + pedals.set_mouse_xyw(*pedal as usize, y[i], 6); + pedals.set_mouse_xyw(*pedal as usize, w[i], 7); + } + } + } + + pedals.update_and_close(); + }, + + Some(Command::Clear { pedal }) => { }, + Some(Command::Read {all: all_var, pedals: ped_list}) => { if ped_list.len() > 3 { error!("Number of pedals may not be bigger than 3!"); @@ -145,6 +260,8 @@ fn main() { goodbye(); }, + + Some(Command::ListKeys { columns:_columns }) => { /* This case will never occur */ }, None => { error!("You did not specify any command. Run './footswitch-rs --help' for more information."); } @@ -157,3 +274,9 @@ fn check_sudo() { error!("Please execute this application as super user!"); } } + +fn check_length(pedal: & Vec, input: & Vec) { + if pedal.len() != input.len() { + error!("You must define as much pedals as you define input values!"); + } +} diff --git a/src/messages.rs b/src/messages.rs index f0bd4d9..fa9beea 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -26,10 +26,15 @@ macro_rules! error { }; } -pub fn welcome(string: &str) { - println!("┌{}┐", "─".repeat(string.len() + 20)); - println!("│{text:^-width$}│", text = string, width = string.len() + 20); - println!("├{}┘", "─".repeat(string.len() + 20)); +pub fn welcome() { + const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS"); + const NAME: &'static str = env!("CARGO_PKG_NAME"); + + let name_authors = &[NAME, " | ", AUTHORS].concat(); + + println!("┌{}┐", "─".repeat(name_authors.len() + 20)); + println!("│{text:^-width$}│", text = name_authors, width = name_authors.len() + 20); + println!("├{}┘", "─".repeat(name_authors.len() + 20)); } pub fn goodbye() { diff --git a/src/pedal_operations.rs b/src/pedal_operations.rs index 7482311..e6bf9a2 100644 --- a/src/pedal_operations.rs +++ b/src/pedal_operations.rs @@ -4,6 +4,7 @@ extern crate hidapi; use std::process; use std::ffi::CString; use colored::*; +use messages::*; #[derive(Copy, Clone)] enum Type { @@ -285,20 +286,12 @@ impl Pedals { self.ped_data[ped].data[4] |= mousebutton as u8; } - pub fn set_mouse_xyw(& mut self, ped:usize, value:&str, direction:usize) { + pub fn set_mouse_xyw(& mut self, ped:usize, value_i8:i8, direction:usize) { // The values of the directions match the array index of ped_data[].data[] // X = 5 // Y = 6 // W = 7 - // Translate value passed by user to integer - let value_i8 = match value.parse::() { - Ok(x) => x, - Err(x) => { - error!("The value of {} ({}) must be in [-128, 127]! Message: {}.", direction, value, x) - } - }; - // Translate to u8 let mut value_u8 = value_i8 as u8; @@ -372,4 +365,17 @@ impl Pedals { } + + /// Update device and close application + pub fn update_and_close(& mut self) { + self.write_pedals(); + + info!("Successfully wrote everything to footpedal!"); + info!("The current state of the device is shown below."); + + // Show user current state of pedal + self.read_pedals(vec![0,1,2]); + + goodbye(); + } }