diff --git a/src/input/target/dualsense.rs b/src/input/target/dualsense.rs index b9b24493..d6074137 100644 --- a/src/input/target/dualsense.rs +++ b/src/input/target/dualsense.rs @@ -124,6 +124,10 @@ pub struct DualSenseDevice { context: u8, hardware: DualSenseHardware, queued_events: Vec, + /// Last report written, used to skip re-emitting identical reports. + last_written: Option>, + /// Whether a consumer has the device open, writes are skipped while closed. + is_open: bool, } impl DualSenseDevice { @@ -137,6 +141,8 @@ impl DualSenseDevice { context: Default::default(), hardware, queued_events: Vec::new(), + last_written: None, + is_open: false, }) } @@ -193,27 +199,29 @@ impl DualSenseDevice { /// Write the current device state to the device fn write_state(&mut self) -> Result<(), Box> { - match self.state { - PackedInputDataReport::Usb(state) => { - let data = state.pack()?; - - // Write the state to the virtual HID - if let Err(e) = self.device.write(&data) { - let err = format!("Failed to write input data report: {:?}", e); - return Err(err.into()); - } - } - PackedInputDataReport::Bluetooth(state) => { - let data = state.pack()?; + // No consumer so don't bother emitting. + if !self.is_open { + return Ok(()); + } - // Write the state to the virtual HID - if let Err(e) = self.device.write(&data) { - let err = format!("Failed to write input data report: {:?}", e); - return Err(err.into()); - } - } + let data = match self.state { + PackedInputDataReport::Usb(state) => state.pack()?.to_vec(), + PackedInputDataReport::Bluetooth(state) => state.pack()?.to_vec(), }; + // Skip re-emitting an identical report: runs every poll, so an + // idle controller would otherwise send the same bytes every cycle. + if self.last_written.as_ref() == Some(&data) { + return Ok(()); + } + + // Write the state to the virtual HID + if let Err(e) = self.device.write(&data) { + let err = format!("Failed to write input data report: {:?}", e); + return Err(err.into()); + } + self.last_written = Some(data); + Ok(()) } @@ -1073,12 +1081,16 @@ impl TargetOutputDevice for DualSenseDevice { // send UHID_INPUT events to the kernel. uhid_virt::OutputEvent::Open => { log::debug!("Open event received"); + self.is_open = true; Ok(vec![]) } // This is sent when there are no more processes which read the HID data. It is // the counterpart of UHID_OPEN and you may as well ignore this event. uhid_virt::OutputEvent::Close => { log::debug!("Close event received"); + // Drop the cached report so the next consumer to open is synced. + self.is_open = false; + self.last_written = None; Ok(vec![]) } // This is sent if the HID device driver wants to send raw data to the I/O