Simplify file checkpoint

This commit is contained in:
Rico Tiongson 2020-04-20 05:58:18 +08:00
parent 4ccf85bed5
commit 66926f7cea
10 changed files with 608 additions and 72 deletions

View File

@ -9,10 +9,16 @@ Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures
## Installation
1. Install git, libinput, and g++
1. Install git and g++
```bash
sudo apt-get install git libinput-tools libxdo-dev g++
sudo apt install git g++
```
1. Install libinput-tools and C libraries
```bash
sudo apt install libinput-tools libconfig-dev libxdo-dev
```
2. Clone this repository

View File

@ -180,7 +180,7 @@ case $i in
exit 0
;;
-v | --version) # eagerly print version
echo "$version"
echo "comfortable-swipe $version"
exit 0
;;
*) # unknown option

View File

@ -0,0 +1,89 @@
#ifndef __comfortable_swipe_buffer__
#define __comfortable_swipe_buffer__
/*
Comfortable Swipe (as of v1.2.0)
by Rico Tiongson
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 <http://www.gnu.org/licenses/>.
*/
#include <cstdio> // fgets_unlocked, stdin
#include <iostream> // ios, cout, cin
#include <confuse.h> // cfg_t
#include "comfortable-swipe-config.cpp"
#include "comfortable-swipe-defines.cpp"
#include "comfortable-swipe-gesture-mousehold.cpp"
#include "comfortable-swipe-gesture-swipe.cpp"
/**
* The main driver program.
*/
int main() {
using namespace std;
using namespace comfortable_swipe;
// unsync with for faster IO
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.flush();
// prepare config file
cfg_ auto config =
comfortable_swipe::read_config_file(COMFORTABLE_SWIPE_CONFIG);
// initialize mouse hold gesture handler
// for now, this supports 3-finger and 4-finger hold
// Examples:
// hold3=move move mouse on 3 fingers
// hold3=button1 hold button 1 on 3 fingers
// hold4=button3 hold button 3 (right click) on 3 fingers
// hold3=ignore <do nothing>
gesture_mousehold mouse_hold(config_get_string("hold3"), config_get_string("hold4"));
// initialize keyboard swipe gesture handler
gesture_swipe = keyboard_swipe(
config_get_float("threshold"),
config_get_string("left3"),
config_get_string("left4"),
config_get_string("right3"),
config_get_string("right4"),
config_get_string("up3"),
config_get_string("up4"),
config_get_string("down3"),
config_get_string("down4"),
);
// prepare data containers
array<char, 256> line;
// start reading lines from input one by one
while (fgets_unlocked(line.data(), line.size(), stdin) != NULL) {
// prioritize mouse hold gesture first
mouse_hold.parse_line(line.data());
// if mouse hold fails, try keyboard hold
if (!mouse_hold.is_mousedown()) {
// attempt to parse keyboard gestures
keyboard_swipe.parse_line(line.data());
}
}
return 0;
}
#endif

View File

@ -0,0 +1,84 @@
#ifndef __comfortable_swipe_config__
#define __comfortable_swipe_config__
/*
Comfortable Swipe (as of v1.2.0)
by Rico Tiongson
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 <http://www.gnu.org/licenses/>.
*/
#include <array> // std::array
#include <iostream> // std::cout
#include <memory> // std::unique_ptr
extern "C" {
#include <confuse.h> // cfg_t
}
#include "comfortable-swipe-defines.cpp"
namespace comfortable_swipe {
// prepare config file
// Examples: cfg_getstr(get_config(), "left3")
// cfg_getfloat(get_config(), "threshold")
cfg_t *get_config() {
using namespace std;
// use std::unique_ptr for auto garbage collection
static std::unique_ptr<cfg_t, decltype(&cfg_free)> config;
// try to return existing config
if (config != nullptr)
return config.get();
// list down possible options here
// second argument is the default value
// make sure to end with CFG_END()
array<cfg_opt_t> cfg_options = {
CFG_STR("left3", "", CFGF_NONE),
CFG_STR("left4", "", CFGF_NONE),
CFG_STR("right3", "", CFGF_NONE),
CFG_STR("right4", "", CFGF_NONE),
CFG_STR("up3", "", CFGF_NONE),
CFG_STR("up4", "", CFGF_NONE),
CFG_STR("down3", "", CFGF_NONE),
CFG_STR("down4", "", CFGF_NONE),
CFG_FLOAT("threshold", 0.0, CFGF_NONE),
CFG_STR("hold3", "", CFGF_NONE),
CFG_STR("hold4", "", CFGF_NONE),
// make sure to end here
CFG_END()
);
// initialize
config = std::auto_ptr(cfg_init(cfg_options.data(), CFGF_NONE)):
if (cfg_parse(config.get(), COMFORTABLE_SWIPE_CONFIG) == CFG_PARSE_ERROR) {
throw runtime_error(
"cannot parse config file at: " COMFORTABLE_SWIPE_CONFIG);
}
return config.get();
}
// utility methods
inline const char *get_config_string(const char *key) {
return cfg_getstr(get_config(), key);
}
inline double get_config_float(const char *key) {
return cfg_getfloat(get_config(), key);
}
} // namespace comfortable_swipe
#endif /* __comfortable_swipe_config__ */

