mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Much better handling of keys
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -626,6 +626,8 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "uhid-virt"
|
name = "uhid-virt"
|
||||||
version = "0.0.2"
|
version = "0.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c6ade685b787ea3b980b5a47bdc54ef3943adbd41a72ea5352a12a0dc9d821"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enumflags2",
|
"enumflags2",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
@@ -4,19 +4,25 @@ use dbus::{
|
|||||||
tree::{Factory, MethodErr},
|
tree::{Factory, MethodErr},
|
||||||
};
|
};
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_lib::core::RogCore;
|
use rog_lib::{
|
||||||
|
core::RogCore,
|
||||||
|
laptops::{match_laptop, Laptop},
|
||||||
|
};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
pub struct Daemon {
|
pub struct Daemon {
|
||||||
rogcore: RogCore,
|
rogcore: RogCore,
|
||||||
|
laptop: Box<dyn Laptop>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Daemon {
|
impl Daemon {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
let laptop = match_laptop();
|
||||||
|
|
||||||
Daemon {
|
Daemon {
|
||||||
rogcore: RogCore::new().map_or_else(
|
rogcore: RogCore::new(&*laptop).map_or_else(
|
||||||
|err| {
|
|err| {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
panic!("{}", err);
|
panic!("{}", err);
|
||||||
@@ -26,6 +32,7 @@ impl Daemon {
|
|||||||
daemon
|
daemon
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
laptop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +67,12 @@ impl Daemon {
|
|||||||
move |m| {
|
move |m| {
|
||||||
// Reads the args passed to the method
|
// Reads the args passed to the method
|
||||||
let bytes: Vec<u8> = m.msg.read1()?;
|
let bytes: Vec<u8> = m.msg.read1()?;
|
||||||
|
let supported =
|
||||||
match daemon.borrow_mut().rogcore.aura_set_and_save(&bytes[..])
|
Vec::from(daemon.borrow().laptop.supported_modes());
|
||||||
|
match daemon
|
||||||
|
.borrow_mut()
|
||||||
|
.rogcore
|
||||||
|
.aura_set_and_save(&supported, &bytes[..])
|
||||||
{
|
{
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let s = format!("Wrote {:x?}", bytes);
|
let s = format!("Wrote {:x?}", bytes);
|
||||||
@@ -86,6 +97,7 @@ impl Daemon {
|
|||||||
tree.start_receive(&connection);
|
tree.start_receive(&connection);
|
||||||
|
|
||||||
let mut key_buf = [0u8; 32];
|
let mut key_buf = [0u8; 32];
|
||||||
|
let hotkey_group_bytes = Vec::from(daemon.borrow().laptop.hotkey_group_bytes());
|
||||||
loop {
|
loop {
|
||||||
connection
|
connection
|
||||||
.process(Duration::from_millis(10))
|
.process(Duration::from_millis(10))
|
||||||
@@ -96,15 +108,18 @@ impl Daemon {
|
|||||||
// READ KEYBOARD
|
// READ KEYBOARD
|
||||||
// TODO: this needs to move to a thread, but there is unsafety
|
// TODO: this needs to move to a thread, but there is unsafety
|
||||||
let mut borrowed_daemon = daemon.borrow_mut();
|
let mut borrowed_daemon = daemon.borrow_mut();
|
||||||
match borrowed_daemon.rogcore.poll_keyboard(&mut key_buf) {
|
match borrowed_daemon
|
||||||
|
.rogcore
|
||||||
|
.poll_keyboard(&hotkey_group_bytes, &mut key_buf)
|
||||||
|
{
|
||||||
Ok(read) => {
|
Ok(read) => {
|
||||||
// Doing this because the Laptop trait takes RogCore, but RogCore contains laptop
|
// Doing this because the Laptop trait takes RogCore, but RogCore contains laptop
|
||||||
// and this makes the borrow checker unhappy, but it's safe for this
|
// and this makes the borrow checker unhappy, but it's safe for this
|
||||||
let mut rogcore = unsafe { &mut (*daemon.as_ptr()).rogcore };
|
let mut rogcore = unsafe { &mut (*daemon.as_ptr()).rogcore };
|
||||||
let laptop = borrowed_daemon.rogcore.laptop();
|
|
||||||
|
|
||||||
if let Some(_count) = read {
|
if let Some(_count) = read {
|
||||||
laptop
|
borrowed_daemon
|
||||||
|
.laptop
|
||||||
.do_hotkey_action(&mut rogcore, key_buf[1])
|
.do_hotkey_action(&mut rogcore, key_buf[1])
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
warn!("{:?}", err);
|
warn!("{:?}", err);
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ sysfs-class = "0.1.2"
|
|||||||
aho-corasick = "0.7"
|
aho-corasick = "0.7"
|
||||||
thiserror = "1.0.15"
|
thiserror = "1.0.15"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
uhid-virt = { path = "../../uhid-fs" }
|
uhid-virt = "0.0.2"
|
||||||
@@ -5,7 +5,6 @@ use aho_corasick::AhoCorasick;
|
|||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use rusb::DeviceHandle;
|
use rusb::DeviceHandle;
|
||||||
use std::cell::{Ref, RefCell};
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -35,18 +34,14 @@ static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
|||||||
pub struct RogCore {
|
pub struct RogCore {
|
||||||
handle: DeviceHandle<rusb::GlobalContext>,
|
handle: DeviceHandle<rusb::GlobalContext>,
|
||||||
initialised: bool,
|
initialised: bool,
|
||||||
led_interface_num: u8,
|
led_iface_num: u8,
|
||||||
keys_interface_num: u8,
|
|
||||||
keys_endpoint: u8,
|
keys_endpoint: u8,
|
||||||
config: Config,
|
config: Config,
|
||||||
laptop: RefCell<Box<dyn Laptop>>,
|
|
||||||
virt_keys: VirtKeys,
|
virt_keys: VirtKeys,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RogCore {
|
impl RogCore {
|
||||||
pub fn new() -> Result<RogCore, AuraError> {
|
pub fn new(laptop: &dyn Laptop) -> Result<RogCore, AuraError> {
|
||||||
let laptop = match_laptop()?;
|
|
||||||
|
|
||||||
let mut dev_handle = RogCore::get_device(laptop.usb_vendor(), laptop.usb_product())?;
|
let mut dev_handle = RogCore::get_device(laptop.usb_vendor(), laptop.usb_product())?;
|
||||||
dev_handle.set_active_configuration(0).unwrap_or(());
|
dev_handle.set_active_configuration(0).unwrap_or(());
|
||||||
|
|
||||||
@@ -76,11 +71,9 @@ impl RogCore {
|
|||||||
Ok(RogCore {
|
Ok(RogCore {
|
||||||
handle: dev_handle,
|
handle: dev_handle,
|
||||||
initialised: false,
|
initialised: false,
|
||||||
led_interface_num,
|
led_iface_num: led_interface_num,
|
||||||
keys_interface_num,
|
|
||||||
keys_endpoint,
|
keys_endpoint,
|
||||||
config: Config::default().read(),
|
config: Config::default().read(),
|
||||||
laptop: RefCell::new(laptop),
|
|
||||||
virt_keys: VirtKeys::new(),
|
virt_keys: VirtKeys::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -89,10 +82,6 @@ impl RogCore {
|
|||||||
&mut self.virt_keys
|
&mut self.virt_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn laptop(&self) -> Ref<Box<dyn Laptop>> {
|
|
||||||
self.laptop.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn config(&self) -> &Config {
|
pub fn config(&self) -> &Config {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
@@ -123,7 +112,7 @@ impl RogCore {
|
|||||||
|
|
||||||
fn aura_write_messages(&mut self, messages: &[&[u8]]) -> Result<(), AuraError> {
|
fn aura_write_messages(&mut self, messages: &[&[u8]]) -> Result<(), AuraError> {
|
||||||
self.handle
|
self.handle
|
||||||
.claim_interface(self.led_interface_num)
|
.claim_interface(self.led_iface_num)
|
||||||
.map_err(|err| AuraError::UsbError(err))?;
|
.map_err(|err| AuraError::UsbError(err))?;
|
||||||
|
|
||||||
if !self.initialised {
|
if !self.initialised {
|
||||||
@@ -143,7 +132,7 @@ impl RogCore {
|
|||||||
self.aura_write(&LED_APPLY)?;
|
self.aura_write(&LED_APPLY)?;
|
||||||
|
|
||||||
self.handle
|
self.handle
|
||||||
.release_interface(self.led_interface_num)
|
.release_interface(self.led_iface_num)
|
||||||
.map_err(|err| AuraError::UsbError(err))?;
|
.map_err(|err| AuraError::UsbError(err))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -159,28 +148,35 @@ impl RogCore {
|
|||||||
Ok(bright)
|
Ok(bright)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aura_set_and_save(&mut self, bytes: &[u8]) -> Result<(), AuraError> {
|
pub fn aura_set_and_save(
|
||||||
|
&mut self,
|
||||||
|
supported_modes: &[BuiltInModeByte],
|
||||||
|
bytes: &[u8],
|
||||||
|
) -> Result<(), AuraError> {
|
||||||
let mode = BuiltInModeByte::from(bytes[3]);
|
let mode = BuiltInModeByte::from(bytes[3]);
|
||||||
if self.laptop().supported_modes().contains(&mode) || bytes[1] == 0xba {
|
if supported_modes.contains(&mode) || bytes[1] == 0xba {
|
||||||
let messages = [bytes];
|
let messages = [bytes];
|
||||||
self.aura_write_messages(&messages)?;
|
self.aura_write_messages(&messages)?;
|
||||||
self.config.set_field_from(bytes);
|
self.config.set_field_from(bytes);
|
||||||
self.config.write();
|
self.config.write();
|
||||||
debug!("Wrote: {:X?}", bytes);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
warn!("{:?} not supported", BuiltInModeByte::from(mode));
|
warn!("{:?} not supported", BuiltInModeByte::from(mode));
|
||||||
Err(AuraError::NotSupported)
|
Err(AuraError::NotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_keyboard(&mut self, buf: &mut [u8; 32]) -> Result<Option<usize>, AuraError> {
|
pub fn poll_keyboard(
|
||||||
|
&mut self,
|
||||||
|
hotkey_group_bytes: &[u8],
|
||||||
|
buf: &mut [u8; 32],
|
||||||
|
) -> Result<Option<usize>, AuraError> {
|
||||||
let res =
|
let res =
|
||||||
match self
|
match self
|
||||||
.handle
|
.handle
|
||||||
.read_interrupt(self.keys_endpoint, buf, Duration::from_micros(1))
|
.read_interrupt(self.keys_endpoint, buf, Duration::from_micros(1))
|
||||||
{
|
{
|
||||||
Ok(o) => {
|
Ok(o) => {
|
||||||
if self.laptop.borrow().hotkey_group_bytes().contains(&buf[0]) {
|
if hotkey_group_bytes.contains(&buf[0]) {
|
||||||
Ok(Some(o))
|
Ok(Some(o))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -337,15 +333,14 @@ impl VirtKeys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn press(&mut self, key: u8) {
|
pub fn press(&mut self, input: [u8; 2]) {
|
||||||
let mut bytes = [0u8; 8];
|
let mut bytes = [0u8; 8];
|
||||||
bytes[0] = 0x02;
|
bytes[0] = 0x02;
|
||||||
bytes[1] = key;
|
bytes[1] = input[0];
|
||||||
// email button
|
bytes[2] = input[1];
|
||||||
// bytes[1] = 0x8a;
|
|
||||||
// bytes[2] = 0x01;
|
|
||||||
self.device.write(&bytes).unwrap();
|
self.device.write(&bytes).unwrap();
|
||||||
bytes[1] = 0;
|
bytes[1] = 0;
|
||||||
|
bytes[2] = 0;
|
||||||
self.device.write(&bytes).unwrap();
|
self.device.write(&bytes).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,18 +364,29 @@ pub const CONSUMER: [u8; 25] = [
|
|||||||
// Needs another Usage (80) for system control
|
// Needs another Usage (80) for system control
|
||||||
// B5 for toggle int/ext display
|
// B5 for toggle int/ext display
|
||||||
// b2 for external
|
// b2 for external
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub enum ConsumerKeys {
|
pub enum ConsumerKeys {
|
||||||
VolUp = 0xe9, // USAGE (Volume up)
|
VolUp = 0x0e9, // USAGE (Volume up)
|
||||||
VolDown = 0xea, // USAGE (Volume down)
|
VolDown = 0x0ea, // USAGE (Volume down)
|
||||||
VolMute = 0xe2, // USAGE (Volume mute)
|
VolMute = 0x0e2, // USAGE (Volume mute)
|
||||||
TrackNext = 0xb6, // USAGE (Track next)
|
TrackNext = 0x0b6, // USAGE (Track next)
|
||||||
PlayToggl = 0xcd, // USAGE (Play/Pause)
|
PlayToggl = 0x0cd, // USAGE (Play/Pause)
|
||||||
TrackPrev = 0xb5, // USAGE (Track prev)
|
TrackPrev = 0x0b5, // USAGE (Track prev)
|
||||||
TrackStop = 0xb7,
|
TrackStop = 0x0b7,
|
||||||
Power = 0x30,
|
Power = 0x030,
|
||||||
Reset = 0x31,
|
Reset = 0x031,
|
||||||
Sleep = 0x32, // USAGE (Sleep)
|
Sleep = 0x032, // USAGE (Sleep)
|
||||||
BacklightInc = 0x6f, // USAGE (Backlight Inc)
|
BacklightInc = 0x06f, // USAGE (Backlight Inc)
|
||||||
BacklightDec = 0x70, // USAGE (Backlight Dec)
|
BacklightDec = 0x070, // USAGE (Backlight Dec)
|
||||||
BacklightTog = 0x72, // USAGE (Backlight toggle? display toggle?)
|
BacklightTog = 0x072, // USAGE (Backlight toggle? display toggle?)
|
||||||
|
Present = 0x188,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ConsumerKeys> for [u8; 2] {
|
||||||
|
fn from(key: ConsumerKeys) -> Self {
|
||||||
|
let mut bytes = [0u8; 2];
|
||||||
|
bytes[0] = key as u8;
|
||||||
|
bytes[1] = (key as u16 >> 8) as u8;
|
||||||
|
bytes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use crate::aura::BuiltInModeByte;
|
use crate::aura::BuiltInModeByte;
|
||||||
use crate::core::{Backlight, RogCore};
|
use crate::core::{Backlight, ConsumerKeys, RogCore};
|
||||||
use crate::error::AuraError;
|
use crate::error::AuraError;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
pub fn match_laptop() -> Result<Box<dyn Laptop>, AuraError> {
|
pub fn match_laptop() -> Box<dyn Laptop> {
|
||||||
let dmi = sysfs_class::DmiId::default();
|
let dmi = sysfs_class::DmiId::default();
|
||||||
let board_name = dmi.board_name()?;
|
let board_name = dmi.board_name().unwrap();
|
||||||
match board_name.as_str() {
|
match board_name.as_str() {
|
||||||
// The hell does it have a \n for anyway?
|
// The hell does it have a \n for anyway?
|
||||||
"GX502GW\n" => Ok(Box::new(LaptopGX502GW::new())),
|
"GX502GW\n" => Box::new(LaptopGX502GW::new()),
|
||||||
_ => {
|
_ => {
|
||||||
panic!("could not match laptop");
|
panic!("could not match laptop");
|
||||||
}
|
}
|
||||||
@@ -77,6 +77,7 @@ impl LaptopGX502GW {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Laptop for LaptopGX502GW {
|
impl Laptop for LaptopGX502GW {
|
||||||
|
// TODO: This really needs to match against u16 in future
|
||||||
fn do_hotkey_action(&self, rogcore: &mut RogCore, key_byte: u8) -> Result<(), AuraError> {
|
fn do_hotkey_action(&self, rogcore: &mut RogCore, key_byte: u8) -> Result<(), AuraError> {
|
||||||
match GX502GWKeys::from(key_byte) {
|
match GX502GWKeys::from(key_byte) {
|
||||||
GX502GWKeys::LedBrightUp => {
|
GX502GWKeys::LedBrightUp => {
|
||||||
@@ -86,7 +87,7 @@ impl Laptop for LaptopGX502GW {
|
|||||||
rogcore.config_mut().brightness = bright;
|
rogcore.config_mut().brightness = bright;
|
||||||
}
|
}
|
||||||
let bytes = RogCore::aura_brightness_bytes(bright)?;
|
let bytes = RogCore::aura_brightness_bytes(bright)?;
|
||||||
rogcore.aura_set_and_save(&bytes)?;
|
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
||||||
}
|
}
|
||||||
GX502GWKeys::LedBrightDown => {
|
GX502GWKeys::LedBrightDown => {
|
||||||
let mut bright = rogcore.config().brightness;
|
let mut bright = rogcore.config().brightness;
|
||||||
@@ -95,7 +96,7 @@ impl Laptop for LaptopGX502GW {
|
|||||||
rogcore.config_mut().brightness = bright;
|
rogcore.config_mut().brightness = bright;
|
||||||
}
|
}
|
||||||
let bytes = RogCore::aura_brightness_bytes(bright)?;
|
let bytes = RogCore::aura_brightness_bytes(bright)?;
|
||||||
rogcore.aura_set_and_save(&bytes)?;
|
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
||||||
}
|
}
|
||||||
GX502GWKeys::AuraNext => {
|
GX502GWKeys::AuraNext => {
|
||||||
let mut mode = rogcore.config().current_mode[3] + 1;
|
let mut mode = rogcore.config().current_mode[3] + 1;
|
||||||
@@ -106,7 +107,7 @@ impl Laptop for LaptopGX502GW {
|
|||||||
}
|
}
|
||||||
rogcore.config_mut().current_mode[3] = mode;
|
rogcore.config_mut().current_mode[3] = mode;
|
||||||
if let Some(bytes) = rogcore.config_mut().get_current() {
|
if let Some(bytes) = rogcore.config_mut().get_current() {
|
||||||
rogcore.aura_set_and_save(&bytes)?;
|
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GX502GWKeys::AuraPrevious => {
|
GX502GWKeys::AuraPrevious => {
|
||||||
@@ -120,7 +121,7 @@ impl Laptop for LaptopGX502GW {
|
|||||||
}
|
}
|
||||||
rogcore.config_mut().current_mode[3] = mode;
|
rogcore.config_mut().current_mode[3] = mode;
|
||||||
if let Some(bytes) = rogcore.config_mut().get_current() {
|
if let Some(bytes) = rogcore.config_mut().get_current() {
|
||||||
rogcore.aura_set_and_save(&bytes)?;
|
rogcore.aura_set_and_save(&self.supported_modes, &bytes)?;
|
||||||
rogcore.config().write();
|
rogcore.config().write();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +140,9 @@ impl Laptop for LaptopGX502GW {
|
|||||||
|
|
||||||
GX502GWKeys::MicToggle => {}
|
GX502GWKeys::MicToggle => {}
|
||||||
GX502GWKeys::Fan => {}
|
GX502GWKeys::Fan => {}
|
||||||
GX502GWKeys::ScreenToggle => {}
|
GX502GWKeys::ScreenToggle => {
|
||||||
|
rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into());
|
||||||
|
}
|
||||||
GX502GWKeys::TouchPadToggle => {}
|
GX502GWKeys::TouchPadToggle => {}
|
||||||
GX502GWKeys::Rog => {}
|
GX502GWKeys::Rog => {}
|
||||||
|
|
||||||
@@ -149,7 +152,7 @@ impl Laptop for LaptopGX502GW {
|
|||||||
"Unmapped key, attempt to pass to virtual device: {:?}, {:X?}",
|
"Unmapped key, attempt to pass to virtual device: {:?}, {:X?}",
|
||||||
&key_byte, &key_byte
|
&key_byte, &key_byte
|
||||||
);
|
);
|
||||||
rogcore.virt_keys().press(key_byte);
|
rogcore.virt_keys().press([key_byte, 0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user