use std::path::Path;
pub struct BarcodeScanner {
device: evdev::Device,
buffer: String,
}
#[derive(Debug, Clone)]
pub struct Error {
msg: String,
}
impl BarcodeScanner {
pub fn open(path: impl AsRef<Path>) -> Result<Self, Error> {
let path = path.as_ref();
let mut device = evdev::Device::open(path)
.map_err(|e| Error::new(format!("Failed to open input device {}: {e}", path.display())))?;
device.grab()
.map_err(|e| Error::new(format!("Failed to grab input device {}: {e}", path.display())))?;
Ok(Self {
device,
buffer: String::new(),
})
}
pub fn open_by_physical_path(physical_path: impl AsRef<str>) -> Result<Option<Self>, Error> {
let physical_path = physical_path.as_ref();
for (_path, mut device) in evdev::enumerate() {
let device_physical_path = match device.physical_path() {
Some(x) => x,
None => continue,
};
if device_physical_path == physical_path {
device.grab()
.map_err(|e| Error::new(format!("Failed to grab input device {physical_path}: {e}")))?;
return Ok(Some(Self {
device,
buffer: String::new(),
}))
}
}
Ok(None)
}
pub fn read(&mut self) -> Result<String, Error> {
loop {
let events = self.device.fetch_events()
.map_err(|e| Error::new(format!("Failed to fetch events from input device: {e}")))?;
for event in events {
if event.event_type() == evdev::EventType::KEY && event.value() == 1 {
let key_name = evdev::Key(event.code());
if let Some(c) = key_to_str(key_name) {
self.buffer.push(c);
}
}
}
if let Some(index) = self.buffer.find('\n') {
let mut barcode: String= self.buffer.drain(..index + 1).collect();
barcode.pop();
return Ok(barcode);
}
}
}
#[cfg(feature = "tokio")]
pub fn into_async_stream(mut self) -> tokio::sync::mpsc::UnboundedReceiver<Result<String, Error>> {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
tokio::task::spawn_blocking(move || {
loop {
if tx.send(self.read()).is_err() {
break;
}
}
});
rx
}
}
fn key_to_str(key: evdev::Key) -> Option<char> {
match key {
evdev::Key::KEY_A => Some('A'),
evdev::Key::KEY_B => Some('B'),
evdev::Key::KEY_C => Some('C'),
evdev::Key::KEY_D => Some('D'),
evdev::Key::KEY_E => Some('E'),
evdev::Key::KEY_F => Some('F'),
evdev::Key::KEY_G => Some('G'),
evdev::Key::KEY_H => Some('H'),
evdev::Key::KEY_I => Some('I'),
evdev::Key::KEY_J => Some('J'),
evdev::Key::KEY_K => Some('K'),
evdev::Key::KEY_L => Some('L'),
evdev::Key::KEY_M => Some('M'),
evdev::Key::KEY_N => Some('N'),
evdev::Key::KEY_O => Some('O'),
evdev::Key::KEY_P => Some('P'),
evdev::Key::KEY_Q => Some('Q'),
evdev::Key::KEY_R => Some('R'),
evdev::Key::KEY_S => Some('S'),
evdev::Key::KEY_T => Some('T'),
evdev::Key::KEY_U => Some('U'),
evdev::Key::KEY_V => Some('V'),
evdev::Key::KEY_W => Some('W'),
evdev::Key::KEY_X => Some('X'),
evdev::Key::KEY_Y => Some('Y'),
evdev::Key::KEY_Z => Some('Z'),
evdev::Key::KEY_0 => Some('0'),
evdev::Key::KEY_1 => Some('1'),
evdev::Key::KEY_2 => Some('2'),
evdev::Key::KEY_3 => Some('3'),
evdev::Key::KEY_4 => Some('4'),
evdev::Key::KEY_5 => Some('5'),
evdev::Key::KEY_6 => Some('6'),
evdev::Key::KEY_7 => Some('7'),
evdev::Key::KEY_8 => Some('8'),
evdev::Key::KEY_9 => Some('9'),
evdev::Key::KEY_ENTER => Some('\n'),
evdev::Key::KEY_KPENTER => Some('\n'),
_ => None,
}
}
impl Error {
fn new(msg: String) -> Self {
Self { msg }
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.msg)
}
}
impl std::error::Error for Error { }