diff --git a/README.md b/README.md
index bb51f9e..030d725 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
Gebaar
=========
-
WM Independent Touchpad Gesture Daemon for libinput
_Gebaar means Gesture in Dutch_
@@ -55,8 +54,20 @@ right_down = ""
down = ""
left = ""
right = ""
+
+[commands.pinch]
+in = ""
+out = ""
+
+[settings]
+pinch.distance = ""
+swipe.threshold = ""
```
+* `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

@@ -67,7 +78,7 @@ right = ""
_~/.config/gebaar/gebaard.toml_
```toml
-[commands.swipe.three]
+[swipe.commands.three]
left_up = ""
right_up = ""
up = "bspc node -f north"
@@ -77,7 +88,8 @@ down = "bspc node -f south"
left = "bspc node -f west"
right = "bspc node -f east"
-[commands.swipe.four]
+
+[swipe.commands.four]
left_up = ""
right_up = ""
up = "rofi -show combi"
@@ -86,6 +98,19 @@ right_down = ""
down = ""
left = "bspc desktop -f prev"
right = "bspc desktop -f next"
+
+[pinch.commands.two]
+in = "xdotool key Control_L+equal"
+out = "xdotool key Control_L+minus"
+
+[pinch.settings]
+threshold=0.25
+one_shot=false
+
+[swipe.settings]
+threshold = 0.5
+one_shot = true
+trigger_on_release = true
```
Add `gebaard -b` to `~/.config/bspwm/bspwmrc`
@@ -93,9 +118,13 @@ Add `gebaard -b` to `~/.config/bspwm/bspwmrc`
### State of the project
- [x] Receiving swipe events from libinput
-- [ ] Receiving pinch/zoom events from libinput
+- [x] Swipe gesture have trigger treshold
+- [x] Receiving pinch/zoom events from libinput
+- [x] 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..0bbd0cc 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 .
*/
@@ -43,23 +43,37 @@ void gebaar::config::Config::load_config()
std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE);
}
- swipe_three_commands[1] = *config->get_qualified_as("commands.swipe.three.left_up");
- swipe_three_commands[2] = *config->get_qualified_as("commands.swipe.three.up");
- swipe_three_commands[3] = *config->get_qualified_as("commands.swipe.three.right_up");
- swipe_three_commands[4] = *config->get_qualified_as("commands.swipe.three.left");
- swipe_three_commands[6] = *config->get_qualified_as("commands.swipe.three.right");
- swipe_three_commands[7] = *config->get_qualified_as("commands.swipe.three.left_down");
- swipe_three_commands[8] = *config->get_qualified_as("commands.swipe.three.down");
- swipe_three_commands[9] = *config->get_qualified_as("commands.swipe.three.right_down");
-
- swipe_four_commands[1] = *config->get_qualified_as("commands.swipe.four.left_up");
- swipe_four_commands[2] = *config->get_qualified_as("commands.swipe.four.up");
- swipe_four_commands[3] = *config->get_qualified_as("commands.swipe.four.right_up");
- swipe_four_commands[4] = *config->get_qualified_as("commands.swipe.four.left");
- swipe_four_commands[6] = *config->get_qualified_as("commands.swipe.four.right");
- swipe_four_commands[7] = *config->get_qualified_as("commands.swipe.four.left_down");
- 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");
+
+ /* Swipe Settings */
+ swipe_three_commands[1] = *config->get_qualified_as("swipe.commands.three.left_up");
+ swipe_three_commands[2] = *config->get_qualified_as("swipe.commands.three.up");
+ swipe_three_commands[3] = *config->get_qualified_as("swipe.commands.three.right_up");
+ swipe_three_commands[4] = *config->get_qualified_as("swipe.commands.three.left");
+ swipe_three_commands[6] = *config->get_qualified_as("swipe.commands.three.right");
+ swipe_three_commands[7] = *config->get_qualified_as("swipe.commands.three.left_down");
+ swipe_three_commands[8] = *config->get_qualified_as("swipe.commands.three.down");
+ swipe_three_commands[9] = *config->get_qualified_as("swipe.commands.three.right_down");
+
+ swipe_four_commands[1] = *config->get_qualified_as("swipe.commands.four.left_up");
+ swipe_four_commands[2] = *config->get_qualified_as("swipe.commands.four.up");
+ swipe_four_commands[3] = *config->get_qualified_as("swipe.commands.four.right_up");
+ swipe_four_commands[4] = *config->get_qualified_as("swipe.commands.four.left");
+ swipe_four_commands[6] = *config->get_qualified_as("swipe.commands.four.right");
+ swipe_four_commands[7] = *config->get_qualified_as("swipe.commands.four.left_down");
+ swipe_four_commands[8] = *config->get_qualified_as("swipe.commands.four.down");
+ swipe_four_commands[9] = *config->get_qualified_as("swipe.commands.four.right_down");
+
+ settings.swipe_threshold = config->get_qualified_as("swipe.settings.threshold").value_or(0.5);
+ settings.swipe_one_shot = config->get_qualified_as("swipe.settings.one_shot").value_or(true);
+ settings.swipe_trigger_on_release = config->get_qualified_as("swipe.settings.trigger_on_release").value_or(true);
+
+ /* Pinch settings */
+ pinch_commands[PINCH_IN] = *config->get_qualified_as("pinch.commands.two.out");
+ pinch_commands[PINCH_OUT] = *config->get_qualified_as("pinch.commands.two.in");
+
+ settings.pinch_threshold = config->get_qualified_as("pinch.settings.threshold").value_or(0.25);
+ settings.pinch_one_shot = config->get_qualified_as("pinch.settings.one_shot").value_or(false);
+
loaded = true;
}
diff --git a/src/config/config.h b/src/config/config.h
index 499eb51..34d7a42 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,16 +33,32 @@ namespace gebaar::config {
void load_config();
+
+ struct settings {
+ bool pinch_one_shot;
+ double pinch_threshold;
+
+ bool swipe_one_shot;
+ double swipe_threshold;
+ bool swipe_trigger_on_release;
+ } settings;
+
+ enum pinch {PINCH_IN, PINCH_OUT};
std::string swipe_three_commands[10];
std::string swipe_four_commands[10];
+ std::string pinch_commands[10];
private:
+
bool config_file_exists();
bool find_config_file();
+
std::string config_file_path;
std::shared_ptr config;
+
+
};
}
#endif //GEBAAR_CONFIG_H
diff --git a/src/io/input.cpp b/src/io/input.cpp
index 943dc96..4c95cf4 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,9 @@ gebaar::io::Input::Input(std::shared_ptr const& config_p
{
config = config_ptr;
gesture_swipe_event = {};
+
+ gesture_pinch_event = {};
+ gesture_pinch_event.scale = DEFAULT_SCALE;
}
/**
@@ -42,6 +45,86 @@ 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 = {};
+ gesture_swipe_event.executed = false;
+}
+
+/**
+ * Reset pinch event struct to defaults
+ */
+void gebaar::io::Input::reset_pinch_event() {
+ gesture_pinch_event = {};
+ gesture_pinch_event.scale = DEFAULT_SCALE;
+ gesture_pinch_event.executed = false;
+}
+
+/**
+ * Pinch one_shot gesture handle
+ * @param new_scale last reported scale between the fingers
+ */
+void gebaar::io::Input::handle_one_shot_pinch(double new_scale) {
+ if (new_scale > gesture_pinch_event.scale) { // Scale up
+ // Add 1 to required distance to get 2 > x > 1
+ if (new_scale > 1 + config->settings.pinch_threshold) {
+ 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 - config->settings.pinch_threshold) {
+ std::system(config->pinch_commands[config->PINCH_OUT].c_str());
+ gesture_pinch_event.executed = true;
+ }
+ }
+}
+
+/**
+ * Pinch continous gesture handle
+ * Calculates the trigger value according to current step
+ * @param new_scale last reported scale between the fingers
+ */
+void gebaar::io::Input::handle_continouos_pinch(double new_scale) {
+ int step = gesture_pinch_event.step == 0 ? gesture_pinch_event.step + 1 : gesture_pinch_event.step;
+ double trigger = 1 + (config->settings.pinch_threshold * step);
+
+ if (new_scale > gesture_pinch_event.scale) { // Scale up
+ if (new_scale >= trigger){
+ std::system(config->pinch_commands[config->PINCH_IN].c_str());
+ inc_step(gesture_pinch_event.step);
+ }
+ } else { // Scale down
+ if (new_scale <= trigger){
+ std::system(config->pinch_commands[config->PINCH_OUT].c_str());
+ dec_step(gesture_pinch_event.step);
+ }
+ }
+}
+
+/**
+ * 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 {
+ double new_scale = libinput_event_gesture_get_scale(gev);
+ if (config->settings.pinch_one_shot && !gesture_pinch_event.executed) handle_one_shot_pinch(new_scale);
+ if (!config->settings.pinch_one_shot) handle_continouos_pinch(new_scale);
+ 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.
@@ -55,41 +138,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 && config->settings.swipe_trigger_on_release) {
+ 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();
}
}
@@ -99,8 +153,57 @@ 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 (config->settings.swipe_one_shot && gesture_swipe_event.executed) return;
+
+ // Since swipe gesture counts in dpi we have to convert
+ int threshold = config->settings.swipe_threshold * 100;
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;
+ }
+}
+
+
+/**
+ * Making calculation for swipe direction and triggering
+ * command accordingly
+ */
+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());
+ }
+
}
/**
@@ -140,7 +243,8 @@ gebaar::io::Input::~Input()
bool gebaar::io::Input::gesture_device_exists()
{
bool device_found = false;
- while ((libinput_event = libinput_get_event(libinput))!=nullptr) {
+
+ while ((libinput_event = libinput_get_event(libinput)) != nullptr) {
auto device = libinput_event_get_device(libinput_event);
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_GESTURE)) {
device_found = true;
@@ -169,6 +273,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 +322,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..17eacd1 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,11 +24,25 @@
#include
#include "../config/config.h"
+#define DEFAULT_SCALE 1.0
+
namespace gebaar::io {
struct gesture_swipe_event {
int fingers;
double x;
double y;
+
+ bool executed;
+ int step;
+ };
+
+ struct gesture_pinch_event {
+ int fingers;
+ double scale;
+ double angle;
+
+ bool executed;
+ int step;
};
class Input {
@@ -47,7 +61,9 @@ namespace gebaar::io {
struct libinput* libinput;
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();
@@ -56,7 +72,7 @@ namespace gebaar::io {
static int open_restricted(const char* path, int flags, void* user_data)
{
int fd = open(path, flags);
- return fd<0 ? -errno : fd;
+ return fd < 0 ? -errno : fd;
}
static void close_restricted(int fd, void* user_data)
@@ -69,11 +85,38 @@ namespace gebaar::io {
.close_restricted = close_restricted,
};
+ /*
+ * Decrements step of current trigger. Just to skip 0
+ * @param cur current step
+ */
+ inline void dec_step(int &cur) { --cur == 0 ? --cur : cur; }
+
+ /*
+ * Increase step of current trigger. Just to pass -1
+ * @param cur current step
+ */
+ inline void inc_step(int &cur) { ++cur == 0 ? ++cur : cur; }
+
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_one_shot_pinch(double new_scale);
+
+ void handle_continouos_pinch(double new_scale);
+
+ void handle_pinch_event(libinput_event_gesture* gev, bool begin);
+
};
}
diff --git a/src/main.cpp b/src/main.cpp
index 9a61700..982ce3d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -48,6 +48,7 @@ int main(int argc, char* argv[])
}
std::shared_ptr config = std::make_shared();
input = new gebaar::io::Input(config);
+
if (input->initialize()) {
input->start_loop();
}