1use std::fs::{File, OpenOptions};
2use std::os::unix::prelude::*;
3use std::path::Path;
4
5use arrayref::array_ref;
6use input_event_codes::{ABS_CNT, BTN_MISC, KEY_CNT};
7
8use crate::event_codes::{AbsoluteAxis, KeyOrButton};
9use crate::io_control::{
10 get_axis_count, get_axis_mapping, get_button_count, get_button_mapping, get_correction_values, get_driver_version,
11 get_event, get_identifier, set_axis_mapping, set_button_mapping, set_correction_values,
12};
13use crate::{Correction, DeviceEvent, Result};
14
15#[derive(Debug)]
17pub struct Device {
18 axis_count: u8,
19 axis_mapping: Vec<AbsoluteAxis>,
20 button_count: u8,
21 button_mapping: Vec<KeyOrButton>,
22 driver_version: u32,
23 file: File,
24 identifier: String,
25}
26
27impl Device {
28 pub const fn axis_count(&self) -> u8 {
30 self.axis_count
31 }
32
33 pub fn axis_mapping(&self) -> &[AbsoluteAxis; ABS_CNT as usize] {
35 array_ref!(self.axis_mapping, 0, ABS_CNT as usize)
36 }
37
38 pub fn axis_mapping_at(&self, number: u8) -> AbsoluteAxis {
40 self.axis_mapping[number as usize]
41 }
42
43 pub const fn button_count(&self) -> u8 {
45 self.button_count
46 }
47
48 pub fn button_mapping(&self) -> &[KeyOrButton; (KEY_CNT - BTN_MISC) as usize] {
50 array_ref!(self.button_mapping, 0, (KEY_CNT - BTN_MISC) as usize)
51 }
52
53 pub fn button_mapping_at(&self, number: u8) -> KeyOrButton {
55 self.button_mapping[number as usize]
56 }
57
58 pub fn driver_version(&self) -> u32 {
60 self.driver_version
61 }
62
63 pub unsafe fn from_raw_fd(fd: RawFd) -> Result<Self> {
70 Self::new(File::from_raw_fd(fd))
71 }
72
73 pub fn get_correction_values(&self) -> Result<Vec<Correction>> {
75 get_correction_values(self.as_raw_fd())
76 }
77
78 pub fn get_event(&self) -> Result<DeviceEvent> {
80 Ok(DeviceEvent::from_event(self, get_event(self.as_raw_fd())?))
81 }
82
83 pub fn identifier(&self) -> &str {
85 self.identifier.as_str()
86 }
87
88 pub fn new(file: File) -> Result<Self> {
95 let axis_count = get_axis_count(file.as_raw_fd())?;
96 let axis_mapping = get_axis_mapping(file.as_raw_fd())?;
97 let button_count = get_button_count(file.as_raw_fd())?;
98 let button_mapping = get_button_mapping(file.as_raw_fd())?;
99 let driver_version = get_driver_version(file.as_raw_fd())?;
100 let identifier = get_identifier(file.as_raw_fd()).unwrap_or_else(|_| "Unknown".to_owned());
101 Ok(Self {
102 axis_count,
103 axis_mapping,
104 button_count,
105 button_mapping,
106 driver_version,
107 file,
108 identifier,
109 })
110 }
111
112 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
118 Self::new(
119 OpenOptions::new()
120 .custom_flags(libc::O_NONBLOCK)
121 .read(true)
122 .open(path)?,
123 )
124 }
125
126 pub fn refresh_axis_mapping(&mut self) -> Result<()> {
128 self.axis_mapping = get_axis_mapping(self.as_raw_fd())?;
129 Ok(())
130 }
131
132 pub fn refresh_button_mapping(&mut self) -> Result<()> {
134 self.button_mapping = get_button_mapping(self.as_raw_fd())?;
135 Ok(())
136 }
137
138 pub fn refresh_mapping(&mut self) -> Result<()> {
140 self.refresh_axis_mapping()?;
141 self.refresh_button_mapping()
142 }
143
144 pub fn set_axis_mapping(&mut self, mapping: &[AbsoluteAxis; ABS_CNT as usize]) -> Result<()> {
146 set_axis_mapping(self.as_raw_fd(), mapping)?;
147 self.refresh_axis_mapping()
148 }
149
150 pub fn set_axis_mapping_at(&mut self, number: u8, axis: AbsoluteAxis) -> Result<()> {
152 let mut mapping = self.axis_mapping.clone();
153 mapping[number as usize] = axis;
154 self.set_axis_mapping(array_ref!(mapping, 0, ABS_CNT as usize))
155 }
156
157 pub fn set_button_mapping(&mut self, mapping: &[KeyOrButton; (KEY_CNT - BTN_MISC) as usize]) -> Result<()> {
159 set_button_mapping(self.as_raw_fd(), mapping)?;
160 self.refresh_button_mapping()
161 }
162
163 pub fn set_button_mapping_at(&mut self, number: u8, button: KeyOrButton) -> Result<()> {
165 let mut mapping = self.button_mapping.clone();
166 mapping[number as usize] = button;
167 self.set_button_mapping(array_ref!(mapping, 0, (KEY_CNT - BTN_MISC) as usize))
168 }
169
170 pub fn set_correction_values(&self, mapping: &[Correction; ABS_CNT as usize]) -> Result<()> {
172 set_correction_values(self.as_raw_fd(), mapping)
173 }
174}
175
176impl AsRawFd for Device {
177 fn as_raw_fd(&self) -> RawFd {
178 self.file.as_raw_fd()
179 }
180}
181
182impl IntoRawFd for Device {
183 fn into_raw_fd(self) -> RawFd {
184 self.file.into_raw_fd()
185 }
186}