From de3f88c83cafbeadff3a40525bf414481e30be97 Mon Sep 17 00:00:00 2001 From: Rico Tiongson Date: Tue, 21 Apr 2020 03:26:48 +0800 Subject: [PATCH] Add command line tools for configurations --- README.md | 213 ++++++++++----- comfortable-swipe | 254 +++++++++++++++--- comfortable-swipe-defines.cpp | 2 +- comfortable-swipe-gesture-swipe-xdokey.cpp | 76 +++--- comfortable-swipe-gesture-swipe-xdomouse.cpp | 116 ++++---- comfortable-swipe-gesture-swipe.cpp | 8 +- comfortable-swipe-main.cpp | 31 ++- compile | 12 + compile.sh | 9 - config/comfortable-swipe.conf | 42 +++ .../comfortable-swipe.desktop | 0 defaults.conf | 34 --- install | 6 +- tests/run_tests | 2 +- tests/test_swipe.sh | 4 +- 15 files changed, 541 insertions(+), 268 deletions(-) create mode 100755 compile delete mode 100755 compile.sh create mode 100644 config/comfortable-swipe.conf rename comfortable-swipe.desktop => config/comfortable-swipe.desktop (100%) delete mode 100644 defaults.conf diff --git a/README.md b/README.md index 0d795ec..56014a7 100644 --- a/README.md +++ b/README.md @@ -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: + autostart is ON + comfortable-swipe program is RUNNING + ``` -``` -gedit $(comfortable-swipe config) +## 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 ``` -| 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) | +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: diff --git a/comfortable-swipe b/comfortable-swipe index d3fa6e3..3b51a7c 100755 --- a/comfortable-swipe +++ b/comfortable-swipe @@ -28,7 +28,7 @@ Commands: restart restarts 3/4-finger gesture service - autostart [on|off|toggle|status|path] + autostart [] toggle to automatically run on startup automatically run on startup (toggleable) buffer @@ -37,7 +37,7 @@ Commands: help shows the help dialog - config + config [...] 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 + function get { + # helper function to print usage + function usage { + echo "Usage: $BASENAME config get " + 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 [...]" + } + # 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 + function set { + # helper function to print usage + function usage { + echo "Usage: $BASENAME config set [=] " + 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] []" >&2 exit 1 fi diff --git a/comfortable-swipe-defines.cpp b/comfortable-swipe-defines.cpp index b749632..1f99873 100644 --- a/comfortable-swipe-defines.cpp +++ b/comfortable-swipe-defines.cpp @@ -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 diff --git a/comfortable-swipe-gesture-swipe-xdokey.cpp b/comfortable-swipe-gesture-swipe-xdokey.cpp index fbcd2f2..16eb070 100644 --- a/comfortable-swipe-gesture-swipe-xdokey.cpp +++ b/comfortable-swipe-gesture-swipe-xdokey.cpp @@ -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. diff --git a/comfortable-swipe-gesture-swipe-xdomouse.cpp b/comfortable-swipe-gesture-swipe-xdomouse.cpp index b977a42..1b66759 100644 --- a/comfortable-swipe-gesture-swipe-xdomouse.cpp +++ b/comfortable-swipe-gesture-swipe-xdomouse.cpp @@ -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); - 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; +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(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); - 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; +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(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(); } diff --git a/comfortable-swipe-gesture-swipe.cpp b/comfortable-swipe-gesture-swipe.cpp index 08873fe..e688606 100644 --- a/comfortable-swipe-gesture-swipe.cpp +++ b/comfortable-swipe-gesture-swipe.cpp @@ -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 . #include // std::cout, std::endl #include // std::regex, std::regex_match, std::cmatch #include // std::stoi, std::stof - extern "C" { #include // 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 diff --git a/comfortable-swipe-main.cpp b/comfortable-swipe-main.cpp index 007418e..5c72665 100644 --- a/comfortable-swipe-main.cpp +++ b/comfortable-swipe-main.cpp @@ -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 - 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; diff --git a/compile b/compile new file mode 100755 index 0000000..8718da7 --- /dev/null +++ b/compile @@ -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\"" diff --git a/compile.sh b/compile.sh deleted file mode 100755 index d9a664d..0000000 --- a/compile.sh +++ /dev/null @@ -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\"" diff --git a/config/comfortable-swipe.conf b/config/comfortable-swipe.conf new file mode 100644 index 0000000..4b78b35 --- /dev/null +++ b/config/comfortable-swipe.conf @@ -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) diff --git a/comfortable-swipe.desktop b/config/comfortable-swipe.desktop similarity index 100% rename from comfortable-swipe.desktop rename to config/comfortable-swipe.desktop diff --git a/defaults.conf b/defaults.conf deleted file mode 100644 index dd34a87..0000000 --- a/defaults.conf +++ /dev/null @@ -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) diff --git a/install b/install index 0eecee0..6eb26ab 100755 --- a/install +++ b/install @@ -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 diff --git a/tests/run_tests b/tests/run_tests index aa27623..6ffd19a 100755 --- a/tests/run_tests +++ b/tests/run_tests @@ -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)" diff --git a/tests/test_swipe.sh b/tests/test_swipe.sh index 0d78429..978090b 100755 --- a/tests/test_swipe.sh +++ b/tests/test_swipe.sh @@ -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)" @@ -20,7 +20,7 @@ echo "threshold = 0.0" >> "$EMPTY_CONFIG" "$COMPILER" "$ROOT/comfortable-swipe-main.cpp" -o "$TEMPOUT" \ -DCOMFORTABLE_SWIPE_AUTOSTART="\"$ROOT/comfortable-swipe.desktop\"" \ -DCOMFORTABLE_SWIPE_CONFIG="\"$EMPTY_CONFIG\"" \ - || abort +|| abort chmod +x "$TEMPOUT" set +x