refactor fakeinput + invert main thread function
- fakeinput is now just a series of free functions that access the global static, which makes more sense than having some arbitrary zero-sized-struct with associated methods on it. - instead of having the active notification run in its own thread, it now runs on the main thread, and the controller runs in a separate thread. This results in midly nicer code, at least IMO. Also, I've had to disable optimizations on the evdev_rs crate, as it seems to be segfaulting on release builds. Very spooky, but it's not something I'm super interested in debugging right now, so I'll just work around it. It's not like I need the _blazing fast performance_ from a Rust wrapper around a C library anyways...
This commit is contained in:
10
Cargo.toml
10
Cargo.toml
@@ -13,3 +13,13 @@ lazy_static = "1.4"
|
||||
notify-rust = "4"
|
||||
parking_lot = "0.11.0"
|
||||
signal-hook = "0.1.16"
|
||||
|
||||
# HACK: Using >1 virtual uinput devices will segfault in release builds.
|
||||
#
|
||||
# While spooky, this isn't a show-stopper for us Pragmatic Programmers™, as we
|
||||
# can simply disable optimizations for `evdev-rs` and have things work Okay™.
|
||||
#
|
||||
# That said, I would like to find some time to narrow down why this is happening
|
||||
# and fix it. Maybe later...
|
||||
[profile.release.package.evdev-rs]
|
||||
opt-level = 0
|
||||
|
||||
@@ -33,8 +33,10 @@ It would be cool to create some sort of GUI overlay (similar to the Windows one)
|
||||
- Operating Modes
|
||||
- [x] Volume Controls
|
||||
- [x] Media Controls
|
||||
- [x] D-Pad (emulated left, right, and space key)
|
||||
- [x] Scrolling / Zooming
|
||||
- [x] Scrolling - using a virtual mouse-wheel
|
||||
- [x] Scrolling - using a virtual touchpad (for [smoother scrolling](https://who-t.blogspot.com/2020/04/high-resolution-wheel-scrolling-in.html))
|
||||
- [x] Zooming
|
||||
- [x] [Paddle](https://www.google.com/search?q=arkanoid+paddle) (emulated left, right, and space key)
|
||||
- [ ] \(meta\) custom modes specified via config file(s)
|
||||
- [x] Dynamically switch between operating modes
|
||||
- [x] Using some-sort of on-device mechanism (e.g: long-press)
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use crate::controller::{ControlMode, ControlModeMeta};
|
||||
use crate::dial_device::DialHaptics;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::fake_input::FakeInput;
|
||||
use crate::fake_input;
|
||||
|
||||
use evdev_rs::enums::EV_KEY;
|
||||
|
||||
pub struct Media {
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
pub struct Media {}
|
||||
|
||||
impl Media {
|
||||
pub fn new() -> Media {
|
||||
Media {
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
Media {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,23 +31,17 @@ impl ControlMode for Media {
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self, _: &DialHaptics) -> Result<()> {
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_PLAYPAUSE])
|
||||
.map_err(Error::Evdev)?;
|
||||
fake_input::key_click(&[EV_KEY::KEY_PLAYPAUSE]).map_err(Error::Evdev)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_dial(&mut self, _: &DialHaptics, delta: i32) -> Result<()> {
|
||||
if delta > 0 {
|
||||
eprintln!("next song");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_NEXTSONG])
|
||||
.map_err(Error::Evdev)?;
|
||||
fake_input::key_click(&[EV_KEY::KEY_NEXTSONG]).map_err(Error::Evdev)?;
|
||||
} else {
|
||||
eprintln!("last song");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_PREVIOUSSONG])
|
||||
.map_err(Error::Evdev)?;
|
||||
fake_input::key_click(&[EV_KEY::KEY_PREVIOUSSONG]).map_err(Error::Evdev)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::time::Duration;
|
||||
use crate::controller::{ControlMode, ControlModeMeta};
|
||||
use crate::dial_device::DialHaptics;
|
||||
use crate::error::Result;
|
||||
use crate::fake_input::FakeInput;
|
||||
use crate::fake_input;
|
||||
|
||||
use evdev_rs::enums::EV_KEY;
|
||||
|
||||
@@ -23,7 +23,6 @@ enum Msg {
|
||||
|
||||
struct Worker {
|
||||
msg: mpsc::Receiver<Msg>,
|
||||
fake_input: FakeInput,
|
||||
|
||||
timeout: u64,
|
||||
falloff: i32,
|
||||
@@ -39,7 +38,6 @@ impl Worker {
|
||||
pub fn new(msg: mpsc::Receiver<Msg>) -> Worker {
|
||||
Worker {
|
||||
msg,
|
||||
fake_input: FakeInput::new(),
|
||||
|
||||
// tweak these for "feel"
|
||||
timeout: 5,
|
||||
@@ -70,13 +68,16 @@ impl Worker {
|
||||
Ok(Msg::Enabled(enabled)) => {
|
||||
self.enabled = enabled;
|
||||
if !enabled {
|
||||
self.fake_input
|
||||
.key_release(&[EV_KEY::KEY_SPACE, EV_KEY::KEY_LEFT, EV_KEY::KEY_RIGHT])
|
||||
fake_input::key_release(&[
|
||||
EV_KEY::KEY_SPACE,
|
||||
EV_KEY::KEY_LEFT,
|
||||
EV_KEY::KEY_RIGHT,
|
||||
])
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
Ok(Msg::ButtonDown) => self.fake_input.key_press(&[EV_KEY::KEY_SPACE]).unwrap(),
|
||||
Ok(Msg::ButtonUp) => self.fake_input.key_release(&[EV_KEY::KEY_SPACE]).unwrap(),
|
||||
Ok(Msg::ButtonDown) => fake_input::key_press(&[EV_KEY::KEY_SPACE]).unwrap(),
|
||||
Ok(Msg::ButtonUp) => fake_input::key_release(&[EV_KEY::KEY_SPACE]).unwrap(),
|
||||
Ok(Msg::Delta(delta)) => {
|
||||
// abrupt direction change!
|
||||
if (delta < 0) != (self.last_delta < 0) {
|
||||
@@ -102,16 +103,14 @@ impl Worker {
|
||||
}
|
||||
|
||||
if self.velocity.abs() < self.deadzone {
|
||||
self.fake_input
|
||||
.key_release(&[EV_KEY::KEY_LEFT, EV_KEY::KEY_RIGHT])
|
||||
.unwrap();
|
||||
fake_input::key_release(&[EV_KEY::KEY_LEFT, EV_KEY::KEY_RIGHT]).unwrap();
|
||||
continue;
|
||||
}
|
||||
|
||||
match self.velocity.cmp(&0) {
|
||||
Ordering::Equal => {}
|
||||
Ordering::Less => self.fake_input.key_press(&[EV_KEY::KEY_LEFT]).unwrap(),
|
||||
Ordering::Greater => self.fake_input.key_press(&[EV_KEY::KEY_RIGHT]).unwrap(),
|
||||
Ordering::Less => fake_input::key_press(&[EV_KEY::KEY_LEFT]).unwrap(),
|
||||
Ordering::Greater => fake_input::key_press(&[EV_KEY::KEY_RIGHT]).unwrap(),
|
||||
}
|
||||
|
||||
// eprintln!("{:?}", self.velocity);
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
use crate::controller::{ControlMode, ControlModeMeta};
|
||||
use crate::dial_device::DialHaptics;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::fake_input::{FakeInput, ScrollStep};
|
||||
use crate::fake_input::{self, ScrollStep};
|
||||
|
||||
pub struct Scroll {
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
pub struct Scroll {}
|
||||
|
||||
impl Scroll {
|
||||
pub fn new() -> Scroll {
|
||||
Scroll {
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
Scroll {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,14 +35,10 @@ impl ControlMode for Scroll {
|
||||
fn on_dial(&mut self, _: &DialHaptics, delta: i32) -> Result<()> {
|
||||
if delta > 0 {
|
||||
eprintln!("scroll down");
|
||||
self.fake_input
|
||||
.scroll_step(ScrollStep::Down)
|
||||
.map_err(Error::Evdev)?;
|
||||
fake_input::scroll_step(ScrollStep::Down).map_err(Error::Evdev)?;
|
||||
} else {
|
||||
eprintln!("scroll up");
|
||||
self.fake_input
|
||||
.scroll_step(ScrollStep::Up)
|
||||
.map_err(Error::Evdev)?;
|
||||
fake_input::scroll_step(ScrollStep::Up).map_err(Error::Evdev)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
use crate::controller::{ControlMode, ControlModeMeta};
|
||||
use crate::dial_device::DialHaptics;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::fake_input::FakeInput;
|
||||
use crate::fake_input;
|
||||
|
||||
pub struct ScrollMT {
|
||||
acc_delta: i32,
|
||||
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
|
||||
impl ScrollMT {
|
||||
pub fn new() -> ScrollMT {
|
||||
ScrollMT {
|
||||
acc_delta: 0,
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
ScrollMT { acc_delta: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,33 +25,31 @@ impl ControlMode for ScrollMT {
|
||||
haptics.set_mode(false, Some(3600))?;
|
||||
self.acc_delta = 0;
|
||||
|
||||
self.fake_input.scroll_mt_start().map_err(Error::Evdev)?;
|
||||
fake_input::scroll_mt_start().map_err(Error::Evdev)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_end(&mut self, _haptics: &DialHaptics) -> Result<()> {
|
||||
self.fake_input.scroll_mt_end().map_err(Error::Evdev)?;
|
||||
fake_input::scroll_mt_end().map_err(Error::Evdev)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// HACK: the button will reset the scroll event, which sometimes helps
|
||||
|
||||
fn on_btn_press(&mut self, _: &DialHaptics) -> Result<()> {
|
||||
self.fake_input.scroll_mt_end().map_err(Error::Evdev)?;
|
||||
fake_input::scroll_mt_end().map_err(Error::Evdev)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self, _haptics: &DialHaptics) -> Result<()> {
|
||||
self.fake_input.scroll_mt_start().map_err(Error::Evdev)?;
|
||||
fake_input::scroll_mt_start().map_err(Error::Evdev)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_dial(&mut self, _: &DialHaptics, delta: i32) -> Result<()> {
|
||||
self.acc_delta += delta;
|
||||
self.fake_input
|
||||
.scroll_mt_step(self.acc_delta)
|
||||
.map_err(Error::Evdev)?;
|
||||
fake_input::scroll_mt_step(self.acc_delta).map_err(Error::Evdev)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use crate::controller::{ControlMode, ControlModeMeta};
|
||||
use crate::dial_device::DialHaptics;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::fake_input::FakeInput;
|
||||
use crate::fake_input;
|
||||
|
||||
use evdev_rs::enums::EV_KEY;
|
||||
|
||||
pub struct Volume {
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
pub struct Volume {}
|
||||
|
||||
impl Volume {
|
||||
pub fn new() -> Volume {
|
||||
Volume {
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
Volume {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,23 +33,19 @@ impl ControlMode for Volume {
|
||||
|
||||
fn on_btn_release(&mut self, _: &DialHaptics) -> Result<()> {
|
||||
eprintln!("play/pause");
|
||||
// self.fake_input.mute()?
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_PLAYPAUSE])
|
||||
.map_err(Error::Evdev)?;
|
||||
// fake_input::mute()?
|
||||
fake_input::key_click(&[EV_KEY::KEY_PLAYPAUSE]).map_err(Error::Evdev)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_dial(&mut self, _: &DialHaptics, delta: i32) -> Result<()> {
|
||||
if delta > 0 {
|
||||
eprintln!("volume up");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTSHIFT, EV_KEY::KEY_VOLUMEUP])
|
||||
fake_input::key_click(&[EV_KEY::KEY_LEFTSHIFT, EV_KEY::KEY_VOLUMEUP])
|
||||
.map_err(Error::Evdev)?;
|
||||
} else {
|
||||
eprintln!("volume down");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTSHIFT, EV_KEY::KEY_VOLUMEDOWN])
|
||||
fake_input::key_click(&[EV_KEY::KEY_LEFTSHIFT, EV_KEY::KEY_VOLUMEDOWN])
|
||||
.map_err(Error::Evdev)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use crate::controller::{ControlMode, ControlModeMeta};
|
||||
use crate::dial_device::DialHaptics;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::fake_input::FakeInput;
|
||||
use crate::fake_input;
|
||||
|
||||
use evdev_rs::enums::EV_KEY;
|
||||
|
||||
pub struct Zoom {
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
pub struct Zoom {}
|
||||
|
||||
impl Zoom {
|
||||
pub fn new() -> Zoom {
|
||||
Zoom {
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
Zoom {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +37,11 @@ impl ControlMode for Zoom {
|
||||
fn on_dial(&mut self, _: &DialHaptics, delta: i32) -> Result<()> {
|
||||
if delta > 0 {
|
||||
eprintln!("zoom in");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_EQUAL])
|
||||
fake_input::key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_EQUAL])
|
||||
.map_err(Error::Evdev)?;
|
||||
} else {
|
||||
eprintln!("zoom out");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_MINUS])
|
||||
fake_input::key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_MINUS])
|
||||
.map_err(Error::Evdev)?;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ pub enum Error {
|
||||
UnexpectedEvt(InputEvent),
|
||||
Evdev(io::Error),
|
||||
Notif(notify_rust::error::Error),
|
||||
TermSig,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
@@ -30,6 +31,7 @@ impl fmt::Display for Error {
|
||||
Error::UnexpectedEvt(evt) => write!(f, "Unexpected event: {:?}", evt),
|
||||
Error::Evdev(e) => write!(f, "Evdev error: {}", e),
|
||||
Error::Notif(e) => write!(f, "Notification error: {}", e),
|
||||
Error::TermSig => write!(f, "Received termination signal (either SIGTERM or SIGINT)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,18 @@ use evdev_rs::{Device, InputEvent, TimeVal, UInputDevice};
|
||||
use parking_lot::ReentrantMutex;
|
||||
|
||||
// this should be a fairly high number, as the axis is from 0..(MT_BASELINE*2)
|
||||
const MT_BASELINE: i32 = std::i32::MAX / 4;
|
||||
const MT_BASELINE: i32 = std::i32::MAX / 8;
|
||||
// higher = more sensitive
|
||||
const MT_SENSITIVITY: i32 = 64;
|
||||
|
||||
pub struct FakeInputs {
|
||||
keyboard: ReentrantMutex<UInputDevice>,
|
||||
touchpad: ReentrantMutex<UInputDevice>,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref FAKE_KEYBOARD: ReentrantMutex<UInputDevice> = {
|
||||
(|| -> io::Result<_> {
|
||||
pub static ref FAKE_INPUTS: FakeInputs = {
|
||||
let keyboard = (|| -> io::Result<_> {
|
||||
let device = Device::new().unwrap();
|
||||
device.set_name("Surface Dial Virtual Keyboard/Mouse");
|
||||
|
||||
@@ -48,11 +53,9 @@ lazy_static::lazy_static! {
|
||||
}
|
||||
|
||||
Ok(ReentrantMutex::new(UInputDevice::create_from_device(&device)?))
|
||||
})().expect("failed to install virtual mouse/keyboard device")
|
||||
};
|
||||
})().expect("failed to install virtual mouse/keyboard device");
|
||||
|
||||
static ref FAKE_TOUCHPAD: ReentrantMutex<UInputDevice> = {
|
||||
(|| -> io::Result<_> {
|
||||
let touchpad = (|| -> io::Result<_> {
|
||||
let device = Device::new().unwrap();
|
||||
device.set_name("Surface Dial Virtual Touchpad");
|
||||
|
||||
@@ -115,14 +118,15 @@ lazy_static::lazy_static! {
|
||||
}
|
||||
|
||||
Ok(ReentrantMutex::new(UInputDevice::create_from_device(&device)?))
|
||||
})().expect("failed to install virtual touchpad device")
|
||||
})().expect("failed to install virtual touchpad device");
|
||||
|
||||
FakeInputs {
|
||||
keyboard,
|
||||
touchpad
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct FakeInput {}
|
||||
|
||||
macro_rules! input_event {
|
||||
($type:ident, $code:ident, $value:expr) => {
|
||||
InputEvent {
|
||||
@@ -134,29 +138,18 @@ macro_rules! input_event {
|
||||
};
|
||||
}
|
||||
|
||||
impl Default for FakeInput {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
fn kbd_syn_report() -> io::Result<()> {
|
||||
(FAKE_INPUTS.keyboard.lock()).write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
||||
}
|
||||
|
||||
impl FakeInput {
|
||||
pub fn new() -> FakeInput {
|
||||
FakeInput {}
|
||||
}
|
||||
|
||||
fn kbd_syn_report(&self) -> io::Result<()> {
|
||||
(FAKE_KEYBOARD.lock()).write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
||||
}
|
||||
|
||||
pub fn key_click(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
||||
self.key_press(keys)?;
|
||||
self.key_release(keys)?;
|
||||
pub fn key_click(keys: &[EV_KEY]) -> io::Result<()> {
|
||||
key_press(keys)?;
|
||||
key_release(keys)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_press(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
||||
let keyboard = FAKE_KEYBOARD.lock();
|
||||
pub fn key_press(keys: &[EV_KEY]) -> io::Result<()> {
|
||||
let keyboard = FAKE_INPUTS.keyboard.lock();
|
||||
|
||||
for key in keys {
|
||||
keyboard.write_event(&InputEvent {
|
||||
@@ -166,12 +159,12 @@ impl FakeInput {
|
||||
value: 1,
|
||||
})?;
|
||||
}
|
||||
self.kbd_syn_report()?;
|
||||
kbd_syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_release(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
||||
let keyboard = FAKE_KEYBOARD.lock();
|
||||
pub fn key_release(keys: &[EV_KEY]) -> io::Result<()> {
|
||||
let keyboard = FAKE_INPUTS.keyboard.lock();
|
||||
|
||||
for key in keys.iter().clone() {
|
||||
keyboard.write_event(&InputEvent {
|
||||
@@ -181,12 +174,12 @@ impl FakeInput {
|
||||
value: 0,
|
||||
})?;
|
||||
}
|
||||
self.kbd_syn_report()?;
|
||||
kbd_syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_step(&self, dir: ScrollStep) -> io::Result<()> {
|
||||
let keyboard = FAKE_KEYBOARD.lock();
|
||||
pub fn scroll_step(dir: ScrollStep) -> io::Result<()> {
|
||||
let keyboard = FAKE_INPUTS.keyboard.lock();
|
||||
|
||||
// copied from my razer blackwidow chroma mouse
|
||||
keyboard.write_event(&InputEvent {
|
||||
@@ -207,16 +200,16 @@ impl FakeInput {
|
||||
ScrollStep::Up => 120,
|
||||
},
|
||||
})?;
|
||||
self.kbd_syn_report()?;
|
||||
kbd_syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn touch_syn_report(&self) -> io::Result<()> {
|
||||
(FAKE_TOUCHPAD.lock()).write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
||||
}
|
||||
fn touch_syn_report() -> io::Result<()> {
|
||||
(FAKE_INPUTS.touchpad.lock()).write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
||||
}
|
||||
|
||||
pub fn scroll_mt_start(&self) -> io::Result<()> {
|
||||
let touchpad = FAKE_TOUCHPAD.lock();
|
||||
pub fn scroll_mt_start() -> io::Result<()> {
|
||||
let touchpad = FAKE_INPUTS.touchpad.lock();
|
||||
|
||||
{
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 0))?;
|
||||
@@ -231,7 +224,7 @@ impl FakeInput {
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_Y, MT_BASELINE))?;
|
||||
}
|
||||
|
||||
self.touch_syn_report()?;
|
||||
touch_syn_report()?;
|
||||
|
||||
{
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 1))?;
|
||||
@@ -243,13 +236,13 @@ impl FakeInput {
|
||||
touchpad.write_event(&input_event!(EV_KEY, BTN_TOOL_DOUBLETAP, 1))?;
|
||||
}
|
||||
|
||||
self.touch_syn_report()?;
|
||||
touch_syn_report()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_mt_step(&self, delta: i32) -> io::Result<()> {
|
||||
let touchpad = FAKE_TOUCHPAD.lock();
|
||||
pub fn scroll_mt_step(delta: i32) -> io::Result<()> {
|
||||
let touchpad = FAKE_INPUTS.touchpad.lock();
|
||||
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 0))?;
|
||||
touchpad.write_event(&input_event!(
|
||||
@@ -266,13 +259,13 @@ impl FakeInput {
|
||||
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_Y, MT_BASELINE + delta))?;
|
||||
|
||||
self.touch_syn_report()?;
|
||||
touch_syn_report()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_mt_end(&self) -> io::Result<()> {
|
||||
let touchpad = FAKE_TOUCHPAD.lock();
|
||||
pub fn scroll_mt_end() -> io::Result<()> {
|
||||
let touchpad = FAKE_INPUTS.touchpad.lock();
|
||||
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 0))?;
|
||||
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_TRACKING_ID, -1))?;
|
||||
@@ -282,10 +275,9 @@ impl FakeInput {
|
||||
touchpad.write_event(&input_event!(EV_KEY, BTN_TOUCH, 0))?;
|
||||
touchpad.write_event(&input_event!(EV_KEY, BTN_TOOL_DOUBLETAP, 0))?;
|
||||
|
||||
self.touch_syn_report()?;
|
||||
touch_syn_report()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ScrollStep {
|
||||
|
||||
78
src/main.rs
78
src/main.rs
@@ -11,15 +11,32 @@ use std::sync::mpsc;
|
||||
|
||||
use crate::controller::DialController;
|
||||
use crate::dial_device::DialDevice;
|
||||
use crate::error::Result;
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
use notify_rust::{Hint, Notification, Timeout};
|
||||
use signal_hook::{iterator::Signals, SIGINT, SIGTERM};
|
||||
|
||||
fn main() {
|
||||
let (kill_notif_tx, kill_notif_rx) = mpsc::channel::<Option<(String, &'static str)>>();
|
||||
let (terminate_tx, terminate_rx) = mpsc::channel::<Result<()>>();
|
||||
|
||||
std::thread::spawn({
|
||||
let terminate_tx = terminate_tx.clone();
|
||||
move || {
|
||||
let signals = Signals::new(&[SIGTERM, SIGINT]).unwrap();
|
||||
for sig in signals.forever() {
|
||||
eprintln!("received signal {:?}", sig);
|
||||
let _ = terminate_tx.send(Err(Error::TermSig));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
std::thread::spawn({
|
||||
let terminate_tx = terminate_tx;
|
||||
move || {
|
||||
let _ = terminate_tx.send(controller_main());
|
||||
}
|
||||
});
|
||||
|
||||
let handle = std::thread::spawn(move || {
|
||||
let active_notification = Notification::new()
|
||||
.hint(Hint::Resident(true))
|
||||
.hint(Hint::Category("device".into()))
|
||||
@@ -28,21 +45,28 @@ fn main() {
|
||||
.body("Active!")
|
||||
.icon("media-optical") // it should be vaguely circular :P
|
||||
.show()
|
||||
.expect("failed to send notification");
|
||||
.expect("Failed to send notification. NOTE: this daemon (probably) can't run as root!");
|
||||
|
||||
let kill_notif = kill_notif_rx.recv();
|
||||
let (silent, msg, icon) = match terminate_rx.recv() {
|
||||
Ok(Ok(())) => (true, "".into(), ""),
|
||||
Ok(Err(e)) => {
|
||||
println!("Error: {}", e);
|
||||
match e {
|
||||
Error::TermSig => (false, "Terminated!".into(), "dialog-warning"),
|
||||
// HACK: silently exit if the dial disconnects
|
||||
Error::Evdev(e) if e.raw_os_error() == Some(19) => (true, "".into(), ""),
|
||||
other => (false, format!("Error: {}", other), "dialog-error"),
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Error: Unexpected Error");
|
||||
(false, "Unexpected Error".into(), "dialog-error")
|
||||
}
|
||||
};
|
||||
|
||||
active_notification.close();
|
||||
|
||||
let (msg, icon) = match kill_notif {
|
||||
Ok(None) => {
|
||||
// shutdown immediately
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(Some((msg, icon))) => (msg, icon),
|
||||
Err(_) => ("Unexpected Error".into(), "dialog-error"),
|
||||
};
|
||||
|
||||
if !silent {
|
||||
Notification::new()
|
||||
.hint(Hint::Transient(true))
|
||||
.hint(Hint::Category("device".into()))
|
||||
@@ -52,33 +76,13 @@ fn main() {
|
||||
.icon(icon)
|
||||
.show()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// cleaning up threads is hard...
|
||||
std::process::exit(1);
|
||||
});
|
||||
|
||||
std::thread::spawn({
|
||||
let kill_notif_tx = kill_notif_tx.clone();
|
||||
move || {
|
||||
let signals = Signals::new(&[SIGTERM, SIGINT]).unwrap();
|
||||
for sig in signals.forever() {
|
||||
eprintln!("received signal {:?}", sig);
|
||||
match kill_notif_tx.send(Some(("Terminated!".into(), "dialog-warning"))) {
|
||||
Ok(_) => {}
|
||||
Err(_) => std::process::exit(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(e) = true_main() {
|
||||
println!("{}", e);
|
||||
}
|
||||
|
||||
let _ = kill_notif_tx.send(None); // silently shut down
|
||||
let _ = handle.join();
|
||||
}
|
||||
|
||||
fn true_main() -> Result<()> {
|
||||
fn controller_main() -> Result<()> {
|
||||
println!("Started");
|
||||
|
||||
let cfg = config::Config::from_disk()?;
|
||||
|
||||
Reference in New Issue
Block a user