From 33c737177a67b216eaa29b304eb9af6fb5478239 Mon Sep 17 00:00:00 2001 From: Alex Zaslavsky Date: Sun, 27 Oct 2019 19:14:50 +0200 Subject: [PATCH 1/3] - Added pinch gestures Basic implementation enables one shot pinch gesture. That is the command from config file will run only once as soon as fingers move 50% from the initial fingers position. - Added a configurable distance variable to pinch gesture. I felt that pinch gesture is kinda tricky to execute on touchpad, so I changed a way of calculation when to trigger the command and added the distance for fingers travel to configuration. Basically a `0.5` distance feels quite ok to me, but it becomes really snappy at `0.1`. --- README.md | 20 ++++++++++++- src/config/config.cpp | 10 +++++-- src/config/config.h | 10 +++++-- src/io/input.cpp | 70 +++++++++++++++++++++++++++++++++++++------ src/io/input.h | 23 ++++++++++++-- 5 files changed, 114 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index bb51f9e..741395f 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,17 @@ right_down = "" down = "" left = "" right = "" + +[commands.pinch] +in = "" +out = "" +distance="" ``` +* `distance` variable in `commands.pinch` sets the distance between fingers where it shold trigger. + Defaults to `0.5` which means fingers should travel exactly half way from their initial position. + + ### Repository versions ![](https://img.shields.io/aur/version/gebaar.svg?style=flat) @@ -77,6 +86,7 @@ down = "bspc node -f south" left = "bspc node -f west" right = "bspc node -f east" + [commands.swipe.four] left_up = "" right_up = "" @@ -86,6 +96,11 @@ right_down = "" down = "" left = "bspc desktop -f prev" right = "bspc desktop -f next" + +[commands.pinch] +in = "xdotool key Control_L+equal" +out = "xdotool key Control_L+minus" +ditance="0.1" ``` Add `gebaard -b` to `~/.config/bspwm/bspwmrc` @@ -93,9 +108,12 @@ Add `gebaard -b` to `~/.config/bspwm/bspwmrc` ### State of the project - [x] Receiving swipe events from libinput -- [ ] Receiving pinch/zoom events from libinput +- [x] Receiving pinch/zoom events from libinput + - [ ] Support continous pinch + - [ ] Support pinch-and-rotate gestures - [ ] Receiving rotation events from libinput - [x] Converting libinput events to motions - [x] Running commands based on motions - [x] Refactor code to be up to Release standards, instead of testing-hell + diff --git a/src/config/config.cpp b/src/config/config.cpp index bafa3c6..d13dcef 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,17 +1,17 @@ /* gebaar Copyright (C) 2019 coffee2code - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -61,6 +61,10 @@ void gebaar::config::Config::load_config() swipe_four_commands[8] = *config->get_qualified_as("commands.swipe.four.down"); swipe_four_commands[9] = *config->get_qualified_as("commands.swipe.four.right_down"); + pinch_commands[PINCH_IN] = *config->get_qualified_as("commands.pinch.out"); + pinch_commands[PINCH_OUT] = *config->get_qualified_as("commands.pinch.in"); + pinch_commands[DISTANCE] = *config->get_qualified_as("commands.pinch.distance"); + loaded = true; } } diff --git a/src/config/config.h b/src/config/config.h index 499eb51..45e7642 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -1,17 +1,17 @@ /* gebaar Copyright (C) 2019 coffee2code - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -33,8 +33,12 @@ namespace gebaar::config { void load_config(); + + enum pinches {PINCH_IN, PINCH_OUT, DISTANCE}; + std::string swipe_three_commands[10]; std::string swipe_four_commands[10]; + std::string pinch_commands[10]; private: bool config_file_exists(); diff --git a/src/io/input.cpp b/src/io/input.cpp index 943dc96..22f1409 100644 --- a/src/io/input.cpp +++ b/src/io/input.cpp @@ -1,17 +1,17 @@ /* gebaar Copyright (C) 2019 coffee2code - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -28,6 +28,7 @@ gebaar::io::Input::Input(std::shared_ptr const& config_p { config = config_ptr; gesture_swipe_event = {}; + gesture_pinch_event = {}; } /** @@ -42,6 +43,54 @@ bool gebaar::io::Input::initialize_context() return libinput_udev_assign_seat(libinput, "seat0")==0; } + + +/** + * Pinch Gesture + * Currently supporting only "one shot" pinch-in and pinch-out gestures. + * @param gev Gesture Event + * @param begin Boolean to denote begin or continuation of gesture. + **/ +void gebaar::io::Input::handle_pinch_event(libinput_event_gesture* gev, bool begin) +{ + if (begin) { + gesture_pinch_event.fingers = libinput_event_gesture_get_finger_count(gev); + // Get pinch distance + try { + gesture_pinch_event.distance = std::stod(config->pinch_commands[config->DISTANCE]); + } + catch (const std::invalid_argument &ia) { + // Set default distance + gesture_pinch_event.distance = DEFAULT_DISTANCE; + } + // Reset pinch data + gesture_pinch_event.scale = DEFAULT_SCALE; + gesture_pinch_event.executed = false; + } + else { + // Ignore input after command execution + if (gesture_pinch_event.executed) return; + double new_scale = libinput_event_gesture_get_scale(gev); + if (new_scale > gesture_pinch_event.scale) { + // Scale up + // Add 1 to required distance to get 2 > x > 1 + if (new_scale > 1 + gesture_pinch_event.distance) { + std::system(config->pinch_commands[config->PINCH_IN].c_str()); + gesture_pinch_event.executed = true; + } + } + else { + // Scale Down + // Substract from 1 to have inverted value for pinch in gesture + if (gesture_pinch_event.scale < 1 - gesture_pinch_event.distance) { + std::system(config->pinch_commands[config->PINCH_OUT].c_str()); + gesture_pinch_event.executed = true; + } + } + gesture_pinch_event.scale = new_scale; + } +} + /** * This event has no coordinates, so it's an event that gives us a begin or end signal. * If it begins, we get the amount of fingers used. @@ -169,6 +218,15 @@ void gebaar::io::Input::handle_event() case LIBINPUT_EVENT_GESTURE_SWIPE_END: handle_swipe_event_without_coords(libinput_event_get_gesture_event(libinput_event), false); break; + case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: + handle_pinch_event(libinput_event_get_gesture_event(libinput_event), true); + break; + case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: + handle_pinch_event(libinput_event_get_gesture_event(libinput_event), false); + break; + case LIBINPUT_EVENT_GESTURE_PINCH_END: + handle_pinch_event(libinput_event_get_gesture_event(libinput_event), false); + break; case LIBINPUT_EVENT_NONE: break; case LIBINPUT_EVENT_DEVICE_ADDED: @@ -209,12 +267,6 @@ void gebaar::io::Input::handle_event() break; case LIBINPUT_EVENT_TABLET_PAD_STRIP: break; - case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: - break; - case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: - break; - case LIBINPUT_EVENT_GESTURE_PINCH_END: - break; case LIBINPUT_EVENT_SWITCH_TOGGLE: break; } diff --git a/src/io/input.h b/src/io/input.h index b40d61f..af52637 100644 --- a/src/io/input.h +++ b/src/io/input.h @@ -1,17 +1,17 @@ /* gebaar Copyright (C) 2019 coffee2code - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . */ @@ -24,6 +24,10 @@ #include #include "../config/config.h" +#define DEFAULT_SCALE 1.0 +#define DEFAULT_DISTANCE 0.5 + + namespace gebaar::io { struct gesture_swipe_event { int fingers; @@ -31,6 +35,15 @@ namespace gebaar::io { double y; }; + struct gesture_pinch_event { + int fingers; + double scale; + double angle; + + double distance; + bool executed; + }; + class Input { public: Input(std::shared_ptr const& config_ptr); @@ -48,6 +61,7 @@ namespace gebaar::io { struct libinput_event* libinput_event; struct udev* udev; struct gesture_swipe_event gesture_swipe_event; + struct gesture_pinch_event gesture_pinch_event; bool initialize_context(); @@ -74,6 +88,9 @@ namespace gebaar::io { void handle_swipe_event_without_coords(libinput_event_gesture* gev, bool begin); void handle_swipe_event_with_coords(libinput_event_gesture* gev); + + void handle_pinch_event(libinput_event_gesture* gev, bool begin); + }; } From 42b068f463fa6434d87b3790d65d47dff39d2079 Mon Sep 17 00:00:00 2001 From: Alex Zaslavsky Date: Thu, 31 Oct 2019 13:31:45 +0200 Subject: [PATCH 2/3] Added swipe gestures threshold * Reorganized code a little bit - Previously swipe gesture was triggered only when fingers leaving touchpad thus threshold was useless. Moved trigger function outside of event handling. - Created reset functions for gestures to reset struct holding event data to default values. * Added swipe threshold. - Added new config keys * `settings.pinch.distance` - now instead of `pinch.commands.distance` holds the value required for fingers to travel before executing pinch gesture. * `settings.swipe.threshold` - new key to set how long should be swipe to execute command. --- src/config/config.cpp | 4 +- src/config/config.h | 4 +- src/io/input.cpp | 122 +++++++++++++++++++++++++++--------------- src/io/input.h | 16 +++++- 4 files changed, 98 insertions(+), 48 deletions(-) diff --git a/src/config/config.cpp b/src/config/config.cpp index d13dcef..6292580 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -63,7 +63,9 @@ void gebaar::config::Config::load_config() pinch_commands[PINCH_IN] = *config->get_qualified_as("commands.pinch.out"); pinch_commands[PINCH_OUT] = *config->get_qualified_as("commands.pinch.in"); - pinch_commands[DISTANCE] = *config->get_qualified_as("commands.pinch.distance"); + + settings[DISTANCE] = *config->get_qualified_as("settings.pinch.distance"); + settings[THRESHOLD] = *config->get_qualified_as("settings.swipe.threshold"); loaded = true; } diff --git a/src/config/config.h b/src/config/config.h index 45e7642..1841e49 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -34,11 +34,13 @@ namespace gebaar::config { void load_config(); - enum pinches {PINCH_IN, PINCH_OUT, DISTANCE}; + enum pinch {PINCH_IN, PINCH_OUT}; + enum settings {THRESHOLD, DISTANCE}; std::string swipe_three_commands[10]; std::string swipe_four_commands[10]; std::string pinch_commands[10]; + std::string settings[10]; private: bool config_file_exists(); diff --git a/src/io/input.cpp b/src/io/input.cpp index 22f1409..380c374 100644 --- a/src/io/input.cpp +++ b/src/io/input.cpp @@ -43,21 +43,26 @@ bool gebaar::io::Input::initialize_context() return libinput_udev_assign_seat(libinput, "seat0")==0; } - +/** + * Reset swipe event struct to defaults + */ +void gebaar::io::Input::reset_swipe_event() { + gesture_swipe_event = {}; + try { + gesture_swipe_event.threshold = std::stoi(config->settings[config->THRESHOLD]); + } + catch (const std::invalid_argument& ia){ + gesture_swipe_event.threshold = DEFAULT_THRESHOLD; + } +} /** - * Pinch Gesture - * Currently supporting only "one shot" pinch-in and pinch-out gestures. - * @param gev Gesture Event - * @param begin Boolean to denote begin or continuation of gesture. - **/ -void gebaar::io::Input::handle_pinch_event(libinput_event_gesture* gev, bool begin) -{ - if (begin) { - gesture_pinch_event.fingers = libinput_event_gesture_get_finger_count(gev); + * Reset pinch event struct to defaults + */ +void gebaar::io::Input::reset_pinch_event() { // Get pinch distance try { - gesture_pinch_event.distance = std::stod(config->pinch_commands[config->DISTANCE]); + gesture_pinch_event.distance = std::stod(config->settings[config->DISTANCE]); } catch (const std::invalid_argument &ia) { // Set default distance @@ -66,8 +71,24 @@ void gebaar::io::Input::handle_pinch_event(libinput_event_gesture* gev, bool beg // Reset pinch data gesture_pinch_event.scale = DEFAULT_SCALE; gesture_pinch_event.executed = false; +} + + +/** + * Pinch Gesture + * Currently supporting only "one shot" pinch-in and pinch-out gestures. + * @param gev Gesture Event + * @param begin Boolean to denote begin or continuation of gesture. + **/ +void gebaar::io::Input::handle_pinch_event(libinput_event_gesture* gev, bool begin) +{ + if (begin) { + reset_pinch_event(); + gesture_pinch_event.fingers = libinput_event_gesture_get_finger_count(gev); } else { + if (gesture_swipe_event.executed) return; + // Ignore input after command execution if (gesture_pinch_event.executed) return; double new_scale = libinput_event_gesture_get_scale(gev); @@ -104,41 +125,12 @@ void gebaar::io::Input::handle_swipe_event_without_coords(libinput_event_gesture if (begin) { gesture_swipe_event.fingers = libinput_event_gesture_get_finger_count(gev); } + // This executed when fingers left the touchpad else { - double x = gesture_swipe_event.x; - double y = gesture_swipe_event.y; - int swipe_type = 5; // middle = no swipe - // 1 = left_up, 2 = up, 3 = right_up... - // 1 2 3 - // 4 5 6 - // 7 8 9 - const double OBLIQUE_RATIO = 0.414; // =~ tan(22.5); - - if (abs(x) > abs(y)) { - // left or right swipe - swipe_type += x < 0 ? -1 : 1; - - // check for oblique swipe - if (abs(y) / abs(x) > OBLIQUE_RATIO) { - swipe_type += y < 0 ? -3 : 3; - } - } else { - // up of down swipe - swipe_type += y < 0 ? -3 : 3; - - // check for oblique swipe - if (abs(x) / abs(y) > OBLIQUE_RATIO) { - swipe_type += x < 0 ? -1 : 1; - } + if (!gesture_swipe_event.executed) { + trigger_swipe_command(); } - - if (gesture_swipe_event.fingers == 3) { - std::system(config->swipe_three_commands[swipe_type].c_str()); - } else if (gesture_swipe_event.fingers == 4) { - std::system(config->swipe_four_commands[swipe_type].c_str()); - } - - gesture_swipe_event = {}; + reset_swipe_event(); } } @@ -148,8 +140,50 @@ void gebaar::io::Input::handle_swipe_event_without_coords(libinput_event_gesture */ void gebaar::io::Input::handle_swipe_event_with_coords(libinput_event_gesture* gev) { + if (gesture_swipe_event.executed) return; + int threshold = std::stoi(config->settings[config->THRESHOLD]); gesture_swipe_event.x += libinput_event_gesture_get_dx(gev); gesture_swipe_event.y += libinput_event_gesture_get_dy(gev); + if (abs(gesture_swipe_event.x) > threshold || abs(gesture_swipe_event.y) > threshold) { + trigger_swipe_command(); + gesture_swipe_event.executed = true; + } +} + +void gebaar::io::Input::trigger_swipe_command() { + double x = gesture_swipe_event.x; + double y = gesture_swipe_event.y; + int swipe_type = 5; // middle = no swipe + // 1 = left_up, 2 = up, 3 = right_up... + // 1 2 3 + // 4 5 6 + // 7 8 9 + const double OBLIQUE_RATIO = 0.414; // =~ tan(22.5); + + if (abs(x) > abs(y)) { + // left or right swipe + swipe_type += x < 0 ? -1 : 1; + + // check for oblique swipe + if (abs(y) / abs(x) > OBLIQUE_RATIO) { + swipe_type += y < 0 ? -3 : 3; + } + } else { + // up of down swipe + swipe_type += y < 0 ? -3 : 3; + + // check for oblique swipe + if (abs(x) / abs(y) > OBLIQUE_RATIO) { + swipe_type += x < 0 ? -1 : 1; + } + } + + if (gesture_swipe_event.fingers == 3) { + std::system(config->swipe_three_commands[swipe_type].c_str()); + } else if (gesture_swipe_event.fingers == 4) { + std::system(config->swipe_four_commands[swipe_type].c_str()); + } + } /** diff --git a/src/io/input.h b/src/io/input.h index af52637..e391c0f 100644 --- a/src/io/input.h +++ b/src/io/input.h @@ -24,8 +24,9 @@ #include #include "../config/config.h" -#define DEFAULT_SCALE 1.0 -#define DEFAULT_DISTANCE 0.5 +#define DEFAULT_SCALE 1.0 +#define DEFAULT_DISTANCE 0.5 +#define DEFAULT_THRESHOLD 100 namespace gebaar::io { @@ -33,6 +34,9 @@ namespace gebaar::io { int fingers; double x; double y; + + int threshold; + bool executed; }; struct gesture_pinch_event { @@ -85,10 +89,18 @@ namespace gebaar::io { void handle_event(); + /* Swipe event */ + void reset_swipe_event(); + void handle_swipe_event_without_coords(libinput_event_gesture* gev, bool begin); void handle_swipe_event_with_coords(libinput_event_gesture* gev); + void trigger_swipe_command(); + + /* Pinch event */ + void reset_pinch_event(); + void handle_pinch_event(libinput_event_gesture* gev, bool begin); }; From 2d57aabd06a612f9df7e825b8758a94d07018ef9 Mon Sep 17 00:00:00 2001 From: Alex Zaslavsky Date: Thu, 31 Oct 2019 15:58:00 +0200 Subject: [PATCH 3/3] Updated README.md with settings examples --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 741395f..833868f 100644 --- a/README.md +++ b/README.md @@ -59,12 +59,15 @@ right = "" [commands.pinch] in = "" out = "" -distance="" + +[settings] +pinch.distance = "" +swipe.threshold = "" ``` -* `distance` variable in `commands.pinch` sets the distance between fingers where it shold trigger. +* `settings.pinch.distance` key sets the distance between fingers where it shold trigger. Defaults to `0.5` which means fingers should travel exactly half way from their initial position. - +* `settings.swipe.threshold` sets the limit when swipe gesture should be executed. Defaults to 100. ### Repository versions @@ -100,7 +103,10 @@ right = "bspc desktop -f next" [commands.pinch] in = "xdotool key Control_L+equal" out = "xdotool key Control_L+minus" -ditance="0.1" + +[settings] +pinch.ditance="0.5" +swipe.threshold = "100" ``` Add `gebaard -b` to `~/.config/bspwm/bspwmrc`