Revert "Use Travis CI (#59)"

This reverts commit 19734c8a2e.
This commit is contained in:
Rico Tiongson 2019-03-08 19:53:42 +08:00 committed by GitHub
parent 19734c8a2e
commit 0e744d539f
58 changed files with 1270 additions and 1559 deletions

120
.gitignore vendored
View File

@ -4,123 +4,3 @@
# IDE-specific
.idea
.vscode
# PYTHON
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
!/lib
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View File

@ -1,25 +0,0 @@
dist: xenial
language: python
sudo: required
python:
- 2.7
- 3.5
- 3.6
- 3.7
- 3.8-dev
addons:
apt:
update: true
sources:
- ubuntu-toolchain-r-test
packages:
- libxdo-dev
- libinput-tools
- g++-7
env:
CC: gcc-7
CXX: g++-7
install:
- pip install .
script:
- python setup.py test

View File

@ -1 +0,0 @@
include comfortable_swipe/res/comfortable-swipe.desktop

172
README.md
View File

@ -1,62 +1,30 @@
# Comfortable Swipe (Debian/Ubuntu)
# Comfortable Swipe (Ubuntu)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![comfortable-swipe: version](https://img.shields.io/github/tag-date/Hikari9/comfortable-swipe.svg?color=informational&label=comfortable-swipe)](https://github.com/Hikari9/comfortable-swipe/releases)
[![build: master](https://img.shields.io/travis/Hikari9/comfortable-swipe/master.svg?label=master)](https://github.com/Hikari9/comfortable-swipe/commits/master)
[![build: develop](https://img.shields.io/travis/Hikari9/comfortable-swipe/develop.svg?label=develop)](https://github.com/Hikari9/comfortable-swipe/commits/develop)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-orange.svg)](https://www.gnu.org/licenses/gpl-3.0)
Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures. Tested in Ubuntu 14.04 LTS and beyond, for Unity, GNOME, and KDE desktop environments.
> **Note**: May work for other Linux distros that support `libinput` and `libxdo` (untested).
Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures for Ubuntu 14.04 LTS and beyond. May work for other Linux distros that support `libinput`.
## Installation
1. Update and install essential tools and libraries
1. Install git, libinput, and g++
```bash
sudo apt update && sudo apt install git g++-7 python3-pip libinput-tools libxdo-dev
sudo apt-get install git libinput-tools libxdo-dev g++
```
2. Install `comfortable-swipe` for your user
2. Clone this repository
```bash
pip3 install --user git+https://github.com/Hikari9/comfortable-swipe
git clone https://github.com/Hikari9/comfortable-swipe-ubuntu.git
cd comfortable-swipe-ubuntu
```
3. You can check status with `comfortable-swipe status`
3. Install
```bash
$> comfortable-swipe status
usr/local/share/comfortable-swipe/comfortable-swipe.conf
threshold = 0.0
left3 = ctrl+alt+Right
left4 = ctrl+alt+shift+Right
right3 = ctrl+alt+Left
right4 = ctrl+alt+shift+Left
up3 = ctrl+alt+Down
up4 = ctrl+alt+shift+Down
down3 = ctrl+alt+Up
down4 = ctrl+alt+shift+Up
autostart is ON
comfortable-swipe program is STOPPED
bash install
```
3. You can list down all commands with `comfortable-swipe` or `comfortable-swipe help`
```bash
$> comfortable-swipe
comfortable-swipe [start|stop|restart|autostart|buffer|help|config|debug|status]
start - starts 3/4-finger gesture service
stop - stops 3/4-finger gesture service
restart - stops then starts 3/4-finger gesture service
autostart - automatically run on startup (toggleable)
buffer - parses output of libinput debug-events
help - shows the help dialog
config - locates the config file
debug - logs raw output from input events taken from libinput
status - checks status of program and autostart
```
4. You may delete the downloaded `comfortable-swipe-ubuntu` folder after installation.
## How to Run
@ -65,84 +33,27 @@ Comfortable, seamless, and fast 3-finger (and 4-finger) touchpad swipe gestures.
sudo gpasswd -a $USER $(ls -l /dev/input/event* | awk '{print $4}' | head --line=1)
```
2. ***Important***: After inputing your `sudo` password, log out then log back in
3. By default, comfortable-swipe should be running. Otherwise, run:
```bash
3. Run
```
comfortable-swipe start
```
You can see if gestures work correctly if you see `SWIPE xxx` in the output:
```bash
$> comfortable-swipe start
SWIPE left3
SWIPE right3
...
4. _Optional_: Automatically run on startup
```
## How to Upgrade
```bash
pip3 install -U --user git+https://github.com/Hikari9/comfortable-swipe
```
## Uninstall
```bash
# Uncomment below to COMPLETELY remove configurations (not recommended)
# rm $(comfortable-swipe config)
pip3 uninstall comfortable-swipe
```
## Other Commands
1. `comfortable-swipe config` - outputs location of configuration file
```bash
$> comfortable-swipe config
/usr/local/share/comfortable-swipe/comfortable-swipe.conf
comfortable-swipe autostart
```
2. `comfortable-swipe autostart` - Toggles autostart
```bash
$> comfortable-swipe autostart
Autostart switched off
5. Check the status of your application by running
```
3. `comfortable-swipe debug` - Debugs input (this is an unbuffered alias of `libinput debug-events`)
```bash
$> comfortable-swipe debug
...
-event9 DEVICE_ADDED TouchPad seat0 default group7 cap:pg size 70x50mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfinger dwt-on
...
event9 GESTURE_SWIPE_BEGIN +2.03s 3
event9 GESTURE_SWIPE_UPDATE +2.03s 3 -9.95/ 2.64 (-26.90/ 7.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.03s 3 -10.44/ 3.19 (-28.22/ 8.62 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.04s 3 -9.71/ 2.64 (-26.25/ 7.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.05s 3 -8.98/ 2.64 (-24.28/ 7.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.06s 3 -7.40/ 2.36 (-20.01/ 6.37 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.06s 3 -6.31/ 2.50 (-17.06/ 6.75 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.07s 3 -5.34/ 1.80 (-14.44/ 4.87 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.08s 3 -4.61/ 2.08 (-12.47/ 5.62 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.09s 3 -4.49/ 1.53 (-12.14/ 4.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.09s 3 -4.01/ 1.25 (-10.83/ 3.37 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.10s 3 -4.13/ 0.42 (-11.15/ 1.12 unaccelerated)
event9 GESTURE_SWIPE_END +2.11s 3
...
comfortable-swipe status
```
If you can see `GESTURE_SWIPE_XXX` in your output, that means your touchpad supports multi-touch swipe gestures.
## Configurations
Comfortable swipe makes use of keyboard shortcuts for configurations. Edit by running
```bash
gedit $(comfortable-swipe config)
```
nano $(comfortable-swipe config)
```
Make sure to restart after making changes:
```bash
Make sure to run after making changes:
```
comfortable-swipe restart
```
@ -174,6 +85,45 @@ Taken from `man xdotool`:
Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a complete list of keycodes you can use.
## Bug Reports
## Debugging
You can check your touchpad driver by running
```bash
comfortable-swipe debug
```
This is an alias of `libinput debug-events`. This logs all gestures you make on your touchpad, along with other input-based events that can be captured by libinput.
A working swipe gesture will show the following:
```bash
$ comfortable-swipe debug
...
-event9 DEVICE_ADDED TouchPad seat0 default group7 cap:pg size 70x50mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfinger dwt-on
...
event9 GESTURE_SWIPE_BEGIN +2.03s 3
event9 GESTURE_SWIPE_UPDATE +2.03s 3 -9.95/ 2.64 (-26.90/ 7.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.03s 3 -10.44/ 3.19 (-28.22/ 8.62 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.04s 3 -9.71/ 2.64 (-26.25/ 7.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.05s 3 -8.98/ 2.64 (-24.28/ 7.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.06s 3 -7.40/ 2.36 (-20.01/ 6.37 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.06s 3 -6.31/ 2.50 (-17.06/ 6.75 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.07s 3 -5.34/ 1.80 (-14.44/ 4.87 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.08s 3 -4.61/ 2.08 (-12.47/ 5.62 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.09s 3 -4.49/ 1.53 (-12.14/ 4.12 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.09s 3 -4.01/ 1.25 (-10.83/ 3.37 unaccelerated)
event9 GESTURE_SWIPE_UPDATE +2.10s 3 -4.13/ 0.42 (-11.15/ 1.12 unaccelerated)
event9 GESTURE_SWIPE_END +2.11s 3
...
```
If you can see `GESTURE_SWIPE_XXX` in your output, that means your touchpad supports multi-touch swipe gestures.
## Uninstall
Download the `uninstall` script then run `bash uninstall`
## Bug Reports
Create an issue [here](https://github.com/Hikari9/comfortable-swipe-ubuntu/issues/new) to report a bug.

2
comfortable-swipe.compile.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
g++ $(dirname $0)/comfortable-swipe.cpp -std=c++11 -O2 -lxdo -Wno-unused-result -o $1

70
comfortable-swipe.cpp Normal file
View File

@ -0,0 +1,70 @@
/*
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 <ios> // std::ios
#include <iostream> // std::cin, std::cout, std::cerr
#include <string> // std::string
#include "lib/comfortable_swipe"
/* MAIN DRIVER 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

@ -1,28 +0,0 @@
from __future__ import print_function
import sys
from comfortable_swipe.autostart import toggle_status
from comfortable_swipe.constants import CONFIG
from comfortable_swipe.status import print_status
from comfortable_swipe.cpp import service as cpp_service
def main():
if len(sys.argv) <= 1:
cpp_service.help()
else:
dict(
start=cpp_service.start,
stop=cpp_service.stop,
restart=cpp_service.restart,
buffer=cpp_service.buffer,
help=cpp_service.help,
debug=cpp_service.debug,
status=print_status,
autostart=lambda: print('Autostart switched', toggle_status()),
config=lambda: print(CONFIG),
)[sys.argv[1]]()
if __name__ == '__main__':
main()

View File

@ -1,66 +0,0 @@
from __future__ import print_function
import os
import sys
from comfortable_swipe.constants import NAME, RES, exe
# status enums
OFF = 'off'
ON = 'on'
# the target path to the autostart desktop file
def target_path():
return os.path.join(
os.getenv(
'XDG_CONFIG_HOME',
os.path.join(os.getenv('HOME'), '.config')
),
'autostart',
'{}.desktop'.format(NAME)
)
# path to the autostart template file to be copied
def template_path():
return os.path.join(RES, '{}.desktop'.format(NAME))
# parsed contents of the template file
def template(raw=False):
with open(template_path(), 'r') as file:
contents = file.read()
if raw:
return contents
return contents.replace('Exec=' + NAME, 'Exec={} {}'.format(sys.executable, exe()))
# gets the current autostart status
def get_status():
return ON if os.path.exists(target_path()) else OFF
# sets the autostart status
def set_status(status=ON):
if status == ON:
# make sure dir exists
path = target_path()
path_dir = os.path.dirname(path)
if not os.path.exists(path_dir):
os.makedirs(path_dir)
with open(target_path(), 'w') as file:
file.write(template())
elif status == OFF:
if os.path.exists(target_path()):
os.remove(target_path())
else:
raise ValueError('invalid status for autostart')
return status
# toggles autostart status
def toggle_status():
return set_status(OFF if get_status() == ON else ON)

View File

@ -1,17 +0,0 @@
import os
import sys
from distutils.spawn import find_executable
NAME = 'comfortable-swipe'
DESCRIPTION = 'Comfortable 3-finger and 4-finger swipe gestures'
BIN = os.path.dirname(sys.executable)
DIR = os.path.dirname(os.path.abspath(__file__))
PYTHON_NAME = os.path.basename(DIR)
RES = os.path.join(DIR, 'res')
CONFIG = os.path.join(sys.prefix, 'local', 'share', NAME, '{}.conf'.format(NAME))
DEFAULT_CONFIG = os.path.join(RES, 'defaults.conf')
def exe():
return find_executable(NAME)

View File

@ -1 +0,0 @@
# This is a placeholder module that will contain the C++ libraries.

View File

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

View File

@ -1,22 +0,0 @@
from __future__ import print_function
import os
from comfortable_swipe import autostart
from comfortable_swipe.cpp import service
from comfortable_swipe.constants import NAME, exe
def print_status():
service.status()
print('autostart is', autostart.get_status().upper())
print('{} program is {}'.format(NAME, 'RUNNING' if is_running() else 'STOPPED'))
def is_running():
import psutil
for process in psutil.process_iter():
process_args = [process.name()] + process.cmdline()
for index in range(len(process_args) - 1):
if process_args[index + 1] == 'start' and process_args[index].endswith(NAME):
return True
return False

View File

@ -1,8 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__index_cpp__
#define __COMFORTABLE_SWIPE__index_cpp__
#include "gesture/_index.cpp"
#include "service/_index.cpp"
#include "util/_index.cpp"
#endif /* __COMFORTABLE_SWIPE__index_cpp__ */

View File

@ -1,8 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__index_hpp__
#define __COMFORTABLE_SWIPE__index_hpp__
#include "gesture/_index.hpp"
#include "service/_index.hpp"
#include "util/_index.hpp"
#endif /* __COMFORTABLE_SWIPE__index_hpp__ */

View File

@ -1,12 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__macro_hpp__
#define __COMFORTABLE_SWIPE__macro_hpp__
#ifndef COMFORTABLE_SWIPE_CONFIG
#error "COMFORTABLE_SWIPE_CONFIG must be defined."
#endif /* COMFORTABLE_SWIPE_CONFIG */
#ifndef COMFORTABLE_SWIPE_VERSION
#warning "COMFORTABLE_SWIPE_VERSION is not defined."
#endif /* COMFORTABLE_SWIPE_VERSION */
#endif /* __COMFORTABLE_SWIPE__macro_hpp__ */

View File

@ -1,7 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__python_cpp__
#define __COMFORTABLE_SWIPE__python_cpp__
#include "service/_python.cpp"
#include "comfortable-swipe.cpp"
#endif /* __COMFORTABLE_SWIPE__python_cpp__ */

View File

@ -1 +0,0 @@
#include "comfortable-swipe.cpp"

View File

@ -1,9 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__gesture_index_cpp__
#define __COMFORTABLE_SWIPE__gesture_index_cpp__
#include "_index.hpp"
#include "xdo_gesture.cpp"
#include "swipe_gesture.cpp"
#include "swipe_gesture.regex.cpp"
#endif /* __COMFORTABLE_SWIPE__gesture_index_cpp__ */

View File

@ -1,7 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__gesture_index_hpp__
#define __COMFORTABLE_SWIPE__gesture_index_hpp__
#include "xdo_gesture.h"
#include "swipe_gesture.h"
#endif /* __COMFORTABLE_SWIPE__gesture_index_hpp__ */

View File

@ -1,216 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__gesture_swipe_gesture__
#define __COMFORTABLE_SWIPE__gesture_swipe_gesture__
/*
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 <string> // std::stoi, std::stof
#include <regex> // std::regex, std::regex_match, std::cmatch
#include <ctime>
#include "swipe_gesture.h"
extern "C"
{
#include <xdo.h> // xdo, xdo_new, xdo_free,
// xdo_get_mouse_location
// CURRENT_WINDOW
}
namespace comfortable_swipe
{
namespace gesture
{
/**
* Constructs a new swipe gesture, given configurations for certain swipe events.
*/
swipe_gesture::swipe_gesture
(
const float threshold,
const char* left3 /* 000 */,
const char* left4 /* 001 */,
const char* right3 /* 010 */,
const char* right4 /* 011 */,
const char* up3 /* 100 */,
const char* up4 /* 101 */,
const char* down3 /* 110 */,
const char* down4 /* 111 */
):
comfortable_swipe::gesture::xdo_gesture(),
threshold_squared(threshold*threshold),
commands(new const char*[8]{left3, left4, right3, right4, up3, up4, down3, down4}),
flag_swiping(false)
{
// improve responsiveness of first gesture by pre-empting xdotool runtime
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
}
/**
* Destructs this swipe gesture.
*/
swipe_gesture::~swipe_gesture()
{
delete[] commands;
}
/**
* Hook on begin of swipe gesture.
*/
void swipe_gesture::begin()
{
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
this->previous_gesture = swipe_gesture::FRESH;
this->x = 0;
this->y = 0;
}
/**
* Hook on update of swipe gesture.
*/
void swipe_gesture::update()
{
this->x += this->dx;
this->y += this->dy;
// scale threshold to 1/10 when gesture is not fresh
float scale = this->previous_gesture == swipe_gesture::FRESH
? 1.00f
: 0.01f; // square root of 1/10
static const float EPSILON = 1e-6f;
if (this->x * this->x + this->y * this->y
> this->threshold_squared * scale + EPSILON)
{
int mask = 0;
if (this->fingers == 3) mask |= swipe_gesture::MSK_THREE_FINGERS;
else if (this->fingers == 4) mask |= swipe_gesture::MSK_FOUR_FINGERS;
const float absx = x >= 0 ? x : -x;
const float absy = y >= 0 ? y : -y;
if (absx > absy)
{ // horizontal
mask |= swipe_gesture::MSK_HORIZONTAL;
if (x < 0)
mask |= swipe_gesture::MSK_NEGATIVE;
else
mask |= swipe_gesture::MSK_POSITIVE;
}
else /* std::abs(x) <= std::abs(y) */
{ // vertical
mask |= swipe_gesture::MSK_VERTICAL;
if (y < 0)
mask |= swipe_gesture::MSK_NEGATIVE;
else
mask |= swipe_gesture::MSK_POSITIVE;
}
// send command on fresh OR opposite gesture
if (this->previous_gesture == swipe_gesture::FRESH
|| this->previous_gesture == (mask ^ swipe_gesture::MSK_POSITIVE))
{
xdo_send_keysequence_window(this->xdo, CURRENTWINDOW, swipe_gesture::commands[mask], 0);
this->x = this->y = 0;
this->previous_gesture = mask;
std::cout << "SWIPE " << swipe_gesture::command_map[mask] << std::endl;
}
}
}
/**
* Hook on end of swipe gesture.
*/
void swipe_gesture::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 swipe_gesture::parse_line(const char * line)
{
static const std::regex gesture_swipe_begin(swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN);
static const std::regex gesture_swipe_update(swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN);
static const std::regex gesture_swipe_end(swipe_gesture::GESTURE_END_REGEX_PATTERN);
// prepare holder for regex matches
static std::cmatch matches;
if (this->flag_swiping)
{
// currently swiping
if (std::regex_match(line, matches, gesture_swipe_update) != 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_swipe_end) != 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_swipe_begin) != 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;
}
/* STATICS DEFINITIONS */
const int swipe_gesture::MSK_THREE_FINGERS = 0;
const int swipe_gesture::MSK_FOUR_FINGERS = 1;
const int swipe_gesture::MSK_NEGATIVE = 0;
const int swipe_gesture::MSK_POSITIVE = 2;
const int swipe_gesture::MSK_HORIZONTAL = 0;
const int swipe_gesture::MSK_VERTICAL = 4;
const int swipe_gesture::FRESH = -1;
const char * const swipe_gesture::command_map[8] = {
"left3",
"left4",
"right3",
"right4",
"up3",
"up4",
"down3",
"down4"
};
}
}
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture__ */

View File

@ -1,85 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__gesture_swipe_gesture_h__
#define __COMFORTABLE_SWIPE__gesture_swipe_gesture_h__
/*
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 "xdo_gesture.h"
namespace comfortable_swipe
{
namespace gesture
{
class swipe_gesture : protected xdo_gesture
{
public:
// constructor
swipe_gesture(
const float threshold,
const char* left3 /* 000 */,
const char* left4 /* 001 */,
const char* right3 /* 010 */,
const char* right4 /* 011 */,
const char* up3 /* 100 */,
const char* up4 /* 101 */,
const char* down3 /* 110 */,
const char* down4 /* 111 */
);
~swipe_gesture();
// fields for xdo
int fingers;
float dx, dy, udx, udy;
void begin() override;
void update() override;
void end() override;
bool parse_line(const char *) override;
protected:
// location of mouse
int screen_num, ix, iy;
// current location
float x, y, threshold_squared;
int previous_gesture;
const char ** commands;
// optimization flag for checking if GESTURE_SWIPE_BEGIN was dispatched
bool flag_swiping;
public:
// static constants
static const int MSK_THREE_FINGERS;
static const int MSK_FOUR_FINGERS;
static const int MSK_NEGATIVE;
static const int MSK_POSITIVE;
static const int MSK_HORIZONTAL;
static const int MSK_VERTICAL;
static const int FRESH;
static const char * const command_map[8];
// regex patterns
static const char* GESTURE_BEGIN_REGEX_PATTERN;
static const char* GESTURE_UPDATE_REGEX_PATTERN;
static const char* GESTURE_END_REGEX_PATTERN;
};
}
}
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture_h__ */