View File

@ -0,0 +1,38 @@
#ifndef __comfortable_swipe_defines__
#define __comfortable_swipe_defines__
// Place #define statements here
/*
Comfortable Swipe (as of v1.2.0)
by Rico Tiongson
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 <http://www.gnu.org/licenses/>.
*/
#ifndef COMFORTABLE_SWIPE_CONFIG
#warning Please define COMFORTABLE_SWIPE_CONFIG during compilation!\
(g++ -DCOMFORTABLE_SWIPE_CONFIG="\"/home/$USER/.config/comfortable-swipe.conf\"")
#endif /* COMFORTABLE_SWIPE_CONFIG */
#ifndef COMFORTABLE_SWIPE_AUTOSTART
#warning Please define COMFORTABLE_SWIPE_AUTOSTART during compilation!\
(g++ -DCOMFORTABLE_SWIPE_AUTOSTART="\"/home/$USER/.config/autostart/comfortable-swipe.desktop\"")
#endif /* COMFORTABLE_SWIPE_AUTOSTART */
#ifndef COMFORTABLE_SWIPE_VERSION
#warning COMFORTABLE_SWIPE_VERSION is not defined
#define COMFORTABLE_SWIPE_VERSION "v(UNKNOWN)"
#endif /* COMFORTABLE_SWIPE_VERSION */
#endif /* __comfortable_swipe_defines__ */

View File

