-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathcomfortable-swipe-gesture-swipe.cpp
229 lines (224 loc) · 7.95 KB
/
comfortable-swipe-gesture-swipe.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#ifndef __comfortable_swipe_gesture_swipe__
#define __comfortable_swipe_gesture_swipe__
/**
* File: comfortable-swipe-gesture-swipe.cpp
*
* This is the base class of all comfortable swipe gestures.
*
* The class `comfortable_swipe::gesture_swipe` handles dispatching
* of swipe gestures. The method `gesture_swipe::run(const char*)`
* parses a line from libinput debug-events and dispatches a begin(),
* update(), or end() function based on a compiled regex pattern.
*
* We statically compile our swipe gesture regex patterns here.
* This is for parsing `libinput debug-events` console output:
*
* GESTURE_SWIPE_BEGIN - libinput's begin wipe command
* GESTURE_SWIPE_UPDATE - libinput's update swipe command
* GESTURE_SWIPE_END - libinput's end swipe command
*
* We dispatch our events based on the regex patterns above, and
* extract important information, such as number of fingers, in
* an efficient way with Regular Expressions (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 <iostream> // std::cout, std::endl
#include <regex> // std::regex, std::regex_match, std::cmatch
#include <string> // std::stoi, std::stof
extern "C" {
#include <xdo.h> // xdo, xdo_new, xdo_free,
// xdo_get_mouse_location
// CURRENT_WINDOW
}
namespace comfortable_swipe {
/**
* Handles swipe gesture input from libinput debug-events.
* Dispatches keyboard commands on swipe using libxdo.
*/
class gesture_swipe {
public:
// constructor
gesture_swipe();
// destructor
virtual ~gesture_swipe();
// fields for xdo
int fingers;
// normal values (for touchpad mapping)
float x, y, dx, dy;
// unaccelerated values (for screen mapping)
float ux, uy, udx, udy;
// hooks that we can override (mark as virtual)
virtual void begin();
virtual void update();
virtual void end();
virtual bool run(const char *);
// public check if currently swiping
virtual bool is_swiping() const { return this->flag_swiping; }
protected:
// xdo container
xdo_t *xdo;
// location of mouse
int screen_num, ix, iy;
// optimization flag for checking if GESTURE_SWIPE_BEGIN was dispatched
bool flag_swiping;
public:
// defined in: comfortable-swipe-gesture-swipe.regex.cpp
static const std::regex GESTURE_SWIPE_BEGIN;
static const std::regex GESTURE_SWIPE_UPDATE;
static const std::regex GESTURE_SWIPE_END;
};
/**
* Constructs a new fresh swipe gesture container.
*/
gesture_swipe::gesture_swipe() : xdo(xdo_new(NULL)), flag_swiping(false) {
// improve responsiveness of first gesture by pre-empting xdotool
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
}
/**
* Destructs this swipe gesture.
*/
gesture_swipe::~gesture_swipe() { xdo_free(this->xdo); }
/**
* Hook on begin of swipe gesture (you can override this).
*/
void gesture_swipe::begin() {
// save current screen location for gestured mouse movement
xdo_get_mouse_location(this->xdo, &this->ix, &this->iy, &this->screen_num);
this->x = 0;
this->y = 0;
this->ux = 0;
this->uy = 0;
}
/**
* Hook on update of swipe gesture (you can override this).
*/
void gesture_swipe::update() {
this->x += this->dx;
this->y += this->dy;
this->ux += this->udx;
this->uy += this->udy;
}
/**
* Hook on end of swipe gesture (you can override this).
*/
void gesture_swipe::end() {
// do nothing
}
/**
* Dispatches begin/update/end depending on the regex pattern provided by this
* class. Returns true if a gesture begin/update/end was parsed.
*
* @param line the line from libinput debug-events to parse
* @return true if begin/update/end was dispatched
*/
bool gesture_swipe::run(const char *line) {
// prepare holder for regex matches
static std::cmatch matches;
if (!this->flag_swiping) {
// 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;
}
} else {
// 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;
}
}
return false;
}
/**
* 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 std::regex
gesture_swipe::GESTURE_SWIPE_BEGIN("^" // 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 std::regex
gesture_swipe::GESTURE_SWIPE_END("^" // 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 _NUMBER_REGEX "-?\\d+(?:\\.\\d+)"
// matches and extracts a space-prefixed signed fraction (eg. "-3.00/ 5.12")
#define _NUMBER_DIVISION "\\s*(" _NUMBER_REGEX ")/\\s*(" _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 std::regex gesture_swipe::GESTURE_SWIPE_UPDATE(
"^" // start of string
"[ -]event\\d+" // event
"\\s+GESTURE_SWIPE_UPDATE" // gesture
"\\s+\\S+" // timestamp
"\\s+(\\d+)" // fingers
"\\s+" _NUMBER_DIVISION // speed (dx/dy)
"\\s+\\(" _NUMBER_DIVISION
"\\s+unaccelerated\\)" // unaccelerated speed (udx/udy)
"\\s*$" // end of string
);
// clean up temporary macros
#undef _NUMBER_DIVISION
#undef _NUMBER_REGEX
} // namespace comfortable_swipe
#endif /* __comfortable_swipe_gesture_swipe__ */