mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Further clean up. Prep for trialling per-key led set
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
rog-core is a utility for Linux to control many aspects (eventually) of the ASUS ROG laptops like the Zephyrus GX502GW.
|
rog-core is a utility for Linux to control many aspects (eventually) of the ASUS ROG laptops like the Zephyrus GX502GW.
|
||||||
|
|
||||||
The laptop I currently have is the GX502RW and so I'll be using that for the basis of this app. If I get wireshark captures from others with different ROG laptops then I should be able to add something like laptop and feature detection.
|
The laptop I currently have is the GX502RW and so I'll be using that for the basis of this app. If I get wireshark captures from others with different ROG laptops then I should be able to add them.
|
||||||
|
|
||||||
I'm now looking at the kernel source to see if I can add the inputs correctly so they show up as proper evdev events.
|
I'm now looking at the kernel source to see if I can add the inputs correctly so they show up as proper evdev events.
|
||||||
|
|
||||||
@@ -101,9 +101,12 @@ First do `lsusb |grep 0b05` and check the part after `0b05:`, output looks like:
|
|||||||
Bus 001 Device 005: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
Bus 001 Device 005: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
||||||
```
|
```
|
||||||
|
|
||||||
Then do `lsusb -vd 0b05:1866 > ~/laptop_info` and give that to me.
|
Then do `sudo lsusb -vd 0b05:1866 > ~/laptop_info` and give that to me.
|
||||||
|
|
||||||
`cat /sys/class/dmi/id/product_name` is the other I'm interested in for the sake of information.
|
Also required:
|
||||||
|
- `cat /sys/class/dmi/id/product_name`
|
||||||
|
- `cat /sys/class/dmi/id/product_family`
|
||||||
|
- `cat /sys/class/dmi/id/board_name`
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
92
src/aura.rs
92
src/aura.rs
@@ -2,6 +2,38 @@ use crate::cli_options::*;
|
|||||||
use crate::core::LED_MSG_LEN;
|
use crate::core::LED_MSG_LEN;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Writes aout the correct byte string for brightness
|
||||||
|
///
|
||||||
|
/// The HID descriptor looks like:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// 0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
|
||||||
|
/// 0x09, 0x76, // Usage (0x76)
|
||||||
|
/// 0xA1, 0x01, // Collection (Application)
|
||||||
|
/// 0x85, 0x5A, // Report ID (90)
|
||||||
|
/// 0x19, 0x00, // Usage Minimum (0x00)
|
||||||
|
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||||
|
/// 0x15, 0x00, // Logical Minimum (0)
|
||||||
|
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
/// 0x75, 0x08, // Report Size (8)
|
||||||
|
/// 0x95, 0x05, // Report Count (5)
|
||||||
|
/// 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
/// 0x19, 0x00, // Usage Minimum (0x00)
|
||||||
|
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||||
|
/// 0x15, 0x00, // Logical Minimum (0)
|
||||||
|
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
/// 0x75, 0x08, // Report Size (8)
|
||||||
|
/// 0x95, 0x3F, // Report Count (63)
|
||||||
|
/// 0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||||
|
/// 0xC0, // End Collection
|
||||||
|
/// ```
|
||||||
|
pub fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
||||||
|
// TODO: check brightness range
|
||||||
|
[
|
||||||
|
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses `SetAuraBuiltin` in to packet data
|
/// Parses `SetAuraBuiltin` in to packet data
|
||||||
///
|
///
|
||||||
/// Byte structure:
|
/// Byte structure:
|
||||||
@@ -44,6 +76,38 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
/// - 0x03 = downwards
|
/// - 0x03 = downwards
|
||||||
///
|
///
|
||||||
/// Bytes 10, 11, 12 are Red, Green, Blue for second colour if mode supports it
|
/// Bytes 10, 11, 12 are Red, Green, Blue for second colour if mode supports it
|
||||||
|
///
|
||||||
|
/// The HID descriptor looks like:
|
||||||
|
/// ```
|
||||||
|
/// 0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
|
||||||
|
/// 0x09, 0x79, // Usage (0x79)
|
||||||
|
/// 0xA1, 0x01, // Collection (Application)
|
||||||
|
/// 0x85, 0x5D, // Report ID (93)
|
||||||
|
/// 0x19, 0x00, // Usage Minimum (0x00)
|
||||||
|
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||||
|
/// 0x15, 0x00, // Logical Minimum (0)
|
||||||
|
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
/// 0x75, 0x08, // Report Size (8)
|
||||||
|
/// 0x95, 0x1F, // Report Count (31)
|
||||||
|
/// 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||||
|
/// 0x19, 0x00, // Usage Minimum (0x00)
|
||||||
|
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||||
|
/// 0x15, 0x00, // Logical Minimum (0)
|
||||||
|
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
/// 0x75, 0x08, // Report Size (8)
|
||||||
|
/// 0x95, 0x3F, // Report Count (63)
|
||||||
|
/// 0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||||
|
/// 0x19, 0x00, // Usage Minimum (0x00)
|
||||||
|
/// 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
||||||
|
/// 0x15, 0x00, // Logical Minimum (0)
|
||||||
|
/// 0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||||
|
/// 0x75, 0x08, // Report Size (8)
|
||||||
|
/// 0x95, 0x3F, // Report Count (63)
|
||||||
|
/// 0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||||
|
/// 0xC0, // End Collection
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This descriptor is also used for the per-key LED settings
|
||||||
impl From<SetAuraBuiltin> for [u8; LED_MSG_LEN] {
|
impl From<SetAuraBuiltin> for [u8; LED_MSG_LEN] {
|
||||||
fn from(mode: SetAuraBuiltin) -> Self {
|
fn from(mode: SetAuraBuiltin) -> Self {
|
||||||
let mut msg = [0u8; LED_MSG_LEN];
|
let mut msg = [0u8; LED_MSG_LEN];
|
||||||
@@ -189,7 +253,7 @@ impl Default for BuiltInModeBytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
|
||||||
pub enum BuiltInModeByte {
|
pub enum BuiltInModeByte {
|
||||||
Stable = 0x00,
|
Stable = 0x00,
|
||||||
Breathe = 0x01,
|
Breathe = 0x01,
|
||||||
@@ -229,3 +293,29 @@ impl From<u8> for BuiltInModeByte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&u8> for BuiltInModeByte {
|
||||||
|
fn from(byte: &u8) -> Self {
|
||||||
|
Self::from(*byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BuiltInModeByte> for u8 {
|
||||||
|
fn from(byte: BuiltInModeByte) -> Self {
|
||||||
|
match byte {
|
||||||
|
BuiltInModeByte::Stable => 0x00,
|
||||||
|
BuiltInModeByte::Breathe => 0x01,
|
||||||
|
BuiltInModeByte::Cycle => 0x02,
|
||||||
|
BuiltInModeByte::Rainbow => 0x03,
|
||||||
|
BuiltInModeByte::Rain => 0x04,
|
||||||
|
BuiltInModeByte::Random => 0x05,
|
||||||
|
BuiltInModeByte::Highlight => 0x06,
|
||||||
|
BuiltInModeByte::Laser => 0x07,
|
||||||
|
BuiltInModeByte::Ripple => 0x08,
|
||||||
|
BuiltInModeByte::Pulse => 0x0a,
|
||||||
|
BuiltInModeByte::ThinZoomy => 0x0b,
|
||||||
|
BuiltInModeByte::WideZoomy => 0x0c,
|
||||||
|
BuiltInModeByte::None => 0xff,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub static CONFIG_PATH: &'static str = "/etc/rogcore.conf";
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub brightness: u8,
|
pub brightness: u8,
|
||||||
pub current_mode: [u8; 4],
|
pub current_mode: [u8; 4],
|
||||||
builtin_modes: BuiltInModeBytes,
|
pub builtin_modes: BuiltInModeBytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -53,15 +53,4 @@ impl Config {
|
|||||||
self.builtin_modes.set_field_from(bytes);
|
self.builtin_modes.set_field_from(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current(&mut self) -> Option<Vec<u8>> {
|
|
||||||
let bytes = self.current_mode;
|
|
||||||
if bytes[0] == 0x5d && bytes[1] == 0xb3 {
|
|
||||||
return self
|
|
||||||
.builtin_modes
|
|
||||||
.get_field_from(bytes[3])
|
|
||||||
.map(|b| b.to_vec());
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/core.rs
99
src/core.rs
@@ -1,7 +1,11 @@
|
|||||||
// Return show-stopping errors, otherwise map error to a log level
|
// Return show-stopping errors, otherwise map error to a log level
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
aura::BuiltInModeByte, config::Config, error::AuraError, laptops::*, virt_device::VirtKeys,
|
aura::{aura_brightness_bytes, BuiltInModeByte},
|
||||||
|
config::Config,
|
||||||
|
error::AuraError,
|
||||||
|
laptops::*,
|
||||||
|
virt_device::VirtKeys,
|
||||||
};
|
};
|
||||||
use aho_corasick::AhoCorasick;
|
use aho_corasick::AhoCorasick;
|
||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
@@ -82,14 +86,6 @@ impl RogCore {
|
|||||||
&mut self.virt_keys
|
&mut self.virt_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn config(&self) -> &Config {
|
|
||||||
&self.config
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn config_mut(&mut self) -> &mut Config {
|
|
||||||
&mut self.config
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_device(
|
fn get_device(
|
||||||
vendor: u16,
|
vendor: u16,
|
||||||
product: u16,
|
product: u16,
|
||||||
@@ -210,7 +206,7 @@ impl RogCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aura_set_and_save(
|
pub(crate) fn aura_set_and_save(
|
||||||
&mut self,
|
&mut self,
|
||||||
supported_modes: &[BuiltInModeByte],
|
supported_modes: &[BuiltInModeByte],
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
@@ -226,6 +222,82 @@ impl RogCore {
|
|||||||
warn!("{:?} not supported", BuiltInModeByte::from(mode));
|
warn!("{:?} not supported", BuiltInModeByte::from(mode));
|
||||||
Err(AuraError::NotSupported)
|
Err(AuraError::NotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn aura_bright_inc(
|
||||||
|
&mut self,
|
||||||
|
supported_modes: &[BuiltInModeByte],
|
||||||
|
max_bright: u8,
|
||||||
|
) -> Result<(), AuraError> {
|
||||||
|
let mut bright = self.config.brightness;
|
||||||
|
if bright < max_bright {
|
||||||
|
bright += 1;
|
||||||
|
self.config.brightness = bright;
|
||||||
|
}
|
||||||
|
let bytes = aura_brightness_bytes(bright);
|
||||||
|
self.aura_set_and_save(supported_modes, &bytes)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn aura_bright_dec(
|
||||||
|
&mut self,
|
||||||
|
supported_modes: &[BuiltInModeByte],
|
||||||
|
min_bright: u8,
|
||||||
|
) -> Result<(), AuraError> {
|
||||||
|
let mut bright = self.config.brightness;
|
||||||
|
if bright > min_bright {
|
||||||
|
bright -= 1;
|
||||||
|
self.config.brightness = bright;
|
||||||
|
}
|
||||||
|
let bytes = aura_brightness_bytes(bright);
|
||||||
|
self.aura_set_and_save(supported_modes, &bytes)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select next Aura effect
|
||||||
|
///
|
||||||
|
/// If the current effect is the last one then the effect selected wraps around to the first.
|
||||||
|
pub(crate) fn aura_mode_next(
|
||||||
|
&mut self,
|
||||||
|
supported_modes: &[BuiltInModeByte],
|
||||||
|
) -> Result<(), AuraError> {
|
||||||
|
let mode_curr = self.config.current_mode[3];
|
||||||
|
let idx = supported_modes.binary_search(&mode_curr.into()).unwrap();
|
||||||
|
let idx_next = if idx < supported_modes.len() - 1 {
|
||||||
|
idx + 1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
let mode_next = self
|
||||||
|
.config
|
||||||
|
.builtin_modes
|
||||||
|
.get_field_from(supported_modes[idx_next].into())
|
||||||
|
.unwrap()
|
||||||
|
.to_owned();
|
||||||
|
self.aura_set_and_save(supported_modes, &mode_next)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select previous Aura effect
|
||||||
|
///
|
||||||
|
/// If the current effect is the first one then the effect selected wraps around to the last.
|
||||||
|
pub(crate) fn aura_mode_prev(
|
||||||
|
&mut self,
|
||||||
|
supported_modes: &[BuiltInModeByte],
|
||||||
|
) -> Result<(), AuraError> {
|
||||||
|
let mode_curr = self.config.current_mode[3];
|
||||||
|
let idx = supported_modes.binary_search(&mode_curr.into()).unwrap();
|
||||||
|
let idx_next = if idx > 0 {
|
||||||
|
idx - 1
|
||||||
|
} else {
|
||||||
|
supported_modes.len() - 1
|
||||||
|
};
|
||||||
|
let mode_next = self
|
||||||
|
.config
|
||||||
|
.builtin_modes
|
||||||
|
.get_field_from(supported_modes[idx_next].into())
|
||||||
|
.unwrap()
|
||||||
|
.to_owned();
|
||||||
|
self.aura_set_and_save(supported_modes, &mode_next)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Backlight {
|
pub(crate) struct Backlight {
|
||||||
@@ -308,10 +380,3 @@ impl FromStr for LedBrightness {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
|
||||||
// TODO: check brightness range
|
|
||||||
[
|
|
||||||
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
244
src/laptops.rs
244
src/laptops.rs
@@ -1,244 +0,0 @@
|
|||||||
use crate::aura::BuiltInModeByte;
|
|
||||||
use crate::core::{aura_brightness_bytes, Backlight, RogCore};
|
|
||||||
use crate::error::AuraError;
|
|
||||||
use crate::virt_device::ConsumerKeys;
|
|
||||||
//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState};
|
|
||||||
use log::info;
|
|
||||||
|
|
||||||
pub(crate) fn match_laptop() -> Box<dyn Laptop> {
|
|
||||||
let dmi = sysfs_class::DmiId::default();
|
|
||||||
let board_name = dmi.board_name().unwrap();
|
|
||||||
match board_name.as_str() {
|
|
||||||
// The hell does it have a \n for anyway?
|
|
||||||
"GX502GW\n" => Box::new(LaptopGX502GW::new()),
|
|
||||||
_ => {
|
|
||||||
panic!("could not match laptop");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All laptop models should implement this trait. The role of a `Laptop` is to
|
|
||||||
/// "drive" the `RogCore`.
|
|
||||||
///
|
|
||||||
/// `do_hotkey_action` is passed the byte that a hotkey emits, and is expected to
|
|
||||||
/// perform whichever action matches that. For now the only key bytes passed in are
|
|
||||||
/// the ones which match `byte[0] == hotkey_group_byte`. On the GX502GW the keyboard
|
|
||||||
/// has 3 explicit groups: main, vol+media, and the ones that the Linux kernel doesn't
|
|
||||||
/// map.
|
|
||||||
pub(crate) trait Laptop {
|
|
||||||
fn board_name(&self) -> &str;
|
|
||||||
fn prod_family(&self) -> &str;
|
|
||||||
fn run(&self, core: &mut RogCore) -> Result<(), AuraError>;
|
|
||||||
fn led_endpoint(&self) -> u8;
|
|
||||||
fn key_endpoint(&self) -> u8;
|
|
||||||
fn usb_vendor(&self) -> u16;
|
|
||||||
fn usb_product(&self) -> u16;
|
|
||||||
fn supported_modes(&self) -> &[BuiltInModeByte];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct LaptopGX502GW {
|
|
||||||
usb_vendor: u16,
|
|
||||||
usb_product: u16,
|
|
||||||
board_name: &'static str,
|
|
||||||
prod_family: &'static str,
|
|
||||||
report_filter_bytes: [u8; 2],
|
|
||||||
min_led_bright: u8,
|
|
||||||
max_led_bright: u8,
|
|
||||||
led_endpoint: u8,
|
|
||||||
key_endpoint: u8,
|
|
||||||
supported_modes: [BuiltInModeByte; 12],
|
|
||||||
backlight: Backlight,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LaptopGX502GW {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
// Find backlight
|
|
||||||
LaptopGX502GW {
|
|
||||||
usb_vendor: 0x0B05,
|
|
||||||
usb_product: 0x1866,
|
|
||||||
board_name: "GX502GW",
|
|
||||||
prod_family: "Zephyrus S",
|
|
||||||
report_filter_bytes: [0x5a, 0x02],
|
|
||||||
min_led_bright: 0x00,
|
|
||||||
max_led_bright: 0x03,
|
|
||||||
led_endpoint: 0x81,
|
|
||||||
key_endpoint: 0x83,
|
|
||||||
supported_modes: [
|
|
||||||
BuiltInModeByte::Stable,
|
|
||||||
BuiltInModeByte::Breathe,
|
|
||||||
BuiltInModeByte::Cycle,
|
|
||||||
BuiltInModeByte::Rainbow,
|
|
||||||
BuiltInModeByte::Rain,
|
|
||||||
BuiltInModeByte::Random,
|
|
||||||
BuiltInModeByte::Highlight,
|
|
||||||
BuiltInModeByte::Laser,
|
|
||||||
BuiltInModeByte::Ripple,
|
|
||||||
BuiltInModeByte::Pulse,
|
|
||||||
BuiltInModeByte::ThinZoomy,
|
|
||||||
BuiltInModeByte::WideZoomy,
|
|
||||||
],
|
|
||||||
backlight: Backlight::new("intel_backlight").unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Laptop for LaptopGX502GW {
|
|
||||||
// TODO: This really needs to match against u16 in future
|
|
||||||
fn run(&self, rogcore: &mut RogCore) -> Result<(), AuraError> {
|
|
||||||
if let Some(key_buf) = rogcore.poll_keyboard(&self.report_filter_bytes) {
|
|
||||||
match GX502GWKeys::from(key_buf[1]) {
|
|
||||||
GX502GWKeys::LedBrightUp => {
|
|
||||||
let mut bright = rogcore.config().brightness;
|
|
||||||
if bright < self.max_led_bright {
|
|
||||||
bright += 1;
|
|
||||||
rogcore.config_mut().brightness = bright;
|
|
||||||
}
|
|
||||||
let bytes = aura_brightness_bytes(bright);
|
|
||||||
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
|
||||||
}
|
|
||||||
GX502GWKeys::LedBrightDown => {
|
|
||||||
let mut bright = rogcore.config().brightness;
|
|
||||||
if bright > self.min_led_bright {
|
|
||||||
bright -= 1;
|
|
||||||
rogcore.config_mut().brightness = bright;
|
|
||||||
}
|
|
||||||
let bytes = aura_brightness_bytes(bright);
|
|
||||||
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
|
||||||
}
|
|
||||||
GX502GWKeys::AuraNext => {
|
|
||||||
let mut mode = rogcore.config().current_mode[3] + 1;
|
|
||||||
if mode > 0x0c {
|
|
||||||
mode = 0x00
|
|
||||||
} else if mode == 0x09 {
|
|
||||||
mode = 0x0a
|
|
||||||
}
|
|
||||||
rogcore.config_mut().current_mode[3] = mode;
|
|
||||||
if let Some(bytes) = rogcore.config_mut().get_current() {
|
|
||||||
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GX502GWKeys::AuraPrevious => {
|
|
||||||
let mut mode = rogcore.config().current_mode[3];
|
|
||||||
if mode == 0x00 {
|
|
||||||
mode = 0x0c
|
|
||||||
} else if mode - 1 == 0x09 {
|
|
||||||
mode = 0x08
|
|
||||||
} else {
|
|
||||||
mode -= 1;
|
|
||||||
}
|
|
||||||
rogcore.config_mut().current_mode[3] = mode;
|
|
||||||
if let Some(bytes) = rogcore.config_mut().get_current() {
|
|
||||||
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
|
||||||
rogcore.config().write();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GX502GWKeys::ScreenBrightUp => {
|
|
||||||
self.backlight.step_up();
|
|
||||||
}
|
|
||||||
GX502GWKeys::ScreenBrightDown => {
|
|
||||||
self.backlight.step_down();
|
|
||||||
}
|
|
||||||
GX502GWKeys::Sleep => {
|
|
||||||
// Direct call to systemd
|
|
||||||
rogcore.suspend_with_systemd();
|
|
||||||
//rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]);
|
|
||||||
// Power menu
|
|
||||||
//rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]);
|
|
||||||
}
|
|
||||||
GX502GWKeys::AirplaneMode => {
|
|
||||||
rogcore.toggle_airplane_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
GX502GWKeys::MicToggle => {}
|
|
||||||
GX502GWKeys::Fan => {}
|
|
||||||
GX502GWKeys::ScreenToggle => {
|
|
||||||
rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into());
|
|
||||||
}
|
|
||||||
GX502GWKeys::TouchPadToggle => {
|
|
||||||
// F21 key, Touchpad toggle
|
|
||||||
rogcore.virt_keys().press([0x01, 0, 0, 0x70, 0, 0, 0, 0]);
|
|
||||||
// rogcore.virt_keys().press([0x01, 0, 0, 0x71, 0, 0, 0, 0]); // Touchpad on F22
|
|
||||||
// rogcore.virt_keys().press([0x01, 0, 0, 0x72, 0, 0, 0, 0]); // Touchpad off F23
|
|
||||||
}
|
|
||||||
GX502GWKeys::Rog => {
|
|
||||||
rogcore.virt_keys().press([0x01, 0, 0, 0x68, 0, 0, 0, 0]); // XF86Tools? F13
|
|
||||||
}
|
|
||||||
|
|
||||||
GX502GWKeys::None => {
|
|
||||||
if key_buf[0] != 0 && key_buf[1] != 0 {
|
|
||||||
info!(
|
|
||||||
"Unmapped key, attempt to pass to virtual device: {:X?}",
|
|
||||||
&key_buf[1]
|
|
||||||
);
|
|
||||||
let mut bytes = [0u8; 8];
|
|
||||||
// TODO: code page
|
|
||||||
bytes[0] = key_buf[0];
|
|
||||||
bytes[1] = key_buf[1];
|
|
||||||
rogcore.virt_keys().press(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn led_endpoint(&self) -> u8 {
|
|
||||||
self.led_endpoint
|
|
||||||
}
|
|
||||||
fn key_endpoint(&self) -> u8 {
|
|
||||||
self.key_endpoint
|
|
||||||
}
|
|
||||||
fn usb_vendor(&self) -> u16 {
|
|
||||||
self.usb_vendor
|
|
||||||
}
|
|
||||||
fn usb_product(&self) -> u16 {
|
|
||||||
self.usb_product
|
|
||||||
}
|
|
||||||
fn supported_modes(&self) -> &[BuiltInModeByte] {
|
|
||||||
&self.supported_modes
|
|
||||||
}
|
|
||||||
fn board_name(&self) -> &str {
|
|
||||||
&self.board_name
|
|
||||||
}
|
|
||||||
fn prod_family(&self) -> &str {
|
|
||||||
&self.prod_family
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) enum GX502GWKeys {
|
|
||||||
Rog = 0x38,
|
|
||||||
MicToggle = 0x7C,
|
|
||||||
Fan = 0xAE,
|
|
||||||
ScreenToggle = 0x35,
|
|
||||||
ScreenBrightDown = 0x10,
|
|
||||||
ScreenBrightUp = 0x20,
|
|
||||||
TouchPadToggle = 0x6b,
|
|
||||||
Sleep = 0x6C,
|
|
||||||
AirplaneMode = 0x88,
|
|
||||||
LedBrightUp = 0xC4,
|
|
||||||
LedBrightDown = 0xC5,
|
|
||||||
AuraPrevious = 0xB2,
|
|
||||||
AuraNext = 0xB3,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for GX502GWKeys {
|
|
||||||
fn from(byte: u8) -> Self {
|
|
||||||
match byte {
|
|
||||||
0x38 => GX502GWKeys::Rog,
|
|
||||||
0x7C => GX502GWKeys::MicToggle,
|
|
||||||
0xAE => GX502GWKeys::Fan,
|
|
||||||
0x35 => GX502GWKeys::ScreenToggle,
|
|
||||||
0x10 => GX502GWKeys::ScreenBrightDown,
|
|
||||||
0x20 => GX502GWKeys::ScreenBrightUp,
|
|
||||||
0x6b => GX502GWKeys::TouchPadToggle,
|
|
||||||
0x6C => GX502GWKeys::Sleep,
|
|
||||||
0x88 => GX502GWKeys::AirplaneMode,
|
|
||||||
0xC4 => GX502GWKeys::LedBrightUp,
|
|
||||||
0xC5 => GX502GWKeys::LedBrightDown,
|
|
||||||
0xB2 => GX502GWKeys::AuraPrevious,
|
|
||||||
0xB3 => GX502GWKeys::AuraNext,
|
|
||||||
_ => GX502GWKeys::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
mod aura;
|
pub mod aura;
|
||||||
/// Contains mostly only what is required for parsing CLI options
|
/// Contains mostly only what is required for parsing CLI options
|
||||||
pub mod cli_options;
|
pub mod cli_options;
|
||||||
mod config;
|
mod config;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use daemon::{
|
use daemon::{
|
||||||
|
aura::aura_brightness_bytes,
|
||||||
cli_options::SetAuraBuiltin,
|
cli_options::SetAuraBuiltin,
|
||||||
core::{aura_brightness_bytes, LedBrightness, LED_MSG_LEN},
|
core::{LedBrightness, LED_MSG_LEN},
|
||||||
daemon::{start_daemon, DBUS_IFACE, DBUS_NAME, DBUS_PATH},
|
daemon::{start_daemon, DBUS_IFACE, DBUS_NAME, DBUS_PATH},
|
||||||
};
|
};
|
||||||
use dbus::Error as DbusError;
|
use dbus::Error as DbusError;
|
||||||
|
|||||||
@@ -1,5 +1,29 @@
|
|||||||
use uhid_virt::{Bus, CreateParams, UHIDDevice};
|
use uhid_virt::{Bus, CreateParams, UHIDDevice};
|
||||||
|
|
||||||
|
/// Create a virtual device to emit key-presses
|
||||||
|
///
|
||||||
|
/// This is required in some instances because either the USB device that
|
||||||
|
/// an interface for a working set of buttons is also captured, or because
|
||||||
|
/// there is no equivalent "system" action to take for a key function and
|
||||||
|
/// a key-press is required to emit a particular key code.
|
||||||
|
///
|
||||||
|
/// The two devices set up mirror that of the GX502GW and can accept the same
|
||||||
|
/// original byte arrays to emit.
|
||||||
|
/// - "Consumer Device" generally has all device type controls like media, backlight, power
|
||||||
|
/// - "Keyboard Device" is a full featured keyboard including special keys like F13-F24
|
||||||
|
///
|
||||||
|
/// # Some example uses:
|
||||||
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x68, 0, 0, 0, 0]); // F13, Config/Control Panel`
|
||||||
|
///
|
||||||
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x70, 0, 0, 0, 0]); // F21, Touchpad toggle, XF86/Gnome`
|
||||||
|
///
|
||||||
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x71, 0, 0, 0, 0]); // F22, Touchpad on, XF86/Gnome`
|
||||||
|
///
|
||||||
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x72, 0, 0, 0, 0]); // F23, Touchpad off, XF86/Gnome`
|
||||||
|
///
|
||||||
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x82, 0, 0, 0, 0]); // Sleep`
|
||||||
|
///
|
||||||
|
/// `rogcore.virt_keys().press([0x01, 0, 0, 0x66, 0, 0, 0, 0]); // Power (menu)`
|
||||||
pub(crate) struct VirtKeys {
|
pub(crate) struct VirtKeys {
|
||||||
device: UHIDDevice<std::fs::File>,
|
device: UHIDDevice<std::fs::File>,
|
||||||
}
|
}
|
||||||
@@ -71,9 +95,10 @@ impl VirtKeys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn press(&mut self, input: [u8; 8]) {
|
/// A single on/off key press
|
||||||
|
pub(crate) fn press(&mut self, input: [u8; 32]) {
|
||||||
self.device.write(&input).unwrap();
|
self.device.write(&input).unwrap();
|
||||||
let mut reset = [0u8; 8];
|
let mut reset = [0u8; 32];
|
||||||
reset[0] = input[0];
|
reset[0] = input[0];
|
||||||
self.device.write(&reset).unwrap();
|
self.device.write(&reset).unwrap();
|
||||||
}
|
}
|
||||||
@@ -130,9 +155,9 @@ pub(crate) enum ConsumerKeys {
|
|||||||
MovieBrowser = 0x1B8,
|
MovieBrowser = 0x1B8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConsumerKeys> for [u8; 8] {
|
impl From<ConsumerKeys> for [u8; 32] {
|
||||||
fn from(key: ConsumerKeys) -> Self {
|
fn from(key: ConsumerKeys) -> Self {
|
||||||
let mut bytes = [0u8; 8];
|
let mut bytes = [0u8; 32];
|
||||||
bytes[0] = 0x02; // report ID for consumer
|
bytes[0] = 0x02; // report ID for consumer
|
||||||
bytes[1] = key as u8;
|
bytes[1] = key as u8;
|
||||||
bytes[2] = (key as u16 >> 8) as u8;
|
bytes[2] = (key as u16 >> 8) as u8;
|
||||||
|
|||||||
Reference in New Issue
Block a user