View File

@ -1,94 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__
#define __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__
/*
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 "swipe_gesture.h"
namespace comfortable_swipe
{
namespace gesture
{
/**
* Regex pattern for the libinput entry for start of swipe.
* Extracts one match for the number of fingers used during the swipe.
*
* eg. event15 GESTURE_SWIPE_BEGIN +34.33s 3
* ^
* fingers
*/
const char* swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN =
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_BEGIN" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s*$" // end of string
;
/**
* Regex pattern for the libinput entry for the end of swipe.
* Extracts one match for the number of fingers used during the swipe.
*
* eg. event15 GESTURE_SWIPE_END +35.03s 3
* ^
* fingers
*/
const char* swipe_gesture::GESTURE_END_REGEX_PATTERN =
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_END" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s*$" // end of string
;
// matches signed decimal numbers (eg. "6.02" "-1.1")
#define CF_NUMBER_REGEX "-?\\d+(?:\\.\\d+)"
// matches and extracts a space-prefixed signed fraction (eg. "-3.00/ 5.12")
#define CF_NUMBER_DIVISION "\\s*(" CF_NUMBER_REGEX ")/\\s*(" CF_NUMBER_REGEX ")"
/**
* Regex pattern for the libinput entry for during a swipe.
* Extracts number of fingers used and the speed (normal and accelerated) of the swipe.
*
* eg. event15 GESTURE_SWIPE_UPDATE +34.70s 3 -0.12/ 4.99 (-0.33/13.50 unaccelerated)
* ^ ^ ^ ^ ^
* fingers dx dy udx udy
*/
const char* swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN =
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_UPDATE" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s+" CF_NUMBER_DIVISION // speed (dx/dy)
"\\s+\\(" CF_NUMBER_DIVISION "\\s+unaccelerated\\)" // unaccelerated speed (udx/udy)
"\\s*$" // end of string
;
// delete macros
#undef CF_NUMBER_DIVISION
#undef CF_NUMBER_EXTRACT
#undef CF_NUMBER_REGEX
}
}
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__ */

