Skip to content

Commit

Permalink
fix(Legion Go): Fix mouse reports. Fix config for different modes.
Browse files Browse the repository at this point in the history
  • Loading branch information
pastaq authored and Derek J. Clark committed Mar 10, 2024
1 parent 376a069 commit 09b731c
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 99 deletions.
23 changes: 14 additions & 9 deletions rootfs/usr/share/inputplumber/devices/legion_go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,31 @@ matches:
# One or more source devices to combine into a single virtual device. The events
# from these devices will be watched and translated according to the key map.
source_devices:
- group: keyboard # Block data
#- group: keyboard # Block data
# hidraw:
# vendor_id: 0x17ef
# product_id: 0x6182
# interface_num: 0
- group: gamepad
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
interface_num: 0
- group: mouse # Only for optical X/Y
interface_num: 2
- group: mouse # Only for optical X/Y
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
interface_num: 3
- group: mouse # Only for optical X/Y
hidraw:
vendor_id: 0x17ef
product_id: 0x6185
interface_num: 1
- group: gamepad
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
product_id: 0x6185
interface_num: 2
- group: mouse # Only for optical X/Y
hidraw:
vendor_id: 0x17ef
product_id: 0x6182
interface_num: 3

# The ID of a device event mapping in the 'event_maps' folder
event_map_id: lego
Expand Down
31 changes: 17 additions & 14 deletions src/drivers/lego/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use packed_struct::{types::SizedInteger, PackedStruct};
use super::{
event::{
AccelerometerEvent, AccelerometerInput, AxisEvent, BinaryInput, ButtonEvent, Event,
JoyAxisInput, StatusEvent, StatusInput, TouchAxisInput, TriggerEvent, TriggerInput,
JoyAxisInput, MouseWheelInput, StatusEvent, StatusInput, TouchAxisInput, TriggerEvent,
TriggerInput,
},
hid_report::{
DInputDataLeftReport, DInputDataRightReport, KeyboardDataReport, MouseDataReport,
Expand All @@ -16,11 +17,12 @@ use super::{

pub const VID: u16 = 0x17ef;
pub const PID: u16 = 0x6182;
pub const PID2: u16 = 0x6185;

const DINPUT_PACKET_SIZE: usize = 13;
const XINPUT_PACKET_SIZE: usize = 60;
const KEYBOARD_PACKET_SIZE: usize = 15;
const MOUSE_PACKET_SIZE: usize = 8;
const MOUSE_PACKET_SIZE: usize = 7;
const TOUCHPAD_PACKET_SIZE: usize = 20;
const HID_TIMEOUT: i32 = 5000;

Expand All @@ -38,12 +40,12 @@ pub const ACCEL_X_MAX: f64 = 255.0;
pub const ACCEL_X_MIN: f64 = 0.0;
pub const ACCEL_Y_MAX: f64 = 255.0;
pub const ACCEL_Y_MIN: f64 = 0.0;
pub const MOUSE_WHEEL_MAX: f64 = 255.0; //TODO: How does this work?
pub const MOUSE_WHEEL_MIN: f64 = 128.0;
pub const MOUSE_X_MAX: f64 = 4095.0;
pub const MOUSE_X_MIN: f64 = 0.0;
pub const MOUSE_Y_MAX: f64 = 4095.0;
pub const MOUSE_Y_MIN: f64 = 0.0;
pub const MOUSE_WHEEL_MAX: f64 = 120.0;
pub const MOUSE_WHEEL_MIN: f64 = -120.0;
pub const MOUSE_X_MAX: f64 = 2048.0;
pub const MOUSE_X_MIN: f64 = -2048.0;
pub const MOUSE_Y_MAX: f64 = 2048.0;
pub const MOUSE_Y_MIN: f64 = -2048.0;
pub const PAD_X_MAX: f64 = 1024.0;
pub const PAD_X_MIN: f64 = 0.0;
pub const PAD_Y_MAX: f64 = 1024.0;
Expand Down Expand Up @@ -79,12 +81,13 @@ pub struct Driver {

impl Driver {
pub fn new(path: String) -> Result<Self, Box<dyn Error + Send + Sync>> {
let fmtpath = path.clone();
let path = CString::new(path)?;
let api = hidapi::HidApi::new()?;
let device = api.open_path(&path)?;
let info = device.get_device_info()?;
if info.vendor_id() != VID || info.product_id() != PID {
return Err("Device '{path}' is not a Legion Go Controller".into());
if info.vendor_id() != VID || (info.product_id() != PID && info.product_id() != PID2) {
return Err(format!("Device '{fmtpath}' is not a Legion Go Controller").into());
}

Ok(Self {
Expand Down Expand Up @@ -315,9 +318,9 @@ impl Driver {
let input_report = MouseDataReport::unpack(&buf)?;

// Print input report for debugging
// log::debug!("--- Input report ---");
// log::debug!("{input_report}");
// log::debug!("---- End Report ----");
log::debug!("--- Input report ---");
log::debug!("{input_report}");
log::debug!("---- End Report ----");

// Update the state
let old_dinput_state = self.update_mouseinput_state(input_report);
Expand Down Expand Up @@ -586,7 +589,7 @@ impl Driver {
})));
}
if state.mouse_z != old_state.mouse_z {
events.push(Event::Trigger(TriggerEvent::MouseWheel(TriggerInput {
events.push(Event::Trigger(TriggerEvent::MouseWheel(MouseWheelInput {
value: state.mouse_z,
})));
}
Expand Down
28 changes: 21 additions & 7 deletions src/drivers/lego/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ pub struct TouchAxisInput {
pub y: u16,
}

/// Axis input contain (x, y) coordinates
#[derive(Clone, Debug)]
pub struct MouseAxisInput {
pub x: i16,
pub y: i16,
}
/// Axis input contain (x, y) coordinates
#[derive(Clone, Debug)]
pub struct JoyAxisInput {
Expand All @@ -41,6 +47,18 @@ pub struct StatusInput {
pub value: u8,
}

/// Mouse Wheel contains negative integars
#[derive(Clone, Debug)]
pub struct MouseWheelInput {
pub value: i8,
}

/// Trigger input contains non-negative integars
#[derive(Clone, Debug)]
pub struct TriggerInput {
pub value: u8,
}

/// Button events represend binary inputs
#[derive(Clone, Debug)]
pub enum ButtonEvent {
Expand Down Expand Up @@ -99,19 +117,15 @@ pub enum AxisEvent {
Touchpad(TouchAxisInput),
LStick(JoyAxisInput),
RStick(JoyAxisInput),
Mouse(MouseAxisInput),
}

/// Trigger input contains non-negative integars
#[derive(Clone, Debug)]
pub struct TriggerInput {
pub value: u8,
}
/// Trigger events contain positive values indicating how far a trigger is pulled
/// Trigger events contain values indicating how far a trigger is pulled
#[derive(Clone, Debug)]
pub enum TriggerEvent {
ATriggerL(TriggerInput),
ATriggerR(TriggerInput),
MouseWheel(TriggerInput),
MouseWheel(MouseWheelInput),
}

/// AccelerometerEvent has data from the accelerometer
Expand Down
90 changes: 23 additions & 67 deletions src/drivers/lego/hid_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,6 @@
#![allow(warnings)]
use packed_struct::prelude::*;

// Input report axis ranges
// TODO: actual mouse range
// TODO: ACCEL Left/Right X/Y, Z?
pub const ACCEL_X_MAX_LEFT: f64 = 1.0;
pub const ACCEL_X_MAX_RIGHT: f64 = 1.0;
pub const ACCEL_X_MIN_LEFT: f64 = 0.0;
pub const ACCEL_X_MIN_RIGHT: f64 = 0.0;
pub const ACCEL_Y_MAX_LEFT: f64 = 1.0;
pub const ACCEL_Y_MAX_RIGHT: f64 = 1.0;
pub const ACCEL_Y_MIN_LEFT: f64 = 0.0;
pub const ACCEL_Y_MIN_RIGHT: f64 = 0.0;
pub const MOUSE_WHEEL_MAX: f64 = 1.0;
pub const MOUSE_WHEEL_MIN: f64 = -1.0;
pub const MOUSE_X_MAX: f64 = 4095.0;
pub const MOUSE_X_MIN: f64 = 0.0;
pub const MOUSE_Y_MAX: f64 = 4095.0;
pub const MOUSE_Y_MIN: f64 = 0.0;
pub const PAD_X_MAX: f64 = 1024.0;
pub const PAD_X_MIN: f64 = 0.0;
pub const PAD_Y_MAX: f64 = 1024.0;
pub const PAD_Y_MIN: f64 = 0.0;
pub const STICK_X_MAX: f64 = 255.0;
pub const STICK_X_MIN: f64 = 0.0;
pub const STICK_Y_MAX: f64 = 255.0;
pub const STICK_Y_MIN: f64 = 0.0;
pub const TRIGG_MAX: f64 = 255.0;
pub const TRIGG_MIN: f64 = 0.0;

// NORMALIZED AXIS
pub const ACCEL_X_LEFT_NORM: f64 = 1.0 / ACCEL_X_MAX_LEFT;
pub const ACCEL_X_RIGHT_NORM: f64 = 1.0 / ACCEL_X_MAX_RIGHT;
pub const ACCEL_Y_LEFT_NORM: f64 = 1.0 / ACCEL_Y_MAX_LEFT;
pub const ACCEL_Y_RIGHT_NORM: f64 = 1.0 / ACCEL_Y_MAX_RIGHT;
pub const MOUSE_WHEEL_NORM: f64 = 1.0 / MOUSE_WHEEL_MAX;
pub const MOUSE_X_NORM: f64 = 1.0 / MOUSE_X_MAX;
pub const MOUSE_Y_NORM: f64 = 1.0 / MOUSE_Y_MAX;
pub const PAD_X_AXIS_NORM: f64 = 1.0 / PAD_X_MAX;
pub const PAD_Y_AXIS_NORM: f64 = 1.0 / PAD_Y_MAX;
pub const STICK_X_AXIS_NORM: f64 = 1.0 / STICK_X_MAX;
pub const STICK_Y_AXIS_NORM: f64 = 1.0 / STICK_Y_MAX;
pub const TRIGG_AXIS_NORM: f64 = 1.0 / TRIGG_MAX;

/// Different reports types
// When in some modes there's another report decriptor with the same ID
// as the touchpad whic is a keyboard with macros tied to different buttons.
Expand Down Expand Up @@ -385,7 +343,7 @@ pub struct XInputDataReport {
pub unk_23: u8,

#[packed_field(bytes = "25")]
pub mouse_z: u8,
pub mouse_z: i8,

#[packed_field(bytes = "26..=27", endian = "msb")]
pub touch_x_0: u16,
Expand Down Expand Up @@ -771,40 +729,38 @@ pub struct DInputDataRightReport {
// # ReportID: 9 / Button: 0 0 1 0 0 | # | X: 0 | Y: 0 | Wheel: 0 | #
// E: 000070.303202 7 09 04 00 00 00 00 00
#[derive(PackedStruct, Debug, Copy, Clone, PartialEq)]
#[packed_struct(bit_numbering = "msb0", size_bytes = "8")]
#[packed_struct(bit_numbering = "msb0", size_bytes = "7")]
pub struct MouseDataReport {
// State
#[packed_field(bytes = "0")]
pub report_id: u8,
#[packed_field(bytes = "1")]
pub report_size: u8,

// Buttons
#[packed_field(bits = "16")]
pub m1: bool,
#[packed_field(bits = "17")]
pub m2: bool,
#[packed_field(bits = "18")]
pub mouse_click: bool,
#[packed_field(bits = "19")]
pub m3: bool,
#[packed_field(bits = "20")]
#[packed_field(bits = "8")]
pub unk_1_0: bool,
#[packed_field(bits = "9")]
pub unk_1_1: bool,
#[packed_field(bits = "10")]
pub unk_1_2: bool,
#[packed_field(bits = "11")]
pub y3: bool,
#[packed_field(bits = "21")]
pub unk_2_21: bool,
#[packed_field(bits = "22")]
pub unk_2_22: bool,
#[packed_field(bits = "23")]
pub unk_2_23: bool,
#[packed_field(bits = "12")]
pub m3: bool,
#[packed_field(bits = "13")]
pub mouse_click: bool,
#[packed_field(bits = "14")]
pub m2: bool,
#[packed_field(bits = "15")]
pub m1: bool,

// Axes
#[packed_field(bits = "24..=35", endian = "lsb")]
pub mouse_x: Integer<u16, packed_bits::Bits<12>>,
#[packed_field(bits = "36..=47", endian = "lsb")]
pub mouse_y: Integer<u16, packed_bits::Bits<12>>,
#[packed_field(bits = "16..=27", endian = "msb")]
pub mouse_x: Integer<i16, packed_bits::Bits<12>>,
#[packed_field(bits = "28..=39", endian = "msb")]
pub mouse_y: Integer<i16, packed_bits::Bits<12>>,
#[packed_field(bytes = "5")]
pub mouse_z: i8,
#[packed_field(bytes = "6")]
pub mouse_z: u8,
#[packed_field(bytes = "7")]
pub report_count: u8,
}

Expand Down
3 changes: 2 additions & 1 deletion src/input/source/hidraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ impl HIDRawDevice {
driver.run().await?;
}
if self.info.vendor_id() == drivers::lego::driver::VID
&& self.info.product_id() == drivers::lego::driver::PID
&& (self.info.product_id() == drivers::lego::driver::PID
|| self.info.product_id() == drivers::lego::driver::PID2)
{
log::info!("Detected Legion Go");
let tx = self.composite_tx.clone();
Expand Down
18 changes: 17 additions & 1 deletion src/input/source/hidraw/lego.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use hidapi::DeviceInfo;
use tokio::sync::broadcast;

use crate::{
drivers::lego::{self, driver::Driver},
drivers::lego::{self, driver::Driver, event::MouseAxisInput},
input::{
capability::{
Capability, Gamepad, GamepadAxis, GamepadButton, GamepadTrigger, Mouse, MouseButton,
Expand Down Expand Up @@ -131,6 +131,19 @@ fn normalize_axis_value(event: lego::event::AxisEvent) -> InputValue {
let y = normalize_signed_value(value.y as f64, min, max);
let y = Some(-y); // Y-Axis is inverted

InputValue::Vector2 { x, y }
}
lego::event::AxisEvent::Mouse(value) => {
let min = lego::driver::MOUSE_X_MIN;
let max = lego::driver::MOUSE_X_MAX;
let x = normalize_signed_value(value.x as f64, min, max);
let x = Some(x);

let min = lego::driver::MOUSE_Y_MIN;
let max = lego::driver::MOUSE_Y_MAX;
let y = normalize_signed_value(value.y as f64, min, max);
let y = Some(y);

InputValue::Vector2 { x, y }
}
}
Expand Down Expand Up @@ -293,6 +306,9 @@ fn translate_event(event: lego::event::Event) -> NativeEvent {
Capability::Gamepad(Gamepad::Axis(GamepadAxis::RightStick)),
normalize_axis_value(axis),
),
lego::event::AxisEvent::Mouse(_) => {
NativeEvent::new(Capability::Mouse(Mouse::Motion), normalize_axis_value(axis))
}
},
lego::event::Event::Trigger(trigg) => match trigg.clone() {
lego::event::TriggerEvent::ATriggerL(_) => NativeEvent::new(
Expand Down

0 comments on commit 09b731c

Please sign in to comment.