footswitch-rs/src/pedal_operations.rs
Dennis 74e23a5b5f Improved user-friendliness. Closes #7
Every function is now a separate subcommand:
 * append (append a key, a modifier, or a string to one or more pedals)
 * clear (clear one or more pedals)
 * help (print a help message)
 * list (print a table with all possible keys)
 * read (read values from the footpedal)
 * set (set a key or mousebutton to one or more pedals)

A disadvantage is that different subcommands cannot be combined in one
call of the application anymore. However, this new structure brings the
major benefit that the program is more intuitive for users.

A second, small change is the fact that the welcome() function now reads
application and authore name from the Cargo file.
2018-11-14 00:20:51 +01:00

382 lines
12 KiB
Rust

#[path = "key_operations.rs"] pub mod key_operations;
extern crate hidapi;
use std::process;
use std::ffi::CString;
use colored::*;
use messages::*;
#[derive(Copy, Clone)]
enum Type {
Unconfigured = 0,
Key = 1,
Mouse = 2,
MouseKey = 3,
String = 4
}
impl Type {
fn u8_to_enum(value:u8) -> Option<Type> {
match value {
0 => Some(Type::Unconfigured),
1 => Some(Type::Key),
2 => Some(Type::Mouse),
3 => Some(Type::MouseKey),
4 => Some(Type::String),
0x81 => Some(Type::Key),
_ => None
}
}
}
pub struct PedalsData {
header: [u8; 8],
data: [u8; 48],
length: u8,
}
pub struct Pedals {
dev:hidapi::HidDevice,
start: [u8; 8],
ped_data: Vec<PedalsData>,
}
impl Pedals {
pub fn new() -> Pedals {
// Open device
let vld_dev = [
(0x0c45u16, 0x7403u16),
(0x0c45 , 0x7404),
(0x413d , 0x2107)
];
info!("Initializing HID object. This can take a moment.");
let api = match hidapi::HidApi::new() {
Ok(res) => {
info!("Successfully initialized HID object.");
res
},
Err(_) => {
error!("Could not initialize HID object.")
},
};
let mut dev_path = CString::new("").unwrap();
for device in api.devices() {
for val in vld_dev.iter() {
if *val == (device.vendor_id, device.product_id) && device.interface_number == 1 {
info!("Found device {:x}:{:x} ({:#?})", device.vendor_id, device.product_id, device.path);
dev_path = device.path.clone();
}
}
}
// Moved this out of loop, because of error of "possibly uninitialized `dev`. Don't try to move it in the loop.
let dev = match api.open_path(&dev_path) {
Ok(res) => {
info!("Successfully opened device.");
res
},
Err(_) => {
error!("Could not open device. Make sure your device is connected. Maybe try to reconnect it.")
},
};
// Prepare variables
let start = [0x01u8, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00];
let header_0 = [0x01u8, 0x81, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00];
let header_1 = [0x01u8, 0x81, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00];
let header_2 = [0x01u8, 0x81, 0x08, 0x03, 0x00, 0x00, 0x00, 0x00];
let mut default_data = [0u8; 48];
default_data[0] = 0x08;
// Initialize actual object
Pedals {
dev: dev,
start: start,
ped_data: vec![
PedalsData {
header: header_0,
data: default_data,
length: 8,
},
PedalsData {
header: header_1,
data: default_data,
length: 8,
},
PedalsData {
header: header_2,
data: default_data,
length: 8, },
]
}
}
pub fn read_pedal(&self, ped:& u8) -> [u8; 8] {
let mut buf = [0u8; 8];
let mut query = [0x01u8, 0x82, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00];
query[3] += ped;
// Write query to device
self.dev.write(&query).unwrap();
// Read answer
self.dev.read(&mut buf[..]).unwrap();
buf
}
/// Read the current values of the pedals
pub fn read_pedals(&self, peds: Vec<u8>) {
let total_width = 55 as usize;
// Check if passed pedal number is valid
for i in peds.iter() {
if *i > 2 {
error!("Pedal value {} is larger than 2 and thus not valid!", i);
}
}
// Print header
println!("{}", "".repeat(total_width));
println!("{name:^width$}", name = "Programmed Keys", width = total_width);
println!("{}", "".repeat(total_width));
// Read and print keys
for (i, ped) in peds.iter().enumerate() {
// Read value from pedal and directly translate it to a key
let mut key_value = self.read_pedal(ped);
let key_name_option = match Type::u8_to_enum(key_value[1]) {
Some(Type::Unconfigured) => None,
Some(Type::Key) => key_operations::print_key(&key_value),
Some(Type::Mouse) => key_operations::print_mousebutton(&key_value),
Some(Type::MouseKey) => key_operations::print_mouse_key(&key_value),
Some(Type::String) => self.print_string(& mut key_value),
None => error!("The key type which was returned by the pedal was invalid!")
};
let key_name = match key_name_option {
Some(key) => key,
None => "< None >".to_string(),
};
println!("│ Pedal {ped}{name:<-width$}", ped = ped, name = key_name, width = total_width - 14);
// Print spacer between lines
if i != peds.len() - 1 {
println!("{}{name:<-width$}", "".repeat(10), name = "".repeat(total_width - 14), width = total_width - 12);
}
}
// Print simple footer
println!("{}", "".repeat(total_width));
}
/// Sets the type of the function. False (0) if everything went fine, True (1) if
/// an error occurred.
fn set_type(& mut self, ped:usize, typ:Type) {
let set_value = if self.ped_data[ped].data[1] == 0 { true } else { false };
if set_value {
self.ped_data[ped].data[1] = typ as u8;
}
let ret = match typ {
Type::String => {
// If nothing is set, set type to string and length to 2
if set_value {
self.ped_data[ped].length = 2;
}
// Check if pedal type is set to String, otherwise error
self.ped_data[ped].data[1] != Type::String as u8
}
_ => {
let ret;
if self.ped_data[ped].data[1] == Type::String as u8 {
// if type is Key or Mouse, and String is already set, return false
ret = true;
}
else {
// else, set type to new type and return true
self.ped_data[ped].data[1] |= typ as u8;
ret = false;
}
ret
}
};
if ret {
error!("Invalid combination of options!");
}
}
fn write_pedal(&self, ped:usize) {
// First, write header
self.dev.write(&self.ped_data[ped].header).unwrap();
// Write data to device in 8 byte chunks
let mut up:usize = 0;
for i in 0..(self.ped_data[ped].length / 8) {
// Set bounds
let low = (i * 8) as usize;
up = 8 * (i + 1) as usize;
// Write to device
self.dev.write(&self.ped_data[ped].data[low..up]).unwrap();
}
// Write remaining values to device
if self.ped_data[ped].length % 8 > 0 {
self.dev.write(&self.ped_data[ped].data[up..(self.ped_data[ped].length as usize)]).unwrap();
}
}
/// This method writes all data from Pedals.peddata to the device
pub fn write_pedals(&self) {
self.dev.write(&self.start).unwrap();
for (i, _pedal) in self.ped_data.iter().enumerate() {
self.write_pedal(i)
}
}
pub fn set_key(& mut self, ped:usize, key:&str) {
if let Some(encoded_key) = key_operations::encode_byte(key) {
self.set_type(ped, Type::Key);
self.ped_data[ped].data[3] = encoded_key;
}
else {
error!("Key '{}' is not recognized! Please provide a valid key, listed in './footswitch-rs --listkeys 4'", key);
}
}
pub fn set_modifier(& mut self, ped:usize, modifier:&str) {
let modifier = match key_operations::Modifier::str_to_enum(modifier) {
Some(x) => x,
None => error!("Unknown modifier! Please use one of the following: ctrl, shift, alt, win."),
};
self.set_type(ped, Type::Key);
self.ped_data[ped].data[2] |= modifier as u8;
}
pub fn set_mousebutton(& mut self, ped:usize, mousebutton:&str) {
let mousebutton = match key_operations::MouseButton::str_to_enum(mousebutton) {
Some(x) => x,
None => error!("Unknown mousebutton! Please use one of the following: mouse_left, mouse_middle, mouse_right, mouse_double."),
};
self.set_type(ped, Type::Mouse);
self.ped_data[ped].data[4] |= mousebutton as u8;
}
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 to u8
let mut value_u8 = value_i8 as u8;
// Check if mouse wheel movement is smaller than 0, if so, add 256
if (direction == 7) & (value_i8 < 0) {
value_u8 += value_i8 as u8 + 256;
}
// Set Mouse Type
self.set_type(ped, Type::Mouse);
// Actually write data
self.ped_data[ped].data[direction] = value_u8;
}
pub fn print_string(&self, response: & mut [u8]) -> Option<String> {
let mut string = String::new();
let mut len = response[0] - 2;
let mut ind = 2;
while len > 0 {
if ind == 8 {
self.dev.read(&mut response[..]).unwrap();
ind = 0;
}
if let Some(key_str) = key_operations::decode_byte(&response[ind]) {
string.push_str(&key_str[..]);
}
len -= 1;
ind += 1;
}
Some(string)
}
pub fn set_string(& mut self, ped:usize, key:&str) {
self.set_type(ped, Type::String);
if key.len() > 38 {
error!("The size of each string must be smaller than or equal to 38.");
}
let encoded_vector = match key_operations::encode_string(&key) {
Some(x) => x,
None => error!("Could not encode string!"),
};
self.compile_string_data(ped, encoded_vector);
}
fn compile_string_data(& mut self, ped:usize, enc_vec:Vec<u8>) {
let len = enc_vec.len() as u8;
if self.ped_data[ped].length + len > 38 {
error!("The size of the accumulated string must be smaller than or equal to 38.")
}
let start_byte = self.ped_data[ped].length as usize;
for (i, c) in enc_vec.iter().enumerate() {
self.ped_data[ped].data[start_byte + i] = *c;
}
self.ped_data[ped].length += len;
self.ped_data[ped].header[2] = self.ped_data[ped].length;
self.ped_data[ped].data[0] = self.ped_data[ped].length;
}
/// 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();
}
}