CasualX / vigem-client

ViGEm client API in pure Rust.
MIT License
17 stars 7 forks source link

DS4 API improvement #10

Open saidsay-so opened 1 year ago

saidsay-so commented 1 year ago

Introduces a new API for DualShock4 reports, which includes builders for the raw reports' structs and some of their special fields. Both versions of the reports have a builder, which is the only way to construct the underlying reports, since their fields are now private to avoid exposing superfluous fields and avoid breaking change if we decide to change their layout.

Example

use vigem_client::{DS4ReportExBuilder, DS4ReportEx, DS4Buttons, DS4SpecialButtons, DS4Status, DS4TouchReport, DS4TouchPoint, BatteryStatus};
let report = DS4ReportExBuilder::new()
    .thumb_lx(0x80)
    .thumb_rx(0x80)
    .thumb_ry(0x80)
    .buttons(DS4Buttons::new().cross(true).square(true))
    .special(DS4SpecialButtons::new().touchpad(true))
    .trigger_l(0)
    .trigger_r(0)
    .timestamp(0)
    .accel_x(0)
    .gyro_x(0)
    .status(DS4Status::with_battery_status(BatteryStatus::Charging(9)))
    .touch_reports(Some(DS4TouchReport::new(0, Some(DS4TouchPoint::new(1920, 942)), Some(DS4TouchPoint::new(22, 5)))), None, None)
    .build();

Special fields

Some fields also have a dedicated builder to allow more ergonomic construction, like the buttons and status.

Buttons

With DS4Buttons, a set of buttons to be pressed (or not) can be built using either the builder pattern or the bitwise operators. This also includes the D-Pad direction, which is set within the same integer as the other buttons internally.

Example

let b = DS4Buttons::new().cross(true).square(true).dpad(DpadDirection::South);
b |= DS4Buttons::TRIANGLE;

Special buttons

Similarly to DS4Buttons, a set of special buttons can be created with DS4SpecialButtons.

Example

use vigem_client::DS4SpecialButtons;
let buttons = DS4SpecialButtons::new();
let buttons = buttons.mic_mute(true).ps_home(true);
let buttons = buttons | DS4SpecialButtons::TOUCHPAD;

Touch reports and touchpoints

Touch reports, which contains two touchpoints, can be created with a single constructor.

Example

let report = DS4TouchReport::new(0, Some(DS4TouchPoint::new(1920, 942)), None);

Status

The status can be built only (maybe others?) with with_battery_status function, which takes a BatteryStatus as argument to reflect the possible battery statuses available.

Example

DS4Status::with_battery_status(BatteryStatus::Charging(9))
saidsay-so commented 1 year ago

@CasualX What do you think of this possible API?

CasualX commented 1 year ago

Hey sorry I haven't been responsive, I've not found the motivation to do any programming (outside of work) lately.

Some quick notes: In general I'm not a fan of builders in general but due to the pain of packed structs I'm willing to tolerate them.

A quick note: you have some indented by spaces in some of the files, I would appreciate if you could change that back to tabs. I like tabs for indentation (and spaces for alignment).

In case you're interested: the way I have dealt with misaligned fields in structs before is: if there's only few fields (like a single one) then I may just break the field up in a smaller integer size and suffix them _hi and _lo. Another strategy I've used is to create 2 structs: a public one (not packed) and a private packed one and convert to packed privately when needed.

But since I'm unlikely to ever use the ds4 code I can live with it :)

Originalimoc commented 1 year ago

What's blocking a merge? It works quite well.

Originalimoc commented 1 year ago

Actually there is a bug, touch pad is keep touching 0,0 even inside report is None.

Edit: Fixed https://github.com/musikid/vigem-client/commit/bd8f2ebe109cace02913f3dd32e4415c6b6fae8d