1use std::path::Path;
29
30pub struct BarcodeScanner {
32 device: evdev::Device,
34
35 buffer: String,
37}
38
39#[derive(Debug, Clone)]
41pub struct Error {
42 msg: String,
43}
44
45impl BarcodeScanner {
46 pub fn open(path: impl AsRef<Path>) -> Result<Self, Error> {
57 let path = path.as_ref();
58 let mut device = evdev::Device::open(path)
59 .map_err(|e| Error::new(format!("Failed to open input device {}: {e}", path.display())))?;
60 device.grab()
61 .map_err(|e| Error::new(format!("Failed to grab input device {}: {e}", path.display())))?;
62
63 Ok(Self {
64 device,
65 buffer: String::new(),
66 })
67 }
68
69 pub fn open_by_physical_path(physical_path: impl AsRef<str>) -> Result<Option<Self>, Error> {
83 let physical_path = physical_path.as_ref();
84 for (_path, mut device) in evdev::enumerate() {
85 let device_physical_path = match device.physical_path() {
87 Some(x) => x,
88 None => continue,
89 };
90 if device_physical_path == physical_path {
91 device.grab()
93 .map_err(|e| Error::new(format!("Failed to grab input device {physical_path}: {e}")))?;
94 return Ok(Some(Self {
95 device,
96 buffer: String::new(),
97 }))
98 }
99 }
100 Ok(None)
101 }
102
103 pub fn read(&mut self) -> Result<String, Error> {
117 loop {
118 let events = self.device.fetch_events()
119 .map_err(|e| Error::new(format!("Failed to fetch events from input device: {e}")))?;
120 for event in events {
121 if event.event_type() == evdev::EventType::KEY && event.value() == 1 {
123 let key_name = evdev::Key(event.code());
125
126 if let Some(c) = key_to_str(key_name) {
128 self.buffer.push(c);
129 }
130 }
131 }
132
133 if let Some(index) = self.buffer.find('\n') {
134 let mut barcode: String= self.buffer.drain(..index + 1).collect();
135 barcode.pop();
136 return Ok(barcode);
137 }
138 }
139 }
140
141 #[cfg(feature = "tokio")]
143 pub fn into_async_stream(mut self) -> tokio::sync::mpsc::UnboundedReceiver<Result<String, Error>> {
144 let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
145 tokio::task::spawn_blocking(move || {
146 loop {
147 if tx.send(self.read()).is_err() {
148 break;
149 }
150 }
151 });
152 rx
153 }
154}
155
156fn key_to_str(key: evdev::Key) -> Option<char> {
158 match key {
159 evdev::Key::KEY_A => Some('A'),
160 evdev::Key::KEY_B => Some('B'),
161 evdev::Key::KEY_C => Some('C'),
162 evdev::Key::KEY_D => Some('D'),
163 evdev::Key::KEY_E => Some('E'),
164 evdev::Key::KEY_F => Some('F'),
165 evdev::Key::KEY_G => Some('G'),
166 evdev::Key::KEY_H => Some('H'),
167 evdev::Key::KEY_I => Some('I'),
168 evdev::Key::KEY_J => Some('J'),
169 evdev::Key::KEY_K => Some('K'),
170 evdev::Key::KEY_L => Some('L'),
171 evdev::Key::KEY_M => Some('M'),
172 evdev::Key::KEY_N => Some('N'),
173 evdev::Key::KEY_O => Some('O'),
174 evdev::Key::KEY_P => Some('P'),
175 evdev::Key::KEY_Q => Some('Q'),
176 evdev::Key::KEY_R => Some('R'),
177 evdev::Key::KEY_S => Some('S'),
178 evdev::Key::KEY_T => Some('T'),
179 evdev::Key::KEY_U => Some('U'),
180 evdev::Key::KEY_V => Some('V'),
181 evdev::Key::KEY_W => Some('W'),
182 evdev::Key::KEY_X => Some('X'),
183 evdev::Key::KEY_Y => Some('Y'),
184 evdev::Key::KEY_Z => Some('Z'),
185 evdev::Key::KEY_0 => Some('0'),
186 evdev::Key::KEY_1 => Some('1'),
187 evdev::Key::KEY_2 => Some('2'),
188 evdev::Key::KEY_3 => Some('3'),
189 evdev::Key::KEY_4 => Some('4'),
190 evdev::Key::KEY_5 => Some('5'),
191 evdev::Key::KEY_6 => Some('6'),
192 evdev::Key::KEY_7 => Some('7'),
193 evdev::Key::KEY_8 => Some('8'),
194 evdev::Key::KEY_9 => Some('9'),
195 evdev::Key::KEY_ENTER => Some('\n'),
196 evdev::Key::KEY_KPENTER => Some('\n'),
197 _ => None,
198 }
199}
200
201impl Error {
202 fn new(msg: String) -> Self {
203 Self { msg }
204 }
205}
206
207impl std::fmt::Display for Error {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 f.write_str(&self.msg)
210 }
211}
212
213impl std::error::Error for Error { }