@ -0,0 +1,218 @@
#ifndef __comfortable_swipe_gesture_mousehold__
#define __comfortable_swipe_gesture_mousehold__
/*
Comfortable Swipe
by Rico Tiongson
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 <http://www.gnu.org/licenses/>.
*/
#include <cstdio> // std::sscanf
#include <cstring> // strncmp
#include <iostream> // std::cout, std::endl
extern "C" {
#include <xdo.h> // xdo, xdo_new, xdo_free,
// xdo_get_mouse_location
// CURRENT_WINDOW
}
#include "comfortable-swipe-gesture-swipe.cpp"
namespace comfortable_swipe {
// enumerations for mouse hold gesture types
enum {
MOUSE_NONE = -1,
MOUSE_MOVE = 0,
MOUSE_LEFT_CLICK = 1,
MOUSE_MIDDLE_CLICK = 2,
MOUSE_RIGHT_CLICK = 3,
MOUSE_WHEEL_UP = 4,
MOUSE_WHEEL_DOWN = 5,
MOUSE_SCROLL = 6,
MOUSE_SCROLL_REVERSE = 7
};
class gesture_mousehold : public gesture_swipe {
public:
// constructor
gesture_mousehold(const char *hold3, // 3 finger mouse down
const char *hold4 // 4 finger mouse down
);
// the button being clicked
int button;
virtual ~gesture_mousehold();
// override begin and end for mousedown
virtual void begin() override;
virtual void update() override;
virtual void end() override;
// provide our own mouse functions
virtual void do_mousedown(const char *);
virtual void do_mouseup(const char *);
virtual bool is_mousedown() const;
// 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;
// flag we can use to check if mouse is down
bool flag_mousedown;
};
} // namespace comfortable_swipe
/**
* Constructs a new mouse gesture, given "hold3" and "hold4" configurations.
*/
gesture_mousehold::gesture_mousehold(const char *hold3, const char *hold4)
: gesture_swipe(), button(MOUSE_NONE), hold3(hold3), hold4(hold4),
flag_mousedown(false) {}
/**
* Destructs this mouse swipe gesture.
*/
gesture_mousehold::~gesture_mousehold() {}
/**
* Run mousedown command on hold input.
*/
void gesture_mousehold::do_mousedown(const char *mouseinput) {
const int button = this->button = this->parse_mouse_button(mouseinput);
if (button != MOUSE_NONE) {
// eg. MOUSE DOWN hold3 mouse1
std::printf("MOUSE DOWN hold%d %s\n", this->fingers, mouseinput);
if (MOUSE_LEFT_CLICK <= button && button <= MOUSE_RIGHT_CLICK) {
// send mouse down on associated button
xdo_mouse_down(this->xdo, CURRENTWINDOW, button);
}
this->flag_mousedown = true;
}
}
/**
* Run mouseup command on hold output.
*/
void gesture_mousehold::do_mouseup(const char *mouseinput) {
const int button = this->button = this->parse_mouse_button(mouseinput);
if (button != MOUSE_NONE) {
std::printf("MOUSE UP hold%d %s\n", this->fingers, mouseinput);
if (MOUSE_LEFT_CLICK <= button && button <= MOUSE_RIGHT_CLICK) {
// send mouse up on associated button
xdo_mouse_up(this->xdo, CURRENTWINDOW, button);
}
this->flag_mousedown = false;
}
}
/**
* Utility method to parse mouse number from input.
* Returns -1 on failure.
*/
int gesture_mousehold::parse_mouse_button(const char *input) {
// just move without holding button down
if (std::strcmp(input, "move") == 0)
return MOUSE_MOVE;
if (std::strcmp(input, "scroll") == 0)
return MOUSE_SCROLL;
if (std::strcmp(input, "scroll_reverse") == 0)
return MOUSE_SCROLL_REVERSE;
// get button number
int button;
if (std::sscanf(input, "button%d", &button) == 1) {
if (1 <= button && button <= 6) {
return button;
}
}
return MOUSE_NONE;
}
/**
* Hook on begin of mouse swipe gesture.
*/
void gesture_mousehold::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);
}
}
/**
* Hook on end of mouse swipe gesture.
*/
void gesture_mousehold::update() {
// call superclass method
gesture_swipe::update();
if (this->is_mousedown()) {
if (0 <= this->button && this->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) {
// perform naive scroll depending on vertical direction
int wheel = MOUSE_WHEEL_DOWN;
if ((this->udy > 0) == (this->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) {
// click wheel button on 4 or 5
xdo_mouse_down(this->xdo, CURRENTWINDOW, this->button);
xdo_mouse_up(this->xdo, CURRENTWINDOW, this->button);
}
}
}
/**
* Hook on end of swipe gesture.
*/
void gesture_mousehold::end() {
if (this->is_mousedown()) {
if (this->fingers == 3) {
this->do_mouseup(this->hold3);
} else if (this->fingers == 4) {
this->do_mouseup(this->hold4);
}
}
// call superclass method
gesture_swipe::end();
}
/**
* Utility method to check if mouse is current held.
*/
bool gesture_mousehold::is_mousedown() const { return this->flag_mousedown; }
}
#endif /* __comfortable_swipe_gesture_mousehold__ */

View File

@ -0,0 +1,156 @@
#ifndef __comfortable_swipe_gesture_swipe__
#define __comfortable_swipe_gesture_swipe__
/*
Comfortable Swipe
by Rico Tiongson
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 <http://www.gnu.org/licenses/>.
*/
#include <iostream> // std::cout, std::endl
#include <regex> // std::regex, std::regex_match, std::cmatch
#include <string> // std::stoi, std::stof
namespace comfortable_swipe {
class gesture_swipe {
public:
// constructor
gesture_swipe();
// destructor
virtual ~gesture_swipe();
// fields for xdo
int fingers;
// normal values (for touchpad mapping)
float x, y, dx, dy;
// unaccelerated values (for screen mapping)
float ux, uy, udx, udy;
// hooks that we can override (mark as virtual)
virtual void begin();
virtual void update();
virtual void end();
virtual bool parse_line(const char *);
protected:
// xdo container
xdo_t *xdo;
// location of mouse
int screen_num, ix, iy;
// optimization flag for checking if GESTURE_SWIPE_BEGIN was dispatched
bool flag_swiping;
public:
// regex patterns
static const std::regex *GESTURE_BEGIN_REGEX;
static const std::regex *GESTURE_UPDATE_REGEX;
static const std::regex *GESTURE_END_REGEX;
};
/**
* Constructs a new fresh swipe gesture container.
*/
gesture_swipe::gesture_swipe() : xdo(xdo_new(NULL)), flag_swiping(false) {
// improve responsiveness of first gesture by pre-empting xdotool
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
}
/**
* Destructs this swipe gesture.
*/
gesture_swipe::~gesture_swipe() { xdo_free(this->xdo); }
/**
* Hook on begin of swipe gesture (you can override this).
*/
void gesture_swipe::begin() {
// save current screen location for gestured mouse movement
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
this->x = 0;
this->y = 0;
this->ux = 0;
this->uy = 0;
}
/**
* Hook on update of swipe gesture (you can override this).
*/
void gesture_swipe::update() {
this->x += this->dx;
this->y += this->dy;
this->ux += this->udx;
this->uy += this->udy;
}
/**
* Hook on end of swipe gesture (you can override this).
*/
void gesture_swipe::end() {}
/**
* Dispatches begin/update/end depending on the regex pattern provided by this
* class.
*
* @param line the line from libinput debug-events to parse
* @return true if begin/update/end was dispatched
*/
bool gesture_swipe::parse_line(const char *line) {
// prepare holder for regex matches
static std::cmatch matches;
if (this->flag_swiping) {
// currently swiping
if (std::regex_match(line, matches, GESTURE_UPDATE_REGEX) != 0) {
// assign necessary variables for swipe update
this->fingers = std::stoi(matches[1]);
this->dx = std::stof(matches[2]);
this->dy = std::stof(matches[3]);
this->udx = std::stof(matches[4]);
this->udy = std::stof(matches[5]);
// dispatch update
this->update();
return true;
} else if (std::regex_match(line, matches, GESTURE_END_REGEX) != 0) {
// assign necessary variables for swipe end
this->flag_swiping = false;
this->fingers = std::stoi(matches[1]);
// dispatch end
this->end();
return true;
}
} else {
// not swiping, check if swipe will begin
if (std::regex_match(line, matches, GESTURE_BEGIN_REGEX) != 0 ||
std::regex_match(line, matches, GESTURE_UPDATE_REGEX) != 0) {
// assign necessary variables for swipe begin
this->flag_swiping = true;
this->fingers = std::stoi(matches[1]);
// dispatch begin
this->begin();
return true;
}
}
return false;
}
} // namespace comfortable_swipe
#endif /* __comfortable_swipe_gesture_swipe__ */

View File

@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=Comfortable Swipe
Comment=Comfortable 3/4-finger touchpad gestures
Exec=comfortable-swipe start
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true

View File

@ -1,67 +0,0 @@
/*
Comfortable Swipe
by Rico Tiongson
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 <http://www.gnu.org/licenses/>.
*/
#include "comfortable_swipe/lib"
#include <ios> // std::ios
#include <iostream> // std::cin, std::cout, std::cerr
#include <string> // std::string
/* Command-line function. */
int main(int argc, char **args) {
// improve buffering by decoupling loggers from stdio
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cerr.tie(0);
if (argc > 1) {
std::string arg = args[1];
// select based on argument
if (arg == "start")
comfortable_swipe::service::start();
else if (arg == "stop")
comfortable_swipe::service::stop();
else if (arg == "restart")
comfortable_swipe::service::restart();
else if (arg == "buffer")
comfortable_swipe::service::buffer();
else if (arg == "autostart")
comfortable_swipe::service::autostart();
else if (arg == "config")
comfortable_swipe::service::config();
else if (arg == "debug")
comfortable_swipe::service::debug();
else if (arg == "status")
comfortable_swipe::service::status();
else /* if (arg == "help") */
comfortable_swipe::service::help();
} else
comfortable_swipe::service::help();
return 0;
}

View File

@ -2,8 +2,12 @@
dir="$(dirname $0)"
version="$(cat "$dir/VERSION" | tr -d '[:space:]')"
libraries=-lxdo -lconfig++
exec g++ $@ \
-std=c++11 \
-O2 -lxdo -Wno-unused-result \
-std=c++14 \
-O2 \
-lxdo \
-lconfig++ \
-Wno-unused-result \
-DCOMFORTABLE_SWIPE_VERSION="\"$version\""