TargetBuilder

Struct TargetBuilder 

Source
pub struct TargetBuilder<'a, T> { /* private fields */ }
Expand description

A builder for creating and plugging in a new virtual target.

Obtain a TargetBuilder from Client::new_x360_target() or Client::new_ds4_target().

Implementations§

Source§

impl<'a, T> TargetBuilder<'a, T>

Source

pub fn with_vid(self, vid: u16) -> Self

Sets a custom Vendor ID (VID) for this virtual device.

If not set, the default VID for the controller type will be used.

Source

pub fn with_pid(self, pid: u16) -> Self

Sets a custom Product ID (PID) for this virtual device.

If not set, the default PID for the controller type will be used.

Source§

impl<'a> TargetBuilder<'a, Xbox360>

Source

pub fn plugin(self) -> Result<TargetHandle<Xbox360>, ClientError>

Plugs the configured target into the ViGEm bus.

WARNING: The virtual controller may not be immediately ready for input updates (e.g., update() calls) upon the return of this function. Windows and the ViGEm driver require time to fully enumerate the device.

For reliable operation, especially when sending updates immediately after plugging in, it is highly recommended to call TargetHandle<T>::wait_for_ready and wait for it to return successfully before sending the first report.

On success, this consumes the builder and returns a TargetHandle which can be used to control the virtual device.

Examples found in repository?
examples/x360.rs (line 12)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // Connect to the ViGEm bus
7    // This can fail if the ViGEm bus driver is not installed.
8    let client = Client::connect()?;
9    println!("Connected to ViGEm bus");
10
11    // Create and plugin the virtual controller
12    let x360 = client.new_x360_target().plugin()?;
13    println!("Plugged in virtual Xbox 360 controller");
14
15    // Wait for the controller to be ready
16    // The virtual controller needs a moment to be recognized
17    // by the system before it can receive updates.
18    x360.wait_for_ready()?;
19    println!("Controller is ready. You can test it at https://hardwaretester.com/gamepad");
20
21    // Set up a notification listener in a separate thread
22    // This allows us to react to feedback from the system, like rumble or LED changes.
23    let notifications = x360.register_notification()?;
24    thread::spawn(move || {
25        println!("Notification Thread Started. Waiting for feedback...");
26        while let Ok(Ok(notification)) = notifications.recv() {
27            println!("Notification Thread Received feedback:");
28            println!(
29                "  - Rumble: Large Motor = {}, Small Motor = {}",
30                notification.large_motor, notification.small_motor
31            );
32            println!("  - LED Number/Player Index: {}", notification.led_number);
33        }
34    });
35
36    // Here, we'll send reports to the controller to simulate input.
37    let mut report = X360Report::default();
38    let mut angle: f64 = 0.0;
39    let mut step = 0;
40
41    loop {
42        // Animate the left thumbstick in a circle
43        angle += 0.1;
44        let (sin, cos) = angle.sin_cos();
45        report.thumb_lx = (sin * 32767.0) as i16;
46        report.thumb_ly = (cos * 32767.0) as i16;
47
48        // Alternate pressing A and B buttons
49        if step % 2 == 0 {
50            report.buttons = X360Button::A;
51        } else {
52            report.buttons = X360Button::B;
53        }
54
55        // Send the updated report to the controller
56        x360.update(&report)?;
57
58        thread::sleep(Duration::from_millis(16));
59        step += 1;
60    }
61}
Source§

impl<'a> TargetBuilder<'a, DualShock4>

Source

pub fn plugin(self) -> Result<TargetHandle<DualShock4>, ClientError>

Plugs the configured target into the ViGEm bus.

WARNING: The virtual controller may not be immediately ready for input updates (e.g., update() calls) upon the return of this function. Windows and the ViGEm driver require time to fully enumerate the device.

For reliable operation, especially when sending updates immediately after plugging in, it is highly recommended to call TargetHandle<T>::wait_for_ready and wait for it to return successfully before sending the first report.

On success, this consumes the builder and returns a TargetHandle which can be used to control the virtual device.

Examples found in repository?
examples/ds4.rs (line 12)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // Connect to the ViGEm bus
7    // This can fail if the ViGEm bus driver is not installed.
8    let client = Client::connect()?;
9    println!("Connected to ViGEm bus");
10
11    // Create and plugin the virtual controller
12    let ds4 = client.new_ds4_target().plugin()?;
13    println!("Plugged in virtual DualShock 4 controller");
14
15    // Wait for the controller to be ready
16    ds4.wait_for_ready()?;
17    println!("Controller is ready. You can test it at https://hardwaretester.com/gamepad");
18
19    // Set up a notification listener in a separate thread
20    // This allows us to react to feedback from the system, like rumble or LED changes.
21    let notifications = ds4.register_notification()?;
22    thread::spawn(move || {
23        println!("Notification Thread Started. Waiting for feedback from the host...");
24        while let Ok(Ok(notification)) = notifications.recv() {
25            println!("Notification Thread Received feedback:");
26            println!(
27                "  - Rumble: Large Motor = {}, Small Motor = {}",
28                notification.large_motor, notification.small_motor
29            );
30            println!(
31                "  - Lightbar Color: R={}, G={}, B={}",
32                notification.lightbar.red, notification.lightbar.green, notification.lightbar.blue
33            );
34        }
35    });
36
37    // Here, we'll send reports to the controller to simulate input.
38
39    let mut report = Ds4Report::default();
40
41    // Hold the right D-pad button
42    report.set_dpad(Ds4Dpad::East);
43    // Hold the Cross button
44    report.buttons |= Ds4Button::CROSS.bits();
45    // Fully press the right trigger
46    report.trigger_r = 255;
47
48    let mut angle: f64 = 0.0;
49
50    loop {
51        // Animate the right thumbstick in a circle
52        let (sin, cos) = angle.sin_cos();
53
54        // DS4 thumbsticks are 0-255, with 128 as the center.
55        report.thumb_rx = (128.0 + sin * 127.0) as u8;
56        report.thumb_ry = (128.0 + cos * 127.0) as u8;
57
58        // Send the updated report to the controller
59        ds4.update(&report)?;
60
61        thread::sleep(Duration::from_millis(16));
62        angle += 0.05;
63    }
64}
More examples
Hide additional examples
examples/ds4_ex.rs (line 13)
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}

Auto Trait Implementations§

§

impl<'a, T> Freeze for TargetBuilder<'a, T>

§

impl<'a, T> RefUnwindSafe for TargetBuilder<'a, T>
where T: RefUnwindSafe,

§

impl<'a, T> Send for TargetBuilder<'a, T>
where T: Send,

§

impl<'a, T> Sync for TargetBuilder<'a, T>
where T: Sync,

§

impl<'a, T> Unpin for TargetBuilder<'a, T>
where T: Unpin,

§

impl<'a, T> UnwindSafe for TargetBuilder<'a, T>
where T: UnwindSafe,

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> 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, 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.