add scroll + notifications
oh my god it took far too long to get notifications working...
This commit is contained in:
@@ -32,3 +32,17 @@ impl ThresholdHelper {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
use notify_rust::error::Result as NotifyResult;
|
||||
use notify_rust::{Hint, Notification, NotificationHandle, Timeout};
|
||||
|
||||
pub fn action_notification(msg: &str, icon: &str) -> NotifyResult<NotificationHandle> {
|
||||
Notification::new()
|
||||
.hint(Hint::Transient(true))
|
||||
.hint(Hint::Category("device".into()))
|
||||
.timeout(Timeout::Milliseconds(100))
|
||||
.summary("Surface Dial")
|
||||
.body(msg)
|
||||
.icon(icon)
|
||||
.show()
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ impl Worker {
|
||||
Ordering::Greater => self.fake_input.key_press(&[EV_KEY::KEY_RIGHT]).unwrap(),
|
||||
}
|
||||
|
||||
eprintln!("{:?}", self.velocity);
|
||||
// eprintln!("{:?}", self.velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ impl Media {
|
||||
|
||||
impl ControlMode for Media {
|
||||
fn on_btn_press(&mut self) -> DynResult<()> {
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self) -> DynResult<()> {
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
mod dpad;
|
||||
mod media;
|
||||
mod scroll_zoom;
|
||||
mod volume;
|
||||
|
||||
pub use self::dpad::*;
|
||||
pub use self::media::*;
|
||||
pub use self::scroll_zoom::*;
|
||||
pub use self::volume::*;
|
||||
|
||||
68
src/controller/controls/scroll_zoom.rs
Normal file
68
src/controller/controls/scroll_zoom.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use crate::common::{action_notification, DialDir, ThresholdHelper};
|
||||
use crate::controller::ControlMode;
|
||||
use crate::fake_input::{FakeInput, ScrollStep};
|
||||
use crate::DynResult;
|
||||
|
||||
use evdev_rs::enums::EV_KEY;
|
||||
|
||||
pub struct ScrollZoom {
|
||||
thresh: ThresholdHelper,
|
||||
zoom: bool,
|
||||
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
|
||||
impl ScrollZoom {
|
||||
pub fn new(sensitivity: i32) -> ScrollZoom {
|
||||
ScrollZoom {
|
||||
thresh: ThresholdHelper::new(sensitivity),
|
||||
zoom: false,
|
||||
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControlMode for ScrollZoom {
|
||||
fn on_btn_press(&mut self) -> DynResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self) -> DynResult<()> {
|
||||
self.zoom = !self.zoom;
|
||||
if self.zoom {
|
||||
action_notification("Zoom Mode", "zoom-in")?;
|
||||
} else {
|
||||
action_notification("ScrollZoom Mode", "input-mouse")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_dial(&mut self, delta: i32) -> DynResult<()> {
|
||||
match self.thresh.update(delta) {
|
||||
None => {}
|
||||
Some(DialDir::Left) => {
|
||||
if self.zoom {
|
||||
eprintln!("zoom out");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_MINUS])?;
|
||||
} else {
|
||||
eprintln!("scroll up");
|
||||
self.fake_input.scroll_step(ScrollStep::Up)?;
|
||||
}
|
||||
}
|
||||
Some(DialDir::Right) => {
|
||||
if self.zoom {
|
||||
eprintln!("zoom in");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_EQUAL])?;
|
||||
} else {
|
||||
eprintln!("scroll down");
|
||||
self.fake_input.scroll_step(ScrollStep::Down)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -24,14 +24,13 @@ impl Volume {
|
||||
impl ControlMode for Volume {
|
||||
fn on_btn_press(&mut self) -> DynResult<()> {
|
||||
// TODO: support double-click to mute
|
||||
|
||||
eprintln!("play/pause");
|
||||
// self.fake_input.mute()?
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self) -> DynResult<()> {
|
||||
eprintln!("play/pause");
|
||||
// self.fake_input.mute()?
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,14 @@ impl DialDevice {
|
||||
let mut control = None;
|
||||
let mut axis = None;
|
||||
|
||||
for e in fs::read_dir("/dev/input/").map_err(Error::Io)? {
|
||||
let e = e.map_err(Error::Io)?;
|
||||
for e in fs::read_dir("/dev/input/").map_err(Error::OpenDevInputDir)? {
|
||||
let e = e.map_err(Error::OpenDevInputDir)?;
|
||||
if !e.file_name().to_str().unwrap().starts_with("event") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let file = fs::File::open(e.path()).map_err(Error::Io)?;
|
||||
let file =
|
||||
fs::File::open(e.path()).map_err(|err| Error::OpenEventFile(e.path(), err))?;
|
||||
let dev = Device::new_from_fd(file).map_err(Error::Evdev)?;
|
||||
|
||||
match dev.name() {
|
||||
|
||||
13
src/error.rs
13
src/error.rs
@@ -1,24 +1,29 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use evdev_rs::InputEvent;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
OpenDevInputDir(io::Error),
|
||||
OpenEventFile(std::path::PathBuf, io::Error),
|
||||
MissingDial,
|
||||
MultipleDials,
|
||||
UnexpectedEvt(InputEvent),
|
||||
Evdev(std::io::Error),
|
||||
Io(std::io::Error),
|
||||
Evdev(io::Error),
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::OpenDevInputDir(e) => write!(f, "Could not open /dev/input directory: {}", e),
|
||||
Error::OpenEventFile(path, e) => write!(f, "Could not open {:?}: {}", path, e),
|
||||
Error::MissingDial => write!(f, "Could not find the Surface Dial"),
|
||||
Error::MultipleDials => write!(f, "Found multiple dials"),
|
||||
Error::UnexpectedEvt(evt) => write!(f, "Unexpected event: {:?}", evt),
|
||||
Error::Evdev(e) => write!(f, "Evdev error: {:?}", e),
|
||||
Error::Io(e) => write!(f, "Io error: {:?}", e),
|
||||
Error::Evdev(e) => write!(f, "Evdev error: {}", e),
|
||||
Error::Io(e) => write!(f, "Io error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,23 +12,35 @@ fn get_fake_input() -> io::Result<&'static UInputDevice> {
|
||||
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::KEY_LEFTSHIFT))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_MUTE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEDOWN))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEUP))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_NEXTSONG))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PLAYPAUSE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PREVIOUSSONG))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_RIGHT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_SPACE))?;
|
||||
|
||||
device.enable(&EventType::EV_MSC)?;
|
||||
device.enable(&EventCode::EV_MSC(EV_MSC::MSC_SCAN))?;
|
||||
|
||||
device.enable(&EventType::EV_KEY)?;
|
||||
{
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFTSHIFT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFTCTRL))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_MUTE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEDOWN))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEUP))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_NEXTSONG))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PLAYPAUSE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PREVIOUSSONG))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_RIGHT))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_SPACE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_EQUAL))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_MINUS))?;
|
||||
}
|
||||
|
||||
device.enable(&EventType::EV_REL)?;
|
||||
{
|
||||
device.enable(&EventCode::EV_REL(EV_REL::REL_WHEEL))?;
|
||||
device.enable(&EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES))?;
|
||||
}
|
||||
|
||||
unsafe { FAKE_INPUT = Some(UInputDevice::create_from_device(&device)?) }
|
||||
}
|
||||
unsafe { Ok(FAKE_INPUT.as_ref().unwrap()) }
|
||||
@@ -99,4 +111,33 @@ impl FakeInput {
|
||||
self.syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn scroll_step(&self, dir: ScrollStep) -> io::Result<()> {
|
||||
// copied from my razer blackwidow chroma mouse
|
||||
self.uinput.write_event(&InputEvent {
|
||||
time: TimeVal::new(0, 0),
|
||||
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL),
|
||||
event_type: EventType::EV_REL,
|
||||
value: match dir {
|
||||
ScrollStep::Down => -1,
|
||||
ScrollStep::Up => 1,
|
||||
},
|
||||
})?;
|
||||
self.uinput.write_event(&InputEvent {
|
||||
time: TimeVal::new(0, 0),
|
||||
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES),
|
||||
event_type: EventType::EV_REL,
|
||||
value: match dir {
|
||||
ScrollStep::Down => -120,
|
||||
ScrollStep::Up => 120,
|
||||
},
|
||||
})?;
|
||||
self.syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ScrollStep {
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
19
src/main.rs
19
src/main.rs
@@ -10,13 +10,24 @@ use crate::controller::DialController;
|
||||
use crate::dial_device::DialDevice;
|
||||
use crate::error::Error;
|
||||
|
||||
fn main() -> DynResult<()> {
|
||||
fn main() {
|
||||
if let Err(e) = true_main() {
|
||||
println!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn true_main() -> DynResult<()> {
|
||||
println!("Started.");
|
||||
|
||||
let dial = DialDevice::new()?;
|
||||
println!("Found the dial.");
|
||||
|
||||
let default_mode = Box::new(controller::controls::Volume::new(30));
|
||||
// let default_mode = Box::new(controls::Media::new(50));
|
||||
// let default_mode = Box::new(controls::DPad::new());
|
||||
common::action_notification("Active!", "input-mouse")?;
|
||||
|
||||
let default_mode = Box::new(controller::controls::ScrollZoom::new(30));
|
||||
// let default_mode = Box::new(controller::controls::Volume::new(30));
|
||||
// let default_mode = Box::new(controller::controls::Media::new(50));
|
||||
// let default_mode = Box::new(controller::controls::DPad::new());
|
||||
|
||||
let mut controller = DialController::new(dial, default_mode);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user