-
Notifications
You must be signed in to change notification settings - Fork 46
/
comfortable-swipe-gesture-swipe-xdokey.cpp
197 lines (187 loc) · 6.25 KB
/
comfortable-swipe-gesture-swipe-xdokey.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
#ifndef __comfortable_swipe_gesture_swipe_xdokey__
#define __comfortable_swipe_gesture_swipe_xdokey__
/*
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 <array> // std::array
#include <iostream> // std::cout, std::endl
#include <string> // std::string
extern "C" {
#include <xdo.h> // xdo_send_keysequence_window
// CURRENT_WINDOW
}
#include "comfortable-swipe-gesture-swipe.cpp"
namespace comfortable_swipe {
/**
* Gesture Swipe keyboard-swipe gestures class with xdo.
*
* Performs a swipe in one of the four cardinal directions:
* left, right, up, down. Applicable for 3 or 4 fingers.
*
* When constructing, please mind the order in the
* `gesture_swipe_xdokey::command_name[]` static array.
*/
class gesture_swipe_xdokey : public gesture_swipe {
public:
// stores the 8 command strings for xdo to execute
std::array<std::string, 8> commands;
// constructor
gesture_swipe_xdokey(const decltype(commands) &commands, float threshold = 0);
// destructor
virtual ~gesture_swipe_xdokey();
// hooks that we override
virtual void begin() override;
virtual void update() override;
virtual void end() override;
// override this when keyboard gesture is to be performed
virtual void do_keyboard_gesture(int mask);
// public accessors
virtual int get_previous_gesture() const { return this->previous_gesture; }
virtual int get_current_mask() const { return this->current_mask; }
protected:
// stores square of threshold so we can compute faster
float threshold_squared;
// stores previous gesture so we don't repeat action
int previous_gesture;
int current_mask;
public:
// static enums we will use for gesture matching
static const int FRESH = -1;
static const int MSK_THREE_FINGERS = 0;
static const int MSK_FOUR_FINGERS = 1;
static const int MSK_NEGATIVE = 0;
static const int MSK_POSITIVE = 2;
static const int MSK_HORIZONTAL = 0;
static const int MSK_VERTICAL = 4;
// mappings to our command string names
static const std::string command_name[];
};
/**
* Our mapped directional command names. These will be
* printed to the console during execution:
*
* SWIPE <command_name>
*
* Refer to the order of this array for the "commands"
* paramter in the constructor.
*/
decltype(
gesture_swipe_xdokey::command_name) gesture_swipe_xdokey::command_name = {
// the order of variables is based on bitmasking
// <VERTICAL?> | <POSITIVE?> | <FOUR FINGERS?>
"left3", // 000
"left4", // 001
"right3", // 010
"right4", // 011
"up3", // 100
"up4", // 101
"down3", // 110
"down4" // 111
};
/**
* Constructs a new keyboard-based swipe gesture, given configurations
* for certain swipe events. Here, we construct our definition based on
* the four directions (left, up, right, down) for 3-finger and 4-finger
* swipes. Note that the direction is based on the Australian natural
* scrolling direction (ie. left3 is natural movement of 3 fingers left).
*/
gesture_swipe_xdokey::gesture_swipe_xdokey(
const decltype(gesture_swipe_xdokey::commands) &commands, float threshold)
: gesture_swipe(), commands(commands),
threshold_squared(threshold * threshold),
previous_gesture(gesture_swipe_xdokey::FRESH),
current_mask(gesture_swipe_xdokey::FRESH) {}
/**
* Destructs this keyboard swipe gesture.
*/
gesture_swipe_xdokey::~gesture_swipe_xdokey() {}
/**
* Hook on begin of swipe gesture.
*/
void gesture_swipe_xdokey::begin() {
// call superclass method
gesture_swipe::begin();
// assign gesture to FRESH
current_mask = FRESH;
previous_gesture = FRESH;
}
/**
* Hook on update of swipe gesture.
*/
void gesture_swipe_xdokey::update() {
// call superclass method
gesture_swipe::update();
// scale threshold to 1/10 when gesture is fresh
// acts like our static friction coefficient
const float scale = get_previous_gesture() == FRESH ? 0.01f : 1.0f;
// we are working with floating points which are not exact
// make sure we compare with a very small value (1e-6f)
// if distance goes out of threshold, perform our swipe
if (x * x + y * y > threshold_squared * scale + 1e-6f) {
// we parse our mask based on the values obtained from the regex
int mask = 0;
if (fingers == 3)
mask |= MSK_THREE_FINGERS;
else if (fingers == 4)
mask |= MSK_FOUR_FINGERS;
const float absx = x >= 0 ? x : -x;
const float absy = y >= 0 ? y : -y;
if (absx > absy) {
// gesture is horizontal
mask |= MSK_HORIZONTAL;
if (x < 0)
mask |= MSK_NEGATIVE;
else
mask |= MSK_POSITIVE;
} else /* std::abs(x) <= std::abs(y) */
{
// gesture is vertical
mask |= MSK_VERTICAL;
if (y < 0)
mask |= MSK_NEGATIVE;
else
mask |= MSK_POSITIVE;
}
// update our mask
current_mask = mask;
// send command on fresh OR opposite gesture
if (previous_gesture == FRESH ||
previous_gesture == (mask ^ MSK_POSITIVE)) {
// do keyboard gesture
do_keyboard_gesture(mask);
// reset our location variables
x = y = 0;
previous_gesture = mask;
}
} else { // not in threshold, set mask to fresh
current_mask = FRESH;
}
}
/**
* Perform our maske command to xdo.
*/
void gesture_swipe_xdokey::do_keyboard_gesture(int mask) {
// perform our keyboard command with xdo_send_keysequence
xdo_send_keysequence_window(xdo, CURRENTWINDOW, commands[mask].data(), 0);
std::cout << "SWIPE " << command_name[mask] << std::endl;
}
/**
* Hook on end of swipe gesture.
*/
void gesture_swipe_xdokey::end() {
// just call superclass method
gesture_swipe::end();
}
} // namespace comfortable_swipe
#endif /* __comfortable_swipe_gesture_swipe_xdokey__ */