Add command line tools for configurations

This commit is contained in:
Rico Tiongson 2020-04-21 03:26:48 +08:00
parent ffe664c7d8
commit de3f88c83c
15 changed files with 541 additions and 268 deletions

215
README.md
View File

@ -3,10 +3,12 @@
[![comfortable-swipe version](https://img.shields.io/github/release/Hikari9/comfortable-swipe.svg?label=comfortable-swipe&color=orange)](https://github.com/Hikari9/comfortable-swipe/releases)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
> **_New in Version 1.1.0!_** Added mouse gestures, see [#mouse-gestures-experimental](#mouse-gestures-experimental)
Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures for Ubuntu 14.04 LTS and beyond. May work for other Linux distros that support `libinput`.
> **_New in Version 1.1.0_**: Added mouse gestures, see [#mouse-gestures-experimental](#mouse-gestures-experimental)
> **_New in Version 1.2.0_**: Autostart now switched ON by default
## Installation
1. Install git and g++
@ -18,7 +20,7 @@ Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures
1. Install libinput-tools and C libraries
```bash
sudo apt install libinput-tools libconfig-dev libxdo-dev
sudo apt install libinput-tools libconfuse-dev libxdo-dev
```
2. Clone this repository
@ -39,44 +41,93 @@ Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures
## How to Run
1. You'll need some group permissions to read touchpad input data. Run
```bash
sudo gpasswd -a $USER $(ls -l /dev/input/event* | awk '{print $4}' | head --line=1)
```
2. **_Important_**: After inputing your `sudo` password, log out then log back in
3. Run
sudo gpasswd -a "$USER" "$(ls -l /dev/input/event* | awk '{print $4}' | head --line=1)"
```
1. **_Important_**: After inputing your `sudo` password, log out then log back in
1. Run
```bash
comfortable-swipe start
```
4. _Optional_: Automatically run on startup
```
comfortable-swipe autostart
```
5. Check the status of your application by running
```
comfortable-swipe status
1. (Optional) Automatically run on startup
```bash
comfortable-swipe autostart on
```
## Swipe Configurations
1. You can check general program status
```basha
$> comfortable-swipe status
Comfortable swipe makes use of keyboard shortcuts for configurations. Edit by running:
```
gedit $(comfortable-swipe config)
autostart is ON
comfortable-swipe program is RUNNING
```
| Property | Description | Default Value | Default Behavior |
| --------- | :------------------------------------------: | -------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| left3 | 3-finger swipe left | ctrl+alt+Right | switch to right workspace |
| left4 | 4-finger swipe left | ctrl+alt+shift+Right | move window to right workspace |
| right3 | 3-finger swipe right | ctrl+alt+Left | switch to left workspace |
| right4 | 4-finger swipe right | ctrl+alt+shift+Left | move window to left workspace |
| up3 | 3-finger swipe up | ctrl+alt+Down | switch to bottom workspace |
| up4 | 4-finger swipe up | ctrl+alt+shift+Down | move window to bottom workspace |
| down3 | 3-finger swipe down | ctrl+alt+Up | switch to above workspace |
| down4 | 4-finger swipe down | ctrl+alt+shift+Up | move window to above workpace |
| threshold | mouse pixels to activate swipe | 0.0 | tweak this if you're having troubles with touchpad sensitivity (higher = less sensitive, values can be as large as 1000.0) |
| hold3 | holds a mouse button when 3 fingers are down | (none) | See [Mouse Gestures (Experimental)](#mouse-gestures-experimental) |
| hold4 | holds a mouse button when 4 fingers are down | (none) | See [Mouse Gestures (Experimental)](#mouse-gestures-experimental) |
## List of Commands
1. Run / stop the program
```
comfortable-swipe start
comfortable-swipe stop
comfortable-swipe restart
```
1. Show help / version
```
comfortable-swipe --help
comfortable-swipe --version
```
1. Show path to configuration file
```bash
comfortable-swipe config
```
1. Toggle autostart
```bash
comfortable-swipe autostart [on|off|toggle|status|path]
```
1. (Advanced) Run program buffer
```bash
comfortable-swipe buffer
```
## Configuring Swipe Gestures
The default configuration file is located at `~/.config/comfortable-swipe.conf`.
Comfortable swipe makes use of keyboard shortcuts to perform swipes through `xdotool`.
An example:
```bash
# File: ~/.config/comfortable-swipe.conf
left3 = ctrl+alt+Right
left4 = ctrl+alt+shift+Right
right3 = ctrl+alt+Left
right4 = ctrl+alt+shift+Left
up3 = ctrl+alt+Down
up4 = ctrl+alt+shift+Down
down3 = ctrl+alt+Up
down4 = ctrl+alt+shift+Up
threshold = 0.0
```
Edit configurations by running:
```
gedit ~/.config/comfortable-swipe.conf
```
After making changes, make sure to restart the program:
@ -84,6 +135,28 @@ After making changes, make sure to restart the program:
comfortable-swipe restart
```
> **Note**: For v1.1.0 below, the configuration file is located at
> `/usr/local/share/comfortable-swipe/comfortable-swipe.conf`
> **Note**: You can locate your configuration by running `comfortable-swipe config`
## Configuration Reference
| Key | Value | Examples |
| --------- | :------------------------------------------: | -------------------- |
| left3 | 3-finger swipe left | ctrl+alt+Right |
| left4 | 4-finger swipe left | ctrl+alt+shift+Right |
| right3 | 3-finger swipe right | ctrl+alt+Left |
| right4 | 4-finger swipe right | ctrl+alt+shift+Left |
| up3 | 3-finger swipe up | ctrl+alt+Down |
| up4 | 4-finger swipe up | ctrl+alt+shift+Down |
| down3 | 3-finger swipe down | ctrl+alt+Up |
| down4 | 4-finger swipe down | ctrl+alt+shift+Up |
| threshold | mouse movement pixels that trigger a swipe (can be as large as 1000.0) | 0.0, 240.0, 1000.0 |
| mouse3 | holds a mouse button when 3 fingers are down | button1 (see [Mouse Gestures](#mouse-gestures-experimental)) | |
| mouse4 | holds a mouse button when 4 fingers are down | button1 (see [Mouse Gestures](#mouse-gestures-experimental) |
Taken from `man xdotool`:
> Type a given keystroke. Examples being "alt+r", "Control_L+J",
@ -100,42 +173,52 @@ Taken from `man xdotool`:
Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a complete list of keycodes you can use.
**Keyboard Shortcuts**:
## Keyboard shortcuts
- Unity: https://cheatography.com/sapemeg/cheat-sheets/ubuntu-unity-16-04/
- GNOME: https://wiki.gnome.org/Design/OS/KeyboardShortcuts
- KDE: https://community.linuxmint.com/tutorial/view/47
- [Unity Keyboard Shortcuts](https://cheatography.com/sapemeg/cheat-sheets/ubuntu-unity-16-04/)
- [GNOME Keyboard Shortcuts](https://wiki.gnome.org/Design/OS/KeyboardShortcuts)
- [KDE Keyboard Shortcuts](https://community.linuxmint.com/tutorial/view/47)
## Swipe Gesture Templates
> **Note**: You can check which desktop you are using with `echo $DESKTOP_SESSION`.
1. Switching workspaces
## Example Configurations
This section includes some example configurations for `~/.config/comfortable-swipe.conf` which you can use for your swipe experience.
1. Switch workspace (horizontal)
```bash
# Unity, KDE
left3 = ctrl+alt+Right
right3 = ctrl+alt+Left
```
1. Switch workspace (vertical)
```
up3 = ctrl+alt+Down
down3 = ctrl+alt+Up
```
```bash
# GNOME
up3 = super+PgDown
down3 = super+PgUp
```
1. Move window to workspace
1. Move window to workspace (horizontal)
```bash
# Unity, KDE
left4 = ctrl+alt+shift+Right
right4 = ctrl+alt+shift+Left
```
1. Move window to workspace (vertical)
```bash
up4 = ctrl+alt+shift+Down
down4 = ctrl+alt+shift+Up
```
```bash
# GNOME
up4 = super+shift+PgDown
down4 = super+shift+PgUp
```
@ -143,7 +226,6 @@ Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a complete li
1. Move window to other monitor
```bash
# GNOME
left4 = super+shift+Right
right4 = super+shift+Left
```
@ -154,20 +236,17 @@ Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a complete li
up3 = super+s
```
1. Show desktop ([setup manually](https://www.itsupportguides.com/knowledge-base/ubuntu/ubuntu-how-to-make-windows-d-show-desktop/))
1. Show desktop
```bash
# Ubuntu
down3 = ctrl+super+d
```
```bash
# GNOME
down3 = super+d
```
```bash
# KDE
down3 = ctrl+super+d
```
```bash
down3 = ctrl+alt+d
```
@ -199,22 +278,26 @@ Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a complete li
## Mouse Gestures (Experimental)
You can also play around with mouse gestures during swipe.
This enables certain mouse behaviour to trigger along with a 3/4-finger swipe.
Keys:
* mouse3 - for 3-finger mouse gestures
* mouse4 - for 4-finger mosue gestures
* hold3 (deprecated) - old equivalent of mouse3
* hold4 (deprecated) - old equivalent of mouse4
We have included simple mouse gestures on swipe by setting `hold3` and `hold4`.
```bash
Possible Values (hold3, hold4):
move # just move the mouse cursor (no mousedown)
button1 # hold left click on finger swipe
button2 # hold middle click on finger swipe
button3 # hold right click on finger swipe
button4 # wheel up on finger swipe (experimental)
button5 # wheel down on finger swipe (experimental)
scroll # naive 3/4 finger natural scroll (no acceleration, very experimental)
scroll_reverse # naive 3/4 finger reverse scroll (no acceleration, very experimental)
```
Any value not mentioned above disables the mouse-hold.
Possible Values:
* button1 - hold left click on finger swipe
* button2 - hold middle click on finger swipe
* button3 - hold right click on finger swipe
* button4 - wheel up on finger swipe (experimental)
* button5 - wheel down on finger swipe (experimental)
* move - just move the mouse cursor with the fingers
* scroll - 3/4 finger natural scroll (no acceleration, very experimental)
* scroll_reverse - 3/4 finger reverse scroll (no acceleration, very experimental)
Examples:

View File

@ -28,7 +28,7 @@ Commands:
restart
restarts 3/4-finger gesture service
autostart [on|off|toggle|status|path]
autostart [<on|off|toggle|status|path>]
toggle to automatically run on startup automatically run on startup (toggleable)
buffer
@ -37,7 +37,7 @@ Commands:
help
shows the help dialog
config
config [<get|set|delete|list|keys|path>...]
shows the location of the config file
debug
@ -60,41 +60,20 @@ function start {
# stop running comfortable-swipe commands (except self)
function stop {
local pids="$(pgrep -f comfortable-swipe | fgrep -v $$)"
local stopped=""
for pid in "$pids"; do
# stop process tree
if kill -- -$pid 2> /dev/null; then
stopped=" $(echo $pid)"
fi
done
if [[ ! -z "$stopped" ]]; then
echo "comfortable-swipe stopped"
else
echo "comfortable-swipe is not running"
fi
function stop_name {
pgrep -f "${1:?}" | fgrep -v $$ | xargs kill --
}
stop_name "$BASENAME"
stop_name "$(which comfortable-swipe)"
stop_name "$(which comfortable-swipe-buffer)"
}
# restart comfortable swipe
function restart {
stop > /dev/null 2>&1
start
}
# parse input from a buffer
# internally calls comfortable-swipe-main.cpp, which is
# installed as: comfortable-swipe-buffer
function buffer {
exec comfortable-swipe-buffer "$@"
}
# get location of configuration file
function config {
# TODO: invoke subcommands
echo "$HOME/.config/comfortable-swipe.conf"
# restart the server in the background
nohup "$BASENAME" start 0<&- &>/dev/null &
}
@ -110,9 +89,204 @@ function debug {
}
# parse input from a buffer
# internally calls comfortable-swipe-main.cpp, which is
# installed as: /usr/local/bin/ comfortable-swipe-buffer
function buffer {
exec comfortable-swipe-buffer "$@"
}
# get location of configuration file
function config {
local CONFIG="$HOME/.config/comfortable-swipe.conf"
local KEYS="left3|left4|right3|right4|up3|up4|down3|down4|threshold|mouse3|mouse4"
local DEPRECATED="hold3|hold4"
local USAGE="Usage: $BASENAME config [get|set|delete|list|keys|path]..."
# show path to config
function path {
echo "$CONFIG"
}
# get all keys from config, without comments
# and show only last among duplicates
function list {
# dispatch subcommands
if [[ $# -eq 0 ]]; then
# no options; just show path
tac "$CONFIG" |\
sed -E "s/[#;].*//g" |\
egrep '\s+' |\
tr -d ' ' |\
egrep "^($KEYS|$DEPRECATED)=" |\
awk '!a[$1]++' |\
tac |\
sed 's/=/ = /g'
else
# filter list to match arguments as pattern
local pattern="$1"
for arg in "${@:2}"; do
pattern="$pattern|$arg"
done
list | egrep "($pattern)[^=]* ="
fi
}
# get a list of all valid keys, one per line
function keys {
echo "$KEYS" | sed 's/|/\n/g'
}
# Get a specific key in the config
# Usage: comfortable-swipe config get <key>
function get {
# helper function to print usage
function usage {
echo "Usage: $BASENAME config get <KEY>"
echo -n "Keys: "
echo "$KEYS" | sed 's/|/, /g'
}
# no next argument: show list
if [[ $# -eq 0 ]]; then
list
exit $?
fi
local KEY="$1"
# check if key is valid
if ! [[ "$KEY" =~ ^($KEYS|$DEPRECATED)$ ]]; then
echo "'$KEY' is an invalid key" >&2
echo >&2
usage >&2
echo >&2
echo "If you want to filter keys, you can instead try:" >&2
echo >&2
echo " $BASENAME config list $@"
echo >&2
exit 1
fi
# get key from config file
list | fgrep -m1 "$KEY =" | sed -E "s/^$KEY = //"
}
# Deletes a key in the config
function delete {
# helper function to print usage
function usage {
echo "Usage: $BASENAME config delete [<KEYS>...]"
}
# no next argument: show help
if [[ $# -eq 0 ]]; then
echo "Key is required!" >&2
# no key; show usage
usage >&2
exit 1
fi
local DELETE="$(list "$@")"
# check if there is something to delete
if [[ -z "$DELETE" ]]; then
echo "No config entry to delete" >&2
exit 1
else
echo "Deleted:"
echo "$DELETE"
local RESULT="$(egrep -v "^\\s*($(echo "$DELETE" | awk '{print $1}' | paste -s -d '|'))\\s*=" "$CONFIG")"
echo "$RESULT" > "$CONFIG"
# restart comfortable-swipe
restart
fi
}
# Set a specific key in the config
# Usage: comfortable-swipe config get <key>
function set {
# helper function to print usage
function usage {
echo "Usage: $BASENAME config set <KEY> [=] <VALUE>"
echo -n "Valid keys: "
echo "$KEYS" | sed 's/|/, /g'
}
# no next argument: show help
if [[ $# -eq 0 ]]; then
echo "Key is required!" >&2
echo >&2
# no key; show usage
usage >&2
exit 1
fi
# parse key and value option
local KEYVALUE="${@:1}"
local KEY=
local VALUE=
case "$KEYVALUE" in
*=*)
# key has equal sign, we split it
KEY="${KEYVALUE%%=*}"
VALUE="${KEYVALUE#*=}"
;;
*)
# default: just get from next arguments combined
if [[ $# -eq 1 ]]; then
echo "Value is required!" >&2
usage >&2
echo >&2
echo "If you want to set value to blank, explicitly pass a blank string:" >&2
echo >&2
echo " $BASENAME config set $@ \"\"" >&2
echo >&2
echo "Or delete explicitly:" >&2
echo >&2
echo " $BASENAME config delete $1"
echo >&2
exit 1
fi
KEY="$1"
VALUE="${@:2}"
;;
esac
# trim leading and trailing spaces from key and value
KEY="$(echo "$KEY" | awk '{$1=$1};1')"
VALUE="$(echo "$VALUE" | awk '{$1=$1};1')"
# check if key is valid
if ! [[ "$KEY" =~ ^($KEYS|$DEPRECATED)$ ]]; then
echo "'$KEY' is an invalid key" >&2
echo >&2
usage
exit 1
fi
# if the key is present in the config, perform a replace
# replace the last value from the config with the given key
if list | grep -P "^\Q$KEY =" > /dev/null 2>&1; then
# apply sed to keep our formatting
# \\1 - keep any kind of indentation
# \\2 - keep any comments after the value (with the whitespace instact)
local RESULT="$(tac "$CONFIG" |\
sed -E "s/^(\\s*)$KEY\\s*=\\s*(\?!(\\s*[#;]))*(.*)\$/\\1$KEY = $VALUE\\2/1" |\
tac)"
# make sure we separate piping from outputing
echo "$RESULT" > "$CONFIG"
else
# otherwise, key is not present so we simply append
echo "$KEY = $VALUE" >> "$CONFIG"
fi
# show newly set value
echo "$KEY = $(get "$KEY")"
restart
}
# dispatch subcommands
if [[ $# -eq 0 ]]; then
# no options; just show path
path
elif declare -f "$1" >/dev/null 2>&1; then
# invoke subcommand function, passing arguments through
# TODO: unset all nonlocal functions
"$@" # same as "$1" "$2" "$3" ... for full argument list
else
echo "Error: function $1 not recognized" >&2
echo "$USAGE" >&2
exit 1
fi
}
# enable or disable autostart
# you can also set manually by running: gnome-session-properties
function autostart {
# path to autostart files
local AUTOSTART="$HOME/.config/autostart/comfortable-swipe.desktop"
local ENABLED="X-GNOME-Autostart-enabled"
# show autostart file path
@ -145,15 +319,17 @@ function autostart {
function toggle {
[[ $(status) = ON ]] && off || on
}
# dispatch subcommands
if [[ $# -eq 0 ]]; then
# default behavior is to toggle
toggle
elif declare -f "$1" >/dev/null 2>&1; then
# invoke subcommand function, passing arguments through
# TODO: unset all nonlocal functions
"$@" # same as "$1" "$2" "$3" ... for full argument list
else
echo "Function $1 not recognized" >&2
echo "Usage: comfortable-swipe autostart [on|off|toggle|status|path]" >&2
echo "Usage: $BASENAME autostart [on|off|toggle|status|path]" >&2
exit 1
fi
}
@ -162,8 +338,8 @@ function autostart {
# verbosely show comfortable-swipe status
function status {
# TODO: show configuration status as well
echo "autostart is $(autostart status)"
if pgrep -f comfortable-swipe | fgrep -v $$ > /dev/null 2>&1; then
echo "Autostart is $("$BASENAME" autostart status)"
if pgrep -f "$BASENAME" | fgrep -v $$ > /dev/null 2>&1; then
echo "comfortable-swipe program is RUNNING"
else
echo "comfortable-swipe program is STOPPED"
@ -193,18 +369,16 @@ case $i in
esac
done
############
# DISPATCH #
############
# dispatch subcommands
if [[ $# -eq 0 ]]; then
# no options; just show help
help
elif declare -f "$1" >/dev/null 2>&1; then
# invoke subcommand function, passing arguments through
# TODO: unset all nonlocal functions
"$@" # same as "$1" "$2" "$3" ... for full argument list
else
echo "error: function $1 not recognized" >&2
echo "full usage: comfortable-swipe --help" >&2
echo "Error: function $1 not recognized" >&2
echo "Usage: $BASENAME [--help|--version] [start|stop|restart|config|autostart|buffer|debug|status] [<args>]" >&2
exit 1
fi

View File

@ -1,6 +1,6 @@
#ifndef __comfortable_swipe_defines__
#define __comfortable_swipe_defines__
/** All global #define statements go here */
// all global #define statements go here
/*
Comfortable Swipe
by Rico Tiongson

View File

@ -54,12 +54,20 @@ public:
virtual void end() override;
// override this when keyboard gesture is to be performed
virtual void do_keyboard_gesture(int mask);
// public accessors
virtual int get_previous_gesture() const {
return this->previous_gesture;
}
virtual int get_current_mask() const {
return this->current_mask;
}
protected:
// stores square of threshold so we can compute faster
float threshold_squared;
// stores previous gesture so we don't repeat action
int previous_gesture;
int current_mask;
public:
// static enums we will use for gesture matching
@ -104,8 +112,12 @@ decltype(
*/
gesture_swipe_xdokey::gesture_swipe_xdokey(
const decltype(gesture_swipe_xdokey::commands) &commands, float threshold)
: gesture_swipe(), commands(commands),
threshold_squared(threshold * threshold) {}
: gesture_swipe(),
commands(commands),
threshold_squared(threshold * threshold),
previous_gesture(gesture_swipe_xdokey::FRESH),
current_mask(gesture_swipe_xdokey::FRESH)
{}
/**
* Destructs this keyboard swipe gesture.
*/
@ -116,8 +128,9 @@ gesture_swipe_xdokey::~gesture_swipe_xdokey() {}
void gesture_swipe_xdokey::begin() {
// call superclass method
gesture_swipe::begin();
// assign previous gesture to FRESH
this->previous_gesture = gesture_swipe_xdokey::FRESH;
// assign gesture to FRESH
current_mask = FRESH;
previous_gesture = FRESH;
}
/**
* Hook on update of swipe gesture.
@ -125,60 +138,59 @@ void gesture_swipe_xdokey::begin() {
void gesture_swipe_xdokey::update() {
// call superclass method
gesture_swipe::update();
// scale threshold to 1/10 when gesture is not fresh
float scale = 1;
if (this->previous_gesture == gesture_swipe_xdokey::FRESH)
scale = 0.01f; // square root of 1/10
// scale threshold to 1/10 when gesture is fresh
// acts like our static friction coefficient
float scale = get_previous_gesture() == FRESH ? 0.01f : 1.0f;
// we are working with floating points which are not exact
// make sure we compare with a very small value (epsilon)
static const float EPSILON = 1e-6f;
const float distance_squared = this->x * this->x + this->y * this->y;
const float beyond_threshold = this->threshold_squared * scale;
// make sure we compare with a very small value (1e-6f)
// if distance goes out of threshold, perform our swipe
if (distance_squared > beyond_threshold + EPSILON) {
if (x * x + y * y > threshold_squared * scale + 1e-6f) {
// we parse our mask based on the values obtained from the regex
int mask = 0;
if (this->fingers == 3)
mask |= gesture_swipe_xdokey::MSK_THREE_FINGERS;
else if (this->fingers == 4)
mask |= gesture_swipe_xdokey::MSK_FOUR_FINGERS;
if (fingers == 3)
mask |= MSK_THREE_FINGERS;
else if (fingers == 4)
mask |= MSK_FOUR_FINGERS;
const float absx = x >= 0 ? x : -x;
const float absy = y >= 0 ? y : -y;
if (absx > absy) {
// gesture is horizontal
mask |= gesture_swipe_xdokey::MSK_HORIZONTAL;
mask |= MSK_HORIZONTAL;
if (x < 0)
mask |= gesture_swipe_xdokey::MSK_NEGATIVE;
mask |= MSK_NEGATIVE;
else
mask |= gesture_swipe_xdokey::MSK_POSITIVE;
mask |= MSK_POSITIVE;
} else /* std::abs(x) <= std::abs(y) */
{
// gesture is vertical
mask |= gesture_swipe_xdokey::MSK_VERTICAL;
mask |= MSK_VERTICAL;
if (y < 0)
mask |= gesture_swipe_xdokey::MSK_NEGATIVE;
mask |= MSK_NEGATIVE;
else
mask |= gesture_swipe_xdokey::MSK_POSITIVE;
mask |= MSK_POSITIVE;
}
// update our mask
current_mask = mask;
// send command on fresh OR opposite gesture
if (this->previous_gesture == gesture_swipe_xdokey::FRESH ||
this->previous_gesture == (mask ^ gesture_swipe_xdokey::MSK_POSITIVE)) {
// finally, perform keyboard gesture
this->do_keyboard_gesture(mask);
if (previous_gesture == FRESH || previous_gesture == (mask ^ MSK_POSITIVE)) {
// do keyboard gesture
do_keyboard_gesture(mask);
// reset our location variables
x = y = 0;
previous_gesture = mask;
}
}
else { // not in threshold, set mask to fresh
current_mask = FRESH;
}
}
/**
* Perform our maske command to xdo.
*/
void gesture_swipe_xdokey::do_keyboard_gesture(int mask) {
// perform our keyboard command with xdo_send_keysequence
xdo_send_keysequence_window(this->xdo, CURRENTWINDOW, commands[mask].data(),
0);
xdo_send_keysequence_window(xdo, CURRENTWINDOW, commands[mask].data(), 0);
std::cout << "SWIPE " << command_name[mask] << std::endl;
// reset our location variables
this->x = this->y = 0;
this->previous_gesture = mask;
}
/**
* Hook on end of swipe gesture.

View File

@ -67,8 +67,8 @@ public:
// the button number being clicked
int button;
// constructor
gesture_swipe_xdomouse(const char *hold3, // 3 finger mouse down
const char *hold4 // 4 finger mouse down
gesture_swipe_xdomouse(const char *mouse3, // 3 finger mouse gesture
const char *mouse4 // 4 finger mouse gesture
);
// destructor
virtual ~gesture_swipe_xdomouse();
@ -77,39 +77,27 @@ public:
virtual void update() override;
virtual void end() override;
// provide our own mouse dispatch functions
virtual void do_mousedown(const char *);
virtual void do_mouseup(const char *);
// utility method to check if mouse is being held
virtual bool is_holding() const;
virtual void do_mousedown(int button, int fingers);
virtual void do_mouseup(int button, int fingers);
// utility method to parse mouse input given config characters
static int parse_mouse_button(const char *);
protected:
// command holders
const char *hold3;
const char *hold4;
const char *mouse3;
const char *mouse4;
private:
// flag we can use to check if mouse is down
bool flag_is_holding;
};
/**
* Constructs a new mouse gesture, given "hold3" and "hold4" configurations.
* Constructs a new mouse gesture, given "mouse3" and "mouse4" configurations.
*/
gesture_swipe_xdomouse::gesture_swipe_xdomouse(const char *hold3,
const char *hold4)
: gesture_swipe(), button(MOUSE_NONE), hold3(hold3), hold4(hold4),
flag_is_holding(false) {}
gesture_swipe_xdomouse::gesture_swipe_xdomouse(const char *mouse3,
const char *mouse4)
: gesture_swipe(), button(MOUSE_NONE), mouse3(mouse3), mouse4(mouse4) {}
/**
* Destructs this mouse swipe gesture.
*/
gesture_swipe_xdomouse::~gesture_swipe_xdomouse() {}
/**
* Determines if some mousehold command is being run.
*/
bool gesture_swipe_xdomouse::is_holding() const {
return this->flag_is_holding;
}
/**
* Utility method to parse mouse number from input.
* Returns MOUSE_NONE on failure.
@ -132,32 +120,21 @@ int gesture_swipe_xdomouse::parse_mouse_button(const char *input) {
return MOUSE_NONE;
}
/**
* Perform mousedown command on hold input.
* Run mousedown command on a mouse button input.
*/
void gesture_swipe_xdomouse::do_mousedown(const char *input) {
const int button = this->button = this->parse_mouse_button(input);
if (button != MOUSE_NONE) {
// eg. MOUSE DOWN hold3 mouse1
std::printf("MOUSE DOWN hold%d %s\n", this->fingers, input);
void gesture_swipe_xdomouse::do_mousedown(int button, int fingers) {
if (MOUSE_LEFT_CLICK <= button && button <= MOUSE_RIGHT_CLICK) {
// send mouse down on associated button
xdo_mouse_down(this->xdo, CURRENTWINDOW, button);
}
this->flag_is_holding = true;
xdo_mouse_down(xdo, CURRENTWINDOW, button);
}
}
/**
* Run mouseup command on hold output.
* Run mouseup command on a mouse button output.
*/
void gesture_swipe_xdomouse::do_mouseup(const char *input) {
const int button = this->button = this->parse_mouse_button(input);
if (button != MOUSE_NONE) {
std::printf("MOUSE UP hold%d %s\n", this->fingers, input);
void gesture_swipe_xdomouse::do_mouseup(int button, int fingers) {
if (MOUSE_LEFT_CLICK <= button && button <= MOUSE_RIGHT_CLICK) {
// send mouse up on associated button
xdo_mouse_up(this->xdo, CURRENTWINDOW, button);
}
this->flag_is_holding = false;
xdo_mouse_up(xdo, CURRENTWINDOW, button);
}
}
/**
@ -166,11 +143,16 @@ void gesture_swipe_xdomouse::do_mouseup(const char *input) {
void gesture_swipe_xdomouse::begin() {
// call superclass method
gesture_swipe::begin();
// dispatch mouse down event
if (this->fingers == 3) {
this->do_mousedown(this->hold3);
} else if (this->fingers == 4) {
this->do_mousedown(this->hold4);
// map fingers to gesture command
auto command = fingers == 3 ? mouse3 : (fingers == 4 ? mouse4 : NULL);
if (command != NULL) {
// get button int from the command
button = parse_mouse_button(command);
// perform mousedown on the button and print to console
if (button != MOUSE_NONE) {
do_mousedown(button, fingers);
std::printf("MOUSE DOWN mouse%d %s\n", this->fingers, command);
}
}
}
/**
@ -179,26 +161,25 @@ void gesture_swipe_xdomouse::begin() {
void gesture_swipe_xdomouse::update() {
// call superclass method
gesture_swipe::update();
if (this->is_holding()) {
if (button != MOUSE_NONE) {
// if MOUSE_MOVE or MOUSE_CLICK*
if (0 <= this->button && this->button <= 3) {
if (0 <= button && button <= 3) {
// drag mouse with pointer during update
xdo_move_mouse_relative(this->xdo, this->udx, this->udy);
} else if (this->button == MOUSE_SCROLL ||
this->button == MOUSE_SCROLL_REVERSE) {
xdo_move_mouse_relative(xdo, udx, udy);
} else if (button == MOUSE_SCROLL ||
button == MOUSE_SCROLL_REVERSE) {
// perform naive scroll depending on vertical direction
int wheel = MOUSE_WHEEL_DOWN;
if ((this->udy > 0) == (this->button == MOUSE_SCROLL))
if ((udy > 0) == (button == MOUSE_SCROLL))
wheel = MOUSE_WHEEL_UP;
// click wheel on update (note: this is not precise)
xdo_mouse_down(this->xdo, CURRENTWINDOW, wheel);
xdo_mouse_up(this->xdo, CURRENTWINDOW, wheel);
} else if (this->button == MOUSE_WHEEL_UP ||
this->button == MOUSE_WHEEL_DOWN) {
xdo_mouse_down(xdo, CURRENTWINDOW, wheel);
xdo_mouse_up(xdo, CURRENTWINDOW, wheel);
} else if (button == MOUSE_WHEEL_UP ||
button == MOUSE_WHEEL_DOWN) {
// click wheel button on 4 or 5
xdo_mouse_down(this->xdo, CURRENTWINDOW, this->button);
xdo_mouse_up(this->xdo, CURRENTWINDOW, this->button);
xdo_mouse_down(xdo, CURRENTWINDOW, button);
xdo_mouse_up(xdo, CURRENTWINDOW, button);
}
}
}
@ -207,13 +188,14 @@ void gesture_swipe_xdomouse::update() {
*/
void gesture_swipe_xdomouse::end() {
// optimization: only perform mouseup when flag is set
if (this->is_holding()) {
if (this->fingers == 3) {
this->do_mouseup(this->hold3);
} else if (this->fingers == 4) {
this->do_mouseup(this->hold4);
}
if (button != MOUSE_NONE) {
// map fingers to gesture command
// perform mouseup on the button and print to console
do_mouseup(button, fingers);
std::printf("MOUSE UP mouse%d %s\n", fingers, fingers == 3 ? mouse3 : mouse4);
}
// reset button
button = MOUSE_NONE;
// call superclass method
gesture_swipe::end();
}

View File

@ -3,7 +3,7 @@
/**
* File: comfortable-swipe-gesture-swipe.cpp
*
* The definition of the class comfortable_swipe::gesture_swipe.
* This is the base class of all comfortable swipe gestures.
*
* The class `comfortable_swipe::gesture_swipe` handles dispatching
* of swipe gestures. The method `gesture_swipe::run(const char*)`
@ -41,13 +41,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <iostream> // std::cout, std::endl
#include <regex> // std::regex, std::regex_match, std::cmatch
#include <string> // std::stoi, std::stof
extern "C" {
#include <xdo.h> // xdo, xdo_new, xdo_free,
// xdo_get_mouse_location
// CURRENT_WINDOW
}
namespace comfortable_swipe {
/**
* Handles swipe gesture input from libinput debug-events.
@ -70,6 +68,10 @@ public:
virtual void update();
virtual void end();
virtual bool run(const char *);
// public check if currently swiping
virtual bool is_swiping() const {
return this->flag_swiping;
}
protected:
// xdo container

View File

@ -83,20 +83,29 @@ int main() {
// initialize mouse hold gesture handler
// for now, this supports 3-finger and 4-finger hold
// Examples:
// hold3=move move mouse on 3 fingers
// hold3=button1 hold button 1 on 3 fingers
// hold4=button3 hold button 3 (right click) on 3 fingers
// hold3=ignore <do nothing>
gesture_swipe_xdomouse mousehold(config["hold3"].data(),
config["hold4"].data());
// mouse3=move move mouse on 3 fingers
// mouse3=button1 hold button 1 on 3 fingers
// mouse4=button3 hold button 3 (right click) on 3 fingers
// warn user that hold3 is deprecated
if (config.count("hold3"))
std::cerr << "WARNING: hold3 is deprecated. Use mouse3 instead." << std:: endl;
if (config.count("hold4"))
std::cerr << "WARNING: hold4 is deprecated. Use mouse4 instead." << std::endl;
// get input values
string mouse3 = config.count("mouse3") ? config["mouse3"] : config["hold3"];
string mouse4 = config.count("mouse4") ? config["mouse4"] : config["hold4"];
// create our mouse gesture holder
gesture_swipe_xdomouse mousehold(mouse3.data(), mouse4.data());
// start reading lines from input one by one
for (string line; getline(cin, line);) {
// prioritize mouse hold gesture first before keyboard gesture
mousehold.run(line.data());
// if mouse hold fails, try keyboard swipe
// attempt to parse keyboard gestures
if (!mousehold.is_holding()) {
// optimization: if no mouse config is set, just run keyboard
if (mousehold.is_swiping() && mousehold.button == MOUSE_NONE) {
keyswipe.run(line.data());
} else if (mousehold.run(line.data())) {
// only allow keyswipe gestures on mouse move
if (mousehold.button == MOUSE_MOVE) {
keyswipe.run(line.data());
}
}
}
return EXIT_SUCCESS;

12
compile Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
# usage: ./compile *.cpp
set -e
DIR="$(dirname $0)"
VERSION="$(cat "$DIR/VERSION" | tr -d '[:space:]')"
CXX='g++'
CXX_FLAGS='-std=c++14 -O2 -Wall -lxdo -linih -lxdo -linih'
g++ "$@" ${CXX_FLAGS} -DCOMFORTABLE_SWIPE_VERSION="\"$VERSION\""

View File

@ -1,9 +0,0 @@
#!/bin/bash
# main compile script
# usage: ./compile.sh *.cpp
set -e
DIR="$(dirname $0)"
VERSION="$(cat "$DIR/VERSION" | tr -d '[:space:]')"
g++ "$@" -std=c++14 -O2 -Wall -lxdo -linih -DCOMFORTABLE_SWIPE_VERSION="\"$VERSION\""

View File

@ -0,0 +1,42 @@
# Comfortable Swipe
#
# Feel free to edit this configuration file if you have different
# keyboard shortcuts that you would like to use. Comments starting
# with a pound (#) or semi-colon (;) are ignored.
#
# Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for
# a list of keycodes you can use.
left3 = ctrl+alt+Right
left4 = ctrl+alt+shift+Right
right3 = ctrl+alt+Left
right4 = ctrl+alt+shift+Left
up3 = ctrl+alt+Down
up4 = ctrl+alt+shift+Down
down3 = ctrl+alt+Up
down4 = ctrl+alt+shift+Up
# Tweak threshold depending on the sensitivity of your touchpad.
# Make this higher to lessen sensitivity.
# (note: values have no limit, can be as large as 1000.0)
threshold = 0.0
# Uncomment below to enable mouse gestures (3 fingers)
; mouse3 = button1 # drag left click
; mouse3 = button2 # drag middle click
; mouse3 = button3 # drag right click
; mouse3 = button4 # drag wheel up
; mouse3 = button5 # drag wheel down
; mouse3 = move # just move mouse along with the cursor
; mouse3 = scroll # natural scroll (experimental)
; mouse3 = scroll_reverse # reverse scroll (experimental)
# Uncomment below to enable mouse gestures (4 fingers)
; mouse4 = button1 # drag left click
; mouse4 = button2 # drag middle click
; mouse4 = button3 # drag right click
; mouse4 = button4 # drag wheel up
; mouse4 = button5 # drag wheel down
; mouse4 = move # just move mouse along with the cursor
; mouse4 = scroll # natural scroll (experimental)
; mouse4 = scroll_reverse # reverse scroll (experimental)

View File

@ -1,34 +0,0 @@
# Comfortable Swipe converts touchpad swipe gestures to keyboard commands. You
# may edit this configuration file if you have different keyboard shortcuts
# that you would like to use. You can ignore a gesture by commenting out with
# a pound(#) symbol.
#
# Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a list of
# keycodes you can use.
left3 = ctrl+alt+Right
left4 = ctrl+alt+shift+Right
right3 = ctrl+alt+Left
right4 = ctrl+alt+shift+Left
up3 = ctrl+alt+Down
up4 = ctrl+alt+shift+Down
down3 = ctrl+alt+Up
down4 = ctrl+alt+shift+Up
# Tweak this value depending on the sensitivity of your mousepad to perform
# gestures. A higher value means less sensitive.
# Note: Sky is the limit! Can be as large as 1000.0
threshold = 0.0
# Uncomment below for mousedown
; hold3 = button1
; hold4 = button1
# Values: button1 (left click)
# button2 (middle click)
# button3 (right click),
# button4 (wheel up)
# button5 (wheel down),
# move (just move with cursor)
# scroll (natural scrolling)
# scroll_reverse (reversed scrolling)

View File

@ -10,17 +10,17 @@ SOURCE="$DIR/comfortable-swipe"
TARGET="/usr/local/bin/comfortable-swipe"
# compile targets
COMPILE="$DIR/compile.sh"
COMPILE="$DIR/compile"
COMPILE_SOURCE="$DIR/comfortable-swipe-main.cpp"
COMPILE_TARGET="/usr/local/bin/comfortable-swipe-buffer"
# configurations
CONF_SOURCE="$DIR/defaults.conf"
CONF_SOURCE="$DIR/config/comfortable-swipe.conf"
CONF_TARGET="$HOME/.config/comfortable-swipe.conf"
OLD_CONF_TARGET="/usr/local/share/comfortable-swipe/comfortable-swipe.conf"
# autostart
AUTOSTART_SOURCE="$DIR/comfortable-swipe.desktop"
AUTOSTART_SOURCE="$DIR/config/comfortable-swipe.desktop"
AUTOSTART_TARGET="$HOME/.config/autostart/comfortable-swipe.desktop"
# stop any running comfortable-swipe if it exists

View File

@ -3,7 +3,7 @@
set -e
DIR="$(dirname "$0")"
COMPILER="$(dirname "$DIR")/compile.sh"
COMPILER="$(dirname "$DIR")/compile"
# just call abort on error
TEMPOUT="$(mktemp)"

View File

@ -4,7 +4,7 @@ set -ex
DIR="$(dirname "$0")"
ROOT="$(dirname "$DIR")"
COMPILER="$ROOT/compile.sh"
COMPILER="$ROOT/compile"
# just call abort on error
TEMPOUT="$(mktemp)"