View File

@ -1,13 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__service_index_cpp__
#define __COMFORTABLE_SWIPE__service_index_cpp__
#include "_index.hpp"
#include "buffer.cpp"
#include "debug.cpp"
#include "help.cpp"
#include "restart.cpp"
#include "start.cpp"
#include "status.cpp"
#include "stop.cpp"
#endif /* __COMFORTABLE_SWIPE__service_index_cpp__ */

View File

@ -1,21 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__service_index_hpp__
#define __COMFORTABLE_SWIPE__service_index_hpp__
#include <map> // std::map
#include <string> // std::string
namespace comfortable_swipe
{
namespace service
{
void buffer();
void debug();
void help();
void restart();
void start();
void stop();
void status();
}
}
#endif /* __COMFORTABLE_SWIPE__service_index_hpp__ */

View File

@ -1,91 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__service_python__
#define __COMFORTABLE_SWIPE__service_python__
#include "_index.hpp"
extern "C"
{
#include <Python.h>
}
// export as python module
namespace comfortable_swipe
{
namespace service
{
namespace python
{
#define __comfortable_swipe_void_method(method) \
static PyObject * \
method(PyObject * self, PyObject * args) \
{ \
comfortable_swipe::service::method(); \
Py_RETURN_NONE; \
}
// create the python method signatures
__comfortable_swipe_void_method(status);
__comfortable_swipe_void_method(start);
__comfortable_swipe_void_method(stop);
__comfortable_swipe_void_method(restart);
// __comfortable_swipe_void_method(autostart);
__comfortable_swipe_void_method(buffer);
__comfortable_swipe_void_method(help);
// __comfortable_swipe_void_method(config);
__comfortable_swipe_void_method(debug);
#undef __comfortable_swipe_void_method
// create the method list for C++
static PyMethodDef methods[] =
{
{ "status", &status, METH_VARARGS , "checks status of program, autostart, and config" },
{ "start", &start, METH_VARARGS , "starts 3/4-finger gesture service" },
{ "stop", &stop, METH_VARARGS , "stops 3/4-finger gesture service" },
{ "restart", &restart, METH_VARARGS , "stops then starts 3/4-finger gesture service" },
// { "autostart", &autostart, METH_VARARGS , "automatically run on startup (toggleable)" },
{ "buffer", &buffer, METH_VARARGS , "parses output of libinput debug-events" },
{ "help", &help, METH_VARARGS , "shows the help dialog" },
// { "config", &config, METH_VARARGS , "locates the config file " },
{ "debug", &debug, METH_VARARGS , "logs raw output from input events taken from libinput" },
{ NULL, NULL, 0, NULL } // sentinel
};
// create the module configuration
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef module_def =
{
PyModuleDef_HEAD_INIT,
"service",
"Comfortable swipe service",
-1,
methods
};
#endif
PyObject * module;
}
}
}
// initialize module
#if PY_MAJOR_VERSION >= 3
PyMODINIT_FUNC
PyInit_service(void)
{
using comfortable_swipe::service::python::module_def;
using comfortable_swipe::service::python::module;
if (module != NULL) return module;
return module = PyModule_Create(&module_def);
}
#else /* PY_MAJOR_VERSION < 3 */
PyMODINIT_FUNC
initservice(void)
{
using comfortable_swipe::service::python::methods;
using comfortable_swipe::service::python::module;
if (module != NULL) return;
module = Py_InitModule("service", methods);
}
#endif /* PY_MAJOR_VERSION */
#endif /* __COMFORTABLE_SWIPE__service_python__ */

