rog-aura: add basic per-key support

This commit is contained in:
Luke D. Jones
2022-08-25 21:45:36 +12:00
parent f378c54815
commit 40987ecd5d
11 changed files with 292 additions and 76 deletions

View File

@@ -15,6 +15,7 @@ use zbus::dbus_interface;
use zvariant::ObjectPath;
use zvariant_derive::Type;
use crate::user_config::ConfigLoadSave;
use crate::{error::Error, user_config::UserAnimeConfig};
#[derive(Debug, Clone, Deserialize, Serialize, Type)]

View File

@@ -1,4 +1,5 @@
use rog_anime::usb::get_anime_type;
use rog_aura::layouts::KeyLayout;
use rog_dbus::RogDbusClientBlocking;
use rog_user::{
ctrl_anime::{CtrlAnime, CtrlAnimeInner},
@@ -6,12 +7,18 @@ use rog_user::{
DBUS_NAME,
};
use smol::Executor;
use std::sync::Arc;
use std::sync::Mutex;
use std::{fs::OpenOptions, io::Read, path::PathBuf, sync::Arc};
use zbus::Connection;
use std::sync::atomic::AtomicBool;
#[cfg(not(feature = "local_data"))]
const DATA_DIR: &str = "/usr/share/rog-gui/";
#[cfg(feature = "local_data")]
const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR");
const BOARD_NAME: &str = "/sys/class/dmi/id/board_name";
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!(" user daemon v{}", rog_user::VERSION);
println!(" rog-anime v{}", rog_anime::VERSION);
@@ -22,49 +29,83 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let supported = client.proxies().supported().supported_functions()?;
let mut config = UserConfig::new();
config.load_config()?;
config.load()?;
let executor = Executor::new();
let early_return = Arc::new(AtomicBool::new(false));
// Set up the anime data and run loop/thread
if supported.anime_ctrl.0 {
let anime_type = get_anime_type()?;
let anime_config = UserAnimeConfig::load_config(config.active_anime)?;
let anime = anime_config.create_anime(anime_type)?;
let anime_config = Arc::new(Mutex::new(anime_config));
if let Some(cfg) = config.active_anime {
let anime_type = get_anime_type()?;
let anime_config = UserAnimeConfig::load(cfg)?;
let anime = anime_config.create(anime_type)?;
let anime_config = Arc::new(Mutex::new(anime_config));
executor
.spawn(async move {
// Create server
let mut connection = Connection::session().await.unwrap();
connection.request_name(DBUS_NAME).await.unwrap();
executor
.spawn(async move {
// Create server
let mut connection = Connection::session().await.unwrap();
connection.request_name(DBUS_NAME).await.unwrap();
// Inner behind mutex required for thread safety
let inner = Arc::new(Mutex::new(
CtrlAnimeInner::new(anime, client, early_return.clone()).unwrap(),
));
// Need new client object for dbus control part
let (client, _) = RogDbusClientBlocking::new().unwrap();
let anime_control =
CtrlAnime::new(anime_config, inner.clone(), client, early_return).unwrap();
anime_control.add_to_server(&mut connection).await;
loop {
if let Ok(inner) = inner.clone().try_lock() {
inner.run().ok();
// Inner behind mutex required for thread safety
let inner = Arc::new(Mutex::new(
CtrlAnimeInner::new(anime, client, early_return.clone()).unwrap(),
));
// Need new client object for dbus control part
let (client, _) = RogDbusClientBlocking::new().unwrap();
let anime_control =
CtrlAnime::new(anime_config, inner.clone(), client, early_return).unwrap();
anime_control.add_to_server(&mut connection).await;
loop {
if let Ok(inner) = inner.clone().try_lock() {
inner.run().ok();
}
}
}
})
.detach();
})
.detach();
}
}
// if supported.keyboard_led.per_key_led_mode {
// executor
// .spawn(async move {
// //
// })
// .detach();
// }
if supported.keyboard_led.per_key_led_mode {
if let Some(cfg) = config.active_aura {
let mut aura_config = UserAuraConfig::load(cfg)?;
// Find and load a matching layout for laptop
let mut file = OpenOptions::new()
.read(true)
.open(PathBuf::from(BOARD_NAME))
.map_err(|e| {
println!("{BOARD_NAME}, {e}");
e
})?;
let mut board_name = String::new();
file.read_to_string(&mut board_name)?;
let layout = KeyLayout::find_layout(board_name.as_str(), PathBuf::from(DATA_DIR))
.map_err(|e| {
println!("{BOARD_NAME}, {e}");
})
.unwrap_or(KeyLayout::ga401_layout());
executor
.spawn(async move {
// Create server
let (client, _) = RogDbusClientBlocking::new().unwrap();
// let connection = Connection::session().await.unwrap();
// connection.request_name(DBUS_NAME).await.unwrap();
loop {
aura_config.aura.next_state(&layout);
let packets = aura_config.aura.create_packets();
client.proxies().led().per_key_raw(packets).unwrap();
std::thread::sleep(std::time::Duration::from_millis(60));
}
})
.detach();
}
}
loop {
smol::block_on(executor.tick());

View File

@@ -5,28 +5,21 @@ use std::{
};
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences, Vec2};
use rog_aura::{keys::Key, Colour, Speed};
use serde::de::DeserializeOwned;
use serde_derive::{Deserialize, Serialize};
use crate::error::Error;
#[derive(Debug, Deserialize, Serialize)]
pub struct UserAnimeConfig {
pub name: String,
pub anime: Vec<ActionLoader>,
}
pub trait ConfigLoadSave<T> {
fn name(&self) -> String;
impl UserAnimeConfig {
pub fn create_anime(&self, anime_type: AnimeType) -> Result<Sequences, Error> {
let mut seq = Sequences::new(anime_type);
fn default_with_name(name: String) -> T;
for (idx, action) in self.anime.iter().enumerate() {
seq.insert(idx, action)?;
}
Ok(seq)
}
pub fn write(&self) -> Result<(), Error> {
fn write(&self) -> Result<(), Error>
where
Self: serde::Serialize,
{
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
@@ -37,7 +30,7 @@ impl UserAnimeConfig {
if !path.exists() {
create_dir(path.clone())?;
}
let name = self.name.clone();
let name = self.name().clone();
path.push(name + ".cfg");
let mut file = OpenOptions::new()
@@ -51,7 +44,10 @@ impl UserAnimeConfig {
Ok(())
}
pub fn load_config(name: String) -> Result<UserAnimeConfig, Error> {
fn load(name: String) -> Result<T, Error>
where
T: DeserializeOwned + serde::Serialize,
{
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
@@ -75,14 +71,11 @@ impl UserAnimeConfig {
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
let default = UserAnimeConfig {
name,
..Default::default()
};
let default = Self::default_with_name(name);
let json = serde_json::to_string_pretty(&default).unwrap();
file.write_all(json.as_bytes())?;
return Ok(default);
} else if let Ok(data) = serde_json::from_str::<UserAnimeConfig>(&buf) {
} else if let Ok(data) = serde_json::from_str::<T>(&buf) {
return Ok(data);
}
}
@@ -90,6 +83,37 @@ impl UserAnimeConfig {
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct UserAnimeConfig {
pub name: String,
pub anime: Vec<ActionLoader>,
}
impl UserAnimeConfig {
pub fn create(&self, anime_type: AnimeType) -> Result<Sequences, Error> {
let mut seq = Sequences::new(anime_type);
for (idx, action) in self.anime.iter().enumerate() {
seq.insert(idx, action)?;
}
Ok(seq)
}
}
impl ConfigLoadSave<UserAnimeConfig> for UserAnimeConfig {
fn name(&self) -> String {
self.name.clone()
}
fn default_with_name(name: String) -> Self {
UserAnimeConfig {
name,
..Default::default()
}
}
}
impl Default for UserAnimeConfig {
fn default() -> Self {
Self {
@@ -151,20 +175,83 @@ impl Default for UserAnimeConfig {
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct UserAuraConfig {
pub name: String,
pub aura: rog_aura::Sequences,
}
impl ConfigLoadSave<UserAuraConfig> for UserAuraConfig {
fn name(&self) -> String {
self.name.clone()
}
fn default_with_name(name: String) -> Self {
UserAuraConfig {
name,
..Default::default()
}
}
}
impl Default for UserAuraConfig {
fn default() -> Self {
let mut seq = rog_aura::Sequences::new();
let mut key = rog_aura::ActionData::new_breathe(
Key::W,
Colour(255, 0, 20),
Colour(20, 255, 0),
Speed::Low,
);
seq.push(key.clone());
key.set_key(Key::A);
seq.push(key.clone());
key.set_key(Key::S);
seq.push(key.clone());
key.set_key(Key::D);
seq.push(key);
let key = rog_aura::ActionData::new_breathe(
Key::F,
Colour(255, 0, 0),
Colour(255, 0, 0),
Speed::High,
);
seq.push(key);
let mut key = rog_aura::ActionData::new_static(Key::RCtrl, Colour(0, 0, 255));
seq.push(key.clone());
key.set_key(Key::LCtrl);
seq.push(key.clone());
key.set_key(Key::Esc);
seq.push(key);
Self {
name: "default".to_string(),
aura: seq,
}
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(default)]
pub struct UserConfig {
/// Name of active anime config file in the user config directory
pub active_anime: String,
pub active_anime: Option<String>,
/// Name of active aura config file in the user config directory
pub active_aura: Option<String>,
}
impl UserConfig {
pub fn new() -> Self {
Self {
active_anime: "anime-default".to_string(),
active_anime: Some("anime-default".to_string()),
active_aura: Some("aura-default".to_string()),
}
}
pub fn load_config(&mut self) -> Result<(), Error> {
pub fn load(&mut self) -> Result<(), Error> {
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
@@ -192,6 +279,7 @@ impl UserConfig {
file.write_all(json.as_bytes())?;
} else if let Ok(data) = serde_json::from_str::<UserConfig>(&buf) {
self.active_anime = data.active_anime;
self.active_aura = data.active_aura;
return Ok(());
}
}