Skip to main content

joydev_rs/
io_control.rs

1//! Safe wrappers for the underling ioctls
2//!
3//! This module is intended for making custom device abstractions. If you're using the provided [`Device`](struct.Device.html) abstraction you
4//! don't have to use this module however mixing is not prohibited and should work.
5
6use std::ffi::CStr;
7use std::mem::size_of;
8use std::os::unix::prelude::*;
9
10use input_event_codes::{ABS_CNT, BTN_MISC, KEY_CNT};
11use libc::read;
12use nix::errno::Errno;
13
14use crate::event_codes::{AbsoluteAxis, KeyOrButton};
15use crate::ioctl::{
16	jsiocgaxes, jsiocgaxmap, jsiocgbtnmap, jsiocgbuttons, jsiocgcorr, jsiocgname, jsiocgversion, jsiocsaxmap,
17	jsiocsbtnmap, jsiocscorr,
18};
19use crate::{Correction, Error, Event, Result};
20
21/// Retrieve number of axis present. Calls `JSIOCGAXES` ioctl.
22pub fn get_axis_count(fd: RawFd) -> Result<u8> {
23	let mut result = 0u8;
24	unsafe { jsiocgaxes(fd, &mut result) }?;
25	Ok(result)
26}
27
28/// Retrieve axes mapping. Calls `JSIOCGAXMAP` ioctl.
29pub fn get_axis_mapping(fd: RawFd) -> Result<Vec<AbsoluteAxis>> {
30	let mut result = vec![AbsoluteAxis::default(); ABS_CNT as usize];
31	unsafe { jsiocgaxmap(fd, result.as_mut_ptr() as *mut _) }?;
32	Ok(result)
33}
34
35/// Retrieve number of buttons present. Calls `JSIOCGBUTTONS` ioctl.
36pub fn get_button_count(fd: RawFd) -> Result<u8> {
37	let mut result = 0u8;
38	unsafe { jsiocgbuttons(fd, &mut result) }?;
39	Ok(result)
40}
41
42/// Retrieve buttons mapping. Calls `JSIOCGBTNMAP` ioctl.
43pub fn get_button_mapping(fd: RawFd) -> Result<Vec<KeyOrButton>> {
44	let mut result = vec![KeyOrButton::default(); (KEY_CNT - BTN_MISC) as usize];
45	unsafe { jsiocgbtnmap(fd, result.as_mut_ptr() as *mut _) }?;
46	Ok(result)
47}
48
49/// Retrieve axes correction values. Calls `JSIOCGCORR` ioctl.
50pub fn get_correction_values(fd: RawFd) -> Result<Vec<Correction>> {
51	let mut result = vec![Correction::default(); ABS_CNT as usize];
52	unsafe { jsiocgcorr(fd, result.as_mut_ptr() as *mut _) }?;
53	Ok(result)
54}
55
56/// Retrieve driver version. Calls `JSIOCGVERSION` ioctl.
57pub fn get_driver_version(fd: RawFd) -> Result<u32> {
58	let mut result = 0u32;
59	unsafe { jsiocgversion(fd, &mut result) }?;
60	Ok(result)
61}
62
63/// Read an event. Calls `read`.
64///
65/// If read fails with EAGAIN return [`Error::QueueEmpty`](../enum.Error.html#variant.QueueEmpty). In this context EAGAIN
66/// is not an error but rather an indicator that the device has no events left. This only applies if the device is
67/// opened in non-blocking mode for blocking mode EAGAIN shouldn't be ever returned.
68pub fn get_event(fd: RawFd) -> Result<Event> {
69	let mut result = Event::default();
70	if unsafe { read(fd, (&mut result as *mut _) as *mut _, size_of::<Event>()) } > 0 {
71		Ok(result)
72	} else {
73		let errno = Errno::last();
74		match errno {
75			Errno::EAGAIN => Err(Error::QueueEmpty),
76			_ => Err(Error::from(errno)),
77		}
78	}
79}
80
81// TODO: Maybe add support for joydev 0.x
82/*/// Read an event the legacy version. Calls `read`.
83pub fn get_event_legacy(fd: RawFd) -> Result<JS_DATA_TYPE> {
84	unimplemented!()
85}*/
86
87/// Retrieve device identifier. Calls `JSIOCGNAME` ioctl.
88pub fn get_identifier(fd: RawFd) -> Result<String> {
89	// TODO: Maybe change to vector?
90	let mut result = [0i8; 128];
91	unsafe { jsiocgname(fd, &mut result) }?;
92	Ok(unsafe { CStr::from_ptr(&result as *const _) }.to_str()?.to_owned())
93}
94
95/// Set axes mapping. Calls `JSIOCSAXMAP` ioctl.
96pub fn set_axis_mapping(fd: RawFd, mapping: &[AbsoluteAxis; ABS_CNT as usize]) -> Result<()> {
97	unsafe { jsiocsaxmap(fd, mapping as *const _ as *const _) }?;
98	Ok(())
99}
100
101/// Set buttons mapping. Calls `JSIOCSBTNMAP` ioctl.
102pub fn set_button_mapping(fd: RawFd, mapping: &[KeyOrButton; (KEY_CNT - BTN_MISC) as usize]) -> Result<()> {
103	unsafe { jsiocsbtnmap(fd, mapping as *const _ as *const _) }?;
104	Ok(())
105}
106
107/// Set axes correction values. Calls `JSIOCSCORR` ioctl.
108pub fn set_correction_values(fd: RawFd, correction: &[Correction; ABS_CNT as usize]) -> Result<()> {
109	unsafe { jsiocscorr(fd, correction as *const _ as *const _) }?;
110	Ok(())
111}