View File

@ -1,48 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__service_help__
#define __COMFORTABLE_SWIPE__service_help__
/*
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::puts, std::printf
namespace comfortable_swipe
{
namespace service
{
/**
* Shows the help window.
*/
void help()
{
std::puts("comfortable-swipe [start|stop|restart|autostart|buffer|help|config|debug|status]");
std::puts("");
std::puts("start - starts 3/4-finger gesture service");
std::puts("stop - stops 3/4-finger gesture service");
std::puts("restart - stops then starts 3/4-finger gesture service");
std::puts("autostart - automatically run on startup (toggleable)");
std::puts("buffer - parses output of libinput debug-events");
std::puts("help - shows the help dialog");
std::puts("config - locates the config file");
std::puts("debug - logs raw output from input events taken from libinput");
std::puts("status - checks status of program and autostart");
}
}
}
#endif /* __COMFORTABLE_SWIPE__service_help__ */

View File

@ -1,66 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__service_start__
#define __COMFORTABLE_SWIPE__service_start__
/*
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 "_index.hpp"
#include <iostream> // std::cin, std::cout, std::ios
#include <cstdlib> // std::system
#include <unistd.h> // pipe, fork, perror, exit
namespace comfortable_swipe
{
namespace service
{
/**
* Starts the comfortable-swipe service by buffering libinput debug-events.
* This method is deferred. Please refer to comfortable_swipe::service::buffer()
* for the technical implementation.
*/
void start()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cout.flush();
// redirect stdout to stdin
int fd[2];
pipe(fd); // create the pipes
int child;
if ((child = fork()) == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (child) {
dup2(fd[1], STDOUT_FILENO);
comfortable_swipe::service::debug();
close(fd[0]);
} else {
dup2(fd[0], STDIN_FILENO);
comfortable_swipe::service::buffer();
close(fd[1]);
}
comfortable_swipe::service::stop();
}
}
}
#endif /* __COMFORTABLE_SWIPE__service_start__ */

View File

@ -1,78 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__service_status__
#define __COMFORTABLE_SWIPE__service_status__
/*
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 "../_macro.cpp"
#include "../util/_index.hpp"
#include "../gesture/_index.hpp"
#include <stdexcept> // std::runtime_error
#include <unistd.h> // popen, pclose, getpid, access, F_OK
#include <memory> // std::unique_ptr
#include <array> // std::array
#include <cstdlib> // std::atoi
#include <cstdio> // FILE, std::feof, std::fgets, std::printf
#include <regex> // std::cmatch, std::regex, std::regex_match
namespace comfortable_swipe
{
namespace service
{
/**
* Prints the status of comfortable-swipe.
*/
void status()
{
// std::printf("autostart is %s\n", autostart_on ? "ON" : "OFF");
// check status of configuration file
try
{
std::puts(COMFORTABLE_SWIPE_CONFIG);
auto config = comfortable_swipe::util::read_config_file(COMFORTABLE_SWIPE_CONFIG);
// print threshold
if (config.count("threshold") > 0)
{
auto & threshold = config["threshold"];
// std::cmatch matches;
// bool ok = (std::regex_match(threshold.data(), matches, std::regex("^\\d+(?:\\.\\d+)??$")) != 0);
// print status of threshold
std::printf(" %9s = %s\n", "threshold", threshold.data()); // ok ? "VALID" : "INVALID"
}
else
std::printf(" %9s is OFF\n", "threshold");
// print swipe commands
for (auto &command : comfortable_swipe::gesture::swipe_gesture::command_map)
{
if (config.count(command) > 0)
std::printf(" %9s = %s\n", command, config[command].data());
else
std::printf(" %9s NOT SET\n", command);
}
}
catch (const std::runtime_error& e)
{
std::printf("config error: %s\n", e.what());
}
}
}
}
#endif /* __COMFORTABLE_SWIPE__service_restart__ */

View File

@ -1,7 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__util_index_cpp__
#define __COMFORTABLE_SWIPE__util_index_cpp__
#include "_index.hpp"
#include "read_config_file.cpp"
#endif /* __COMFORTABLE_SWIPE__util_index_cpp__ */

View File

@ -1,15 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__util_index_hpp__
#define __COMFORTABLE_SWIPE__util_index_hpp__
#include <map> // std::map
#include <string> // std::string
namespace comfortable_swipe
{
namespace util
{
std::map<std::string, std::string> read_config_file(const char*);
}
}
#endif /* __COMFORTABLE_SWIPE__util_index_hpp__ */

View File

@ -1,107 +0,0 @@
#ifndef __COMFORTABLE_SWIPE__util_read_config_file__
#define __COMFORTABLE_SWIPE__util_read_config_file__
/*
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 <map> // std::map
#include <string> // std::string
#include <fstream> // std::ifstream
#include <iostream> // std::endl, std::getline
#include <sstream> // std::ostringstream
#include <cstdlib> // exit
#include <cctype> // std::isspace
#include <stdexcept> // std::runtime_error
namespace comfortable_swipe
{
namespace util
{
/**
* A utility method for reading the config file.
*
* @param filename (const char*) the path of the config file.
*/
std::map<std::string, std::string> read_config_file(const char* filename)
{
std::map<std::string, std::string> conf;
std::ifstream fin(filename, std::ios::in);
if (!fin.is_open())
{
throw std::runtime_error("config file does not exist");
}
static std::string line, token[2];
int line_number = 0;
while (std::getline(fin, line))
{
++line_number;
token[0].clear();
token[1].clear();
int length = line.length();
int equal_flag = 0;
// tokenize comfig config
for (int i = 0; i < length; ++i)
{
if (line[i] == '#') // skip comments
break;
if (line[i] == '=') // flag equal sign
{
if (++equal_flag > 1)
{
std::ostringstream stream;
stream << "error in conf file " << filename << std::endl;
stream << "multiple equal signs in line " << line_number << std::endl;
throw std::runtime_error(stream.str());
}
}
else if (!std::isspace(line[i]))
{
// add to buffer
token[equal_flag].push_back(line[i]);
}
}
// ignore empty lines
if (equal_flag == 0 && token[0].length() == 0)
continue;
// no equal sign found in non-empty line
if (equal_flag == 0)
{
std::ostringstream stream;
stream << "error in conf file: " << filename << std::endl;
stream << "equal sign expected in line " << line_number << std::endl;
throw std::runtime_error(stream.str());
}
// equal sign found, add to tokens
if (token[1].length() > 0)
conf[token[0]] = token[1];
}
return conf;
}
}
}
#endif /* __COMFORTABLE_SWIPE__util_read_config_file__ */

View File

@ -5,46 +5,59 @@
#
# Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a list of
# keycodes you can use.
#################
# MISCELLANEOUS #
#################
# Threshold
# Tweak this value depending on the sensitivity of your mousepad to perform
# gestures. A higher value means less sensitive.
#
# (Note: Sky is the limit! Can be as large as 1000.0)
#
# Default: threshold = 0.0
threshold = 0.0
#############################
# THREE / FOUR FINGER SWIPE #
#############################
# 3-finger swipe left
# The default shortcut is switching to the right workspace.
# Default: left3 = ctrl+alt+Right
left3 = ctrl+alt+Right
# 3-finger swipe right
# The default shortcut is switching to the left workspace.
# Default: right3 = ctrl+alt+Left
right3 = ctrl+alt+Left
# 4-finger swipe left
# The default shortcut is moving current window to the right workspace.
# Default: left4=ctrl+alt+shift+Right
left4 = ctrl+alt+shift+Right
# 3-finger swipe right
# The default shortcut is switching to the left workspace.
# Default: right3 = ctrl+alt+Left
right3 = ctrl+alt+Left
# 4-finger swipe right
# The default shortcut is moving current window to the left workspace.
# Default: right4=ctrl+alt+shift+Left
right4 = ctrl+alt+shift+Left
# 3-finger swipe up
# The default shortcut is switching to the workspace below.
# Default: up3 = ctrl+alt+Down
up3 = ctrl+alt+Down
# 3-finger swipe down
# The default shortcut is switching to the workspace above.
# Default: down3 = ctrl+alt+Up
down3 = ctrl+alt+Up
# 4-finger swipe up
# The default shortcut is moving current window to the bottom workspace.
# Default: ctrl+alt+shift+Down
up4 = ctrl+alt+shift+Down
# 3-finger swipe down
# The default shortcut is switching to the workspace above.
# Default: down3 = ctrl+alt+Up
down3 = ctrl+alt+Up
# 4-finger swipe down
# The default shortcut is moving current window to the above workspace.
# Default: ctrl+alt+shift+Up

