experimental multitouch based smooth scrolling
high-resolution mouse wheels aren't supported in userland yet, so why
don't we fake a high resolution touchpad instead 😄
it's somewhat working, though it seems to crash on startup when
installed (among other weird bugs).
This commit is contained in:
79
Cargo.lock
generated
79
Cargo.lock
generated
@@ -71,6 +71,12 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.19"
|
version = "0.4.19"
|
||||||
@@ -84,6 +90,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cloudabi"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -97,7 +112,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -169,7 +184,7 @@ version = "0.1.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
@@ -185,6 +200,15 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -206,13 +230,22 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -295,6 +328,32 @@ dependencies = [
|
|||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"cloudabi",
|
||||||
|
"instant",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.19"
|
version = "0.3.19"
|
||||||
@@ -336,6 +395,12 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
@@ -356,6 +421,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum"
|
name = "strum"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -379,7 +450,9 @@ dependencies = [
|
|||||||
"directories",
|
"directories",
|
||||||
"evdev-rs",
|
"evdev-rs",
|
||||||
"hidapi",
|
"hidapi",
|
||||||
|
"lazy_static",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
|
"parking_lot",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,7 @@ directories = "3.0"
|
|||||||
# master includes a PR that implements `Send` for `Device` and `UInputDevice`
|
# master includes a PR that implements `Send` for `Device` and `UInputDevice`
|
||||||
evdev-rs = { git = "https://github.com/ndesh26/evdev-rs.git", rev = "8e995b8bf" }
|
evdev-rs = { git = "https://github.com/ndesh26/evdev-rs.git", rev = "8e995b8bf" }
|
||||||
hidapi = { version = "1.2.3", default-features = false, features = ["linux-shared-hidraw"] }
|
hidapi = { version = "1.2.3", default-features = false, features = ["linux-shared-hidraw"] }
|
||||||
|
lazy_static = "1.4"
|
||||||
notify-rust = "4"
|
notify-rust = "4"
|
||||||
|
parking_lot = "0.11.0"
|
||||||
signal-hook = "0.1.16"
|
signal-hook = "0.1.16"
|
||||||
|
|||||||
4559
notes/touchpad_evtest.txt
Normal file
4559
notes/touchpad_evtest.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ mod media;
|
|||||||
mod null;
|
mod null;
|
||||||
mod paddle;
|
mod paddle;
|
||||||
mod scroll;
|
mod scroll;
|
||||||
|
mod scroll_mt;
|
||||||
mod volume;
|
mod volume;
|
||||||
mod zoom;
|
mod zoom;
|
||||||
|
|
||||||
@@ -9,5 +10,6 @@ pub use self::media::*;
|
|||||||
pub use self::null::*;
|
pub use self::null::*;
|
||||||
pub use self::paddle::*;
|
pub use self::paddle::*;
|
||||||
pub use self::scroll::*;
|
pub use self::scroll::*;
|
||||||
|
pub use self::scroll_mt::*;
|
||||||
pub use self::volume::*;
|
pub use self::volume::*;
|
||||||
pub use self::zoom::*;
|
pub use self::zoom::*;
|
||||||
|
|||||||
61
src/controller/controls/scroll_mt.rs
Normal file
61
src/controller/controls/scroll_mt.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use crate::controller::{ControlMode, ControlModeMeta};
|
||||||
|
use crate::dial_device::DialHaptics;
|
||||||
|
use crate::fake_input::FakeInput;
|
||||||
|
use crate::DynResult;
|
||||||
|
|
||||||
|
pub struct ScrollMT {
|
||||||
|
acc_delta: i32,
|
||||||
|
|
||||||
|
fake_input: FakeInput,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScrollMT {
|
||||||
|
pub fn new() -> ScrollMT {
|
||||||
|
ScrollMT {
|
||||||
|
acc_delta: 0,
|
||||||
|
fake_input: FakeInput::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControlMode for ScrollMT {
|
||||||
|
fn meta(&self) -> ControlModeMeta {
|
||||||
|
ControlModeMeta {
|
||||||
|
name: "Scroll",
|
||||||
|
icon: "input-mouse",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_start(&mut self, haptics: &DialHaptics) -> DynResult<()> {
|
||||||
|
haptics.set_mode(false, Some(3600))?;
|
||||||
|
self.acc_delta = 0;
|
||||||
|
|
||||||
|
self.fake_input.scroll_mt_start()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_end(&mut self, _haptics: &DialHaptics) -> DynResult<()> {
|
||||||
|
self.fake_input.scroll_mt_end()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: the button will reset the scroll event, which sometimes helps
|
||||||
|
|
||||||
|
fn on_btn_press(&mut self, _: &DialHaptics) -> DynResult<()> {
|
||||||
|
self.fake_input.scroll_mt_end()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_btn_release(&mut self, _haptics: &DialHaptics) -> DynResult<()> {
|
||||||
|
self.fake_input.scroll_mt_start()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_dial(&mut self, _: &DialHaptics, delta: i32) -> DynResult<()> {
|
||||||
|
self.acc_delta += delta;
|
||||||
|
self.fake_input.scroll_mt_step(self.acc_delta)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,13 @@ use std::io;
|
|||||||
|
|
||||||
use evdev_rs::enums::*;
|
use evdev_rs::enums::*;
|
||||||
use evdev_rs::{Device, InputEvent, TimeVal, UInputDevice};
|
use evdev_rs::{Device, InputEvent, TimeVal, UInputDevice};
|
||||||
|
use parking_lot::ReentrantMutex;
|
||||||
|
|
||||||
static mut FAKE_INPUT: Option<UInputDevice> = None;
|
lazy_static::lazy_static! {
|
||||||
fn get_fake_input() -> io::Result<&'static UInputDevice> {
|
static ref FAKE_KEYBOARD: ReentrantMutex<UInputDevice> = {
|
||||||
if unsafe { FAKE_INPUT.is_none() } {
|
(|| -> io::Result<_> {
|
||||||
let device = Device::new().unwrap();
|
let device = Device::new().unwrap();
|
||||||
device.set_name("Surface Dial Virtual Input");
|
device.set_name("Surface Dial Virtual Keyboard/Mouse");
|
||||||
|
|
||||||
device.enable(&EventType::EV_SYN)?;
|
device.enable(&EventType::EV_SYN)?;
|
||||||
device.enable(&EventCode::EV_SYN(EV_SYN::SYN_REPORT))?;
|
device.enable(&EventCode::EV_SYN(EV_SYN::SYN_REPORT))?;
|
||||||
@@ -41,15 +42,82 @@ fn get_fake_input() -> io::Result<&'static UInputDevice> {
|
|||||||
device.enable(&EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES))?;
|
device.enable(&EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { FAKE_INPUT = Some(UInputDevice::create_from_device(&device)?) }
|
Ok(ReentrantMutex::new(UInputDevice::create_from_device(&device)?))
|
||||||
|
})().expect("failed to install virtual mouse/keyboard device")
|
||||||
|
};
|
||||||
|
|
||||||
|
static ref FAKE_TOUCHPAD: ReentrantMutex<UInputDevice> = {
|
||||||
|
(|| -> io::Result<_> {
|
||||||
|
let device = Device::new().unwrap();
|
||||||
|
device.set_name("Surface Dial Virtual Touchpad");
|
||||||
|
|
||||||
|
device.enable(&InputProp::INPUT_PROP_BUTTONPAD)?;
|
||||||
|
device.enable(&InputProp::INPUT_PROP_POINTER)?;
|
||||||
|
|
||||||
|
device.enable(&EventType::EV_SYN)?;
|
||||||
|
device.enable(&EventCode::EV_SYN(EV_SYN::SYN_REPORT))?;
|
||||||
|
|
||||||
|
device.enable(&EventType::EV_KEY)?;
|
||||||
|
{
|
||||||
|
device.enable(&EventCode::EV_KEY(EV_KEY::BTN_LEFT))?;
|
||||||
|
device.enable(&EventCode::EV_KEY(EV_KEY::BTN_TOOL_FINGER))?;
|
||||||
|
device.enable(&EventCode::EV_KEY(EV_KEY::BTN_TOUCH))?;
|
||||||
|
device.enable(&EventCode::EV_KEY(EV_KEY::BTN_TOOL_DOUBLETAP))?;
|
||||||
|
device.enable(&EventCode::EV_KEY(EV_KEY::BTN_TOOL_TRIPLETAP))?;
|
||||||
|
device.enable(&EventCode::EV_KEY(EV_KEY::BTN_TOOL_QUADTAP))?;
|
||||||
}
|
}
|
||||||
unsafe { Ok(FAKE_INPUT.as_ref().unwrap()) }
|
|
||||||
|
// roughly copied from my laptop's trackpad (Aero 15x)
|
||||||
|
device.enable(&EventType::EV_ABS)?;
|
||||||
|
{
|
||||||
|
let mut abs_info = evdev_rs::AbsInfo {
|
||||||
|
value: 0,
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 0,
|
||||||
|
fuzz: 0,
|
||||||
|
flat: 0,
|
||||||
|
resolution: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
abs_info.minimum = 0;
|
||||||
|
abs_info.maximum = 4;
|
||||||
|
device.enable_event_code(&EventCode::EV_ABS(EV_ABS::ABS_MT_SLOT), Some(&abs_info))?;
|
||||||
|
|
||||||
|
abs_info.minimum = 0;
|
||||||
|
abs_info.maximum = 65535;
|
||||||
|
device.enable_event_code(
|
||||||
|
&EventCode::EV_ABS(EV_ABS::ABS_MT_TRACKING_ID),
|
||||||
|
Some(&abs_info),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// higher = more sensitive
|
||||||
|
const SENSITIVITY: i32 = 64;
|
||||||
|
|
||||||
|
abs_info.minimum = 0;
|
||||||
|
abs_info.maximum = std::i32::MAX;
|
||||||
|
abs_info.resolution = SENSITIVITY;
|
||||||
|
device.enable_event_code(
|
||||||
|
&EventCode::EV_ABS(EV_ABS::ABS_MT_POSITION_X),
|
||||||
|
Some(&abs_info),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
abs_info.minimum = 0;
|
||||||
|
abs_info.maximum = std::i32::MAX;
|
||||||
|
abs_info.resolution = SENSITIVITY;
|
||||||
|
device.enable_event_code(
|
||||||
|
&EventCode::EV_ABS(EV_ABS::ABS_MT_POSITION_Y),
|
||||||
|
Some(&abs_info),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ReentrantMutex::new(UInputDevice::create_from_device(&device)?))
|
||||||
|
})().expect("failed to install virtual touchpad device")
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct FakeInput {
|
pub struct FakeInput {}
|
||||||
uinput: &'static UInputDevice,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! input_event {
|
macro_rules! input_event {
|
||||||
($type:ident, $code:ident, $value:expr) => {
|
($type:ident, $code:ident, $value:expr) => {
|
||||||
@@ -70,14 +138,11 @@ impl Default for FakeInput {
|
|||||||
|
|
||||||
impl FakeInput {
|
impl FakeInput {
|
||||||
pub fn new() -> FakeInput {
|
pub fn new() -> FakeInput {
|
||||||
FakeInput {
|
FakeInput {}
|
||||||
uinput: get_fake_input().expect("could not install fake input device"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syn_report(&self) -> io::Result<()> {
|
fn kbd_syn_report(&self) -> io::Result<()> {
|
||||||
self.uinput
|
(FAKE_KEYBOARD.lock()).write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
||||||
.write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_click(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
pub fn key_click(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
||||||
@@ -87,34 +152,40 @@ impl FakeInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_press(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
pub fn key_press(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
||||||
|
let keyboard = FAKE_KEYBOARD.lock();
|
||||||
|
|
||||||
for key in keys {
|
for key in keys {
|
||||||
self.uinput.write_event(&InputEvent {
|
keyboard.write_event(&InputEvent {
|
||||||
time: TimeVal::new(0, 0),
|
time: TimeVal::new(0, 0),
|
||||||
event_code: EventCode::EV_KEY(*key),
|
event_code: EventCode::EV_KEY(*key),
|
||||||
event_type: EventType::EV_KEY,
|
event_type: EventType::EV_KEY,
|
||||||
value: 1,
|
value: 1,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
self.syn_report()?;
|
self.kbd_syn_report()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_release(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
pub fn key_release(&self, keys: &[EV_KEY]) -> io::Result<()> {
|
||||||
|
let keyboard = FAKE_KEYBOARD.lock();
|
||||||
|
|
||||||
for key in keys.iter().clone() {
|
for key in keys.iter().clone() {
|
||||||
self.uinput.write_event(&InputEvent {
|
keyboard.write_event(&InputEvent {
|
||||||
time: TimeVal::new(0, 0),
|
time: TimeVal::new(0, 0),
|
||||||
event_code: EventCode::EV_KEY(*key),
|
event_code: EventCode::EV_KEY(*key),
|
||||||
event_type: EventType::EV_KEY,
|
event_type: EventType::EV_KEY,
|
||||||
value: 0,
|
value: 0,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
self.syn_report()?;
|
self.kbd_syn_report()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_step(&self, dir: ScrollStep) -> io::Result<()> {
|
pub fn scroll_step(&self, dir: ScrollStep) -> io::Result<()> {
|
||||||
|
let keyboard = FAKE_KEYBOARD.lock();
|
||||||
|
|
||||||
// copied from my razer blackwidow chroma mouse
|
// copied from my razer blackwidow chroma mouse
|
||||||
self.uinput.write_event(&InputEvent {
|
keyboard.write_event(&InputEvent {
|
||||||
time: TimeVal::new(0, 0),
|
time: TimeVal::new(0, 0),
|
||||||
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL),
|
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL),
|
||||||
event_type: EventType::EV_REL,
|
event_type: EventType::EV_REL,
|
||||||
@@ -123,7 +194,7 @@ impl FakeInput {
|
|||||||
ScrollStep::Up => 1,
|
ScrollStep::Up => 1,
|
||||||
},
|
},
|
||||||
})?;
|
})?;
|
||||||
self.uinput.write_event(&InputEvent {
|
keyboard.write_event(&InputEvent {
|
||||||
time: TimeVal::new(0, 0),
|
time: TimeVal::new(0, 0),
|
||||||
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES),
|
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES),
|
||||||
event_type: EventType::EV_REL,
|
event_type: EventType::EV_REL,
|
||||||
@@ -132,11 +203,89 @@ impl FakeInput {
|
|||||||
ScrollStep::Up => 120,
|
ScrollStep::Up => 120,
|
||||||
},
|
},
|
||||||
})?;
|
})?;
|
||||||
self.syn_report()?;
|
self.kbd_syn_report()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn touch_syn_report(&self) -> io::Result<()> {
|
||||||
|
(FAKE_TOUCHPAD.lock()).write_event(&input_event!(EV_SYN, SYN_REPORT, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_mt_start(&self) -> io::Result<()> {
|
||||||
|
let touchpad = FAKE_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))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_POSITION_X, MT_BASELINE))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_POSITION_Y, MT_BASELINE))?;
|
||||||
|
|
||||||
|
touchpad.write_event(&input_event!(EV_KEY, BTN_TOUCH, 1))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_KEY, BTN_TOOL_FINGER, 1))?;
|
||||||
|
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_X, MT_BASELINE))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_Y, MT_BASELINE))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.touch_syn_report()?;
|
||||||
|
|
||||||
|
{
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 1))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_TRACKING_ID, 2))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_POSITION_X, std::i32::MAX / 3))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_POSITION_Y, MT_BASELINE))?;
|
||||||
|
|
||||||
|
touchpad.write_event(&input_event!(EV_KEY, BTN_TOOL_FINGER, 0))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_KEY, BTN_TOOL_DOUBLETAP, 1))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.touch_syn_report()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_mt_step(&self, delta: i32) -> io::Result<()> {
|
||||||
|
let touchpad = FAKE_TOUCHPAD.lock();
|
||||||
|
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 0))?;
|
||||||
|
touchpad.write_event(&input_event!(
|
||||||
|
EV_ABS,
|
||||||
|
ABS_MT_POSITION_Y,
|
||||||
|
MT_BASELINE + delta
|
||||||
|
))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 1))?;
|
||||||
|
touchpad.write_event(&input_event!(
|
||||||
|
EV_ABS,
|
||||||
|
ABS_MT_POSITION_Y,
|
||||||
|
MT_BASELINE + delta
|
||||||
|
))?;
|
||||||
|
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_Y, MT_BASELINE + delta))?;
|
||||||
|
|
||||||
|
self.touch_syn_report()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_mt_end(&self) -> io::Result<()> {
|
||||||
|
let touchpad = FAKE_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))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_SLOT, 1))?;
|
||||||
|
touchpad.write_event(&input_event!(EV_ABS, ABS_MT_TRACKING_ID, -1))?;
|
||||||
|
|
||||||
|
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()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MT_BASELINE: i32 = std::i32::MAX / 2;
|
||||||
|
|
||||||
pub enum ScrollStep {
|
pub enum ScrollStep {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
|
|||||||
12
src/main.rs
12
src/main.rs
@@ -62,8 +62,8 @@ fn main() {
|
|||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
kill_notif_tx.send(None).unwrap(); // silently shut down
|
let _ = kill_notif_tx.send(None); // silently shut down
|
||||||
handle.join().unwrap();
|
let _ = handle.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn true_main(kill_notif_tx: mpsc::Sender<Option<(String, &'static str)>>) -> DynResult<()> {
|
fn true_main(kill_notif_tx: mpsc::Sender<Option<(String, &'static str)>>) -> DynResult<()> {
|
||||||
@@ -78,9 +78,10 @@ fn true_main(kill_notif_tx: mpsc::Sender<Option<(String, &'static str)>>) -> Dyn
|
|||||||
let signals = Signals::new(&[SIGTERM, SIGINT]).unwrap();
|
let signals = Signals::new(&[SIGTERM, SIGINT]).unwrap();
|
||||||
for sig in signals.forever() {
|
for sig in signals.forever() {
|
||||||
eprintln!("received signal {:?}", sig);
|
eprintln!("received signal {:?}", sig);
|
||||||
kill_notif_tx
|
match kill_notif_tx.send(Some(("Terminated!".into(), "dialog-warning"))) {
|
||||||
.send(Some(("Terminated!".into(), "dialog-warning")))
|
Ok(_) => {}
|
||||||
.unwrap();
|
Err(_) => std::process::exit(1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -88,6 +89,7 @@ fn true_main(kill_notif_tx: mpsc::Sender<Option<(String, &'static str)>>) -> Dyn
|
|||||||
dial,
|
dial,
|
||||||
cfg.last_mode,
|
cfg.last_mode,
|
||||||
vec![
|
vec![
|
||||||
|
// Box::new(controller::controls::ScrollMT::new()),
|
||||||
Box::new(controller::controls::Scroll::new()),
|
Box::new(controller::controls::Scroll::new()),
|
||||||
Box::new(controller::controls::Zoom::new()),
|
Box::new(controller::controls::Zoom::new()),
|
||||||
Box::new(controller::controls::Volume::new()),
|
Box::new(controller::controls::Volume::new()),
|
||||||
|
|||||||
Reference in New Issue
Block a user