mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
rog-aura: bringup the per-key LED stuff again
This commit is contained in:
113
asusctl/examples/aura-rgb-ball.rs
Normal file
113
asusctl/examples/aura-rgb-ball.rs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
//! Very bad rushed example. The better way to do this would be to have
|
||||||
|
//! the balles move on their own square grid, then translate that to the
|
||||||
|
//! key layout via shape by pitch etc.
|
||||||
|
use rog_aura::{
|
||||||
|
layouts::{KeyLayout, KeyRow},
|
||||||
|
KeyColourArray,
|
||||||
|
};
|
||||||
|
use rog_dbus::RogDbusClientBlocking;
|
||||||
|
use std::collections::LinkedList;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Ball {
|
||||||
|
position: (f32, f32),
|
||||||
|
direction: (f32, f32),
|
||||||
|
trail: LinkedList<(f32, f32)>,
|
||||||
|
}
|
||||||
|
impl Ball {
|
||||||
|
fn new(x: f32, y: f32, trail_len: u32) -> Self {
|
||||||
|
let mut trail = LinkedList::new();
|
||||||
|
for _ in 1..=trail_len {
|
||||||
|
trail.push_back((x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ball {
|
||||||
|
position: (x, y),
|
||||||
|
direction: (1.0, 1.0),
|
||||||
|
trail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
|
fn update(&mut self, key_map: &[KeyRow]) {
|
||||||
|
self.position.0 += self.direction.0;
|
||||||
|
self.position.1 += self.direction.1;
|
||||||
|
|
||||||
|
if self.position.1.abs() as usize >= key_map.len() {
|
||||||
|
self.direction.1 *= -1.0;
|
||||||
|
self.position.1 += self.direction.1;
|
||||||
|
self.direction.0 *= -1.0;
|
||||||
|
self.position.0 += self.direction.0;
|
||||||
|
}
|
||||||
|
if self.position.0.abs() as usize >= key_map[self.position.1.abs() as usize].row_ref().len()
|
||||||
|
{
|
||||||
|
self.direction.1 *= -1.0;
|
||||||
|
self.position.1 += self.direction.1;
|
||||||
|
}
|
||||||
|
if self.position.0 as usize >= key_map[self.position.1.abs() as usize].row_ref().len() {
|
||||||
|
self.direction.0 *= -1.0;
|
||||||
|
self.position.0 += self.direction.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = self.position;
|
||||||
|
|
||||||
|
if pos.1 == key_map[pos.1.abs() as usize].row_ref().len() as f32 - 1.0 || pos.1 <= 0.0 {
|
||||||
|
self.direction.0 *= -1.0;
|
||||||
|
} else if key_map[(pos.1) as usize].row_ref()[(pos.0) as usize].is_placeholder() {
|
||||||
|
self.direction.0 *= -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos.0 == key_map.len() as f32 - 1.0 || pos.0 <= 0.0 {
|
||||||
|
self.direction.1 *= -1.0;
|
||||||
|
} else if key_map[(pos.1) as usize].row_ref()[(pos.0) as usize].is_placeholder() {
|
||||||
|
self.direction.1 *= -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.trail.pop_front();
|
||||||
|
self.trail.push_back(self.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let (dbus, _) = RogDbusClientBlocking::new()?;
|
||||||
|
|
||||||
|
let mut colours = KeyColourArray::new();
|
||||||
|
let layout = KeyLayout::gx502_layout();
|
||||||
|
|
||||||
|
let mut balls = [Ball::new(2.0, 1.0, 12), Ball::new(5.0, 2.0, 12)];
|
||||||
|
// let mut balls = [Ball::new(2, 1, 12)];
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for (n, ball) in balls.iter_mut().enumerate() {
|
||||||
|
ball.update(layout.rows_ref());
|
||||||
|
for (i, pos) in ball.trail.iter().enumerate() {
|
||||||
|
if let Some(c) = colours
|
||||||
|
.rgb_for_key(layout.rows_ref()[pos.1.abs() as usize].row_ref()[pos.0 as usize])
|
||||||
|
{
|
||||||
|
c[0] = 0;
|
||||||
|
c[1] = 0;
|
||||||
|
c[2] = 0;
|
||||||
|
if n == 0 {
|
||||||
|
c[0] = i as u8 * (255 / ball.trail.len() as u8);
|
||||||
|
} else if n == 1 {
|
||||||
|
c[1] = i as u8 * (255 / ball.trail.len() as u8);
|
||||||
|
} else if n == 2 {
|
||||||
|
c[2] = i as u8 * (255 / ball.trail.len() as u8);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(c) = colours.rgb_for_key(
|
||||||
|
layout.rows_ref()[ball.position.1.abs() as usize].row_ref()
|
||||||
|
[ball.position.0 as usize],
|
||||||
|
) {
|
||||||
|
c[0] = 255;
|
||||||
|
c[1] = 255;
|
||||||
|
c[2] = 255;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
dbus.proxies().led().per_key_raw(colours.get())?;
|
||||||
|
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(150));
|
||||||
|
}
|
||||||
|
}
|
||||||
34
asusctl/examples/aura-rgb-iterate-keys.rs
Normal file
34
asusctl/examples/aura-rgb-iterate-keys.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//! Using a combination of key-colour array plus a key layout to generate outputs.
|
||||||
|
|
||||||
|
use rog_aura::{layouts::KeyLayout, KeyColourArray};
|
||||||
|
use rog_dbus::RogDbusClientBlocking;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let (client, _) = RogDbusClientBlocking::new().unwrap();
|
||||||
|
let layout = KeyLayout::gx502_layout();
|
||||||
|
loop {
|
||||||
|
let mut key_colours = KeyColourArray::new();
|
||||||
|
for row in layout.rows() {
|
||||||
|
for (k, key) in row.row().enumerate() {
|
||||||
|
if k != 0 {
|
||||||
|
if let Some(prev) = row.row().nth(k - 1) {
|
||||||
|
if let Some(c) = key_colours.rgb_for_key(*prev) {
|
||||||
|
c[0] = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if key.is_placeholder() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(c) = key_colours.rgb_for_key(*key) {
|
||||||
|
c[0] = 255;
|
||||||
|
};
|
||||||
|
|
||||||
|
client.proxies().led().per_key_raw(key_colours.get())?;
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ use async_trait::async_trait;
|
|||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_aura::{
|
use rog_aura::{
|
||||||
usb::{AuraDevice, LED_APPLY, LED_SET},
|
usb::{AuraDevice, LED_APPLY, LED_SET},
|
||||||
AuraEffect, LedBrightness, LED_MSG_LEN,
|
AuraEffect, KeyColourArray, LedBrightness, PerKeyRaw, LED_MSG_LEN,
|
||||||
};
|
};
|
||||||
use rog_aura::{AuraZone, Direction, Speed, GRADIENT};
|
use rog_aura::{AuraZone, Direction, Speed, GRADIENT};
|
||||||
use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions};
|
use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions};
|
||||||
@@ -70,6 +70,7 @@ pub struct CtrlKbdLed {
|
|||||||
pub kd_brightness: KeyboardLed,
|
pub kd_brightness: KeyboardLed,
|
||||||
pub supported_modes: LaptopLedData,
|
pub supported_modes: LaptopLedData,
|
||||||
pub flip_effect_write: bool,
|
pub flip_effect_write: bool,
|
||||||
|
pub per_key_mode_active: bool,
|
||||||
pub config: AuraConfig,
|
pub config: AuraConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +216,7 @@ impl CtrlKbdLed {
|
|||||||
kd_brightness: rgb_led, // If was none then we already returned above
|
kd_brightness: rgb_led, // If was none then we already returned above
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
|
per_key_mode_active: false,
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
Ok(ctrl)
|
Ok(ctrl)
|
||||||
@@ -294,17 +296,24 @@ impl CtrlKbdLed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write an effect block. This is for per-key
|
/// Write an effect block. This is for per-key
|
||||||
fn _write_effect(&mut self, effect: &[Vec<u8>]) -> Result<(), RogError> {
|
pub fn write_per_key_block(&mut self, effect: &PerKeyRaw) -> Result<(), RogError> {
|
||||||
if let LEDNode::Rog(hid_raw) = &self.led_node {
|
if !self.per_key_mode_active {
|
||||||
if self.flip_effect_write {
|
if let LEDNode::Rog(hid_raw) = &self.led_node {
|
||||||
for row in effect.iter().rev() {
|
let init = KeyColourArray::get_init_msg();
|
||||||
hid_raw.write_bytes(row)?;
|
hid_raw.write_bytes(&init)?;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for row in effect.iter() {
|
|
||||||
hid_raw.write_bytes(row)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.per_key_mode_active = true;
|
||||||
|
}
|
||||||
|
if let LEDNode::Rog(hid_raw) = &self.led_node {
|
||||||
|
// if self.flip_effect_write {
|
||||||
|
// for row in effect.iter().rev() {
|
||||||
|
// hid_raw.write_bytes(row)?;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
for row in effect.iter() {
|
||||||
|
hid_raw.write_bytes(row)?;
|
||||||
|
}
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
self.flip_effect_write = !self.flip_effect_write;
|
self.flip_effect_write = !self.flip_effect_write;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -345,7 +354,7 @@ impl CtrlKbdLed {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> {
|
fn write_mode(&mut self, mode: &AuraEffect) -> Result<(), RogError> {
|
||||||
if let LEDNode::KbdLed(platform) = &self.led_node {
|
if let LEDNode::KbdLed(platform) = &self.led_node {
|
||||||
let buf = [
|
let buf = [
|
||||||
1,
|
1,
|
||||||
@@ -365,6 +374,7 @@ impl CtrlKbdLed {
|
|||||||
} else {
|
} else {
|
||||||
return Err(RogError::NoAuraKeyboard);
|
return Err(RogError::NoAuraKeyboard);
|
||||||
}
|
}
|
||||||
|
self.per_key_mode_active = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,17 +397,17 @@ impl CtrlKbdLed {
|
|||||||
self.create_multizone_default()?;
|
self.create_multizone_default()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(multizones) = self.config.multizone.as_ref() {
|
if let Some(multizones) = self.config.multizone.as_mut() {
|
||||||
if let Some(set) = multizones.get(&mode) {
|
if let Some(set) = multizones.get(&mode) {
|
||||||
for mode in set {
|
for mode in set.clone() {
|
||||||
self.write_mode(mode)?;
|
self.write_mode(&mode)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mode = self.config.current_mode;
|
let mode = self.config.current_mode;
|
||||||
if let Some(effect) = self.config.builtins.get(&mode) {
|
if let Some(effect) = self.config.builtins.get(&mode).cloned() {
|
||||||
self.write_mode(effect)?;
|
self.write_mode(&effect)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,6 +472,7 @@ mod tests {
|
|||||||
kd_brightness: KeyboardLed::default(),
|
kd_brightness: KeyboardLed::default(),
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
|
per_key_mode_active: false,
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -524,6 +535,7 @@ mod tests {
|
|||||||
kd_brightness: KeyboardLed::default(),
|
kd_brightness: KeyboardLed::default(),
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
|
per_key_mode_active: false,
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -561,6 +573,7 @@ mod tests {
|
|||||||
kd_brightness: KeyboardLed::default(),
|
kd_brightness: KeyboardLed::default(),
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
|
per_key_mode_active: false,
|
||||||
config,
|
config,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness};
|
use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw};
|
||||||
use zbus::{dbus_interface, Connection, SignalContext};
|
use zbus::{dbus_interface, Connection, SignalContext};
|
||||||
|
|
||||||
use super::controller::CtrlKbdLedZbus;
|
use super::controller::CtrlKbdLedZbus;
|
||||||
@@ -210,6 +210,13 @@ impl CtrlKbdLedZbus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> {
|
||||||
|
if let Ok(mut ctrl) = self.0.try_lock() {
|
||||||
|
ctrl.write_per_key_block(&data)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the current LED brightness
|
/// Return the current LED brightness
|
||||||
#[dbus_interface(property)]
|
#[dbus_interface(property)]
|
||||||
async fn led_brightness(&self) -> i8 {
|
async fn led_brightness(&self) -> i8 {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Copy, Clone, Serialize, Deserialize)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
VolUp,
|
VolUp,
|
||||||
VolDown,
|
VolDown,
|
||||||
MicMute,
|
MicMute,
|
||||||
|
#[default]
|
||||||
Rog,
|
Rog,
|
||||||
Fan,
|
Fan,
|
||||||
Esc,
|
Esc,
|
||||||
@@ -151,6 +152,13 @@ pub enum Key {
|
|||||||
RowEndSpacer,
|
RowEndSpacer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Key {
|
||||||
|
pub fn is_placeholder(&self) -> bool {
|
||||||
|
let shape = KeyShape::from(self);
|
||||||
|
shape.is_blank() || shape.is_spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Types of shapes of LED on keyboards. The shape is used for visual representations
|
/// Types of shapes of LED on keyboards. The shape is used for visual representations
|
||||||
///
|
///
|
||||||
/// A post fix of Spacer *must be ignored by per-key effects
|
/// A post fix of Spacer *must be ignored by per-key effects
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ impl KeyLayout {
|
|||||||
pub fn rows(&self) -> Iter<KeyRow> {
|
pub fn rows(&self) -> Iter<KeyRow> {
|
||||||
self.rows.iter()
|
self.rows.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rows_ref(&self) -> &[KeyRow] {
|
||||||
|
&self.rows
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
@@ -66,6 +70,10 @@ impl KeyRow {
|
|||||||
self.row.iter()
|
self.row.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn row_ref(&self) -> &[Key] {
|
||||||
|
&self.row
|
||||||
|
}
|
||||||
|
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
self.height
|
self.height
|
||||||
}
|
}
|
||||||
|
|||||||
168
rog-aura/src/layouts/old_gx502.rs
Normal file
168
rog-aura/src/layouts/old_gx502.rs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
pub struct GX502Layout(Vec<[Key; 17]>);
|
||||||
|
|
||||||
|
impl KeyLayout for GX502Layout {
|
||||||
|
fn get_rows(&self) -> &Vec<[Key; 17]> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GX502Layout {
|
||||||
|
fn default() -> Self {
|
||||||
|
GX502Layout(vec![
|
||||||
|
[
|
||||||
|
Key::NormalSpacer,
|
||||||
|
Key::FuncSpacer,
|
||||||
|
Key::VolDown,
|
||||||
|
Key::VolUp,
|
||||||
|
Key::MicMute,
|
||||||
|
Key::Rog,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::Esc,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::F1,
|
||||||
|
Key::F2,
|
||||||
|
Key::F3,
|
||||||
|
Key::F4,
|
||||||
|
Key::NormalBlank, // not sure which key to put here
|
||||||
|
Key::F5,
|
||||||
|
Key::F6,
|
||||||
|
Key::F7,
|
||||||
|
Key::F8,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::F9,
|
||||||
|
Key::F10,
|
||||||
|
Key::F11,
|
||||||
|
Key::F12,
|
||||||
|
Key::Del,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::Tilde,
|
||||||
|
Key::N1,
|
||||||
|
Key::N2,
|
||||||
|
Key::N3,
|
||||||
|
Key::N4,
|
||||||
|
Key::N5,
|
||||||
|
Key::N6,
|
||||||
|
Key::N7,
|
||||||
|
Key::N8,
|
||||||
|
Key::N9,
|
||||||
|
Key::N0,
|
||||||
|
Key::Hyphen,
|
||||||
|
Key::Equals,
|
||||||
|
Key::BkSpc3_1,
|
||||||
|
Key::BkSpc3_2,
|
||||||
|
Key::BkSpc3_3,
|
||||||
|
Key::Home,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::Tab,
|
||||||
|
Key::Q,
|
||||||
|
Key::W,
|
||||||
|
Key::E,
|
||||||
|
Key::R,
|
||||||
|
Key::T,
|
||||||
|
Key::Y,
|
||||||
|
Key::U,
|
||||||
|
Key::I,
|
||||||
|
Key::O,
|
||||||
|
Key::P,
|
||||||
|
Key::LBracket,
|
||||||
|
Key::RBracket,
|
||||||
|
Key::BackSlash,
|
||||||
|
Key::BackSlash,
|
||||||
|
Key::BackSlash,
|
||||||
|
Key::PgUp,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::Caps,
|
||||||
|
Key::A,
|
||||||
|
Key::S,
|
||||||
|
Key::D,
|
||||||
|
Key::F,
|
||||||
|
Key::G,
|
||||||
|
Key::H,
|
||||||
|
Key::J,
|
||||||
|
Key::K,
|
||||||
|
Key::L,
|
||||||
|
Key::SemiColon,
|
||||||
|
Key::Quote,
|
||||||
|
Key::Quote,
|
||||||
|
Key::Return3_1,
|
||||||
|
Key::Return3_2,
|
||||||
|
Key::Return3_3,
|
||||||
|
Key::PgDn,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::LShift,
|
||||||
|
Key::LShift,
|
||||||
|
Key::Z,
|
||||||
|
Key::X,
|
||||||
|
Key::C,
|
||||||
|
Key::V,
|
||||||
|
Key::B,
|
||||||
|
Key::N,
|
||||||
|
Key::M,
|
||||||
|
Key::Comma,
|
||||||
|
Key::Period,
|
||||||
|
Key::FwdSlash,
|
||||||
|
Key::FwdSlash,
|
||||||
|
Key::Rshift3_1,
|
||||||
|
Key::Rshift3_2,
|
||||||
|
Key::Rshift3_3,
|
||||||
|
Key::End,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::LCtrl,
|
||||||
|
Key::LFn,
|
||||||
|
Key::Meta,
|
||||||
|
Key::LAlt,
|
||||||
|
Key::Space5_1,
|
||||||
|
Key::Space5_2,
|
||||||
|
Key::Space5_3,
|
||||||
|
Key::Space5_4,
|
||||||
|
Key::Space5_5,
|
||||||
|
Key::RAlt,
|
||||||
|
Key::PrtSc,
|
||||||
|
Key::RCtrl,
|
||||||
|
Key::RCtrl,
|
||||||
|
Key::Left,
|
||||||
|
Key::Up,
|
||||||
|
Key::Right,
|
||||||
|
Key::RFn,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::NormalBlank,
|
||||||
|
Key::Left,
|
||||||
|
Key::Down,
|
||||||
|
Key::Right,
|
||||||
|
Key::NormalBlank,
|
||||||
|
],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
use crate::keys::Key;
|
use crate::keys::Key;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
#[cfg(feature = "dbus")]
|
||||||
|
use zvariant::Type;
|
||||||
|
|
||||||
|
/// Represents the per-key raw USB packets
|
||||||
|
pub type PerKeyRaw = Vec<Vec<u8>>;
|
||||||
|
|
||||||
/// A `KeyColourArray` contains all data to change the full set of keyboard
|
/// A `KeyColourArray` contains all data to change the full set of keyboard
|
||||||
/// key colours individually.
|
/// key colours individually.
|
||||||
@@ -7,16 +13,19 @@ use crate::keys::Key;
|
|||||||
/// to the keyboard EC. One row controls one group of keys, these keys are not
|
/// to the keyboard EC. One row controls one group of keys, these keys are not
|
||||||
/// necessarily all on the same row of the keyboard, with some splitting between
|
/// necessarily all on the same row of the keyboard, with some splitting between
|
||||||
/// two rows.
|
/// two rows.
|
||||||
#[derive(Clone)]
|
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||||
pub struct KeyColourArray([[u8; 64]; 11]);
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct KeyColourArray(PerKeyRaw);
|
||||||
|
|
||||||
impl Default for KeyColourArray {
|
impl Default for KeyColourArray {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyColourArray {
|
impl KeyColourArray {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut set = [[0u8; 64]; 11];
|
let mut set = vec![vec![0u8; 64]; 11];
|
||||||
for (count, row) in set.iter_mut().enumerate() {
|
for (count, row) in set.iter_mut().enumerate() {
|
||||||
row[0] = 0x5d; // Report ID
|
row[0] = 0x5d; // Report ID
|
||||||
row[1] = 0xbc; // Mode = custom??, 0xb3 is builtin
|
row[1] = 0xbc; // Mode = custom??, 0xb3 is builtin
|
||||||
@@ -211,15 +220,31 @@ impl KeyColourArray {
|
|||||||
Key::Fan | Key::Space | Key::BkSpc => return None,
|
Key::Fan | Key::Space | Key::BkSpc => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(&mut self.0[row][col..2])
|
Some(&mut self.0[row][col..=col + 2])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self) -> &[[u8; 64]; 11] {
|
pub fn get(&self) -> PerKeyRaw {
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_ref(&self) -> &PerKeyRaw {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mut(&mut self) -> &mut PerKeyRaw {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait KeyLayout {
|
pub trait KeyLayout {
|
||||||
fn get_rows(&self) -> &Vec<[Key; 17]>;
|
fn get_rows(&self) -> &Vec<[Key; 17]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<KeyColourArray> for PerKeyRaw {
|
||||||
|
fn from(k: KeyColourArray) -> Self {
|
||||||
|
k.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,43 @@
|
|||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::{keys::Key, Colour, KeyColourArray, PerKeyRaw, Speed};
|
||||||
|
|
||||||
/// All the possible AniMe actions that can be used. The enum is intended to be
|
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||||
/// used in a array allowing the user to cycle through a series of actions.
|
pub struct PerKey {
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
pub key: Key,
|
||||||
pub enum ActionData {
|
pub action: ActionData,
|
||||||
Static,
|
/// The end resulting colour after stepping through effect
|
||||||
|
#[serde(skip)]
|
||||||
|
colour: Colour,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum ActionData {
|
||||||
|
Static(Colour),
|
||||||
|
Breathe {
|
||||||
|
/// The starting colour
|
||||||
|
colour1: Colour,
|
||||||
|
/// The secondary starting colour
|
||||||
|
colour2: Colour,
|
||||||
|
/// The speed at which to cycle between the colours
|
||||||
|
speed: Speed,
|
||||||
|
/// Temporary data to help keep state
|
||||||
|
#[serde(skip)]
|
||||||
|
colour1_actual: Colour,
|
||||||
|
/// Temporary data to help keep state
|
||||||
|
#[serde(skip)]
|
||||||
|
colour2_actual: Colour,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ActionData {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Static(Colour::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An optimised precomputed set of actions that the user can cycle through
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||||
pub struct Sequences(Vec<ActionData>);
|
pub struct Sequences(Vec<PerKey>);
|
||||||
|
|
||||||
impl Sequences {
|
impl Sequences {
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -19,51 +45,76 @@ impl Sequences {
|
|||||||
Self(Vec::new())
|
Self(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use a base `AnimeAction` to generate the precomputed data and insert in to
|
|
||||||
/// the run buffer
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn insert(&mut self, _index: usize) -> Result<(), Error> {
|
pub fn push(&mut self, action: PerKey) {
|
||||||
Ok(())
|
self.0.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, index: usize, action: PerKey) {
|
||||||
|
self.0.insert(index, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove an item at this position from the run buffer. If the `index` supplied
|
/// Remove an item at this position from the run buffer. If the `index` supplied
|
||||||
/// is not in range then `None` is returned, otherwise the `ActionData` at that location
|
/// is not in range then `None` is returned, otherwise the `ActionData` at that location
|
||||||
/// is yeeted and returned.
|
/// is yeeted and returned.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove_item(&mut self, index: usize) -> Option<ActionData> {
|
pub fn remove_item(&mut self, index: usize) -> Option<PerKey> {
|
||||||
if index < self.0.len() {
|
if index < self.0.len() {
|
||||||
return Some(self.0.remove(index));
|
return Some(self.0.remove(index));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> ActionIterator {
|
pub fn next_state(&mut self) {
|
||||||
ActionIterator {
|
for effect in self.0.iter_mut() {
|
||||||
actions: self,
|
match effect.action {
|
||||||
next_idx: 0,
|
ActionData::Static(c) => effect.colour = c,
|
||||||
|
ActionData::Breathe {
|
||||||
|
colour1,
|
||||||
|
colour2,
|
||||||
|
speed,
|
||||||
|
colour1_actual,
|
||||||
|
colour2_actual,
|
||||||
|
} => {
|
||||||
|
effect.colour = colour1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_packets(&self) -> PerKeyRaw {
|
||||||
|
let mut keys = KeyColourArray::new();
|
||||||
|
for effect in self.0.iter() {
|
||||||
|
if let Some(rgb) = keys.rgb_for_key(effect.key) {
|
||||||
|
rgb[0] = effect.colour.0;
|
||||||
|
rgb[1] = effect.colour.1;
|
||||||
|
rgb[2] = effect.colour.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keys.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iteractor helper for iterating over all the actions in `Sequences`
|
#[cfg(test)]
|
||||||
pub struct ActionIterator<'a> {
|
mod tests {
|
||||||
actions: &'a Sequences,
|
use crate::{keys::Key, Colour, PerKey, Sequences};
|
||||||
next_idx: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for ActionIterator<'a> {
|
#[test]
|
||||||
type Item = &'a ActionData;
|
fn single_key_next_state_then_create() {
|
||||||
|
let mut seq = Sequences::new();
|
||||||
|
seq.0.push(PerKey {
|
||||||
|
key: Key::F,
|
||||||
|
action: crate::ActionData::Static(Colour(255, 127, 0)),
|
||||||
|
colour: Default::default(),
|
||||||
|
});
|
||||||
|
|
||||||
#[inline]
|
seq.next_state();
|
||||||
fn next(&mut self) -> Option<&'a ActionData> {
|
let packets = seq.create_packets();
|
||||||
if self.next_idx == self.actions.0.len() {
|
|
||||||
self.next_idx = 0;
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current = self.next_idx;
|
assert_eq!(packets[0][0], 0x5d);
|
||||||
self.next_idx += 1;
|
assert_eq!(packets[5][33], 255);
|
||||||
|
assert_eq!(packets[5][34], 127);
|
||||||
Some(&self.actions.0[current])
|
assert_eq!(packets[5][35], 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use std::collections::BTreeMap;
|
|||||||
use zbus::{blocking::Connection, Result};
|
use zbus::{blocking::Connection, Result};
|
||||||
use zbus_macros::dbus_proxy;
|
use zbus_macros::dbus_proxy;
|
||||||
|
|
||||||
use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, KeyColourArray, LedBrightness};
|
use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw};
|
||||||
|
|
||||||
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
|
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
|
||||||
|
|
||||||
@@ -53,6 +53,8 @@ trait Led {
|
|||||||
|
|
||||||
fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>;
|
fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>;
|
||||||
|
|
||||||
|
fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()>;
|
||||||
|
|
||||||
/// NotifyLed signal
|
/// NotifyLed signal
|
||||||
#[dbus_proxy(signal)]
|
#[dbus_proxy(signal)]
|
||||||
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
|
fn notify_led(&self, data: AuraEffect) -> zbus::Result<()>;
|
||||||
@@ -93,30 +95,9 @@ impl<'a> LedProxyPerkey<'a> {
|
|||||||
/// Intentionally blocks for 10ms after sending to allow the block to
|
/// Intentionally blocks for 10ms after sending to allow the block to
|
||||||
/// be written to the keyboard EC. This should not be async.
|
/// be written to the keyboard EC. This should not be async.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_per_key(&self, key_colour_array: &KeyColourArray) -> Result<()> {
|
pub fn set_per_key(&self, per_key_raw: PerKeyRaw) -> Result<()> {
|
||||||
let group = key_colour_array.get();
|
self.0.per_key_raw(per_key_raw)?;
|
||||||
let mut vecs = Vec::with_capacity(group.len());
|
|
||||||
for v in group {
|
|
||||||
vecs.push(v.to_vec());
|
|
||||||
}
|
|
||||||
// TODO: let mode = AuraModes::PerKey(vecs);
|
|
||||||
// self.set_led_mode(&mode)?;
|
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME));
|
std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME));
|
||||||
|
|
||||||
// if self.stop.load(Ordering::Relaxed) {
|
|
||||||
// println!("Keyboard backlight was changed, exiting");
|
|
||||||
// std::process::exit(1)
|
|
||||||
// }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method must always be called before the very first write to initialise
|
|
||||||
/// the keyboard LED EC in the correct mode
|
|
||||||
#[inline]
|
|
||||||
pub fn init_effect(&self) -> Result<()> {
|
|
||||||
// TODO: let mode = AuraModes::PerKey(vec![vec![]]);
|
|
||||||
// self.0.set_led_mode(&serde_json::to_string(&mode).unwrap())
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user