Read /dev/input for touchscreen #3
@@ -51,7 +51,7 @@ Usage for most of the included windows and window-likes are included in `docs/wi
|
|||||||
|
|
||||||
More or the less the same, but includes with an onscreen keyboard for touchscreens.
|
More or the less the same, but includes with an onscreen keyboard for touchscreens.
|
||||||
|
|
||||||
`evtest` needs to be installed. Currently, the input device is assumed to be at `/dev/input/by-path/first-touchscreen`, but this is easily editable (see `src/bin/wm.rs`). So, for touchscreen support, the user running `ming` needs to have read permissions for that `dev/input/` file.
|
Currently, the touchscreen input device is assumed to be at `/dev/input/by-path/first-touchscreen`, but this is easily editable (see `src/bin/wm.rs`). For touchscreen support, the user running `ming` needs to have read permissions for that `/dev/input/` file.
|
||||||
|
|
||||||
```
|
```
|
||||||
ming touch
|
ming touch
|
||||||
|
|||||||
@@ -75,4 +75,4 @@ PS:
|
|||||||
> ### Update
|
> ### Update
|
||||||
> Ignoring the audio player dependencies and `bmp-rust`, the only dependencies not written by me are now `libc` for libc Rust bindings and `bitcoin-hashes` for SHA-512 password hashing (yes, I know SHA-512 is not the greatest password hash function, but it is lightweight, relatively).
|
> Ignoring the audio player dependencies and `bmp-rust`, the only dependencies not written by me are now `libc` for libc Rust bindings and `bitcoin-hashes` for SHA-512 password hashing (yes, I know SHA-512 is not the greatest password hash function, but it is lightweight, relatively).
|
||||||
>
|
>
|
||||||
> Prior dependencies like `termion`, `linux_framebuffer`, `pty-process`, have been removed and replaced by a me-written version in the `linux` crate. As of v1.1, the dependency removing goal has been achieved. Huzzah!
|
> Prior dependencies like `termion`, `linux_framebuffer`, `pty-process`, `evtest` have been removed and replaced by a me-written version in the `linux` crate. As of v1.1, the dependency removing goal has been achieved. Huzzah!
|
||||||
|
|||||||
108
linux/src/input.rs
Normal file
108
linux/src/input.rs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
use std::os::fd::RawFd;
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
use libc::{ open, close, read, poll, pollfd, input_event, timeval, __u16, __s32, c_void };
|
||||||
|
|
||||||
|
//https://stackoverflow.com/questions/15949163/read-from-dev-input#15949311
|
||||||
|
//https://www.man7.org/linux/man-pages/man2/poll.2.html
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[repr(u16)]
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum EventType {
|
||||||
|
EV_SYN = 0, //event sep
|
||||||
|
EV_KEY,
|
||||||
|
EV_REL,
|
||||||
|
EV_ABS,
|
||||||
|
//nothing below will probably ever be relevant to ming-wm
|
||||||
|
EV_MSC, //misc
|
||||||
|
EV_SW, //switch/toggle
|
||||||
|
EV_LED,
|
||||||
|
EV_SND,
|
||||||
|
EV_REP,
|
||||||
|
EV_FF,
|
||||||
|
EV_PWR,
|
||||||
|
EV_FF_STATUS,
|
||||||
|
Unknown(__u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<__u16> for EventType {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: __u16) -> Result<Self, Self::Error> {
|
||||||
|
//if the list is any longer should probably somehow make this a macro
|
||||||
|
let values = [Self::EV_SYN, Self::EV_KEY, Self::EV_REL, Self::EV_ABS, Self::EV_MSC, Self::EV_SW, Self::EV_LED, Self::EV_SND, Self::EV_REP, Self::EV_FF, Self::EV_PWR, Self::EV_FF_STATUS];
|
||||||
|
let value = value as usize;
|
||||||
|
if value >= values.len() {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(values[value])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//we do not care about time. no one cares about time (probably)
|
||||||
|
pub struct InputEvent {
|
||||||
|
pub type_: EventType,
|
||||||
|
pub code: __u16, //depends on EventType
|
||||||
|
pub value: __s32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Input(RawFd);
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
pub fn new(input_name: &str) -> Result<Self, ()> {
|
||||||
|
let input_name = CString::new(input_name).unwrap();
|
||||||
|
let fd = unsafe { open(input_name.as_ptr(), libc::O_RDONLY | libc::O_NONBLOCK) };
|
||||||
|
if fd == -1 {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
Ok(Self(fd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Input {
|
||||||
|
type Item = InputEvent;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
//wait until there is something available
|
||||||
|
let mut fds = vec![pollfd {
|
||||||
|
fd: self.0,
|
||||||
|
events: libc::POLLIN, //return when "there is data to read"
|
||||||
|
revents: 0,
|
||||||
|
}];
|
||||||
|
let poll_result = unsafe { poll(fds.as_mut_ptr(), 1, -1) }; //neg num means no timeout
|
||||||
|
if poll_result == -1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
//now read the event
|
||||||
|
let ie_size = size_of::<input_event>();
|
||||||
|
let mut ie = input_event {
|
||||||
|
time: timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
},
|
||||||
|
type_: 0,
|
||||||
|
code: 0,
|
||||||
|
value: 0,
|
||||||
|
};
|
||||||
|
let read_result = unsafe { read(self.0, &mut ie as *mut _ as *mut c_void, ie_size) };
|
||||||
|
if read_result == -1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let type_ = ie.type_.try_into().unwrap_or(EventType::Unknown(ie.type_));
|
||||||
|
Some(Self::Item {
|
||||||
|
type_,
|
||||||
|
code: ie.code,
|
||||||
|
value: ie.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Input {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { close(self.0) };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ pub mod fb;
|
|||||||
pub mod raw;
|
pub mod raw;
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
pub mod pty;
|
pub mod pty;
|
||||||
|
pub mod input;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::process::{ Command, Stdio };
|
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::io::{ stdin, stdout, BufReader, BufRead, Write };
|
use std::io::{ stdin, stdout, Write };
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use linux::fb::Framebuffer;
|
use linux::fb::Framebuffer;
|
||||||
use linux::raw::RawStdout;
|
use linux::raw::RawStdout;
|
||||||
use linux::keys::{ RawStdin, Key };
|
use linux::keys::{ RawStdin, Key };
|
||||||
|
use linux::input::{ Input, EventType };
|
||||||
use wm::framebuffer::{ FramebufferWriter, FramebufferInfo };
|
use wm::framebuffer::{ FramebufferWriter, FramebufferInfo };
|
||||||
use wm::window_manager::WindowManager;
|
use wm::window_manager::WindowManager;
|
||||||
|
|
||||||
@@ -112,35 +112,35 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
|||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
//spawn evtest, parse it for touch coords
|
//spawn evtest, parse it for touch coords
|
||||||
if touch {
|
if touch {
|
||||||
let mut evtest = Command::new("evtest").arg("/dev/input/by-path/first-touchscreen").stdout(Stdio::piped()).spawn().unwrap();
|
let mut events = Input::new("/dev/input/by-path/first-touchscreen").unwrap(); //panics in threads don't matter in this case
|
||||||
let reader = BufReader::new(evtest.stdout.as_mut().unwrap());
|
|
||||||
let mut x: Option<usize> = None;
|
let mut x: Option<usize> = None;
|
||||||
let mut y: Option<usize> = None;
|
let mut y: Option<usize> = None;
|
||||||
for line in reader.lines() {
|
loop {
|
||||||
let line = line.unwrap();
|
let event = events.next();
|
||||||
println!(" "); //without any stdout, on my phone, for some reason the framebuffer doesn't get redrawn to the screen
|
if let Some(event) = event {
|
||||||
if line.contains("ABS_X), value ") || line.contains("ABS_Y), value ") {
|
//ABS_X = 0, ABS_Y = 1
|
||||||
let value: Vec<_> = line.split("), value ").collect();
|
if event.type_ == EventType::EV_ABS && (event.code == 0 || event.code == 1) {
|
||||||
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
if event.code == 0 {
|
||||||
if line.contains("ABS_X") {
|
x = Some(event.value as usize); //event.value is u16 so this should be fine. unless usize is u8, lmao
|
||||||
x = Some(value);
|
|
||||||
} else {
|
|
||||||
y = Some(value);
|
|
||||||
}
|
|
||||||
if x.is_some() && y.is_some() {
|
|
||||||
let (x2, y2) = if rotate {
|
|
||||||
(dimensions[0] - y.unwrap(), x.unwrap())
|
|
||||||
} else {
|
} else {
|
||||||
(x.unwrap(), y.unwrap())
|
y = Some(event.value as usize);
|
||||||
};
|
}
|
||||||
//top right, clear
|
if x.is_some() && y.is_some() {
|
||||||
//useful sometimes, I think.
|
let (x2, y2) = if rotate {
|
||||||
if x2 > dimensions[0] - 100 && y2 < 100 {
|
(dimensions[0] - y.unwrap(), x.unwrap())
|
||||||
tx1.send(ThreadMessage::Clear).unwrap();
|
} else {
|
||||||
|
(x.unwrap(), y.unwrap())
|
||||||
|
};
|
||||||
|
//top right, clear
|
||||||
|
//useful sometimes, I think.
|
||||||
|
if x2 > dimensions[0] - 100 && y2 < 100 {
|
||||||
|
tx1.send(ThreadMessage::Clear).unwrap();
|
||||||
|
}
|
||||||
|
println!(" "); //without any stdout, on my phone, for some reason the framebuffer doesn't get redrawn to the screen
|
||||||
|
tx1.send(ThreadMessage::Touch(x2, y2)).unwrap();
|
||||||
|
x = None;
|
||||||
|
y = None;
|
||||||
}
|
}
|
||||||
tx1.send(ThreadMessage::Touch(x2, y2)).unwrap();
|
|
||||||
x = None;
|
|
||||||
y = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(1));
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
|||||||
Reference in New Issue
Block a user