diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index b3c3529e..37308dfd 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -6,7 +6,7 @@ on: [push, pull_request]
jobs:
lint:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v3
diff --git a/.github/workflows/release-ppa.yml b/.github/workflows/release-ppa.yml
index 4384cc12..d8b32ea7 100644
--- a/.github/workflows/release-ppa.yml
+++ b/.github/workflows/release-ppa.yml
@@ -13,7 +13,7 @@ on:
jobs:
update-ppa-branch:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v3
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0c822a64..aa87f22a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,13 +11,14 @@ on:
jobs:
deb-package:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
env:
target_docker_image: debian:bookworm-backports
target_distribution: bookworm
strategy:
matrix:
- target_arch: ["amd64", "armhf", "arm64"]
+ target_arch: ["amd64"]
+ # target_arch: ["amd64", "armhf", "arm64"]
steps:
- name: GitHub Environment Variables Action
uses: FranzDiebold/github-env-vars-action@v1.2.1
@@ -50,13 +51,13 @@ jobs:
dpkg_buildpackage_opts: "--no-sign --no-check-builddeps --post-clean"
- name: Upload Debian package artifacts
- uses: "actions/upload-artifact@v2"
+ uses: "actions/upload-artifact@v4"
with:
name: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_${{matrix.target_arch}}.deb"
path: "${{ github.workspace }}/artifacts/${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_${{matrix.target_arch}}.deb"
rpm-package-rhel:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
container:
image: almalinux:8
steps:
@@ -91,20 +92,20 @@ jobs:
rpmbuild -ba ${{ env.GITHUB_REPOSITORY_NAME }}/rpm/${{ env.GITHUB_REPOSITORY_NAME }}.spec
- name: Upload RPM package
- uses: "actions/upload-artifact@v2"
+ uses: "actions/upload-artifact@v4"
with:
name: "rhel8_${{ env.GITHUB_REPOSITORY_NAME }}-${{ env.GITHUB_REF_NAME }}-1.x86_64.rpm"
path: "~/rpmbuild/RPMS/x86_64/${{ env.GITHUB_REPOSITORY_NAME }}-${{ env.GITHUB_REF_NAME }}-1.x86_64.rpm"
rpm-package-fedora:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
container:
- image: fedora:38
+ image: fedora:42
steps:
- name: Install dependencies
run: |
dnf upgrade -y
- dnf groupinstall -y "Development Tools"
+ dnf group install -y "development-tools"
dnf install -y gcc gcc-c++ cmake rpm-build libudev-devel libinput-devel pugixml-devel cairo-devel libX11-devel libXtst-devel libXrandr-devel libXi-devel glib2-devel gtk3-devel
- name: GitHub Environment Variables Action
@@ -128,20 +129,20 @@ jobs:
rpmbuild -ba ${{ env.GITHUB_REPOSITORY_NAME }}/rpm/${{ env.GITHUB_REPOSITORY_NAME }}.spec
- name: Upload RPM package
- uses: "actions/upload-artifact@v2"
+ uses: "actions/upload-artifact@v4"
with:
name: "fedora34_${{ env.GITHUB_REPOSITORY_NAME }}-${{ env.GITHUB_REF_NAME }}-1.x86_64.rpm"
path: "~/rpmbuild/RPMS/x86_64/${{ env.GITHUB_REPOSITORY_NAME }}-${{ env.GITHUB_REF_NAME }}-1.x86_64.rpm"
create-release:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
needs: [ deb-package, rpm-package-rhel, rpm-package-fedora ]
steps:
- name: GitHub Environment Variables Action
uses: FranzDiebold/github-env-vars-action@v1.2.1
- name: Download packages
- uses: "actions/download-artifact@v2"
+ uses: "actions/download-artifact@v4"
with:
path: ./
@@ -166,25 +167,25 @@ jobs:
asset_name: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_amd64.deb"
asset_content_type: application/vnd.debian.binary-package
- - name: Upload Debian package (armhf)
- uses: actions/upload-release-asset@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- upload_url: ${{ steps.create_release.outputs.upload_url }}
- asset_path: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_armhf.deb/${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_armhf.deb"
- asset_name: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_armhf.deb"
- asset_content_type: application/vnd.debian.binary-package
-
- - name: Upload Debian package (arm64)
- uses: actions/upload-release-asset@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- upload_url: ${{ steps.create_release.outputs.upload_url }}
- asset_path: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_arm64.deb/${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_arm64.deb"
- asset_name: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_arm64.deb"
- asset_content_type: application/vnd.debian.binary-package
+ # - name: Upload Debian package (armhf)
+ # uses: actions/upload-release-asset@v1
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # with:
+ # upload_url: ${{ steps.create_release.outputs.upload_url }}
+ # asset_path: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_armhf.deb/${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_armhf.deb"
+ # asset_name: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_armhf.deb"
+ # asset_content_type: application/vnd.debian.binary-package
+
+ # - name: Upload Debian package (arm64)
+ # uses: actions/upload-release-asset@v1
+ # env:
+ # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # with:
+ # upload_url: ${{ steps.create_release.outputs.upload_url }}
+ # asset_path: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_arm64.deb/${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_arm64.deb"
+ # asset_name: "${{ env.GITHUB_REPOSITORY_NAME }}_${{ env.GITHUB_REF_NAME }}_arm64.deb"
+ # asset_content_type: application/vnd.debian.binary-package
- name: Upload RPM package (RHEL)
uses: actions/upload-release-asset@v1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c501b367..7e79ade6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
# Changelog
+## 2.0.18 - 2025-05-24
+
+ - Allow to execute actions on gesture begin and end
+
+ Until now, it was only possible to execute the MOUSE_CLICK, SEND_KEYS an
+ RUN_COMMAND actions when the gesture started or when the gesture ended.
+
+ Include a third option, begin-and-end allowing to run the actions
+ both when the gesture starts and ends.
+
+ When this new setting is used, MOUSE_CLICK starts presses the mouse button
+ when the gesture starts and releases it when the gesture ends.
+
+ In the case of RUN_COMMAND, a environment variable is set
+ (TOUCHEGG_GESTURE_ON) allowing the executed script to take different actions
+ at the beginning and the end of the gesture.
+
+ https://github.com/JoseExposito/touchegg/pull/670
+
## 2.0.17 - 2023-08-13
This version does not include any new features, but the deb and rpm packages
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3df99d6f..c131bf36 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.0.0)
project(touchegg)
set(MAJOR_VERSION "2")
set(MINOR_VERSION "0")
-set(PATCH_VERSION "17")
+set(PATCH_VERSION "18")
add_definitions(-D_VERSION="v${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}")
set(CMAKE_CXX_STANDARD 17)
diff --git a/HACKING.md b/HACKING.md
index d62194ce..5d3f3499 100755
--- a/HACKING.md
+++ b/HACKING.md
@@ -9,7 +9,7 @@ $ sudo apt-get install git build-essential gdb cmake debhelper \
libgtk-3-dev # GTK is optional, see "Compilation flags"
# Red Hat, Fedora, CentOS and derivatives:
-$ sudo dnf groupinstall "Development Tools"
+$ sudo dnf group install "development-tools"
$ sudo dnf install git gcc gcc-c++ gdb cmake rpm-build \
libudev-devel libinput-devel pugixml-devel cairo-devel libX11-devel libXtst-devel libXrandr-devel libXi-devel glib2-devel \
gtk3-devel # GTK is optional, see "Compilation flags"
diff --git a/README.md b/README.md
index 4c25990f..2e984ed8 100644
--- a/README.md
+++ b/README.md
@@ -544,7 +544,7 @@ Options:
| repeat | `true`/`false` | Whether to execute the keyboard shortcut multiple times (default: `false`). This is useful to perform actions like pinch to zoom. |
| modifiers | Keysym | Typical values are: `Shift_L`, `Control_L`, `Alt_L`, `Alt_R`, `Meta_L`, `Super_L`, `Hyper_L`. You can use multiple keysyms: `Control_L+Alt_L`.See "Keysyms" below for more information. |
| keys | Keysym | Shortcut keys. You can use multiple keysyms: `A+B+C`. See "Keysyms" below for more information. |
-| on | `begin`/`end` | Only used when `repeat` is `false`. Whether to execute the shortcut at the beginning or at the end of the gesture. |
+| on | `begin`/`end`/`begin-and-end` | Only used when `repeat` is `false`. Whether to execute the shortcut at the beginning and/or at the end of the gesture. |
| decreaseKeys | Keysym | Only used when `repeat` is `true`. Keys to press when you change the gesture direction to the opposite. You can use multiple keysyms: `A+B+C`. This is useful to perform actions like pinch to zoom, check `Example 2` below. |
| times | 2...15 | Only used when `repeat` is `true`. Number of times to repeat the action. |
| animate | `true`/`false` | Set it to `true` to display the animation set in `animation`. `false` otherwise. |
@@ -640,7 +640,7 @@ Options:
| - | - | - |
| repeat | `true`/`false` | `true` if the command should be executed multiple times. `false` otherwise. |
| command | Command | The command to execute. |
-| on | `begin`/`end` | Only used when `repeat` is `false`. If the command should be executed on the beginning or on the end of the gesture. |
+| on | `begin`/`end`/`begin-and-end` | Only used when `repeat` is `false`. If the command should be executed and/on the beginning or on the end of the gesture. |
| decreaseCommand | Command | Only used when `repeat` is `true`. Command to run when you change the gesture direction to the opposite. Check `Example 2` below. |
| times | 2...15 | Only used when `repeat` is `true`. Number of times to repeat the action. |
| animate | `true`/`false` | Set it to `true` to display the animation set in `animation`. `false` otherwise. |
@@ -654,7 +654,7 @@ Example 1:
false
- notify-send 'Hello World' "Swipe down, DEVICE_TYPE=$TOUCHEGG_DEVICE_TYPE"
+ notify-send 'Hello World' "Swipe down, DEVICE_TYPE=$TOUCHEGG_DEVICE_TYPE TOUCHEGG_GESTURE_ON=$TOUCHEGG_GESTURE_ON"
begin
@@ -681,7 +681,9 @@ Options:
| Option | Value | Description |
| - | - | - |
| button | `1`/`2`/`3`/`8`/`9` | Left click (1), middle click (2), right click (3), back button (8) or forward button (9) |
-| on | `begin`/`end` | If the command should be executed on the beginning or on the end of the gesture. |
+| on | `begin`/`end`/`begin-and-end` | If the mouse click should be executed on the beginning and/or on the end of the gesture. |
+
+When the `begin-and-end` option is used, the mouse button is down when the gesture begins and up when the gesture ends.
Example:
diff --git a/debian/changelog b/debian/changelog
index 6188717b..6f7fc26a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+touchegg (2.0.18) focal; urgency=medium
+
+ * Allow to execute actions on gesture begin and end
+
+ -- José Expósito Sat, 24 May 2025 12:00:00 +0100
+
touchegg (2.0.17) focal; urgency=medium
* Upgrade the target Debian version on CI
diff --git a/rpm/touchegg.spec b/rpm/touchegg.spec
index 12f2d77e..7ae42de0 100644
--- a/rpm/touchegg.spec
+++ b/rpm/touchegg.spec
@@ -1,7 +1,7 @@
Name: touchegg
Summary: Multi-touch gesture recognizer
Url: https://github.com/JoseExposito/touchegg
-Version: 2.0.17
+Version: 2.0.18
Release: 1
License: GPLv3+
Group: Applications/Productivity
@@ -84,8 +84,10 @@ fi
%changelog
+* Sat May 24 2025 José Expósito - 2.0.18-1
+- Allow to execute actions on gesture begin and end
-* Sun Aug 13 2023 José Expósito - 2.0.16-1
+* Sun Aug 13 2023 José Expósito - 2.0.17-1
- Upgrade the target Fedora and RHEL version on CI
* Mon Feb 06 2023 José Expósito - 2.0.16-1
diff --git a/src/actions/execute-action-on.h b/src/actions/execute-action-on.h
new file mode 100644
index 00000000..d9aa8332
--- /dev/null
+++ b/src/actions/execute-action-on.h
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2011 - 2024 José Expósito
+ *
+ * This file is part of Touchégg.
+ *
+ * Touchégg 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.
+ *
+ * Touchégg 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
+ * Touchégg. If not, see .
+ */
+#ifndef ACTIONS_EXECUTE_ACTION_ON_H_
+#define ACTIONS_EXECUTE_ACTION_ON_H_
+
+#include
+
+enum class ExecuteActionOn {
+ NOT_SUPPORTED,
+ BEGIN,
+ END,
+ BEGIN_AND_END,
+ // Adding a new value? Don't forget to add it in executeActionOnFromStr and
+ // shouldExecuteAction
+};
+
+inline ExecuteActionOn executeActionOnFromStr(const std::string &str) {
+ if (str == "begin") {
+ return ExecuteActionOn::BEGIN;
+ }
+ if (str == "end") {
+ return ExecuteActionOn::END;
+ }
+ if (str == "begin-and-end") {
+ return ExecuteActionOn::BEGIN_AND_END;
+ }
+ return ExecuteActionOn::NOT_SUPPORTED;
+}
+
+inline bool shouldExecuteAction(ExecuteActionOn phase, ExecuteActionOn config) {
+ switch (config) {
+ case ExecuteActionOn::BEGIN:
+ return phase == ExecuteActionOn::BEGIN;
+ case ExecuteActionOn::END:
+ return phase == ExecuteActionOn::END;
+ case ExecuteActionOn::BEGIN_AND_END:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#endif // ACTIONS_EXECUTE_ACTION_ON_H_
diff --git a/src/actions/mouse-click.cpp b/src/actions/mouse-click.cpp
index 72731017..cbf2a19c 100644
--- a/src/actions/mouse-click.cpp
+++ b/src/actions/mouse-click.cpp
@@ -23,18 +23,26 @@ void MouseClick::onGestureBegin(const Gesture& /*gesture*/) {
}
if (this->settings.count("on") == 1) {
- this->onBegin = (this->settings.at("on") == "begin");
+ this->executeActionOn = executeActionOnFromStr(this->settings.at("on"));
}
- if (this->onBegin) {
- this->windowSystem.sendMouseClick(this->button);
+ if (shouldExecuteAction(ExecuteActionOn::BEGIN, this->executeActionOn)) {
+ this->windowSystem.sendMouseDown(this->button);
+
+ if (this->executeActionOn != ExecuteActionOn::BEGIN_AND_END) {
+ this->windowSystem.sendMouseUp(this->button);
+ }
}
}
void MouseClick::onGestureUpdate(const Gesture& /*gesture*/) {}
void MouseClick::onGestureEnd(const Gesture& /*gesture*/) {
- if (!this->onBegin) {
- this->windowSystem.sendMouseClick(this->button);
+ if (shouldExecuteAction(ExecuteActionOn::END, this->executeActionOn)) {
+ if (this->executeActionOn != ExecuteActionOn::BEGIN_AND_END) {
+ this->windowSystem.sendMouseDown(this->button);
+ }
+
+ this->windowSystem.sendMouseUp(this->button);
}
}
diff --git a/src/actions/mouse-click.h b/src/actions/mouse-click.h
index afdc1492..830878c6 100644
--- a/src/actions/mouse-click.h
+++ b/src/actions/mouse-click.h
@@ -21,6 +21,7 @@
#include
#include "actions/action.h"
+#include "actions/execute-action-on.h"
/**
* Action to emulate a shortcut.
@@ -35,7 +36,7 @@ class MouseClick : public Action {
private:
int button = 1;
- bool onBegin = true;
+ ExecuteActionOn executeActionOn = ExecuteActionOn::BEGIN;
};
#endif // ACTIONS_MOUSE_CLICK_H_
diff --git a/src/actions/repeated-action.cpp b/src/actions/repeated-action.cpp
index e200d4ec..43e10aa4 100644
--- a/src/actions/repeated-action.cpp
+++ b/src/actions/repeated-action.cpp
@@ -34,14 +34,15 @@ void RepeatedAction::onGestureBegin(const Gesture &gesture) {
}
if (this->settings.count("on") == 1) {
- this->onBegin = (this->settings.at("on") == "begin");
+ this->executeActionOn = executeActionOnFromStr(this->settings.at("on"));
}
// execute supplied prelude
this->executePrelude();
// run action on begin
- if (!this->repeat && this->onBegin) {
+ if (!this->repeat &&
+ shouldExecuteAction(ExecuteActionOn::BEGIN, this->executeActionOn)) {
this->executeAction(gesture);
}
}
@@ -70,8 +71,12 @@ void RepeatedAction::onGestureUpdate(const Gesture &gesture) {
}
void RepeatedAction::onGestureEnd(const Gesture &gesture) {
- if (!this->repeat && !this->onBegin) {
- if (gesture.percentage() >= this->threshold) {
+ if (!this->repeat &&
+ shouldExecuteAction(ExecuteActionOn::END, this->executeActionOn)) {
+ // Do not take into account the threshold is the action is executed on begin
+ // and end. Otherwise, we could miss could execute only the on begin part.
+ if (this->executeActionOn == ExecuteActionOn::BEGIN_AND_END ||
+ gesture.percentage() >= this->threshold) {
this->executeAction(gesture);
}
}
diff --git a/src/actions/repeated-action.h b/src/actions/repeated-action.h
index 693c7f3a..9a6f32d5 100644
--- a/src/actions/repeated-action.h
+++ b/src/actions/repeated-action.h
@@ -19,6 +19,7 @@
#define ACTIONS_REPEATED_ACTION_H_
#include "actions/animated-action.h"
+#include "actions/execute-action-on.h"
class RepeatedAction : public AnimatedAction {
public:
@@ -84,7 +85,7 @@ class RepeatedAction : public AnimatedAction {
/**
* Whether the action should be executed on gesture begin or end.
*/
- bool onBegin = true;
+ ExecuteActionOn executeActionOn = ExecuteActionOn::BEGIN;
};
#endif // ACTIONS_REPEATED_ACTION_H_
diff --git a/src/actions/run-command.cpp b/src/actions/run-command.cpp
index 86c4f8de..af9cd0cb 100644
--- a/src/actions/run-command.cpp
+++ b/src/actions/run-command.cpp
@@ -22,6 +22,7 @@
#include "animations/animation-factory.h"
void RunCommand::onGestureBegin(const Gesture &gesture) {
+ setenv("TOUCHEGG_GESTURE_ON", "begin", 1);
RepeatedAction::onGestureBegin(gesture);
if (!this->animate) {
@@ -38,6 +39,16 @@ void RunCommand::onGestureBegin(const Gesture &gesture) {
}
}
+void RunCommand::onGestureUpdate(const Gesture &gesture) {
+ setenv("TOUCHEGG_GESTURE_ON", "update", 1);
+ RepeatedAction::onGestureUpdate(gesture);
+}
+
+void RunCommand::onGestureEnd(const Gesture &gesture) {
+ setenv("TOUCHEGG_GESTURE_ON", "end", 1);
+ RepeatedAction::onGestureEnd(gesture);
+}
+
void RunCommand::executePrelude() {
if (this->settings.count("command") == 1) {
this->command = this->settings.at("command");
diff --git a/src/actions/run-command.h b/src/actions/run-command.h
index 7c24035c..fded290d 100644
--- a/src/actions/run-command.h
+++ b/src/actions/run-command.h
@@ -29,6 +29,8 @@ class RunCommand : public RepeatedAction {
public:
using RepeatedAction::RepeatedAction;
void onGestureBegin(const Gesture &gesture) override;
+ void onGestureUpdate(const Gesture &gesture) override;
+ void onGestureEnd(const Gesture &gesture) override;
bool runOnSystemWindows() override { return true; }
void executePrelude() override;
void executeAction(const Gesture &gesture) override;
diff --git a/src/animations/animation.h b/src/animations/animation.h
index 9da70d6f..14f6bdbe 100644
--- a/src/animations/animation.h
+++ b/src/animations/animation.h
@@ -20,6 +20,7 @@
#include
+#include
#include
#include "window-system/cairo-surface.h"
diff --git a/src/config/config.cpp b/src/config/config.cpp
old mode 100755
new mode 100644
index 666aaaa7..75b9a5b7
--- a/src/config/config.cpp
+++ b/src/config/config.cpp
@@ -46,27 +46,43 @@ std::string Config::getGlobalSetting(const std::string &name) const {
void Config::saveGestureConfig(
const std::string &application, GestureType gestureType,
const std::string &numFingers, GestureDirection gestureDirection,
- ActionType actionType,
+ GestureAxis gestureAxis, ActionType actionType,
const std::unordered_map &actionSettings) {
std::string key = Config::getConfigKey(application, gestureType, numFingers,
- gestureDirection);
+ gestureDirection, gestureAxis);
this->config[key] = std::make_pair(actionType, actionSettings);
}
bool Config::hasGestureConfig(const std::string &application,
GestureType gestureType, int numFingers,
- GestureDirection gestureDirection) const {
- std::string key = Config::getConfigKey(
- application, gestureType, std::to_string(numFingers), gestureDirection);
+ GestureDirection gestureDirection,
+ GestureAxis gestureAxis) const {
+ std::string key = Config::getConfigKey(application,
+ gestureType, std::to_string(numFingers),
+ gestureDirection, gestureAxis);
+ if (this->config.count(key) == 1) return true;
+
+ // Check for definitions with no axis specified
+ key = Config::getConfigKey(application,
+ gestureType, std::to_string(numFingers),
+ gestureDirection, GestureAxis::UNKNOWN);
return (this->config.count(key) == 1);
}
std::pair>
Config::getGestureConfig(const std::string &application,
GestureType gestureType, int numFingers,
- GestureDirection gestureDirection) const {
- std::string key = Config::getConfigKey(
- application, gestureType, std::to_string(numFingers), gestureDirection);
+ GestureDirection gestureDirection,
+ GestureAxis gestureAxis) const {
+ std::string key = Config::getConfigKey(application,
+ gestureType, std::to_string(numFingers),
+ gestureDirection, gestureAxis);
+ auto match = this->config.find(key);
+ if (match != this->config.end()) return match->second;
+
+ key = Config::getConfigKey(application,
+ gestureType, std::to_string(numFingers),
+ gestureDirection, GestureAxis::UNKNOWN);
return this->config.at(key);
}
@@ -78,9 +94,12 @@ void Config::loadDefaultGlobalSettings() {
std::string Config::getConfigKey(const std::string &application,
GestureType gestureType,
const std::string &numFingers,
- GestureDirection gestureDirection) {
+ GestureDirection gestureDirection,
+ GestureAxis gestureAxis) {
auto gestureTypeInt = static_cast(gestureType);
auto gestureDirectionInt = static_cast(gestureDirection);
+ auto gestureAxisInt = static_cast(gestureAxis);
return toLower(application) + "_" + std::to_string(gestureTypeInt) + "_" +
- numFingers + "_" + std::to_string(gestureDirectionInt);
+ numFingers + "_" + std::to_string(gestureDirectionInt) + "_" +
+ std::to_string(gestureAxisInt);
}
diff --git a/src/config/config.h b/src/config/config.h
old mode 100755
new mode 100644
index 0165d4e4..e9bc91d6
--- a/src/config/config.h
+++ b/src/config/config.h
@@ -23,6 +23,7 @@
#include
#include "actions/action-type.h"
+#include "gesture/gesture-axis.h"
#include "gesture/gesture-direction.h"
#include "gesture/gesture-type.h"
@@ -66,22 +67,23 @@ class Config {
void saveGestureConfig(
const std::string &application, GestureType gestureType,
const std::string &numFingers, GestureDirection gestureDirection,
- ActionType actionType,
+ GestureAxis gestureAxis, ActionType actionType,
const std::unordered_map &actionSettings);
/**
* @returns If there is an action configured for the gesture.
*/
bool hasGestureConfig(const std::string &application, GestureType gestureType,
- int numFingers,
- GestureDirection gestureDirection) const;
+ int numFingers, GestureDirection gestureDirection,
+ GestureAxis gestureAxis) const;
/**
* @returns The action configured for the gesture.
*/
std::pair>
getGestureConfig(const std::string &application, GestureType gestureType,
- int numFingers, GestureDirection gestureDirection) const;
+ int numFingers, GestureDirection gestureDirection,
+ GestureAxis gestureAxis) const;
private:
/**
@@ -113,7 +115,8 @@ class Config {
static std::string getConfigKey(const std::string &application,
GestureType gestureType,
const std::string &numFingers,
- GestureDirection gestureDirection);
+ GestureDirection gestureDirection,
+ GestureAxis gestureAxis);
};
#endif // CONFIG_CONFIG_H_
diff --git a/src/config/xml-config-loader.cpp b/src/config/xml-config-loader.cpp
index b708d267..b5aecaf1 100644
--- a/src/config/xml-config-loader.cpp
+++ b/src/config/xml-config-loader.cpp
@@ -101,6 +101,7 @@ void XmlConfigLoader::parseApplicationXmlNodes(const pugi::xml_node &rootNode) {
const std::string gestureType = gestureNode.attribute("type").value();
const std::string fingers = gestureNode.attribute("fingers").value();
const std::string direction = gestureNode.attribute("direction").value();
+ const std::string axis = gestureNode.attribute("axis").value();
pugi::xml_node actionNode = gestureNode.child("action");
const std::string actionType = actionNode.attribute("type").value();
@@ -116,8 +117,8 @@ void XmlConfigLoader::parseApplicationXmlNodes(const pugi::xml_node &rootNode) {
for (const std::string &application : applications) {
this->config->saveGestureConfig(
trim(application), gestureTypeFromStr(gestureType), fingers,
- gestureDirectionFromStr(direction), actionTypeFromStr(actionType),
- actionSettings);
+ gestureDirectionFromStr(direction), gestureAxisFromStr(axis),
+ actionTypeFromStr(actionType), actionSettings);
}
}
}
diff --git a/src/daemon/daemon-client.cpp b/src/daemon/daemon-client.cpp
index 2f8d25a9..cab975d3 100644
--- a/src/daemon/daemon-client.cpp
+++ b/src/daemon/daemon-client.cpp
@@ -56,10 +56,12 @@ void DaemonClient::connect() {
std::this_thread::sleep_for(std::chrono::seconds(5));
} else {
tlg::info << "Connection with Touchégg established" << std::endl;
+ auto interfaceVersion = (sizeof(DBUS_INTERFACE_NAMES)/sizeof(DBUS_INTERFACE_NAMES[0])) - 1;
+ auto objectPathVersion = (sizeof(DBUS_OBJECT_PATHS)/sizeof(DBUS_OBJECT_PATHS[0])) - 1;
g_dbus_connection_signal_subscribe(
- connection, nullptr, DBUS_INTERFACE_NAME, nullptr, DBUS_OBJECT_PATH,
- nullptr, G_DBUS_SIGNAL_FLAGS_NONE, DaemonClient::onNewMessage, this,
- nullptr);
+ connection, nullptr, DBUS_INTERFACE_NAMES[interfaceVersion], nullptr,
+ DBUS_OBJECT_PATHS[objectPathVersion], nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
+ DaemonClient::onNewMessage, this, nullptr);
g_signal_connect(
connection, "closed",
@@ -122,15 +124,16 @@ std::unique_ptr DaemonClient::makeGestureFromSignalParams(
GVariant *signalParameters) {
GestureType type = GestureType::NOT_SUPPORTED;
GestureDirection direction = GestureDirection::UNKNOWN;
+ GestureAxis axis = GestureAxis::UNKNOWN;
double percentage = -1;
int fingers = -1;
DeviceType deviceType = DeviceType::UNKNOWN;
uint64_t elapsedTime = -1;
g_variant_get(signalParameters, // NOLINT
- "(uudiut)", &type, &direction, &percentage, &fingers,
+ "(uuudiut)", &type, &direction, &axis, &percentage, &fingers,
&deviceType, &elapsedTime);
- return std::make_unique(type, direction, percentage, fingers,
+ return std::make_unique(type, direction, axis, percentage, fingers,
deviceType, elapsedTime);
}
diff --git a/src/daemon/daemon-server.cpp b/src/daemon/daemon-server.cpp
index 0fbb25cb..7a5d0439 100644
--- a/src/daemon/daemon-server.cpp
+++ b/src/daemon/daemon-server.cpp
@@ -82,10 +82,14 @@ gboolean DaemonServer::onNewConnection(GDBusServer * /*server*/,
tlg::info << "New client connection request" << std::endl;
GDBusInterfaceVTable interfaceVTable{nullptr, nullptr, nullptr};
- int id = g_dbus_connection_register_object(
- connection, DBUS_OBJECT_PATH,
- self->introspectionData->interfaces[0], // NOLINT
- &interfaceVTable, nullptr, nullptr, nullptr);
+ int id = 0;
+ for (auto i = 0; i < sizeof(DBUS_OBJECT_PATHS)/sizeof(DBUS_OBJECT_PATHS[0]); i++) {
+ id = g_dbus_connection_register_object(
+ connection, DBUS_OBJECT_PATHS[i],
+ self->introspectionData->interfaces[0], // NOLINT
+ &interfaceVTable, nullptr, nullptr, nullptr);
+ if (id != 0) break;
+ }
if (id == 0) {
tlg::error << "Error connecting client" << std::endl;
@@ -114,34 +118,51 @@ void DaemonServer::send(const std::string &signalName,
std::unique_ptr gesture) {
std::vector closedConnections{};
+ GVariant* signalParams[sizeof(DBUS_INTERFACE_NAMES)/sizeof(DBUS_INTERFACE_NAMES[0])] = {0};
+ auto i = 0;
// Copy every gesture field into the signal parameters for serialization
- GVariant *signalParams =
+ // Offer signal versions in order from oldest to newest
+ signalParams[i] = {
g_variant_new("(uudiut)", // NOLINT
- static_cast(gesture->type()), // u
- static_cast(gesture->direction()), // u
- gesture->percentage(), // d
- gesture->fingers(), // i
- static_cast(gesture->performedOnDeviceType()), // u
- gesture->elapsedTime()); // t
- g_variant_ref_sink(signalParams);
+ static_cast(gesture->type()), // u
+ static_cast(gesture->direction()), // u
+ gesture->percentage(), // d
+ gesture->fingers(), // i
+ static_cast(gesture->performedOnDeviceType()), // u
+ gesture->elapsedTime())}; // t
+ g_variant_ref_sink(signalParams[i++]);
+ signalParams[i] = {
+ g_variant_new("(uuudiut)", // NOLINT
+ static_cast(gesture->type()), // u
+ static_cast(gesture->direction()), // u
+ static_cast(gesture->axis()), // u
+ gesture->percentage(), // d
+ gesture->fingers(), // i
+ static_cast(gesture->performedOnDeviceType()), // u
+ gesture->elapsedTime())}; // t
+ g_variant_ref_sink(signalParams[i++]);
// Send the message to every client
- for (auto *connection : this->connections) {
- if (g_dbus_connection_is_closed(connection) == TRUE) {
- closedConnections.push_back(connection);
- } else {
- GError *error = nullptr;
- gboolean sent = g_dbus_connection_emit_signal(
- connection, nullptr, DBUS_OBJECT_PATH, DBUS_INTERFACE_NAME,
- signalName.c_str(), signalParams, &error);
- if (sent == FALSE) {
- tlg::error << "Error sending message: " << error->message << std::endl;
+ while (--i >= 0) {
+ for (auto *connection : this->connections) {
+ if (g_dbus_connection_is_closed(connection) == TRUE) {
closedConnections.push_back(connection);
+ } else {
+ GError *error = nullptr;
+ gboolean sent = g_dbus_connection_emit_signal(
+ connection, nullptr, DBUS_OBJECT_PATHS[i], DBUS_INTERFACE_NAMES[i],
+ signalName.c_str(), signalParams[i], &error);
+ if (sent == FALSE) {
+ if (error != nullptr) {
+ tlg::error << "Error sending message: " << error->message << std::endl;
+ }
+ closedConnections.push_back(connection);
+ }
}
}
- }
- g_variant_unref(signalParams);
+ g_variant_unref(signalParams[i]);
+ }
// Remove dead clients
for (auto *connection : closedConnections) {
diff --git a/src/daemon/dbus.h b/src/daemon/dbus.h
index 9e9f1924..021842ea 100644
--- a/src/daemon/dbus.h
+++ b/src/daemon/dbus.h
@@ -24,14 +24,27 @@ constexpr auto DBUS_ADDRESS = "unix:path=/tmp/touchegg#0";
constexpr auto DBUS_ADDRESS = "unix:abstract=touchegg";
#endif
+// Singular is legacy
constexpr auto DBUS_OBJECT_PATH = "/io/github/joseexposito/Touchegg";
+// New versions should be appended to the bottom of the list
+constexpr const char* DBUS_OBJECT_PATHS[] = {
+ "/io/github/joseexposito/Touchegg", // 0 for legacy
+ "/io/github/joseexposito/Touchegg1"
+};
+// Singular is legacy
constexpr auto DBUS_INTERFACE_NAME = "io.github.joseexposito.Touchegg";
+// New versions should be appended to the bottom of the list
+constexpr const char* DBUS_INTERFACE_NAMES[] = {
+ "io.github.joseexposito.Touchegg", // 0 for legacy
+ "io.github.joseexposito.Touchegg1"
+};
constexpr auto DBUS_ON_GESTURE_BEGIN = "OnGestureBegin";
constexpr auto DBUS_ON_GESTURE_UPDATE = "OnGestureUpdate";
constexpr auto DBUS_ON_GESTURE_END = "OnGestureEnd";
+// Versions should be in order from oldest to newest
constexpr auto DBUS_INTROSPECTION_XML =
""
" "
@@ -60,6 +73,35 @@ constexpr auto DBUS_INTROSPECTION_XML =
" "
" "
" "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
"";
#endif // DAEMON_DBUS_H_
diff --git a/src/gesture-controller/gesture-controller.cpp b/src/gesture-controller/gesture-controller.cpp
old mode 100755
new mode 100644
index 5801c963..b76903a7
--- a/src/gesture-controller/gesture-controller.cpp
+++ b/src/gesture-controller/gesture-controller.cpp
@@ -25,6 +25,7 @@
#include "actions/action-type.h"
#include "actions/action.h"
#include "config/config.h"
+#include "gesture/gesture-axis.h"
#include "gesture/gesture-direction.h"
#include "gesture/gesture-type.h"
#include "gesture/gesture.h"
@@ -36,12 +37,18 @@ GestureController::GestureController(const Config &config,
: config(config), windowSystem(windowSystem) {}
void GestureController::onGestureBegin(std::unique_ptr gesture) {
+ // Deduce axis from direction when possible
+ if (gesture->axis() == GestureAxis::UNKNOWN) {
+ gesture->setAxis(gestureAxisFromDirection(gesture->direction()));
+ }
+
tlg::debug << "Gesture begin detected" << std::endl;
tlg::debug << "\tGesture information:" << std::endl;
tlg::debug << "\t\tFingers: " << gesture->fingers() << std::endl;
tlg::debug << "\t\tType: " << gestureTypeToStr(gesture->type()) << std::endl;
tlg::debug << "\t\tDirection: " << gestureDirectionToStr(gesture->direction())
<< std::endl;
+ tlg::debug << "\t\tAxis: " << gestureAxisToStr(gesture->axis()) << std::endl;
this->rotatedDirection = this->windowSystem.calculateRotation(
gesture->type(), gesture->performedOnDeviceType(), gesture->direction());
@@ -49,6 +56,7 @@ void GestureController::onGestureBegin(std::unique_ptr gesture) {
tlg::debug << "\t\tDirection after rotation: "
<< gestureDirectionToStr(this->rotatedDirection) << std::endl;
gesture->setDirection(this->rotatedDirection);
+ gesture->setAxis(gestureAxisFromDirection(this->rotatedDirection));
}
this->window = this->windowSystem.getWindowUnderCursor();
@@ -102,18 +110,19 @@ std::unique_ptr GestureController::getActionForGesture(
const GestureType gestureType = gesture.type();
int fingers = gesture.fingers();
const GestureDirection direction = gesture.direction();
+ const GestureAxis axis = gesture.axis();
// First check if there is an specific application gesture
application = this->windowSystem.getWindowClassName(window);
tlg::debug << "\tGesture performed on app: " << application << std::endl;
hasAction = this->config.hasGestureConfig(application, gestureType, fingers,
- direction);
+ direction, axis);
// If no gesture was configured, check the global gestures
if (!hasAction) {
application = "All";
hasAction = this->config.hasGestureConfig(application, gestureType, fingers,
- direction);
+ direction, axis);
}
if (!hasAction) {
@@ -124,7 +133,7 @@ std::unique_ptr GestureController::getActionForGesture(
tlg::debug << "\tAction configured for this gesture" << std::endl;
auto pair = this->config.getGestureConfig(application, gestureType, fingers,
- direction);
+ direction, axis);
ActionType actionType = pair.first;
std::unordered_map actionSettings = pair.second;
diff --git a/src/gesture-controller/gesture-controller.h b/src/gesture-controller/gesture-controller.h
old mode 100755
new mode 100644
index e9dc6bdc..1af51d86
--- a/src/gesture-controller/gesture-controller.h
+++ b/src/gesture-controller/gesture-controller.h
@@ -60,10 +60,11 @@ class GestureController : public GestureControllerDelegate {
bool executeAction = false;
/**
- * If the screen is rotated, this values is set on gesture begin to match the
- * screen rotation.
+ * If the screen is rotated, these values are set on gesture begin to match
+ * the screen rotation.
*/
GestureDirection rotatedDirection = GestureDirection::UNKNOWN;
+ GestureAxis rotatedAxis = GestureAxis::UNKNOWN;
/**
* @returns The action associated to a gesture or nullptr.
diff --git a/src/gesture-gatherer/libinput-handler.cpp b/src/gesture-gatherer/libinput-handler.cpp
index f09a22b8..d6623b58 100644
--- a/src/gesture-gatherer/libinput-handler.cpp
+++ b/src/gesture-gatherer/libinput-handler.cpp
@@ -58,6 +58,12 @@ GestureDirection LininputHandler::calculateSwipeDirection(double deltaX,
return (deltaY > 0) ? GestureDirection::DOWN : GestureDirection::UP;
}
+GestureAxis LininputHandler::calculatePinchAxis(double deltaX,
+ double deltaY) {
+ return (std::abs(deltaX) > std::abs(deltaY)) ?
+ GestureAxis::HORIZONTAL : GestureAxis::VERTICAL;
+}
+
double LininputHandler::calculateSwipeAnimationPercentage(
const LibinputDeviceInfo &info, GestureDirection direction, double deltaX,
double deltaY) {
diff --git a/src/gesture-gatherer/libinput-handler.h b/src/gesture-gatherer/libinput-handler.h
index bf7ac02a..0d82d600 100644
--- a/src/gesture-gatherer/libinput-handler.h
+++ b/src/gesture-gatherer/libinput-handler.h
@@ -54,6 +54,11 @@ class LininputHandler {
*/
static GestureDirection calculateSwipeDirection(double deltaX, double deltaY);
+ /**
+ * @returns The primary axis of a pinch gesture.
+ */
+ static GestureAxis calculatePinchAxis(double deltaX, double deltaY);
+
/**
* @returns The percentage (between 0 and 100) of the gesture animation.
*/
diff --git a/src/gesture-gatherer/libinput-pinch-handler.cpp b/src/gesture-gatherer/libinput-pinch-handler.cpp
index 189fd8d6..bdbbc01d 100644
--- a/src/gesture-gatherer/libinput-pinch-handler.cpp
+++ b/src/gesture-gatherer/libinput-pinch-handler.cpp
@@ -22,8 +22,19 @@
#include "gesture/device-type.h"
-void LininputPinchHandler::handlePinchBegin(struct libinput_event * /*event*/) {
+void LininputPinchHandler::handlePinchBegin(struct libinput_event *event) {
this->state.reset();
+
+ struct libinput_event_gesture *gestureEvent =
+ libinput_event_get_gesture_event(event);
+ if (
+ std::abs(libinput_event_gesture_get_dx(gestureEvent))
+ > std::abs(libinput_event_gesture_get_dy(gestureEvent))
+ ) {
+ this->state.axis = GestureAxis::HORIZONTAL;
+ } else {
+ this->state.axis = GestureAxis::VERTICAL;
+ }
}
void LininputPinchHandler::handlePinchUpdate(struct libinput_event *event) {
@@ -36,14 +47,19 @@ void LininputPinchHandler::handlePinchUpdate(struct libinput_event *event) {
this->state.startTimestamp = LininputHandler::getTimestamp();
this->state.direction =
(this->state.delta > 1) ? GestureDirection::OUT : GestureDirection::IN;
+ this->state.axis = (std::abs(libinput_event_gesture_get_dx(gestureEvent)) >
+ std::abs(libinput_event_gesture_get_dy(gestureEvent)))
+ ? GestureAxis::HORIZONTAL
+ : GestureAxis::VERTICAL;
this->state.percentage = LininputHandler::calculatePinchAnimationPercentage(
this->state.direction, this->state.delta);
this->state.fingers = libinput_event_gesture_get_finger_count(gestureEvent);
uint64_t elapsedTime = 0;
auto gesture = std::make_unique(
- GestureType::PINCH, this->state.direction, this->state.percentage,
- this->state.fingers, DeviceType::TOUCHPAD, elapsedTime);
+ GestureType::PINCH, this->state.direction, this->state.axis,
+ this->state.percentage, this->state.fingers, DeviceType::TOUCHPAD,
+ elapsedTime);
this->gestureController->onGestureBegin(std::move(gesture));
} else {
this->state.percentage = LininputHandler::calculatePinchAnimationPercentage(
@@ -52,8 +68,9 @@ void LininputPinchHandler::handlePinchUpdate(struct libinput_event *event) {
LininputHandler::calculateElapsedTime(this->state.startTimestamp);
auto gesture = std::make_unique(
- GestureType::PINCH, this->state.direction, this->state.percentage,
- this->state.fingers, DeviceType::TOUCHPAD, elapsedTime);
+ GestureType::PINCH, this->state.direction, this->state.axis,
+ this->state.percentage, this->state.fingers, DeviceType::TOUCHPAD,
+ elapsedTime);
this->gestureController->onGestureUpdate(std::move(gesture));
}
}
@@ -69,8 +86,9 @@ void LininputPinchHandler::handlePinchEnd(struct libinput_event *event) {
LininputHandler::calculateElapsedTime(this->state.startTimestamp);
auto gesture = std::make_unique(
- GestureType::PINCH, this->state.direction, this->state.percentage,
- this->state.fingers, DeviceType::TOUCHPAD, elapsedTime);
+ GestureType::PINCH, this->state.direction, this->state.axis,
+ this->state.percentage, this->state.fingers, DeviceType::TOUCHPAD,
+ elapsedTime);
this->gestureController->onGestureEnd(std::move(gesture));
}
diff --git a/src/gesture-gatherer/libinput-pinch-handler.h b/src/gesture-gatherer/libinput-pinch-handler.h
index 78a7a428..16a1a986 100644
--- a/src/gesture-gatherer/libinput-pinch-handler.h
+++ b/src/gesture-gatherer/libinput-pinch-handler.h
@@ -32,6 +32,7 @@ struct LibinputPinchState {
uint64_t startTimestamp = 0;
double delta = 1;
GestureDirection direction = GestureDirection::UNKNOWN;
+ GestureAxis axis = GestureAxis::UNKNOWN;
double percentage = 0;
int fingers = 0;
@@ -40,6 +41,7 @@ struct LibinputPinchState {
startTimestamp = 0;
delta = 1;
direction = GestureDirection::UNKNOWN;
+ axis = GestureAxis::UNKNOWN;
percentage = 0;
fingers = 0;
}
diff --git a/src/gesture-gatherer/libinput-touch-handler.cpp b/src/gesture-gatherer/libinput-touch-handler.cpp
index 2f8b3837..d35fae41 100644
--- a/src/gesture-gatherer/libinput-touch-handler.cpp
+++ b/src/gesture-gatherer/libinput-touch-handler.cpp
@@ -124,10 +124,12 @@ void LibinputTouchHandler::handleTouchMotion(struct libinput_event *event) {
this->state.startFingers = this->state.currentFingers;
this->state.startTimestamp = LininputHandler::getTimestamp();
this->state.type = this->getGestureType();
- this->state.direction =
- (this->state.type == GestureType::SWIPE)
- ? LininputHandler::calculateSwipeDirection(deltaX, deltaY)
- : this->calculatePinchDirection();
+ if (this->state.type == GestureType::SWIPE) {
+ this->state.direction = LininputHandler::calculateSwipeDirection(deltaX, deltaY);
+ } else {
+ this->state.direction = this->calculatePinchDirection();
+ this->state.axis = this->calculatePinchAxis(deltaX, deltaY);
+ }
// Once the direction is calculated, save the currentX/Y as startX/Y so
// the startThreshold is not included in the percentage calculations
@@ -136,8 +138,9 @@ void LibinputTouchHandler::handleTouchMotion(struct libinput_event *event) {
this->state.startY = this->state.currentY;
auto gesture = std::make_unique(
- this->state.type, this->state.direction, percentage,
- this->state.startFingers, DeviceType::TOUCHSCREEN, 0);
+ this->state.type, this->state.direction, this->state.axis,
+ percentage, this->state.startFingers, DeviceType::TOUCHSCREEN,
+ 0);
this->gestureController->onGestureBegin(std::move(gesture));
}
} else {
diff --git a/src/gesture-gatherer/libinput-touch-handler.h b/src/gesture-gatherer/libinput-touch-handler.h
index ccd5333f..daf1be38 100644
--- a/src/gesture-gatherer/libinput-touch-handler.h
+++ b/src/gesture-gatherer/libinput-touch-handler.h
@@ -22,6 +22,7 @@
#include
#include "gesture-gatherer/libinput-handler.h"
+#include "gesture/gesture-axis.h"
#include "gesture/gesture-direction.h"
#include "gesture/gesture-type.h"
@@ -32,6 +33,7 @@ struct LibinputTouchState {
bool started = false;
GestureType type = GestureType::NOT_SUPPORTED;
GestureDirection direction = GestureDirection::UNKNOWN;
+ GestureAxis axis = GestureAxis::UNKNOWN;
uint64_t startTimestamp = 0;
int startFingers = 0;
std::unordered_map startX;
@@ -45,6 +47,7 @@ struct LibinputTouchState {
started = false;
type = GestureType::NOT_SUPPORTED;
direction = GestureDirection::UNKNOWN;
+ axis = GestureAxis::UNKNOWN;
startTimestamp = 0;
startFingers = 0;
tapFingers = 0;
diff --git a/src/gesture/gesture-axis.h b/src/gesture/gesture-axis.h
new file mode 100644
index 00000000..f7b84579
--- /dev/null
+++ b/src/gesture/gesture-axis.h
@@ -0,0 +1,77 @@
+/**
+ * Copyright 2011 - 2022 José Expósito
+ *
+ * This file is part of Touchégg.
+ *
+ * Touchégg 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.
+ *
+ * Touchégg 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
+ * Touchégg. If not, see .
+ */
+#ifndef GESTURE_GESTURE_AXIS_H_
+#define GESTURE_GESTURE_AXIS_H_
+
+#include
+#include "gesture-direction.h"
+
+enum class GestureAxis {
+ // A gesture may have an unknown axis until we have more information
+ UNKNOWN = 0,
+
+ HORIZONTAL = 1,
+ VERTICAL = 2
+ // DISTAL = 3
+
+ // Adding a new GestureDirection? Don't forget to add it in
+ // gestureAxisToStr and gestureAxisFromStr as well
+};
+
+inline std::string gestureAxisToStr(GestureAxis gestureAxis) {
+ switch (gestureAxis) {
+ case GestureAxis::HORIZONTAL:
+ return "HORIZONTAL";
+ case GestureAxis::VERTICAL:
+ return "VERTICAL";
+ // case GestureAxis::DISTAL:
+ // return "DISTAL";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+inline GestureAxis gestureAxisFromStr(const std::string &str) {
+ if (str == "HORIZONTAL") {
+ return GestureAxis::HORIZONTAL;
+ }
+ if (str == "VERTICAL") {
+ return GestureAxis::VERTICAL;
+ }
+ // if (str == "DISTAL") {
+ // return GestureAxis::DISTAL;
+ // }
+ return GestureAxis::UNKNOWN;
+}
+
+inline GestureAxis gestureAxisFromDirection(GestureDirection gestureDirection) {
+ switch (gestureDirection) {
+ case GestureDirection::UP:
+ return GestureAxis::VERTICAL;
+ case GestureDirection::DOWN:
+ return GestureAxis::VERTICAL;
+ case GestureDirection::LEFT:
+ return GestureAxis::HORIZONTAL;
+ case GestureDirection::RIGHT:
+ return GestureAxis::HORIZONTAL;
+ default:
+ return GestureAxis::UNKNOWN;
+ }
+}
+
+#endif // GESTURE_GESTURE_AXIS_H_
diff --git a/src/gesture/gesture.h b/src/gesture/gesture.h
index 8a7e320d..57446405 100644
--- a/src/gesture/gesture.h
+++ b/src/gesture/gesture.h
@@ -21,6 +21,7 @@
#include
#include "gesture/device-type.h"
+#include "gesture/gesture-axis.h"
#include "gesture/gesture-direction.h"
#include "gesture/gesture-type.h"
@@ -34,6 +35,17 @@ class Gesture {
int fingers, DeviceType performedOnDeviceType, uint64_t elapsedTime)
: gestureType(type),
gestureDirection(direction),
+ gestureAxis(gestureAxisFromDirection(direction)),
+ gesturePercentage(percentage),
+ gestureFingers(fingers),
+ deviceType(performedOnDeviceType),
+ gestureElapsedTime(elapsedTime) {}
+ Gesture(GestureType type, GestureDirection direction, GestureAxis axis,
+ double percentage, int fingers, DeviceType performedOnDeviceType,
+ uint64_t elapsedTime)
+ : gestureType(type),
+ gestureDirection(direction),
+ gestureAxis(axis),
gesturePercentage(percentage),
gestureFingers(fingers),
deviceType(performedOnDeviceType),
@@ -51,6 +63,12 @@ class Gesture {
*/
GestureDirection direction() const { return this->gestureDirection; }
+ /**
+ * @returns The gesture axis.
+ * @see GestureAxis
+ */
+ GestureAxis axis() const { return this->gestureAxis; }
+
/**
* Percentage of the gesture performed, used for animations.
* @return Value between 0 and 100.
@@ -81,9 +99,16 @@ class Gesture {
this->gestureDirection = direction;
}
+ /**
+ * Set the gesture axis.
+ * @see GestureAxis
+ */
+ void setAxis(GestureAxis axis) { this->gestureAxis = axis; }
+
protected:
GestureType gestureType = GestureType::NOT_SUPPORTED;
GestureDirection gestureDirection = GestureDirection::UNKNOWN;
+ GestureAxis gestureAxis = GestureAxis::UNKNOWN;
double gesturePercentage = -1;
int gestureFingers = -1;
DeviceType deviceType = DeviceType::UNKNOWN;
diff --git a/src/window-system/window-system.h b/src/window-system/window-system.h
index aa77ae29..0c9fd75c 100644
--- a/src/window-system/window-system.h
+++ b/src/window-system/window-system.h
@@ -133,13 +133,22 @@ class WindowSystem {
bool isPress) const = 0;
/**
- * Simulates a mouse click.
+ * Simulates a mouse down event.
* @param button One of this values:
* 1 – Left button click
* 2 – Middle button click
* 3 – Right button click
*/
- virtual void sendMouseClick(int button) const = 0;
+ virtual void sendMouseDown(int button) const = 0;
+
+ /**
+ * Simulates a mouse up event.
+ * @param button One of this values:
+ * 1 – Left button click
+ * 2 – Middle button click
+ * 3 – Right button click
+ */
+ virtual void sendMouseUp(int button) const = 0;
/**
* @returns The size of the desktop workarea, ie, the area of the desktop not
diff --git a/src/window-system/x11.cpp b/src/window-system/x11.cpp
index 3a587af4..3001ec32 100644
--- a/src/window-system/x11.cpp
+++ b/src/window-system/x11.cpp
@@ -466,8 +466,12 @@ void X11::sendKeys(const std::vector &keycodes,
XFlush(this->display);
}
-void X11::sendMouseClick(int button) const {
+void X11::sendMouseDown(int button) const {
XTestFakeButtonEvent(this->display, button, True, 0);
+ XFlush(this->display);
+}
+
+void X11::sendMouseUp(int button) const {
XTestFakeButtonEvent(this->display, button, False, 0);
XFlush(this->display);
}
diff --git a/src/window-system/x11.h b/src/window-system/x11.h
index fcb1df78..a2713ee0 100644
--- a/src/window-system/x11.h
+++ b/src/window-system/x11.h
@@ -66,7 +66,8 @@ class X11 : public WindowSystem {
void sendKeys(const std::vector &keycodes,
bool isPress) const override;
- void sendMouseClick(int button) const override;
+ void sendMouseDown(int button) const override;
+ void sendMouseUp(int button) const override;
Rectangle getDesktopWorkarea() const override;
void changeDesktop(ActionDirection direction, bool cyclic) const override;