82
install Executable file
View File

@ -0,0 +1,82 @@
#!/bin/bash
# prefer running as root
DIR=$(dirname $0)
PROGRAM=/usr/local/bin/comfortable-swipe
COMPILE=$DIR/comfortable-swipe.compile.sh
CONF_PATH=/usr/local/share/comfortable-swipe/comfortable-swipe.conf
DCONF_PATH=$DIR/defaults.conf
OLD_CONF_PATH=${XDG_CONFIG_HOME:-$HOME/.config}/comfortable-swipe.conf
if [ -x "$(command -v $PROGRAM)" ]; then
# stop any running comfortable-swipe if it exists
$PROGRAM stop
fi
#copy config file
abort () {
exec echo "Installation aborted"
}
sudo mkdir -p $(dirname $CONF_PATH) || abort
# check if "-y" or "--yes" is passed as an argument
YES=false
while test $# -gt 0
do
case "$1" in
-y) YES=true
;;
--yes) YES=true
;;
esac
shift
done
sudo chown $USER $(dirname $CONF_PATH)
if [ ! -f $CONF_PATH ]; then
if [ ! -f $OLD_CONF_PATH ]; then
# old config file not found, create from scratch
cat $DCONF_PATH > $CONF_PATH || abort
else
# old config file found, move to the new path
cat $OLD_CONF_PATH > $CONF_PATH || abort
echo "Configuration copied from $OLD_CONF_PATH to $CONF_PATH"
fi
else
# config file found, ask user if overwrite
echo "Old conf file found in $CONF_PATH"
if [ $YES == false ]; then
read -r -p "Keep the old conf file? (default: yes) [Y/n] " response
response=${response,,} # tolower
if [[ "$response" =~ ^(no|n)$ ]]; then
read -r -p "Conf file will be overwritten. Are you sure? [Y/n] " response
response=${response,,}
if [[ "$response" =~ ^(yes|y)$ ]]; then
cat $DCONF_PATH > $CONF_PATH || abort
else
abort
fi
fi
fi
fi
echo "Installing..."
# remove existing comfortable-swipe
if [ -x "$(command -v $PROGRAM)" ]; then
sudo rm -f $(which comfortable-swipe)
fi
# compile library
sudo $COMPILE $PROGRAM || abort
# add permissions to input group (defer)
# GROUP=$(ls -l /dev/input/event* | awk '{print $4}' | head --line=1) || abort
# toggle autostart twice to refresh any changes
$PROGRAM autostart > /dev/null || abort
$PROGRAM autostart > /dev/null || abort
echo "Successfully installed comfortable-swipe."
echo "Configuration file is located at $CONF_PATH"
echo ""
echo "Try running 'comfortable-swipe start' to test."

44
lib/comfortable_swipe Normal file
View File

@ -0,0 +1,44 @@
#ifndef __COMFORTABLE_SWIPE__
#define __COMFORTABLE_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 "index.hpp"
/**
* Make sure to include all implementation (.cpp) files below to be ready for export.
*/
#include "gesture/xdo_gesture.cpp"
#include "gesture/swipe_gesture.cpp"
#include "gesture/swipe_gesture.regex.cpp"
#include "service/autostart.cpp"
#include "service/buffer.cpp"
#include "service/config.cpp"
#include "service/debug.cpp"
#include "service/help.cpp"
#include "service/restart.cpp"
#include "service/start.cpp"
#include "service/status.cpp"
#include "service/stop.cpp"
#include "util/autostart_filename.cpp"
#include "util/conf_filename.cpp"
#include "util/read_config_file.cpp"
#endif /* __COMFORTABLE_SWIPE__ */

View File

@ -0,0 +1,214 @@
#ifndef __COMFORTABLE_SWIPE__gesture_swipe_gesture__
#define __COMFORTABLE_SWIPE__gesture_swipe_gesture__
/*
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 <string> // std::stoi, std::stof
#include <regex> // std::regex, std::regex_match, std::cmatch
#include "swipe_gesture.h"
extern "C"
{
#include <xdo.h> // xdo, xdo_new, xdo_free,
// xdo_get_mouse_location
// CURRENT_WINDOW
}
namespace comfortable_swipe::gesture
{
/**
* Constructs a new swipe gesture, given configurations for certain swipe events.
*/
swipe_gesture::swipe_gesture
(
const float threshold,
const char* left3 /* 000 */,
const char* left4 /* 001 */,
const char* right3 /* 010 */,
const char* right4 /* 011 */,
const char* up3 /* 100 */,
const char* up4 /* 101 */,
const char* down3 /* 110 */,
const char* down4 /* 111 */
):
comfortable_swipe::gesture::xdo_gesture(),
threshold_squared(threshold*threshold),
commands(new const char*[8]{left3, left4, right3, right4, up3, up4, down3, down4}),
flag_swiping(false)
{
// improve responsiveness of first gesture by pre-empting xdotool runtime
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
}
/**
* Destructs this swipe gesture.
*/
swipe_gesture::~swipe_gesture()
{
delete[] commands;
}
/**
* Hook on begin of swipe gesture.
*/
void swipe_gesture::begin()
{
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
this->previous_gesture = swipe_gesture::FRESH;
this->x = 0;
this->y = 0;
}
/**
* Hook on update of swipe gesture.
*/
void swipe_gesture::update()
{
this->x += this->dx;
this->y += this->dy;
// scale threshold to 1/10 when gesture is not fresh
float scale = this->previous_gesture == swipe_gesture::FRESH
? 1.00f
: 0.01f; // square root of 1/10
static const float EPSILON = 1e-6f;
if (this->x * this->x + this->y * this->y
> this->threshold_squared * scale + EPSILON)
{
int mask = 0;
if (this->fingers == 3) mask |= swipe_gesture::MSK_THREE_FINGERS;
else if (this->fingers == 4) mask |= swipe_gesture::MSK_FOUR_FINGERS;
const float absx = x >= 0 ? x : -x;
const float absy = y >= 0 ? y : -y;
if (absx > absy)
{ // horizontal
mask |= swipe_gesture::MSK_HORIZONTAL;
if (x < 0)
mask |= swipe_gesture::MSK_NEGATIVE;
else
mask |= swipe_gesture::MSK_POSITIVE;
}
else /* std::abs(x) <= std::abs(y) */
{ // vertical
mask |= swipe_gesture::MSK_VERTICAL;
if (y < 0)
mask |= swipe_gesture::MSK_NEGATIVE;
else
mask |= swipe_gesture::MSK_POSITIVE;
}
// send command on fresh OR opposite gesture
if (this->previous_gesture == swipe_gesture::FRESH
|| this->previous_gesture == (mask ^ swipe_gesture::MSK_POSITIVE))
{
xdo_send_keysequence_window(this->xdo, CURRENTWINDOW, swipe_gesture::commands[mask], 0);
this->x = this->y = 0;
this->previous_gesture = mask;
std::cout << "SWIPE " << swipe_gesture::command_map[mask] << std::endl;
}
}
}
/**
* Hook on end of swipe gesture.
*/
void swipe_gesture::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 swipe_gesture::parse_line(const char * line)
{
// prepare regex matchers (will only load at most once)
static const std::regex gesture_swipe_begin(swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN);
static const std::regex gesture_swipe_update(swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN);
static const std::regex gesture_swipe_end(swipe_gesture::GESTURE_END_REGEX_PATTERN);
// prepare holder for regex matches
static std::cmatch matches;
if (this->flag_swiping)
{
// currently swiping
if (std::regex_match(line, matches, gesture_swipe_update) != 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_swipe_end) != 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_swipe_begin) != 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;
}
/* STATICS DEFINITIONS */
const int swipe_gesture::MSK_THREE_FINGERS = 0;
const int swipe_gesture::MSK_FOUR_FINGERS = 1;
const int swipe_gesture::MSK_NEGATIVE = 0;
const int swipe_gesture::MSK_POSITIVE = 2;
const int swipe_gesture::MSK_HORIZONTAL = 0;
const int swipe_gesture::MSK_VERTICAL = 4;
const int swipe_gesture::FRESH = -1;
const char * const swipe_gesture::command_map[8] = {
"left3",
"left4",
"right3",
"right4",
"up3",
"up4",
"down3",
"down4"
};
}
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture__ */

