Travis (#62)
* Use a requirements.txt * Add initial travis configuration * Attempt fix travis configuration * Attempt fix g++ error * Bugfix missing path dir on autostart * Attempt install build-essential instead of g++ * Add missing psutil from requirements * Modify README * Attempt fix build errors in travis * Update README * Add simple build badges
This commit is contained in:
parent
adcb3d5e02
commit
044e215d97
25
.travis.yml
Normal file
25
.travis.yml
Normal file
@ -0,0 +1,25 @@
|
||||
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
|
||||
172
README.md
172
README.md
@ -1,30 +1,62 @@
|
||||
# Comfortable Swipe (Ubuntu)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
# Comfortable Swipe (Debian/Ubuntu)
|
||||
|
||||
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`.
|
||||
[](https://github.com/Hikari9/comfortable-swipe/releases)
|
||||
[](https://github.com/Hikari9/comfortable-swipe/commits/master)
|
||||
[](https://github.com/Hikari9/comfortable-swipe/commits/develop)
|
||||
[](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).
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install Python3, libinput, and g++
|
||||
1. Update and install essential tools and libraries
|
||||
|
||||
```bash
|
||||
sudo apt-get install git python3-dev libinput-tools libxdo-dev
|
||||
sudo apt update && sudo apt install git g++-7 python3-pip libinput-tools libxdo-dev
|
||||
```
|
||||
|
||||
2. Clone this repository
|
||||
2. Install `comfortable-swipe` for your user
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Hikari9/comfortable-swipe-ubuntu.git
|
||||
cd comfortable-swipe-ubuntu
|
||||
pip3 install --user git+https://github.com/Hikari9/comfortable-swipe
|
||||
```
|
||||
|
||||
3. Install
|
||||
3. You can check status with `comfortable-swipe status`
|
||||
|
||||
```bash
|
||||
bash install
|
||||
$> 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
|
||||
```
|
||||
|
||||
4. You may delete the downloaded `comfortable-swipe-ubuntu` folder after installation.
|
||||
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
|
||||
```
|
||||
|
||||
## How to Run
|
||||
|
||||
@ -33,27 +65,84 @@ 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. Run
|
||||
```
|
||||
3. By default, comfortable-swipe should be running. Otherwise, run:
|
||||
```bash
|
||||
comfortable-swipe start
|
||||
```
|
||||
4. _Optional_: Automatically run on startup
|
||||
You can see if gestures work correctly if you see `SWIPE xxx` in the output:
|
||||
|
||||
```bash
|
||||
$> comfortable-swipe start
|
||||
SWIPE left3
|
||||
SWIPE right3
|
||||
...
|
||||
```
|
||||
comfortable-swipe autostart
|
||||
|
||||
## 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
|
||||
```
|
||||
5. Check the status of your application by running
|
||||
|
||||
2. `comfortable-swipe autostart` - Toggles autostart
|
||||
```bash
|
||||
$> comfortable-swipe autostart
|
||||
Autostart switched off
|
||||
```
|
||||
comfortable-swipe status
|
||||
|
||||
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
|
||||
...
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
nano $(comfortable-swipe config)
|
||||
|
||||
```bash
|
||||
gedit $(comfortable-swipe config)
|
||||
```
|
||||
|
||||
Make sure to run after making changes:
|
||||
```
|
||||
Make sure to restart after making changes:
|
||||
```bash
|
||||
comfortable-swipe restart
|
||||
```
|
||||
|
||||
@ -85,45 +174,6 @@ Taken from `man xdotool`:
|
||||
|
||||
Refer to https://www.linux.org/threads/xdotool-keyboard.10528/ for a complete list of keycodes you can use.
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
@ -45,6 +45,11 @@ def get_status():
|
||||
# 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:
|
||||
|
||||
@ -32,182 +32,185 @@ extern "C"
|
||||
// CURRENT_WINDOW
|
||||
}
|
||||
|
||||
namespace comfortable_swipe::gesture
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* 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)
|
||||
namespace gesture
|
||||
{
|
||||
// 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)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// improve responsiveness of first gesture by pre-empting xdotool runtime
|
||||
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
/**
|
||||
* Destructs this swipe gesture.
|
||||
*/
|
||||
swipe_gesture::~swipe_gesture()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
delete[] commands;
|
||||
}
|
||||
else
|
||||
|
||||
/**
|
||||
* Hook on begin of swipe gesture.
|
||||
*/
|
||||
void swipe_gesture::begin()
|
||||
{
|
||||
// not swiping, check if swipe will begin
|
||||
if (std::regex_match(line, matches, gesture_swipe_begin) != 0)
|
||||
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)
|
||||
{
|
||||
// assign necessary variables for swipe begin
|
||||
this->flag_swiping = true;
|
||||
this->fingers = std::stoi(matches[1]);
|
||||
// dispatch begin
|
||||
this->begin();
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Hook on end of swipe gesture.
|
||||
*/
|
||||
void swipe_gesture::end()
|
||||
{ }
|
||||
|
||||
/* 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"
|
||||
};
|
||||
/**
|
||||
* 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__ */
|
||||
|
||||
@ -21,70 +21,65 @@ 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
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
class swipe_gesture : protected xdo_gesture
|
||||
namespace 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 */
|
||||
);
|
||||
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();
|
||||
~swipe_gesture();
|
||||
|
||||
// fields for xdo
|
||||
int fingers;
|
||||
float dx, dy, udx, udy;
|
||||
// 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;
|
||||
void begin() override;
|
||||
void update() override;
|
||||
void end() override;
|
||||
bool parse_line(const char *) override;
|
||||
|
||||
protected:
|
||||
// location of mouse
|
||||
int screen_num, ix, iy;
|
||||
protected:
|
||||
// location of mouse
|
||||
int screen_num, ix, iy;
|
||||
|
||||
// current location
|
||||
float x, y, threshold_squared;
|
||||
int previous_gesture;
|
||||
const char ** commands;
|
||||
// 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;
|
||||
// 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;
|
||||
};
|
||||
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__ */
|
||||
|
||||
@ -21,71 +21,74 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "swipe_gesture.h"
|
||||
|
||||
namespace comfortable_swipe::gesture
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
;
|
||||
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
|
||||
;
|
||||
/**
|
||||
* 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 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 ")"
|
||||
// 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
|
||||
;
|
||||
/**
|
||||
* 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
|
||||
// delete macros
|
||||
#undef CF_NUMBER_DIVISION
|
||||
#undef CF_NUMBER_EXTRACT
|
||||
#undef CF_NUMBER_REGEX
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __COMFORTABLE_SWIPE__gesture_swipe_gesture_regex__ */
|
||||
|
||||
@ -26,21 +26,24 @@ extern "C"
|
||||
|
||||
#include "xdo_gesture.h"
|
||||
|
||||
namespace comfortable_swipe::gesture
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* 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()
|
||||
namespace gesture
|
||||
{
|
||||
xdo_free(this->xdo);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,20 +4,17 @@
|
||||
#include <map> // std::map
|
||||
#include <string> // std::string
|
||||
|
||||
extern "C"
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
namespace comfortable_swipe
|
||||
namespace service
|
||||
{
|
||||
namespace service
|
||||
{
|
||||
void buffer();
|
||||
void debug();
|
||||
void help();
|
||||
void restart();
|
||||
void start();
|
||||
void stop();
|
||||
void status();
|
||||
}
|
||||
void buffer();
|
||||
void debug();
|
||||
void help();
|
||||
void restart();
|
||||
void start();
|
||||
void stop();
|
||||
void status();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,60 +2,69 @@
|
||||
#define __COMFORTABLE_SWIPE__service_python__
|
||||
|
||||
#include "_index.hpp"
|
||||
#include <Python.h>
|
||||
extern "C"
|
||||
{
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
// export as python module
|
||||
namespace comfortable_swipe::service::python
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
#define __comfortable_swipe_void_method(method) \
|
||||
static PyObject * \
|
||||
method(PyObject * self, PyObject * args) \
|
||||
{ \
|
||||
comfortable_swipe::service::method(); \
|
||||
Py_RETURN_NONE; \
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@ -21,14 +21,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cstdlib> // std::system
|
||||
|
||||
namespace comfortable_swipe::service
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* Debugs output from `libinput debug-events`.
|
||||
*/
|
||||
void debug()
|
||||
namespace service
|
||||
{
|
||||
(void) std::system("bash -c \"stdbuf -oL -e0 libinput debug-events 2> >(grep -v 'double tracking')\"");
|
||||
/**
|
||||
* Debugs output from `libinput debug-events`.
|
||||
*/
|
||||
void debug()
|
||||
{
|
||||
(void) std::system("bash -c \"stdbuf -oL -e0 libinput debug-events 2> >(grep -v 'double tracking')\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,24 +21,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cstdio> // std::puts, std::printf
|
||||
|
||||
namespace comfortable_swipe::service
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* Shows the help window.
|
||||
*/
|
||||
void help()
|
||||
namespace service
|
||||
{
|
||||
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");
|
||||
/**
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,15 +21,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "../service/_index.hpp"
|
||||
|
||||
namespace comfortable_swipe::service
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* Restarts the comfortable-swipe service.
|
||||
*/
|
||||
void restart()
|
||||
namespace service
|
||||
{
|
||||
comfortable_swipe::service::stop();
|
||||
comfortable_swipe::service::start();
|
||||
/**
|
||||
* Restarts the comfortable-swipe service.
|
||||
*/
|
||||
void restart()
|
||||
{
|
||||
comfortable_swipe::service::stop();
|
||||
comfortable_swipe::service::start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -24,39 +24,42 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <cstdlib> // std::system
|
||||
#include <unistd.h> // pipe, fork, perror, exit
|
||||
|
||||
namespace comfortable_swipe::service
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* 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()
|
||||
namespace service
|
||||
{
|
||||
std::ios::sync_with_stdio(false);
|
||||
std::cin.tie(0);
|
||||
std::cout.tie(0);
|
||||
std::cout.flush();
|
||||
/**
|
||||
* 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
|
||||
// redirect stdout to stdin
|
||||
int fd[2];
|
||||
pipe(fd); // create the pipes
|
||||
|
||||
int child;
|
||||
if ((child = fork()) == -1) {
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,44 +30,47 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <cstdio> // FILE, std::feof, std::fgets, std::printf
|
||||
#include <regex> // std::cmatch, std::regex, std::regex_match
|
||||
|
||||
namespace comfortable_swipe::service
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* Prints the status of comfortable-swipe.
|
||||
*/
|
||||
void status()
|
||||
namespace service
|
||||
{
|
||||
// std::printf("autostart is %s\n", autostart_on ? "ON" : "OFF");
|
||||
|
||||
// check status of configuration file
|
||||
try
|
||||
/**
|
||||
* Prints the status of comfortable-swipe.
|
||||
*/
|
||||
void status()
|
||||
{
|
||||
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");
|
||||
// std::printf("autostart is %s\n", autostart_on ? "ON" : "OFF");
|
||||
|
||||
// print swipe commands
|
||||
for (auto &command : comfortable_swipe::gesture::swipe_gesture::command_map)
|
||||
// check status of configuration file
|
||||
try
|
||||
{
|
||||
if (config.count(command) > 0)
|
||||
std::printf(" %9s = %s\n", command, config[command].data());
|
||||
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 NOT SET\n", command);
|
||||
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());
|
||||
}
|
||||
}
|
||||
catch (const std::runtime_error& e)
|
||||
{
|
||||
std::printf("config error: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,41 +29,44 @@ 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::service
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* Stops all comfortable-swipe instances.
|
||||
*/
|
||||
void stop()
|
||||
namespace service
|
||||
{
|
||||
|
||||
// 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()))
|
||||
/**
|
||||
* Stops all comfortable-swipe instances.
|
||||
*/
|
||||
void stop()
|
||||
{
|
||||
if (std::fgets(buffer.data(), buffer.size(), pipe.get()) != NULL)
|
||||
|
||||
// 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()))
|
||||
{
|
||||
int pid = std::atoi(buffer.data());
|
||||
if (pid != getpid())
|
||||
if (std::fgets(buffer.data(), buffer.size(), pipe.get()) != NULL)
|
||||
{
|
||||
kill += " ";
|
||||
kill += std::to_string(pid);
|
||||
int pid = std::atoi(buffer.data());
|
||||
if (pid != getpid())
|
||||
{
|
||||
kill += " ";
|
||||
kill += std::to_string(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run "kill {pid1} {pid2}..."
|
||||
(void) std::system(kill.data());
|
||||
// run "kill {pid1} {pid2}..."
|
||||
(void) std::system(kill.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,14 +4,11 @@
|
||||
#include <map> // std::map
|
||||
#include <string> // std::string
|
||||
|
||||
extern "C"
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
namespace comfortable_swipe
|
||||
namespace util
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
std::map<std::string, std::string> read_config_file(const char*);
|
||||
}
|
||||
std::map<std::string, std::string> read_config_file(const char*);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,82 +22,86 @@ 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 <sstream> // std::ostringstream
|
||||
#include <cstdlib> // exit
|
||||
#include <cctype> // std::isspace
|
||||
#include <stdexcept> // std::runtime_error
|
||||
|
||||
namespace comfortable_swipe::util
|
||||
namespace comfortable_swipe
|
||||
{
|
||||
/**
|
||||
* 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)
|
||||
namespace util
|
||||
{
|
||||
|
||||
std::map<std::string, std::string> conf;
|
||||
std::ifstream fin(filename);
|
||||
|
||||
if (!fin.is_open())
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
throw std::runtime_error("config file does not exist");
|
||||
}
|
||||
|
||||
static std::string line, token[2];
|
||||
int line_number = 0;
|
||||
std::map<std::string, std::string> conf;
|
||||
std::ifstream fin(filename, std::ios::in);
|
||||
|
||||
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 (!fin.is_open())
|
||||
{
|
||||
if (line[i] == '#') // skip comments
|
||||
break;
|
||||
if (line[i] == '=') // flag equal sign
|
||||
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 (++equal_flag > 1)
|
||||
if (line[i] == '#') // skip comments
|
||||
break;
|
||||
if (line[i] == '=') // flag equal sign
|
||||
{
|
||||
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());
|
||||
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]);
|
||||
}
|
||||
}
|
||||
else if (!std::isspace(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)
|
||||
{
|
||||
// add to buffer
|
||||
token[equal_flag].push_back(line[i]);
|
||||
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];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __COMFORTABLE_SWIPE__util_read_config_file__ */
|
||||
|
||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
psutil==5.6.0
|
||||
8
setup.py
8
setup.py
@ -54,7 +54,7 @@ try:
|
||||
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'],
|
||||
extra_compile_args=['-O2', '-Wno-unused-result', '-std=c++11', '-lstdc++'],
|
||||
libraries=['xdo']
|
||||
) for extension_name in extension_names]
|
||||
|
||||
@ -134,6 +134,10 @@ try:
|
||||
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 = [
|
||||
@ -166,7 +170,7 @@ try:
|
||||
entry_points=dict(console_scripts=['{}={}.__main__:main'.format(NAME, PYTHON_NAME)]),
|
||||
ext_modules=extensions,
|
||||
cmdclass=cmdclass,
|
||||
install_requires=['psutil'],
|
||||
install_requires=install_requires,
|
||||
classifiers=classifiers
|
||||
)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user