Ds4Touch

Struct Ds4Touch 

Source
#[repr(C, packed(1))]
pub struct Ds4Touch { pub packet_counter: u8, pub is_up_tracking_num_1: u8, pub touch_data_1: [u8; 3], pub is_up_tracking_num_2: u8, pub touch_data_2: [u8; 3], }
Expand description

Represents a single packet of touchpad data for a DualShock 4 controller.

The DS4 can track up to two simultaneous touch points. This struct contains the state for both potential touches, along with a counter to sequence the packets. It is used within the Ds4ReportExData struct.

Fields§

§packet_counter: u8

A timestamp or packet counter that increments with each new touch data packet, used to sequence events.

§is_up_tracking_num_1: u8

Touch state and tracking ID for the first touch point. This is a bit-packed field:

  • The most significant bit (MSB, 0x80) indicates the contact state. This is “active-low”, meaning 0 for touch down and 1 for touch up.
  • The lower 7 bits (0x7F) are the tracking ID for the finger. This ID is unique for a single press-drag-release gesture and increments for a new press.
§touch_data_1: [u8; 3]

The raw X/Y coordinate data for the first touch point, with a resolution of 1920x943.

This is a packed 24-bit value encoding a 12-bit X and 12-bit Y coordinate. The middle byte holds the 4 least significant bits of X and the 4 most significant bits of Y.

You can unpack the coordinates like this:

let x = (self.touch_data_1[0] as u16) | (((self.touch_data_1[1] & 0x0F) as u16) << 8);
let y = (((self.touch_data_1[1] & 0xF0) as u16) >> 4) | ((self.touch_data_1[2] as u16) << 4);
§is_up_tracking_num_2: u8

Touch state and tracking ID for the second touch point. Formatted identically to is_up_tracking_num_1.

§touch_data_2: [u8; 3]

The raw X/Y coordinate data for the second touch point. Formatted identically to touch_data_1.

Implementations§

Source§

impl Ds4Touch

Source

pub fn set_touch_1(&mut self, is_down: bool, tracking_num: u8, x: u16, y: u16)

Sets the state for the first touch contact, abstracting away the bit-packing.

§Arguments
  • is_down - true if the finger is touching the pad, false otherwise.
  • tracking_num - A unique ID for the finger gesture (0-127).
  • x - The X coordinate (0-1919).
  • y - The Y coordinate (0-942).
Examples found in repository?
examples/ds4_ex.rs (line 63)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7    // Connect to the ViGEm bus
8    // This can fail if the ViGEm bus driver is not installed.
9    let client = Client::connect()?;
10    println!("Connected to ViGEm bus");
11
12    // Create and plugin the virtual controller
13    let ds4 = client.new_ds4_target().plugin()?;
14    println!("Plugged in virtual DualShock 4 controller");
15
16    // Wait for the controller to be ready
17    ds4.wait_for_ready()?;
18    println!("Controller is ready. You can test it at https://hardwaretester.com/gamepad");
19
20    let notifications = ds4.register_notification()?;
21    thread::spawn(move || {
22        println!("Notification Thread Started. Waiting for feedback from the host...");
23        while let Ok(Ok(notification)) = notifications.recv() {
24            println!("Notification Thread Received feedback:");
25            println!(
26                "  - Rumble: Large Motor = {}, Small Motor = {}",
27                notification.large_motor, notification.small_motor
28            );
29            println!(
30                "  - Lightbar Color: R={}, G={}, B={}",
31                notification.lightbar.red, notification.lightbar.green, notification.lightbar.blue
32            );
33        }
34    });
35
36    // Main input loop for extended reports
37    let mut report_ex = Ds4ReportEx::default();
38
39    // Variables to animate the touch point
40    let mut packet_counter: u8 = 0;
41    let mut touch_x: i32 = 0;
42    let mut direction: i32 = 12;
43
44    loop {
45        // Move the touch point back and forth horizontally.
46        if touch_x <= 0 {
47            direction = 12;
48        }
49        if touch_x >= 1919 {
50            direction = -12;
51        }
52        touch_x += direction;
53
54        report_ex.touch_packets_n = 1;
55
56        // Get a mut reference to the touch data struct inside the report.
57        let touch = &mut report_ex.current_touch;
58
59        // This counter should increment for each new packet of touch data (not sure if necessary for functionality).
60        touch.packet_counter = packet_counter;
61        packet_counter = packet_counter.wrapping_add(1);
62
63        touch.set_touch_1(true, 1, touch_x as u16, 471); // Finger 1 is down, centered vertically.
64        touch.set_touch_2(false, 0, 0, 0); // Finger 2 is up (inactive).
65
66        // Send the updated report to the controller
67        ds4.update_ex(&report_ex)?;
68
69        thread::sleep(Duration::from_millis(16));
70    }
71}
Source