View File

@ -0,0 +1,90 @@
#ifndef __COMFORTABLE_SWIPE__gesture_swipe_gesture_h__
#define __COMFORTABLE_SWIPE__gesture_swipe_gesture_h__
/*
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 "xdo_gesture.h"
#ifdef __cplusplus
extern "C" {
#endif
namespace comfortable_swipe::gesture
{
class swipe_gesture : protected xdo_gesture
{
public:
// constructor
swipe_gesture(
const float threshold,
const char* left3 /* 000 */,
const char* left4 /* 001 */,
const char* right3 /* 010 */,
const char* right4 /* 011 */,
const char* up3 /* 100 */,
const char* up4 /* 101 */,
const char* down3 /* 110 */,
const char* down4 /* 111 */
);
~swipe_gesture();
// fields for xdo
int fingers;
float dx, dy, udx, udy;
void begin() override;
void update() override;
void end() override;
bool parse_line(const char *) override;
protected:
// location of mouse
int screen_num, ix, iy;
// current location
float x, y, threshold_squared;
int previous_gesture;
const char ** commands;
// optimization flag for checking if GESTURE_SWIPE_BEGIN was dispatched
bool flag_swiping;
public:
// static constants
static const int MSK_THREE_FINGERS;
static const int MSK_FOUR_FINGERS;
static const int MSK_NEGATIVE;
static const int MSK_POSITIVE;
static const int MSK_HORIZONTAL;
static const int MSK_VERTICAL;
static const int FRESH;
static const char * const command_map[8];
// regex patterns
static const char* GESTURE_BEGIN_REGEX_PATTERN;
static const char* GESTURE_UPDATE_REGEX_PATTERN;
static const char* GESTURE_END_REGEX_PATTERN;
};
}
#ifdef __cplusplus
}
#endif
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture_h__ */

View File

@ -0,0 +1,91 @@
#ifndef __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__
#define __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__
/*
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 "swipe_gesture.h"
namespace comfortable_swipe::gesture
{
/**
* Regex pattern for the libinput entry for start of swipe.
* Extracts one match for the number of fingers used during the swipe.
*
* eg. event15 GESTURE_SWIPE_BEGIN +34.33s 3
* ^
* fingers
*/
const char* swipe_gesture::GESTURE_BEGIN_REGEX_PATTERN =
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_BEGIN" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s*$" // end of string
;
/**
* Regex pattern for the libinput entry for the end of swipe.
* Extracts one match for the number of fingers used during the swipe.
*
* eg. event15 GESTURE_SWIPE_END +35.03s 3
* ^
* fingers
*/
const char* swipe_gesture::GESTURE_END_REGEX_PATTERN =
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_END" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s*$" // end of string
;
// matches signed decimal numbers (eg. "6.02" "-1.1")
#define CF_NUMBER_REGEX "-?\\d+(?:\\.\\d+)"
// matches and extracts a space-prefixed signed fraction (eg. "-3.00/ 5.12")
#define CF_NUMBER_DIVISION "\\s*(" CF_NUMBER_REGEX ")/\\s*(" CF_NUMBER_REGEX ")"
/**
* Regex pattern for the libinput entry for during a swipe.
* Extracts number of fingers used and the speed (normal and accelerated) of the swipe.
*
* eg. event15 GESTURE_SWIPE_UPDATE +34.70s 3 -0.12/ 4.99 (-0.33/13.50 unaccelerated)
* ^ ^ ^ ^ ^
* fingers dx dy udx udy
*/
const char* swipe_gesture::GESTURE_UPDATE_REGEX_PATTERN =
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_UPDATE" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s+" CF_NUMBER_DIVISION // speed (dx/dy)
"\\s+\\(" CF_NUMBER_DIVISION "\\s+unaccelerated\\)" // unaccelerated speed (udx/udy)
"\\s*$" // end of string
;
// delete macros
#undef CF_NUMBER_DIVISION
#undef CF_NUMBER_EXTRACT
#undef CF_NUMBER_REGEX
}
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__ */

View File

@ -26,24 +26,21 @@ extern "C"
#include "xdo_gesture.h"
namespace comfortable_swipe
namespace comfortable_swipe::gesture
{
namespace gesture
{
/**
* Constructs a new gesture handler with xdo.
*/
xdo_gesture::xdo_gesture():
xdo(xdo_new(NULL))
{ }
/**
* Constructs a new gesture handler with xdo.
*/
xdo_gesture::xdo_gesture():
xdo(xdo_new(NULL))
{ }
/**
* Constructs a new swipe gesture with xdo.
*/
xdo_gesture::~xdo_gesture()
{
xdo_free(this->xdo);
}
/**
* Constructs a new swipe gesture with xdo.
*/
xdo_gesture::~xdo_gesture()
{
xdo_free(this->xdo);
}
}

64
lib/index.hpp Normal file
View File

@ -0,0 +1,64 @@
#ifndef __COMFORTABLE_SWIPE__index_hpp__
#define __COMFORTABLE_SWIPE__index_hpp__
/*
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/>.
*/
// global defines
#ifndef __COMFORTABLE_SWIPE__PROGRAM__
#define __COMFORTABLE_SWIPE__PROGRAM__ "/usr/local/bin/comfortable-swipe"
#endif /* __COMFORTABLE_SWIPE__PROGRAM__ */
#ifndef __COMFORTABLE_SWIPE__CONFIG__
#define __COMFORTABLE_SWIPE__CONFIG__ "/usr/local/share/comfortable-swipe/comfortable-swipe.conf"
#endif /* __COMFORTABLE_SWIPE__CONFIG__ */
#include <map> // std::map
#include <string> // std::string
/**
* Make sure to include your header files here so that they can be imported by other modules.
*/
#include "gesture/xdo_gesture.h"
#include "gesture/swipe_gesture.h"
extern "C"
{
namespace comfortable_swipe
{
namespace util
{
const char* autostart_filename();
constexpr const char* conf_filename();
std::map<std::string, std::string> read_config_file(const char*);
}
namespace service
{
void autostart();
void buffer();
void config();
void debug();
void help();
void restart();
void start();
void status();
void stop();
}
}
}
#endif /* __COMFORTABLE_SWIPE__index_hpp__ */

75
lib/service/autostart.cpp Normal file
View File

@ -0,0 +1,75 @@
#ifndef __COMFORTABLE_SWIPE__service_autostart__
#define __COMFORTABLE_SWIPE__service_autostart__
/*
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::cerr, std::cout, std::endl
#include <fstream> // std::ifstream, std::ofstream
#include <string> // std::string
#include <cstdio> // std::remove
#include <cstdlib> // std::system
#include "../index.hpp"
namespace comfortable_swipe::service
{
/**
* Toggles automatic startup of comfortable swipe.
*/
void autostart()
{
using comfortable_swipe::util::autostart_filename;
const std::string& path = autostart_filename();
if (std::ifstream(path.data()).good())
{
// file found, delete it
if (std::remove(path.data()) != 0)
std::cerr << "Error: failed to switch off autostart. "
<< "Maybe the autostart file is in use?"
<< std::endl;
else
std::cout << "Autostart switched off" << std::endl;
}
else {
// file not found, create it
int result = std::system(("mkdir -p $(dirname " + path + ")").data());
std::ofstream fout(path.data());
if (result != 0 || !fout.good())
std::cerr << "Error: failed to switch on autostart. "
<< "Are you sure you have the permissions?"
<< std::endl;
else {
fout <<
"[Desktop Entry]\n"
"Type=Application\n"
"Exec=bash -c \""
__COMFORTABLE_SWIPE__PROGRAM__
" start\"\n"
"Hidden=false\n"
"NoDisplay=false\n"
"X-GNOME-Autostart-enabled=true\n"
"Name=Comfortable Swipe\n"
"Comment=3 or 4 touchpad gestures\n";
std::cout << "Autostart switched on" << std::endl;
}
}
}
}
#endif /* __COMFORTABLE_SWIPE__service_autostart__ */

View File

@ -19,10 +19,9 @@ 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 "../_macro.cpp"
#include "../util/_index.hpp"
#include "../gesture/_index.hpp"
#include <cstdio> // fgets_unlocked, stdin
#include <iostream> // std::ios, std::cout, std::cin
#include "../index.hpp"
/**
* Starts the comfortable-swipe service by buffering libinput debug-events.
@ -31,8 +30,13 @@ namespace comfortable_swipe::service
{
void buffer()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cout.flush();
// read config file
auto config = comfortable_swipe::util::read_config_file(COMFORTABLE_SWIPE_CONFIG);
auto config = comfortable_swipe::util::read_config_file(comfortable_swipe::util::conf_filename());
// initialize swipe gesture handler
comfortable_swipe::gesture::swipe_gesture swipe_gesture_handler

38
lib/service/config.cpp Normal file
View File

@ -0,0 +1,38 @@
#ifndef __COMFORTABLE_SWIPE__service_config__
#define __COMFORTABLE_SWIPE__service_config__
/*
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 "../index.hpp"
#include <cstdio> // std::puts
namespace comfortable_swipe::service
{
/**
* Prints where the config file of comfortable swipe is located.
*
* Usage: nano $(comfortable-swipe config)
*/
void config()
{
std::puts(comfortable_swipe::util::conf_filename());
}
}
#endif /* __COMFORTABLE_SWIPE__service_config__ */

