Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add get_input_report (currently not supported on windows native backend) #163

Merged
merged 3 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ target
Cargo.lock
.idea/
hidapi-rs.iml
.helix/
.vscode/
5 changes: 5 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ extern "C" {
data: *const c_uchar,
length: size_t,
) -> c_int;
pub fn hid_get_input_report(
device: *mut HidDevice,
data: *mut c_uchar,
length: size_t,
) -> c_int;
pub fn hid_close(device: *mut HidDevice);
pub fn hid_get_manufacturer_string(
device: *mut HidDevice,
Expand Down
10 changes: 10 additions & 0 deletions src/hidapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,16 @@ impl HidDeviceBackendBase for HidDevice {
}
}

fn get_input_report(&self, data: &mut [u8]) -> HidResult<usize> {
if data.is_empty() {
return Err(HidError::InvalidZeroSizeData);
}
let res = unsafe {
ffi::hid_get_input_report(self._hid_device, data.as_mut_ptr(), data.len() as size_t)
};
self.check_size(res)
}

fn set_blocking_mode(&self, blocking: bool) -> HidResult<()> {
let res = unsafe {
ffi::hid_set_nonblocking(self._hid_device, if blocking { 0i32 } else { 1i32 })
Expand Down
41 changes: 28 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,8 @@ trait HidDeviceBackendBase {
fn send_feature_report(&self, data: &[u8]) -> HidResult<()>;
fn get_feature_report(&self, buf: &mut [u8]) -> HidResult<usize>;
fn send_output_report(&self, data: &[u8]) -> HidResult<()>;
#[cfg(any(hidapi, target_os = "linux"))]
fn get_input_report(&self, data: &mut [u8]) -> HidResult<usize>;
fn set_blocking_mode(&self, blocking: bool) -> HidResult<()>;
fn get_device_info(&self) -> HidResult<DeviceInfo>;
fn get_manufacturer_string(&self) -> HidResult<Option<String>>;
Expand Down Expand Up @@ -595,23 +597,36 @@ impl HidDevice {
self.inner.get_feature_report(buf)
}

// Send a Output report to the device.
//
// Output reports are sent over the Control endpoint as a Set_Report
// transfer. The first byte of data[] must contain the Report ID.
// For devices which only support a single report, this must be set
// to 0x0. The remaining bytes contain the report data. Since the
// Report ID is mandatory, calls to hid_send_output_report() will
// always contain one more byte than the report contains. For example,
// if a hid report is 16 bytes long, 17 bytes must be passed to
// hid_send_output_report(): the Report ID (or 0x0, for devices
// which do not use numbered reports), followed by the report
// data (16 bytes). In this example, the length passed in
// would be 17.
/// Send a Output report to the device.
///
/// Output reports are sent over the Control endpoint as a Set_Report
/// transfer. The first byte of data[] must contain the Report ID.
/// For devices which only support a single report, this must be set
/// to 0x0. The remaining bytes contain the report data. Since the
/// Report ID is mandatory, calls to hid_send_output_report() will
/// always contain one more byte than the report contains. For example,
/// if a hid report is 16 bytes long, 17 bytes must be passed to
/// hid_send_output_report(): the Report ID (or 0x0, for devices
/// which do not use numbered reports), followed by the report
/// data (16 bytes). In this example, the length passed in
/// would be 17.
pub fn send_output_report(&self, data: &[u8]) -> HidResult<()> {
self.inner.send_output_report(data)
}

/// Get a input report from a HID device
///
/// Set the first byte of data to the report id of the report to be read.
/// Set the first byte to zero if your device does not use numbered reports.
/// After calling the function, the first byte will still contain the same report id.
///
/// If successful, returns the number of bytes read plus one for the report ID (which is still
/// in the first byte).
#[cfg(any(hidapi, target_os = "linux"))]
pub fn get_input_report(&self, data: &mut [u8]) -> HidResult<usize> {
self.inner.get_input_report(data)
}

/// Set the device handle to be in blocking or in non-blocking mode. In
/// non-blocking mode calls to `read()` will return immediately with an empty
/// slice if there is no data to be read. In blocking mode, `read()` will
Expand Down
12 changes: 11 additions & 1 deletion src/linux_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use nix::{

use super::{BusType, DeviceInfo, HidDeviceBackendBase, HidError, HidResult, WcharString};
use ioctl::{
hidraw_ioc_get_feature, hidraw_ioc_grdescsize, hidraw_ioc_set_feature, hidraw_ioc_set_output,
hidraw_ioc_get_feature, hidraw_ioc_get_input, hidraw_ioc_grdescsize, hidraw_ioc_set_feature,
hidraw_ioc_set_output,
};

// Bus values from linux/input.h
Expand Down Expand Up @@ -578,6 +579,15 @@ impl HidDeviceBackendBase for HidDevice {
Ok(())
}

fn get_input_report(&self, data: &mut [u8]) -> HidResult<usize> {
match unsafe { hidraw_ioc_get_input(self.fd.as_raw_fd(), data) } {
Ok(n) => Ok(n as usize),
Err(e) => Err(HidError::HidApiError {
message: format!("ioctl (GINPUT): {e}"),
}),
}
}

fn set_blocking_mode(&self, blocking: bool) -> HidResult<()> {
self.blocking.set(blocking);
Ok(())
Expand Down
2 changes: 2 additions & 0 deletions src/linux_native/ioctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const HIDRAW_IOC_GRDESCSIZE: u8 = 0x01;
const HIDRAW_SET_FEATURE: u8 = 0x06;
const HIDRAW_GET_FEATURE: u8 = 0x07;
const HIDRAW_SET_OUTPUT: u8 = 0x0b;
const HIDRAW_GET_INPUT: u8 = 0x0a;

ioctl_read!(
hidraw_ioc_grdescsize,
Expand All @@ -34,3 +35,4 @@ ioctl_write_buf!(
HIDRAW_SET_OUTPUT,
u8
);
ioctl_read_buf!(hidraw_ioc_get_input, HIDRAW_IOC_MAGIC, HIDRAW_GET_INPUT, u8);
Loading