-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Cargo.toml * Add actions module * Add events module * Add main.rs
- Loading branch information
1 parent
b56fc72
commit 30f1216
Showing
8 changed files
with
502 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "lillinput" | ||
version = "0.1.0" | ||
authors = ["Diego M. Rodríguez <diego@moreda.io>"] | ||
edition = "2018" | ||
description = "Connect libinput gestures to i3 and others" | ||
repository = "https://github.com/diego-plan9/lillinput/" | ||
license = "BSD-3-Clause" | ||
keywords = ["i3", "swipe", "touchpad", "x11", "libinput", "gestures"] | ||
categories = ["command-line-utilities", "gui"] | ||
|
||
[dependencies] | ||
input = "0.5.0" | ||
libc = "0.2.84" | ||
i3ipc = "0.10.1" | ||
filedescriptor = "0.7.3" | ||
clap = "3.0.0-beta.2" | ||
strum = { version = "0.21", features = ["derive"] } | ||
shlex = "1.0.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
//! Action for executing commands. | ||
|
||
use super::{Action, ActionExt}; | ||
use shlex::split; | ||
use std::process::Command; | ||
|
||
pub struct CommandAction { | ||
command: String, | ||
} | ||
|
||
impl Action for CommandAction { | ||
fn execute_command(&mut self) { | ||
// Perform the command, if specified. | ||
let split_commands = split(&self.command).unwrap(); | ||
// TODO: capture result gracefully. | ||
Command::new(&split_commands[0]) | ||
.args(&split_commands[1..]) | ||
.output() | ||
.expect("Failed to execute command"); | ||
} | ||
} | ||
|
||
impl ActionExt for CommandAction { | ||
fn new(command: String) -> CommandAction { | ||
CommandAction { command } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
//! Controller for actions. | ||
|
||
use super::commandaction::CommandAction; | ||
use super::i3action::{I3Action, I3ActionExt}; | ||
use super::{Action, ActionChoices, ActionController, ActionEvents, ActionExt, ActionMap, Opts}; | ||
use i3ipc::I3Connection; | ||
|
||
use std::cell::RefCell; | ||
use std::rc::Rc; | ||
use std::str::FromStr; | ||
|
||
impl ActionController for ActionMap { | ||
fn new(opts: &Opts) -> Self { | ||
// Create the I3 connection if needed. | ||
let connection = match opts | ||
.enabled_actions | ||
.contains(&ActionChoices::I3.to_string()) | ||
{ | ||
true => match I3Connection::connect() { | ||
Ok(mut conn) => { | ||
println!( | ||
"i3: opened connection ... ({:?})", | ||
conn.get_version().unwrap().human_readable | ||
); | ||
Some(Rc::new(RefCell::new(conn))) | ||
} | ||
Err(error) => { | ||
println!("i3: could not establish a connection: {:?}", error); | ||
None | ||
} | ||
}, | ||
false => None, | ||
}; | ||
|
||
ActionMap { | ||
threshold: opts.threshold, | ||
connection, | ||
swipe_left: vec![], | ||
swipe_right: vec![], | ||
swipe_up: vec![], | ||
swipe_down: vec![], | ||
} | ||
} | ||
|
||
fn populate_actions(&mut self, opts: &Opts) { | ||
/// Add actions to a destination vector. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `arguments` - list of command line arguments | ||
/// * `destination` - vector to append actions to | ||
/// * `connection` - optional i3 connection | ||
fn parse_action_list( | ||
arguments: &[String], | ||
destination: &mut Vec<Box<dyn Action>>, | ||
connection: &Option<Rc<RefCell<I3Connection>>>, | ||
) { | ||
for value in arguments.iter() { | ||
// Split the arguments, in the form "{type}:{value}". | ||
let mut splitter = value.splitn(2, ':'); | ||
let action_type = splitter.next().unwrap(); | ||
let action_value = splitter.next().unwrap(); | ||
|
||
// Create new actions and add them to the controller. | ||
match ActionChoices::from_str(action_type) { | ||
Ok(ActionChoices::Command) => { | ||
destination.push(Box::new(CommandAction::new(action_value.to_string()))); | ||
} | ||
Ok(ActionChoices::I3) => match connection { | ||
Some(conn) => { | ||
destination.push(Box::new(I3Action::new( | ||
action_value.to_string(), | ||
Rc::clone(&conn), | ||
))); | ||
} | ||
None => { | ||
println!("ignoring i3 action, as the i3 connection could not be set.") | ||
} | ||
}, | ||
Err(_) => {} | ||
} | ||
} | ||
} | ||
|
||
parse_action_list(&opts.swipe_left_3, &mut self.swipe_left, &self.connection); | ||
parse_action_list(&opts.swipe_right_3, &mut self.swipe_right, &self.connection); | ||
parse_action_list(&opts.swipe_up_3, &mut self.swipe_up, &self.connection); | ||
parse_action_list(&opts.swipe_down_3, &mut self.swipe_down, &self.connection); | ||
|
||
// Print information. | ||
println!( | ||
"Controller started: {:?}/{:?}/{:?}/{:?} actions enabled", | ||
self.swipe_left.len(), | ||
self.swipe_right.len(), | ||
self.swipe_up.len(), | ||
self.swipe_down.len(), | ||
); | ||
} | ||
|
||
#[allow(clippy::collapsible_else_if)] | ||
fn receive_end_event(&mut self, dx: &f64, dy: &f64) { | ||
// Avoid acting if the displacement is below the threshold. | ||
if dx.abs() < self.threshold && dy.abs() < self.threshold { | ||
return; | ||
} | ||
|
||
// Determine the command for the event. | ||
let command: ActionEvents; | ||
if dx.abs() > dy.abs() { | ||
if dx > &0.0 { | ||
command = ActionEvents::ThreeFingerSwipeRight | ||
} else { | ||
command = ActionEvents::ThreeFingerSwipeLeft | ||
} | ||
} else { | ||
if dy > &0.0 { | ||
command = ActionEvents::ThreeFingerSwipeUp | ||
} else { | ||
command = ActionEvents::ThreeFingerSwipeDown | ||
} | ||
} | ||
|
||
// Invoke actions. | ||
match command { | ||
ActionEvents::ThreeFingerSwipeLeft => { | ||
for action in self.swipe_left.iter_mut() { | ||
action.execute_command(); | ||
} | ||
} | ||
ActionEvents::ThreeFingerSwipeRight => { | ||
for action in self.swipe_right.iter_mut() { | ||
action.execute_command(); | ||
} | ||
} | ||
ActionEvents::ThreeFingerSwipeUp => { | ||
for action in self.swipe_up.iter_mut() { | ||
action.execute_command(); | ||
} | ||
} | ||
ActionEvents::ThreeFingerSwipeDown => { | ||
for action in self.swipe_down.iter_mut() { | ||
action.execute_command(); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
//! Action for interacting with `i3`. | ||
|
||
use super::Action; | ||
use i3ipc::I3Connection; | ||
|
||
use std::cell::RefCell; | ||
use std::rc::Rc; | ||
|
||
pub struct I3Action { | ||
connection: Rc<RefCell<I3Connection>>, | ||
command: String, | ||
} | ||
|
||
impl Action for I3Action { | ||
fn execute_command(&mut self) { | ||
// Perform the command, if specified. | ||
// TODO: capture result. | ||
Rc::clone(&self.connection) | ||
.borrow_mut() | ||
.run_command(&self.command) | ||
.unwrap(); | ||
} | ||
} | ||
|
||
pub trait I3ActionExt { | ||
fn new(command: String, connection: Rc<RefCell<I3Connection>>) -> Self; | ||
} | ||
|
||
impl I3ActionExt for I3Action { | ||
fn new(command: String, connection: Rc<RefCell<I3Connection>>) -> Self { | ||
I3Action { | ||
connection, | ||
command, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
//! Traits for actions. | ||
//! | ||
//! Provides the interface for defining `Action`s that handle the different | ||
//! events. | ||
|
||
pub mod commandaction; | ||
pub mod controller; | ||
pub mod i3action; | ||
|
||
use super::{ActionChoices, ActionEvents, Opts}; | ||
use i3ipc::I3Connection; | ||
|
||
use std::cell::RefCell; | ||
use std::rc::Rc; | ||
|
||
/// Maps between events and actions. | ||
pub struct ActionMap { | ||
threshold: f64, | ||
connection: Option<Rc<RefCell<I3Connection>>>, | ||
swipe_left: Vec<Box<dyn Action>>, | ||
swipe_right: Vec<Box<dyn Action>>, | ||
swipe_up: Vec<Box<dyn Action>>, | ||
swipe_down: Vec<Box<dyn Action>>, | ||
} | ||
|
||
/// Controller that connects events and actions. | ||
pub trait ActionController { | ||
fn new(opts: &Opts) -> Self; | ||
|
||
/// Create the individual actions used by this controller. | ||
/// | ||
/// Parse the command line arguments and add the individual actions to | ||
/// the internal structures in this controller. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `self` - action controller. | ||
/// * `opts` - command line arguments. | ||
fn populate_actions(&mut self, opts: &Opts); | ||
|
||
/// Receive the end of swipe gesture event. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `self` - action controller. | ||
/// * `dx` - the current position in the `x` axis | ||
/// * `dy` - the current position in the `y` axis | ||
fn receive_end_event(&mut self, dx: &f64, dy: &f64); | ||
} | ||
|
||
/// Action handler for events. | ||
pub trait Action { | ||
/// Execute the command for this action. | ||
fn execute_command(&mut self); | ||
} | ||
|
||
/// Extended trait for action handler for events. | ||
pub trait ActionExt { | ||
/// Return a new action. | ||
fn new(command: String) -> Self; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
//! Components for interacting with `libinput`. | ||
|
||
use std::fs::{File, OpenOptions}; | ||
use std::os::unix::fs::OpenOptionsExt; | ||
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; | ||
use std::path::Path; | ||
|
||
use input::LibinputInterface; | ||
|
||
use libc::{O_RDONLY, O_RDWR, O_WRONLY}; | ||
|
||
/// Struct for libinput interface. | ||
pub struct Interface; | ||
|
||
impl LibinputInterface for Interface { | ||
#[allow(clippy::bad_bit_mask)] | ||
fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<RawFd, i32> { | ||
OpenOptions::new() | ||
.custom_flags(flags) | ||
.read((flags & O_RDONLY != 0) | (flags & O_RDWR != 0)) | ||
.write((flags & O_WRONLY != 0) | (flags & O_RDWR != 0)) | ||
.open(path) | ||
.map(|file| file.into_raw_fd()) | ||
.map_err(|err| err.raw_os_error().unwrap()) | ||
} | ||
|
||
fn close_restricted(&mut self, fd: RawFd) { | ||
unsafe { | ||
File::from_raw_fd(fd); | ||
} | ||
} | ||
} |
Oops, something went wrong.