View File

@ -21,17 +21,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <cstdlib> // std::system
namespace comfortable_swipe
namespace comfortable_swipe::service
{
namespace service
/**
* Debugs output from `libinput debug-events`.
*/
void debug()
{
/**
* Debugs output from `libinput debug-events`.
*/
void debug()
{
(void) std::system("bash -c \"stdbuf -oL -e0 libinput debug-events 2> >(grep -v 'double tracking')\"");
}
(void) std::system("bash -c \"stdbuf -oL -e0 libinput debug-events 2> >(grep -v 'double tracking')\"");
}
}

49
lib/service/help.cpp Normal file
View File

@ -0,0 +1,49 @@
#ifndef __COMFORTABLE_SWIPE__service_help__
#define __COMFORTABLE_SWIPE__service_help__
/*
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::puts, std::printf
#include "../index.hpp"
namespace comfortable_swipe::service
{
/**
* Shows the help window.
*/
void help()
{
using comfortable_swipe::util::conf_filename;
std::puts("comfortable-swipe [start|stop|restart|autostart|buffer|help|config|debug|status]");
std::puts("");
std::puts("start - starts 3/4-finger gesture service");
std::puts("stop - stops 3/4-finger gesture service");
std::puts("restart - stops then starts 3/4-finger gesture service");
std::puts("autostart - automatically run on startup (toggleable)");
std::puts("buffer - parses output of libinput debug-events");
std::puts("help - shows the help dialog");
std::puts("config - locates the config file [/usr/share/comfortable-swipe/comfortable-swipe.conf]");
std::puts("debug - logs raw output from input events taken from libinput");
std::puts("status - checks status of program and autostart");
std::puts("");
std::printf("Configuration file can be found in %s\n", conf_filename());
}
}
#endif /* __COMFORTABLE_SWIPE__service_help__ */

View File

@ -19,20 +19,17 @@ 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 "../service/_index.hpp"
#include "../index.hpp"
namespace comfortable_swipe
namespace comfortable_swipe::service
{
namespace service
/**
* Restarts the comfortable-swipe service.
*/
void restart()
{
/**
* Restarts the comfortable-swipe service.
*/
void restart()
{
comfortable_swipe::service::stop();
comfortable_swipe::service::start();
}
comfortable_swipe::service::stop();
comfortable_swipe::service::start();
}
}

38
lib/service/start.cpp Normal file
View File

@ -0,0 +1,38 @@
#ifndef __COMFORTABLE_SWIPE__service_start__
#define __COMFORTABLE_SWIPE__service_start__
/*
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 "../index.hpp"
#include <cstdlib> // std::system
namespace comfortable_swipe::service
{
/**
* Starts the comfortable-swipe service by buffering libinput debug-events.
* This method is deferred. Please refer to comfortable_swipe::service::buffer()
* for the technical implementation.
*/
void start()
{
(void) std::system(__COMFORTABLE_SWIPE__PROGRAM__ " debug | " __COMFORTABLE_SWIPE__PROGRAM__ " buffer");
}
}
#endif /* __COMFORTABLE_SWIPE__service_start__ */

97
lib/service/status.cpp Normal file
View File

@ -0,0 +1,97 @@
#ifndef __COMFORTABLE_SWIPE__service_status__
#define __COMFORTABLE_SWIPE__service_status__
/*
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 "../index.hpp"
#include <stdexcept> // std::runtime_error
#include <unistd.h> // popen, pclose, getpid, access, F_OK
#include <memory> // std::unique_ptr
#include <array> // std::array
#include <cstdlib> // std::atoi
#include <cstdio> // FILE, std::feof, std::fgets, std::printf
#include <regex> // std::cmatch, std::regex, std::regex_match
namespace comfortable_swipe::service
{
/**
* Prints the status of comfortable-swipe.
*/
void status()
{
// check if comfortable-swipe is running
bool running = false;
std::array<char, 128> buffer;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("pgrep -f comfortable-swipe", "r"), pclose);
if (pipe && !std::feof(pipe.get()) && std::fgets(buffer.data(), buffer.size(), pipe.get()) != NULL)
{
int pid = std::atoi(buffer.data());
if (pid != getpid())
running = true;
}
// check if autostart is on
auto autostart_f = comfortable_swipe::util::autostart_filename();
bool autostart_on = access(autostart_f, F_OK) != -1;
// print status
std::printf("program is %s\n", running ? "ON" : "OFF");
std::printf("autostart is %s\n", autostart_on ? "ON" : "OFF");
std::printf("config file at %s\n", comfortable_swipe::util::conf_filename());
// check status of configuration file
try
{
auto config = comfortable_swipe::util::read_config_file(comfortable_swipe::util::conf_filename());
// print keys and values of config file
std::printf("\nConfigurations:\n");
// print threshold
if (config.count("threshold") > 0)
{
auto & threshold = config["threshold"];
// check if regex pattern matches threshold
std::cmatch matches;
bool ok = (std::regex_match(threshold.data(), matches, std::regex("^\\d+(?:\\.\\d+)??$")) != 0);
// print status of threshold
std::printf(" %9s is %s (%s)\n", "threshold", ok ? "OK" : "INVALID", threshold.data());
}
else
std::printf(" %9s is OFF\n", "threshold");
// print swipe commands
for (auto &command : comfortable_swipe::gesture::swipe_gesture::command_map)
{
if (config.count(command) > 0)
std::printf(" %9s is OK (%s)\n", command, config[command].data());
else
std::printf(" %9s is OFF\n", command);
}
}
catch (const std::runtime_error& e)
{
std::printf("config error: %s\n", e.what());
}
}
}
#endif /* __COMFORTABLE_SWIPE__service_restart__ */

View File

@ -29,44 +29,41 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <cstdlib> // std::atoi
#include <cstdio> // FILE, std::feof, std::fgets
namespace comfortable_swipe
namespace comfortable_swipe::service
{
namespace service
/**
* Stops all comfortable-swipe instances.
*/
void stop()
{
/**
* Stops all comfortable-swipe instances.
*/
void stop()
// read all service names from process (pgrep)
std::array<char, 128> buffer;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("pgrep -f comfortable-swipe", "r"), pclose);
// make sure pipe exists
if (!pipe)
throw std::runtime_error("stop command failed");
// buffer what to kill
std::string kill = "kill";
// read until end of line
while (!std::feof(pipe.get()))
{
// read all service names from process (pgrep)
std::array<char, 128> buffer;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("pgrep -f comfortable-swipe", "r"), pclose);
// make sure pipe exists
if (!pipe)
throw std::runtime_error("stop command failed");
// buffer what to kill
std::string kill = "kill";
// read until end of line
while (!std::feof(pipe.get()))
if (std::fgets(buffer.data(), buffer.size(), pipe.get()) != NULL)
{
if (std::fgets(buffer.data(), buffer.size(), pipe.get()) != NULL)
int pid = std::atoi(buffer.data());
if (pid != getpid())
{
int pid = std::atoi(buffer.data());
if (pid != getpid())
{
kill += " ";
kill += std::to_string(pid);
}
kill += " ";
kill += std::to_string(pid);
}
}
// run "kill {pid1} {pid2}..."
(void) std::system(kill.data());
}
// run "kill {pid1} {pid2}..."
(void) std::system(kill.data());
}
}

View File

@ -0,0 +1,46 @@
#ifndef __COMFORTABLE_SWIPE__util_autostart_filename__
#define __COMFORTABLE_SWIPE__util_autostart_filename__
/*
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 <string> // std::string
#include <unistd.h> // getenv
namespace comfortable_swipe::util
{
/**
* The path where the autostart configuration is located.
*/
const char* autostart_filename()
{
static std::string filename;
if (filename.empty()) {
const char* xdg_config = getenv("XDG_CONFIG_HOME");
std::string config(
xdg_config == NULL
? std::string(getenv("HOME")) + "/.config"
: xdg_config
);
filename = config + "/autostart/comfortable-swipe.desktop";
}
return filename.data();
}
}
#endif /* __COMFORTABLE_SWIPE__util_autostart_filename__ */

View File

