From 44fb0ee1391456b6cb6901f54e99091a328c41a8 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 21 Apr 2020 16:01:44 +1200 Subject: [PATCH] Add virtual keyboard so touchpad can be toggled :/ --- README.md | 4 +- rog-core/Cargo.toml | 2 +- rog-lib/Cargo.toml | 5 +- rog-lib/src/core.rs | 85 +--------------------- rog-lib/src/laptops.rs | 26 +++++-- rog-lib/src/lib.rs | 1 + rog-lib/src/virt_device.rs | 140 +++++++++++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+), 92 deletions(-) create mode 100644 rog-lib/src/virt_device.rs diff --git a/README.md b/README.md index 2950b5c6..0f19410a 100644 --- a/README.md +++ b/README.md @@ -62,10 +62,10 @@ Currently if no options are supplied for the CLI mode selection then a default i + [X] Airplane mode + [X] Screen off? Now mapped to a keycode but has no effect + [X] Screen brightness up/down - + [ ] ROG key custom mapping (Can be done) + + [ ] ROG key custom mapping (Can be done in source) + [ ] Fan/Performance mode + [ ] Screen off?? - + [ ] Touchpad toggle + + [X] Touchpad toggle (using a virtual keyboard to emit F21...) - [X] Capture and use hotkeys **Partially completed: aura keys work** + [X] Aura control by Aura keys + [X] Volume + media controls work diff --git a/rog-core/Cargo.toml b/rog-core/Cargo.toml index 1289c13e..600df9ad 100644 --- a/rog-core/Cargo.toml +++ b/rog-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog-core" -version = "0.3.2" +version = "0.3.3" authors = ["Luke "] edition = "2018" diff --git a/rog-lib/Cargo.toml b/rog-lib/Cargo.toml index 517068dc..a20e3985 100644 --- a/rog-lib/Cargo.toml +++ b/rog-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog-lib" -version = "0.4.0" +version = "0.4.1" authors = ["Luke "] edition = "2018" @@ -14,4 +14,5 @@ sysfs-class = "0.1.2" aho-corasick = "0.7" thiserror = "1.0.15" log = "0.4" -uhid-virt = "0.0.2" \ No newline at end of file +uhid-virt = "0.0.2" +#keycode = "0.3" \ No newline at end of file diff --git a/rog-lib/src/core.rs b/rog-lib/src/core.rs index ea501c6a..d18f690b 100644 --- a/rog-lib/src/core.rs +++ b/rog-lib/src/core.rs @@ -1,6 +1,8 @@ // Return show-stopping errors, otherwise map error to a log level -use crate::{aura::BuiltInModeByte, config::Config, error::AuraError, laptops::*}; +use crate::{ + aura::BuiltInModeByte, config::Config, error::AuraError, laptops::*, virt_device::VirtKeys, +}; use aho_corasick::AhoCorasick; use gumdrop::Options; use log::{debug, warn}; @@ -9,7 +11,6 @@ use std::process::Command; use std::str::FromStr; use std::time::Duration; use sysfs_class::{Brightness, SysClass}; -use uhid_virt::{Bus, CreateParams, UHIDDevice}; pub const LED_MSG_LEN: usize = 17; static LED_INIT1: [u8; 2] = [0x5d, 0xb9]; @@ -310,83 +311,3 @@ impl FromStr for LedBrightness { } } } - -pub struct VirtKeys { - pub device: UHIDDevice, -} - -impl VirtKeys { - pub fn new() -> Self { - VirtKeys { - device: UHIDDevice::create(CreateParams { - name: String::from("Virtual ROG buttons"), - phys: String::from(""), - uniq: String::from(""), - bus: Bus::USB, - vendor: 0x0b05, - product: 0x1866, - version: 0, - country: 0, - rd_data: CONSUMER.to_vec(), - }) - .unwrap(), - } - } - - pub fn press(&mut self, input: [u8; 2]) { - let mut bytes = [0u8; 8]; - bytes[0] = 0x02; - bytes[1] = input[0]; - bytes[2] = input[1]; - self.device.write(&bytes).unwrap(); - bytes[1] = 0; - bytes[2] = 0; - self.device.write(&bytes).unwrap(); - } -} - -pub const CONSUMER: [u8; 25] = [ - 0x05, 0x0C, // Usage Page (Consumer) - 0x09, 0x01, // Usage (Consumer Control) - 0xA1, 0x01, // Collection (Application) - 0x85, 0x02, // Report ID (2) - 0x19, 0x00, // Usage Minimum (Unassigned) - 0x2A, 0x3C, 0x02, // Usage Maximum (AC Format) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0x3C, 0x02, // Logical Maximum (572) - 0x75, 0x10, // Report Size (16) - 0x95, 0x02, // Report Count (2) - 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, -]; - -// Usage 04 for microphone -// Needs another Usage (80) for system control -// B5 for toggle int/ext display -// b2 for external -#[derive(Copy, Clone)] -pub enum ConsumerKeys { - VolUp = 0x0e9, // USAGE (Volume up) - VolDown = 0x0ea, // USAGE (Volume down) - VolMute = 0x0e2, // USAGE (Volume mute) - TrackNext = 0x0b6, // USAGE (Track next) - PlayToggl = 0x0cd, // USAGE (Play/Pause) - TrackPrev = 0x0b5, // USAGE (Track prev) - TrackStop = 0x0b7, - Power = 0x030, - Reset = 0x031, - Sleep = 0x032, // USAGE (Sleep) - BacklightInc = 0x06f, // USAGE (Backlight Inc) - BacklightDec = 0x070, // USAGE (Backlight Dec) - BacklightTog = 0x072, // USAGE (Backlight toggle? display toggle?) - Present = 0x188, -} - -impl From 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 - } -} diff --git a/rog-lib/src/laptops.rs b/rog-lib/src/laptops.rs index dfddb481..8aa0e945 100644 --- a/rog-lib/src/laptops.rs +++ b/rog-lib/src/laptops.rs @@ -1,6 +1,8 @@ use crate::aura::BuiltInModeByte; -use crate::core::{Backlight, ConsumerKeys, RogCore}; +use crate::core::{Backlight, RogCore}; use crate::error::AuraError; +use crate::virt_device::ConsumerKeys; +//use keycode::{KeyMap, KeyMappingId, KeyState, KeyboardState}; use log::info; pub fn match_laptop() -> Box { @@ -132,7 +134,11 @@ impl Laptop for LaptopGX502GW { self.backlight.step_down(); } GX502GWKeys::Sleep => { + // Direct call to systemd rogcore.suspend(); + //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(); @@ -143,8 +149,15 @@ impl Laptop for LaptopGX502GW { GX502GWKeys::ScreenToggle => { rogcore.virt_keys().press(ConsumerKeys::BacklightTog.into()); } - GX502GWKeys::TouchPadToggle => {} - GX502GWKeys::Rog => {} + 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_byte != 0 { @@ -152,11 +165,14 @@ impl Laptop for LaptopGX502GW { "Unmapped key, attempt to pass to virtual device: {:?}, {:X?}", &key_byte, &key_byte ); - rogcore.virt_keys().press([key_byte, 0]); + let mut bytes = [0u8; 8]; + // TODO: code page + bytes[0] = 0x02; + bytes[1] = key_byte; + rogcore.virt_keys().press(bytes); } } } - //info!("Pressed: {:?}, {:X?}", &key_byte, &key_byte); Ok(()) } fn hotkey_group_bytes(&self) -> &[u8] { diff --git a/rog-lib/src/lib.rs b/rog-lib/src/lib.rs index 3fcff22d..a7c600bb 100644 --- a/rog-lib/src/lib.rs +++ b/rog-lib/src/lib.rs @@ -5,3 +5,4 @@ pub mod config; pub mod core; mod error; pub mod laptops; +mod virt_device; diff --git a/rog-lib/src/virt_device.rs b/rog-lib/src/virt_device.rs new file mode 100644 index 00000000..5397ae15 --- /dev/null +++ b/rog-lib/src/virt_device.rs @@ -0,0 +1,140 @@ +use uhid_virt::{Bus, CreateParams, UHIDDevice}; + +pub struct VirtKeys { + pub device: UHIDDevice, +} + +impl VirtKeys { + pub fn new() -> Self { + VirtKeys { + device: UHIDDevice::create(CreateParams { + name: String::from("Virtual ROG buttons"), + phys: String::from(""), + uniq: String::from(""), + bus: Bus::USB, + vendor: 0x0b05, + product: 0x1866, + version: 0, + country: 0, + // This is a device which emits the usage code as a whole, rather than as bits + rd_data: [ + // Consumer Device TLC + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x02, // Report ID (2) + 0x19, 0x00, // Usage Minimum (Unassigned) + 0x2A, 0x3C, 0x02, // Usage Maximum (AC Format) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0x3C, 0x02, // Logical Maximum (572) + 0x75, 0x10, // Report Size (16) + 0x95, 0x02, // Report Count (2) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State) + 0xC0, // + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0xE0, // Usage Minimum (0xE0) + 0x29, 0xE7, // Usage Maximum (0xE7) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State) + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Page (LEDs) + 0x19, 0x01, // Usage Minimum (Num Lock) + 0x29, 0x05, // Usage Maximum (Kana) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State) + 0x95, 0x1E, // Report Count (30) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0x00, // Usage Minimum (0x00) + 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State) + 0xC0, // End Collection + ] + .to_vec(), + }) + .unwrap(), + } + } + + pub fn press(&mut self, input: [u8; 8]) { + self.device.write(&input).unwrap(); + let mut reset = [0u8; 8]; + reset[0] = input[0]; + self.device.write(&reset).unwrap(); + } +} + +#[derive(Copy, Clone)] +pub enum ConsumerKeys { + Power = 0x30, + Sleep = 0x32, + Menu = 0x0040, + + MediaRecord = 0xB2, + MediaFastFwd = 0xB3, + MediaRewind = 0xB4, + MediaNext = 0xB5, + MediaPrev = 0xB6, + MediaStop = 0xB7, + MediaPlayPause = 0xCD, + MediaPause = 0xB0, + + MediaVolMute = 0xE2, + MediaVolUp = 0xE9, + MediaVolDown = 0xEA, + + BacklightInc = 0x006F, + BacklightDec = 0x0070, + + BacklightTog = 0x072, // USAGE (Backlight toggle? display toggle?) + BacklightMin = 0x73, + BacklightMax = 0x74, + + ControlConfig = 0x183, + + LaunchWordEditor = 0x184, + LaunchTextEditor = 0x185, + LaunchSpreadSheet = 0x186, + LaunchGraphicsEditor = 0x187, + LaunchPresentationApp = 0x188, + LaunchDatabaseEditor = 0x189, + LaunchEmailApp = 0x18A, + LaunchNewsReader = 0x18B, + LaunchCalendarApp = 0x018e, + LaunchTaskManagementApp = 0x18F, + LaunchWebBrowser = 0x196, + ControlPanel = 0x19F, + + VideoOutStep = 0x82, + + Documents = 0x1A7, + FileBrowser = 0x1B4, + ImageBrowser = 0x1B6, + AudioBrowser = 0x1B7, + MovieBrowser = 0x1B8, +} + +impl From for [u8; 8] { + fn from(key: ConsumerKeys) -> Self { + let mut bytes = [0u8; 8]; + bytes[0] = 0x02; // report ID for consumer + bytes[1] = key as u8; + bytes[2] = (key as u16 >> 8) as u8; + bytes + } +}