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, Key};
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<Key>,
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) -> &[Key; (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) -> Key {
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> {
74 Self::new(File::from_raw_fd(fd))
75 }
76
77 pub fn get_correction_values(&self) -> Result<Vec<Correction>> {
79 get_correction_values(self.as_raw_fd())
80 }
81
82 pub fn get_event(&self) -> Result<DeviceEvent> {
84 Ok(DeviceEvent::from_event(self, get_event(self.as_raw_fd())?))
85 }
86
87 pub fn identifier(&self) -> &str {
89 self.identifier.as_str()
90 }
91
92 pub fn new(file: File) -> Result<Self> {
99 let axis_count = get_axis_count(file.as_raw_fd())?;
100 let axis_mapping = get_axis_mapping(file.as_raw_fd())?;
101 let button_count = get_button_count(file.as_raw_fd())?;
102 let button_mapping = get_button_mapping(file.as_raw_fd())?;
103 let driver_version = get_driver_version(file.as_raw_fd())?;
104 let identifier = get_identifier(file.as_raw_fd()).unwrap_or_else(|_| "Unknown".to_owned());
105 Ok(Self {
106 axis_count,
107 axis_mapping,
108 button_count,
109 button_mapping,
110 driver_version,
111 file,
112 identifier,
113 })
114 }
115
116 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
122 Self::new(
123 OpenOptions::new()
124 .custom_flags(libc::O_NONBLOCK)
125 .read(true)
126 .open(path)?,
127 )
128 }
129
130 pub fn refresh_axis_mapping(&mut self) -> Result<()> {
132 self.axis_mapping = get_axis_mapping(self.as_raw_fd())?;
133 Ok(())
134 }
135
136 pub fn refresh_button_mapping(&mut self) -> Result<()> {
138 self.button_mapping = get_button_mapping(self.as_raw_fd())?;
139 Ok(())
140 }
141
142 pub fn refresh_mapping(&mut self) -> Result<()> {
144 self.refresh_axis_mapping()?;
145 self.refresh_button_mapping()
146 }
147
148 pub fn set_axis_mapping(&mut self, mapping: &[AbsoluteAxis; ABS_CNT as usize]) -> Result<()> {
150 set_axis_mapping(self.as_raw_fd(), mapping)?;
151 self.refresh_axis_mapping()
152 }
153
154 pub fn set_axis_mapping_at(&mut self, number: u8, axis: AbsoluteAxis) -> Result<()> {
156 let mut mapping = self.axis_mapping.clone();
157 mapping[number as usize] = axis;
158 self.set_axis_mapping(array_ref!(mapping, 0, ABS_CNT as usize))
159 }
160
161 pub fn set_button_mapping(&mut self, mapping: &[Key; (KEY_CNT - BTN_MISC) as usize]) -> Result<()> {
163 set_button_mapping(self.as_raw_fd(), mapping)?;
164 self.refresh_button_mapping()
165 }
166
167 pub fn set_button_mapping_at(&mut self, number: u8, button: Key) -> Result<()> {
169 let mut mapping = self.button_mapping.clone();
170 mapping[number as usize] = button;
171 self.set_button_mapping(array_ref!(mapping, 0, (KEY_CNT - BTN_MISC) as usize))
172 }
173
174 pub fn set_correction_values(&self, mapping: &[Correction; ABS_CNT as usize]) -> Result<()> {
176 set_correction_values(self.as_raw_fd(), mapping)
177 }
178}
179
180impl AsRawFd for Device {
181 fn as_raw_fd(&self) -> RawFd {
182 self.file.as_raw_fd()
183 }
184}
185
186impl IntoRawFd for Device {
187 fn into_raw_fd(self) -> RawFd {
188 self.file.into_raw_fd()
189 }
190}