@ -1,5 +1,5 @@
#ifndef __COMFORTABLE_SWIPE__
#define __COMFORTABLE_SWIPE__
#ifndef __COMFORTABLE_SWIPE__util_conf_filename__
#define __COMFORTABLE_SWIPE__util_conf_filename__
/*
Comfortable Swipe
@ -19,8 +19,17 @@ 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 "_macro.cpp"
#include "_index.hpp"
#include "_index.cpp"
#include "../index.hpp"
#endif /* __COMFORTABLE_SWIPE__ */
namespace comfortable_swipe::util
{
/**
* The path where the configuration file is located.
*/
constexpr const char* conf_filename()
{
return __COMFORTABLE_SWIPE__CONFIG__;
}
}
#endif /* __COMFORTABLE_SWIPE__util_conf_filename__ */

View File

@ -0,0 +1,103 @@
#ifndef __COMFORTABLE_SWIPE__util_read_config_file__
#define __COMFORTABLE_SWIPE__util_read_config_file__
/*
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 <map> // std::map
#include <string> // std::string
#include <fstream> // std::ifstream
#include <sstream> // std::ostringstream
#include <iostream> // std::endl, std::getline
#include <cstdlib> // exit
#include <cctype> // std::isspace
#include <stdexcept> // std::runtime_error
namespace comfortable_swipe::util
{
/**
* A utility method for reading the config file.
*
* @param filename (const char*) the path of the config file.
*/
std::map<std::string, std::string> read_config_file(const char* filename)
{
std::map<std::string, std::string> conf;
std::ifstream fin(filename);
if (!fin.is_open())
{
throw std::runtime_error("config file does not exist");
}
static std::string line, token[2];
int line_number = 0;
while (std::getline(fin, line))
{
++line_number;
token[0].clear();
token[1].clear();
int length = line.length();
int equal_flag = 0;
// tokenize comfig config
for (int i = 0; i < length; ++i)
{
if (line[i] == '#') // skip comments
break;
if (line[i] == '=') // flag equal sign
{
if (++equal_flag > 1)
{
std::ostringstream stream;
stream << "error in conf file " << filename << std::endl;
stream << "multiple equal signs in line " << line_number << std::endl;
throw std::runtime_error(stream.str());
}
}
else if (!std::isspace(line[i]))
{
// add to buffer
token[equal_flag].push_back(line[i]);
}
}
// ignore empty lines
if (equal_flag == 0 && token[0].length() == 0)
continue;
// no equal sign found in non-empty line
if (equal_flag == 0)
{
std::ostringstream stream;
stream << "error in conf file: " << filename << std::endl;
stream << "equal sign expected in line " << line_number << std::endl;
throw std::runtime_error(stream.str());
}
// equal sign found, add to tokens
if (token[1].length() > 0)
conf[token[0]] = token[1];
}
return conf;
}
}
#endif /* __COMFORTABLE_SWIPE__util_read_config_file__ */

View File

@ -1 +0,0 @@
psutil==5.6.0

View File

@ -1,2 +0,0 @@
[build]
compiler = unix

179
setup.py
View File

@ -1,179 +0,0 @@
from __future__ import print_function
import os
import sys
import setuptools
from shutil import copyfile
from setuptools import setup, find_packages
from setuptools.extension import Extension
from setuptools.command.develop import develop
from setuptools.command.install import install
from setuptools.command.easy_install import easy_install
from wheel.bdist_wheel import bdist_wheel
VERSION = '1.1.0-beta'
__CWD__ = os.getcwd()
__DIR__ = os.path.dirname(os.path.abspath(__file__))
__URL__ = 'https://github.com/Hikari9/comfortable-swipe-ubuntu'
extension_names = ['service']
try:
# make sure working directory is here
os.chdir(__DIR__)
# save README as long_description
with open('README.md', 'r') as README_file:
README = README_file.read()
# match constants with source
from comfortable_swipe.constants import *
# include old conf paths to list from previous versions
conf_paths = [
DEFAULT_CONFIG,
os.path.join(os.getenv('HOME', ''), '.config', 'comfortable-swipe', 'comfortable-swipe.conf'),
os.path.join('/usr/local/share', 'comfortable-swipe', 'comfortable-swipe.conf'),
CONFIG
]
# for C++ library
cpp_macros = dict(
COMFORTABLE_SWIPE_VERSION='"{}"'.format(VERSION),
COMFORTABLE_SWIPE_CONFIG='"{}"'.format(CONFIG)
)
# read C++ libraries for comfortable swipe
extensions = [Extension(
name='{}.cpp.{}'.format(PYTHON_NAME, extension_name),
define_macros=list(cpp_macros.items()),
sources=[os.path.join('cpp', '_python.cpp')],
extra_compile_args=['-O2', '-Wno-unused-result', '-std=c++11', '-lstdc++'],
libraries=['xdo']
) for extension_name in extension_names]
class Command:
outer_installer = None
outer_uninstaller = None
def pre_install(self):
# make sure only outer install script will run post_install
if self.__class__.outer_installer is not None: return
self.__class__.outer_installer = self
print('running pre_install')
def post_install(self):
# make sure post_install will only run when command is outer installer
if self.__class__.outer_installer is not self: return
print('running post_install')
# create program/config directories
if not os.path.exists(os.path.dirname(CONFIG)):
os.makedirs(os.path.dirname(CONFIG))
# copy any of the old config files
conf_files = [path for path in conf_paths if os.path.exists(path) and os.path.isfile(path)]
print('Using configuration file at', conf_files[-1])
if conf_files[-1] != CONFIG:
# new installation or upgrading from old version, copy to new location
copyfile(conf_files[-1], CONFIG)
if conf_files[-1] == DEFAULT_CONFIG:
# new installation - copy default configuration
print('Copying configuration file to', CONFIG)
else:
# upgrading - delete the deprecated config file (failsafe)
print('warning: depcrecated configuration file at', conf_files[-1])
print(' you have to remove this manually')
# enable autostart by default
from comfortable_swipe import autostart
autostart.set_status(autostart.ON)
print('Autostart created at', autostart.target_path())
print('\nInstallation successful\nTry running: {} start'.format(NAME))
def pre_uninstall(self):
# make sure only outer uninstall script will run post_uninstall
if self.__class__.outer_uninstaller is not None: return
self.__class__.outer_uninstaller = self
print('running pre_uninstall')
def post_uninstall(self):
# make sure post_uninstall will only run when command is outer uninstaller
if self.__class__.outer_uninstaller is not self: return
print('running post_uninstall')
from comfortable_swipe import autostart
if autostart.get_status() is autostart.ON:
print('Removing autostart at', autostart.target_path())
autostart.set_status(autostart.OFF)
# add post_install script to install method
def wrap_command(base_cls, uninstall=False):
class InstallCommand(Command, base_cls):
def run(self):
self.pre_uninstall() if uninstall and self.uninstall else self.pre_install()
base_cls.run(self)
self.post_uninstall() if uninstall and self.uninstall else self.post_install()
InstallCommand.__name__ = base_cls.__name__
return InstallCommand
# Override command classes here
cmdclass = dict(
install=wrap_command(install),
easy_install=wrap_command(easy_install),
develop=wrap_command(develop, uninstall=True),
bdist_wheel=wrap_command(bdist_wheel)
)
# install requiremenh open('requirements.txt', 'r') as requirements:
with open('requirements.txt', 'r') as requirements:
install_requires = requirements.read().splitlines()
# classifiers
# https://pypi.org/classifiers/
classifiers = [
'Development Status :: 4 - Beta'
'Intended Audience :: End Users/Desktop',
'Operating System :: POSIX :: Linux',
'Operating System :: Unix',
'Programming Language :: C++',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Environment :: Console'
]
# setup python script
setup_script = setup(
name=NAME,
version=VERSION,
description=DESCRIPTION,
long_description=README,
license='MIT',
author='Rico Tiongson',
author_email='thericotiongson@gmail.com',
url=__URL__,
zip_safe=False,
packages=find_packages(),
include_package_data=True,
entry_points=dict(console_scripts=['{}={}.__main__:main'.format(NAME, PYTHON_NAME)]),
ext_modules=extensions,
cmdclass=cmdclass,
install_requires=install_requires,
classifiers=classifiers
)
finally:
# move working directory back to where it was before
os.chdir(__CWD__)

7
uninstall Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
echo "Uninstalling..."
rm ${XDG_CONFIG_HOME:-$HOME/.config}/autostart/comfortable-swipe.desktop 2> /dev/null
comfortable-swipe stop 2> /dev/null
rm $HOME/.local/bin/comfortable-swipe 2> /dev/null # compat
sudo rm /usr/local/bin/comfortable-swipe 2> /dev/null
echo "Successfully uninstalled comfortable-swipe"