Skip to content

Commit

Permalink
v0.19.3 (#141)
Browse files Browse the repository at this point in the history
* Fix tray icon handling

* Fix unresponsive icon when not focused

Adresses #122

* Mention LOQ models in the udev rules

* Clean up some code

* Update deps

- Change PathBuf to Path for the saving trait
- Remove deprecated into_report
- Fix debug only egui style visuals

* Add a saturation boost option to AmbientLight

* Fix the CMD appearing in Windows builds

* Fix underflow on zone index for ripple

* Fmt

* Properly detect if another instance is running

Rust really likes dropping stuff

* Stop the inner thread loop when dropping EffectManager

* Update project edition

* Update flake

* Update version and deps
  • Loading branch information
4JX authored Oct 13, 2023
1 parent 56f13be commit 028eb0e
Show file tree
Hide file tree
Showing 22 changed files with 1,182 additions and 495 deletions.
815 changes: 648 additions & 167 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[workspace]
members = ["app", "driver"]
resolver = "2"
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ The best way to add a new effect is to directly edit the source code, as it allo
# Regular legions
SUBSYSTEM=="usb", ATTR{idVendor}=="048d", ATTR{idProduct}=="c985", MODE="0666"
SUBSYSTEM=="usb", ATTR{idVendor}=="048d", ATTR{idProduct}=="c984", MODE="0666"

# LOQ Models
SUBSYSTEM=="usb", ATTR{idVendor}=="048d", ATTR{idProduct}=="c983", MODE="0666"
```

- **2022 Models:**
Expand Down
65 changes: 42 additions & 23 deletions app/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,53 +1,72 @@
[package]
name = "legion-kb-rgb"
version = "0.19.2"
version = "0.19.3"
authors = ["4JX"]
edition = "2018"
edition = "2021"
homepage = "https://github.com/4JX/L5P-Keyboard-RGB"
license = "GPL-3.0"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# Main driver
legion-rgb-driver = { path = "../driver" }

# Cli
clap = { version = "4.1.2", features = ["color", "cargo", "derive"] }

# Ui
eframe = "0.23.0"
egui-modal = "0.2.5"
# egui-modal = { git = "https://github.com/n00kii/egui-modal", rev = "8443238" }
egui_file = "0.11.0"
egui-notify = "0.10.0"
# egui-notify = { git = "https://github.com/ItsEthra/egui-notify", rev = "bc5eb67" }

# App window, taskbar and tray icon loading
image = "0.24.5"

# AmbientLight effect
scrap = { git = "https://github.com/rustdesk/rustdesk", rev = "6c15dd6", features = [
"wayland",
] }
rand = "0.8.5"
fast_image_resize = "2.4.0"
tray-item = { version = "0.5.0-alpha", git = "https://github.com/njust/tray-item-rs" }
clap = { version = "4.1.2", features = ["color", "cargo", "derive"] }
strum = "0.24.1"
strum_macros = "0.24.3"
# default-features = false just removes the use_wasm feature that removes a lot of unecessary slack
# since this app wont ever use the web
# photon-rs = { version = "0.3.2", default-features = false }
photon-rs = { git = "https://github.com/silvia-odwyer/photon", rev = "3e8a2a6", default-features = false }


# Keyboard and mouse grabbing
device_query = "1.1.3"

rand = "0.8.5"
strum = "0.25.0"
strum_macros = "0.25.2"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
color-eyre = "0.6.2"
sysinfo = "0.29.0"
crossbeam-channel = "0.5.8"
thiserror = "1.0.38"
single-instance = "0.3.3"
image = "0.24.5"
open = "4.1.0"
error-stack = "0.3.1"
eframe = "0.22.0"
# egui-modal = "0.1.8"
egui-modal = { git = "https://github.com/n00kii/egui-modal", rev = "8443238" }
egui_file = "0.9.0"
# egui-notify = "0.6.0"
egui-notify = { git = "https://github.com/ItsEthra/egui-notify", rev = "bc5eb67" }
device_query = "1.1.3"
open = "5.0.0"
error-stack = "0.4.1"
winapi = { version = "0.3.9", features = ["consoleapi", "wincon"] }

# Fix versions to stop cargo from yelling about dependency resolution

# Dependabot alerts

# Fix version to stop cargo from yelling about dependency resolution
bytes = "1.4.0"

# Dependabot alertsa
regex = "1.6.0"
crossbeam-utils = "0.8.12"
[target.'cfg(target_os = "windows")'.dependencies]
tray-item = { version = "0.8.0" }

[target.'cfg(target_os = "linux")'.dependencies]
tray-item = { version = "0.8.0", features = ["ksni"] }

[build-dependencies]
winres = "0.1.12"
windres = "0.2.2"

[package.metadata.vcpkg]
git = "https://github.com/microsoft/vcpkg"
Expand Down
10 changes: 5 additions & 5 deletions app/build.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
extern crate winres;
extern crate windres;

fn main() {
if cfg!(target_os = "windows") {
let mut res = winres::WindowsResource::new();
res.set_icon_with_id("./res/trayIcon.ico", "trayIcon");
res.compile().unwrap();
#[cfg(target_os = "windows")]
{
use windres::Build;
Build::new().compile("./res/resources.rc").unwrap();
}
}
1 change: 1 addition & 0 deletions app/res/resources.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
trayIcon ICON "trayIcon.ico"
205 changes: 121 additions & 84 deletions app/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use strum::IntoEnumIterator;
use thiserror::Error;

use crate::{
effects::custom_effect::CustomEffect,
effects::{self, custom_effect::CustomEffect, ManagerCreationError},
enums::{Brightness, Direction, Effects},
profile::{self, Profile},
};
Expand Down Expand Up @@ -108,15 +108,34 @@ fn parse_colors(arg: &str) -> std::result::Result<[u8; 12], String> {
}
}

pub struct CliOutput {
/// Indicates if the user wants to start the GUI
pub start_gui_maybe_hidden: Option<bool>,
pub enum CliOutput {
/// Start the UI
Gui { hide_window: bool, output: OutputType },

/// What instruction was received through the CLI
pub output: CliOutputType,
/// CLI arguments were passed
Cli(OutputType),
}

pub enum CliOutputType {
impl CliOutput {
fn maybe_gui(start_gui: bool, hide_window: bool, output: OutputType) -> Self {
if start_gui {
Self::Gui { hide_window, output }
} else {
Self::Cli(output)
}
}
}

pub enum GuiCommand {
/// Start the UI
Start { hide_window: bool, output: OutputType },

/// Close the program as the CLI was invoked
Exit,
}

/// What instruction was received through the CLI
pub enum OutputType {
Profile(Profile),
Custom(CustomEffect),
NoArgs,
Expand All @@ -127,93 +146,111 @@ pub enum CliOutputType {
#[error("There was an error while executing the CLI")]
pub struct CliError;

pub fn try_cli(is_unique_instance: bool) -> Result<CliOutput, CliError> {
let cli = Cli::parse();

match cli.command {
Some(subcommand) => {
// Early logic for specific subcommands
if let Commands::Set { .. } | Commands::CustomEffect { .. } = subcommand {
assert!(is_unique_instance, "Another instance of the program is already running, please close it before starting a new one.");
pub fn try_cli() -> Result<GuiCommand, CliError> {
let output = parse_cli()?;

match output {
CliOutput::Gui { hide_window, output } => Ok(GuiCommand::Start { hide_window, output }),
CliOutput::Cli(output) => {
let manager_result = effects::EffectManager::new(effects::OperationMode::Cli);

let instance_not_unique = if let Err(err) = &manager_result {
&ManagerCreationError::InstanceAlreadyRunning == err.current_context()
} else {
false
};

// Don't interrupt other instances if trying to interact with the keyboard
if let OutputType::Profile(..) | OutputType::Custom(..) = output {
if instance_not_unique {
println!("Another instance of the program is already running, please close it before starting a new one.");
process::exit(0);
}
}

match subcommand {
Commands::Set {
effect,
colors,
brightness,
speed,
direction,
save,
} => {
let direction = direction.unwrap_or_default();

let rgb_array: [u8; 12] = if effect.takes_color_array() {
colors.unwrap_or_else(|| {
println!("This effect requires specifying the colors to use.");
process::exit(0);
})
} else {
[0; 12]
};

let profile = Profile {
name: "Profile".to_string(),
rgb_zones: profile::arr_to_zones(rgb_array),
effect,
direction,
speed,
brightness,
};

if let Some(filename) = save {
profile.save_profile(filename).expect("Failed to save.");
}

Ok(CliOutput {
start_gui_maybe_hidden: if cli.gui { Some(cli.hide_window) } else { None },
output: CliOutputType::Profile(profile),
})
let mut effect_manager = manager_result.unwrap();

match output {
OutputType::Profile(profile) => {
effect_manager.set_profile(profile);
effect_manager.join_and_exit();
Ok(GuiCommand::Exit)
}
Commands::List => {
println!("List of available effects:");
for (i, effect) in Effects::iter().enumerate() {
println!("{i}. {effect}",);
}

Ok(CliOutput {
start_gui_maybe_hidden: None,
output: CliOutputType::Exit,
})
OutputType::Custom(effect) => {
effect_manager.custom_effect(effect);
effect_manager.join_and_exit();
Ok(GuiCommand::Exit)
}
OutputType::Exit => Ok(GuiCommand::Exit),
OutputType::NoArgs => unreachable!("No arguments were provided but the app is in CLI mode"),
}
}
}
}

Commands::LoadProfile { path } => {
let profile = Profile::load_profile(path).change_context(CliError)?;

Ok(CliOutput {
start_gui_maybe_hidden: if cli.gui { Some(cli.hide_window) } else { None },
output: CliOutputType::Profile(profile),
})
}
fn parse_cli() -> Result<CliOutput, CliError> {
let cli = Cli::parse();

Commands::CustomEffect { path } => {
let effect = CustomEffect::from_file(path).change_context(CliError)?;
let Some(subcommand) = cli.command else {
let exec_name = std::env::current_exe().unwrap().file_name().unwrap().to_string_lossy().into_owned();
println!("No subcommands found, starting in GUI mode. To view the possible subcommands type \"{exec_name} --help\".",);
return Ok(CliOutput::maybe_gui(true, cli.hide_window, OutputType::NoArgs));
};

match subcommand {
Commands::Set {
effect,
colors,
brightness,
speed,
direction,
save,
} => {
let direction = direction.unwrap_or_default();

let rgb_array: [u8; 12] = if effect.takes_color_array() {
colors.unwrap_or_else(|| {
println!("This effect requires specifying the colors to use.");
process::exit(0);
})
} else {
[0; 12]
};

let profile = Profile {
name: "Profile".to_string(),
rgb_zones: profile::arr_to_zones(rgb_array),
effect,
direction,
speed,
brightness,
};

if let Some(filename) = save {
profile.save_profile(&filename).expect("Failed to save.");
}

Ok(CliOutput {
start_gui_maybe_hidden: if cli.gui { Some(cli.hide_window) } else { None },
output: CliOutputType::Custom(effect),
})
}
Ok(CliOutput::maybe_gui(cli.gui, cli.hide_window, OutputType::Profile(profile)))
}
Commands::List => {
println!("List of available effects:");
for (i, effect) in Effects::iter().enumerate() {
println!("{}. {effect}", i + 1);
}

Ok(CliOutput::maybe_gui(false, cli.hide_window, OutputType::Exit))
}

Commands::LoadProfile { path } => {
let profile = Profile::load_profile(&path).change_context(CliError)?;

Ok(CliOutput::maybe_gui(cli.gui, cli.hide_window, OutputType::Profile(profile)))
}

None => {
let exec_name = std::env::current_exe().unwrap().file_name().unwrap().to_string_lossy().into_owned();
println!("No subcommands found, starting in GUI mode. To view the possible subcommands type \"{exec_name} --help\".",);
Ok(CliOutput {
start_gui_maybe_hidden: Some(cli.hide_window),
output: CliOutputType::NoArgs,
})
Commands::CustomEffect { path } => {
let effect = CustomEffect::from_file(&path).change_context(CliError)?;

Ok(CliOutput::maybe_gui(cli.gui, cli.hide_window, OutputType::Custom(effect)))
}
}
}
Loading

0 comments on commit 028eb0e

Please sign in to comment.