extern crate hidapi;
use argh::FromArgs;
use hidapi::HidApi;
mod keycodes;
mod keymap;
mod protocol;
mod commands;
mod common;
#[derive(FromArgs)]
struct VialClient {
#[argh(option, short = 'i')]
id: Option<u16>,
#[argh(switch, short = 'v')]
version: bool,
#[argh(subcommand)]
command: Option<CommandEnum>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum CommandEnum {
Devices(CommandDevices),
Lock(CommandLock),
Settings(CommandSettings),
Layers(CommandLayers),
Keys(CommandKeys),
Encoders(CommandEncoders),
Combos(CommandCombos),
Macros(CommandMacros),
TapDances(CommandTapDances),
KeyOverrides(CommandKeyOverrides),
AltRepeats(CommandAltRepeats),
Load(CommandLoad),
Save(CommandSave),
Rgb(commands::CommandRgb),
Layout(CommandLayout),
Tester(CommandTester),
Bootload(CommandBootload),
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "devices")]
struct CommandDevices {
#[argh(switch, short = 'c')]
capabilities: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "lock")]
struct CommandLock {
#[argh(switch, short = 'u')]
unlock: bool,
#[argh(switch, short = 'l')]
lock: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "combos")]
struct CommandCombos {
#[argh(option, short = 'n')]
number: Option<u8>,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "macros")]
struct CommandMacros {
#[argh(option, short = 'n')]
number: Option<u8>,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "tapdances")]
struct CommandTapDances {
#[argh(option, short = 'n')]
number: Option<u8>,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "keyoverrides")]
struct CommandKeyOverrides {
#[argh(option, short = 'n')]
number: Option<u8>,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "altrepeats")]
struct CommandAltRepeats {
#[argh(option, short = 'n')]
number: Option<u8>,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "layers")]
struct CommandLayers {
#[argh(option, short = 'm')]
meta: Option<String>,
#[argh(switch, short = 'p')]
positions: bool,
#[argh(option, short = 'n')]
number: Option<u8>,
#[argh(option, short = 'o')]
options: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "keys")]
struct CommandKeys {
#[argh(option, short = 'm')]
meta: Option<String>,
#[argh(option, short = 'l')]
layer: u8,
#[argh(option, short = 'p')]
position: String,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "settings")]
struct CommandSettings {
#[argh(option, short = 'q')]
qsid: Option<f64>,
#[argh(option, short = 'v')]
value: Option<String>,
#[argh(switch, short = 'r')]
reset: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "load")]
struct CommandLoad {
#[argh(option, short = 'm')]
meta: Option<String>,
#[argh(option, short = 'f')]
file: String,
#[argh(switch, short = 'p')]
preview: bool,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "save")]
struct CommandSave {
#[argh(option, short = 'm')]
meta: Option<String>,
#[argh(option, short = 'f')]
file: String,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "layout")]
struct CommandLayout {
#[argh(option, short = 'm')]
meta: Option<String>,
#[argh(option, short = 'o')]
option: Option<u8>,
#[argh(option, short = 'v')]
value: Option<u8>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "encoders")]
struct CommandEncoders {
#[argh(option, short = 'l')]
layer: u8,
#[argh(option, short = 'p')]
position: String,
#[argh(option, short = 'v')]
value: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "tester")]
struct CommandTester {
#[argh(option, short = 'm')]
meta: Option<String>,
}
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "bootload")]
struct CommandBootload {}
fn command_for_devices(id: Option<u16>, command: &CommandEnum) {
match HidApi::new() {
Ok(api) => {
let mut found = false;
for device in api.device_list() {
if device.usage_page() == protocol::USAGE_PAGE
&& device.usage() == protocol::USAGE_ID
&& (id.is_none() || id.unwrap() == device.product_id())
{
found = true;
println!(
"Product name: {:?} id: {:?},\nManufacturer name: {:?}, id: {:?},\nRelease: {:?}, Serial: {:?}, Path: {:?}",
device.product_string().unwrap(),
device.product_id(),
device.manufacturer_string().unwrap(),
device.vendor_id(),
device.release_number(),
device.serial_number().unwrap(),
device.path(),
);
let result = match command {
CommandEnum::Devices(ops) => {
commands::devices_run(&api, device, ops.capabilities)
}
CommandEnum::Lock(ops) => {
commands::lock_run(&api, device, ops.unlock, ops.lock)
}
CommandEnum::Combos(ops) => {
commands::combos_run(&api, device, ops.number, &ops.value)
}
CommandEnum::Macros(ops) => {
commands::macros_run(&api, device, ops.number, &ops.value)
}
CommandEnum::TapDances(ops) => {
commands::tapdances_run(&api, device, ops.number, &ops.value)
}
CommandEnum::KeyOverrides(ops) => {
commands::keyoverrides_run(&api, device, ops.number, &ops.value)
}
CommandEnum::AltRepeats(ops) => {
commands::altrepeats_run(&api, device, ops.number, &ops.value)
}
CommandEnum::Layers(ops) => commands::layers_run(
&api,
device,
&ops.meta,
ops.positions,
ops.number,
&ops.options,
),
CommandEnum::Keys(ops) => commands::keys_run(
&api,
device,
&ops.meta,
ops.layer,
&ops.position,
&ops.value,
),
CommandEnum::Encoders(ops) => commands::encoders_run(
&api,
device,
ops.layer,
&ops.position,
&ops.value,
),
CommandEnum::Settings(ops) => {
commands::settings_run(&api, device, &ops.qsid, &ops.value, ops.reset)
}
CommandEnum::Load(ops) => {
commands::load_run(&api, device, &ops.meta, &ops.file, ops.preview)
}
CommandEnum::Save(ops) => {
commands::save_run(&api, device, &ops.meta, &ops.file)
}
CommandEnum::Rgb(ops) => commands::rgb_run(&api, device, ops),
CommandEnum::Layout(ops) => {
commands::layout_run(&api, device, &ops.meta, &ops.option, &ops.value)
}
CommandEnum::Tester(ops) => commands::tester_run(&api, device, &ops.meta),
CommandEnum::Bootload(_) => commands::bootload_run(&api, device),
};
match result {
Ok(_) => {
}
Err(e) => {
eprintln!("Error: {}", e)
}
}
}
}
if !found {
eprintln!("No matching devices found");
}
}
Err(e) => {
eprintln!("Error: {:?}", e);
}
}
}
fn main() {
let options: VialClient = argh::from_env();
if options.version {
println!("{0} {1}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"))
} else if let Some(command) = options.command {
command_for_devices(options.id, &command);
} else {
println!(
"{0} {1}\nRun {0} --help for more information.",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
)
}
}