pub fn set_touch_2(&mut self, is_down: bool, tracking_num: u8, x: u16, y: u16)

Sets the state for the second touch contact, abstracting away the bit-packing.

§Arguments
  • is_down - true if the finger is touching the pad, false otherwise.
  • tracking_num - A unique ID for the finger gesture (0-127).
  • x - The X coordinate (0-1919).
  • y - The Y coordinate (0-942).
Examples found in repository?
examples/ds4_ex.rs (line 64)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7    // Connect to the ViGEm bus
8    // This can fail if the ViGEm bus driver is not installed.
9    let client = Client::connect()?;
10    println!("Connected to ViGEm bus");
11
12    // Create and plugin the virtual controller
13    let ds4 = client.new_ds4_target().plugin()?;
14    println!("Plugged in virtual DualShock 4 controller");
15
16    // Wait for the controller to be ready
17    ds4.wait_for_ready()?;
18    println!("Controller is ready. You can test it at https://hardwaretester.com/gamepad");
19
20    let notifications = ds4.register_notification()?;
21    thread::spawn(move || {
22        println!("Notification Thread Started. Waiting for feedback from the host...");
23        while let Ok(Ok(notification)) = notifications.recv() {
24            println!("Notification Thread Received feedback:");
25            println!(
26                "  - Rumble: Large Motor = {}, Small Motor = {}",
27                notification.large_motor, notification.small_motor
28            );
29            println!(
30                "  - Lightbar Color: R={}, G={}, B={}",
31                notification.lightbar.red, notification.lightbar.green, notification.lightbar.blue
32            );
33        }
34    });
35
36    // Main input loop for extended reports
37    let mut report_ex = Ds4ReportEx::default();
38
39    // Variables to animate the touch point
40    let mut packet_counter: u8 = 0;
41    let mut touch_x: i32 = 0;
42    let mut direction: i32 = 12;
43
44    loop {
45        // Move the touch point back and forth horizontally.
46        if touch_x <= 0 {
47            direction = 12;
48        }
49        if touch_x >= 1919 {
50            direction = -12;
51        }
52        touch_x += direction;
53
54        report_ex.touch_packets_n = 1;
55
56        // Get a mut reference to the touch data struct inside the report.
57        let touch = &mut report_ex.current_touch;
58
59        // This counter should increment for each new packet of touch data (not sure if necessary for functionality).
60        touch.packet_counter = packet_counter;
61        packet_counter = packet_counter.wrapping_add(1);
62
63        touch.set_touch_1(true, 1, touch_x as u16, 471); // Finger 1 is down, centered vertically.
64        touch.set_touch_2(false, 0, 0, 0); // Finger 2 is up (inactive).
65
66        // Send the updated report to the controller
67        ds4.update_ex(&report_ex)?;
68
69        thread::sleep(Duration::from_millis(16));
70    }
71}
Source

pub fn get_packet_counter(&self) -> u8

Returns the packet counter/timestamp for this touch event.

Source

pub fn get_is_down_1(&self) -> bool

Returns true if the first touch point is active (finger is down).

Source

pub fn get_tracking_num_1(&self) -> u8

Returns the tracking ID for the first touch point (0-127).

Source

pub fn get_coords_1(&self) -> (u16, u16)

Returns the (X, Y) coordinates for the first touch point. X is in the range 0-1919, Y is in the range 0-942.

Source

pub fn get_is_down_2(&self) -> bool

Returns true if the second touch point is active (finger is down).

Source

pub fn get_tracking_num_2(&self) -> u8

Returns the tracking ID for the second touch point (0-127).

Source

pub fn get_coords_2(&self) -> (u16, u16)

Returns the (X, Y) coordinates for the second touch point. X is in the range 0-1919, Y is in the range 0-942.

Trait Implementations§

Source§

impl Clone for Ds4Touch

Source§

fn clone(&self) -> Ds4Touch

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Ds4Touch

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Ds4Touch

Source§

fn default() -> Ds4Touch

Returns the “default value” for a type. Read more
Source§

impl Copy for Ds4Touch

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.