Skip to content

Commit 69bb71b

Browse files
author
Robin Müller
committed
Added functionality to distinguish between scrolling and zooming using 2 fingers
1 parent f36bdc1 commit 69bb71b

File tree

3 files changed

+93
-17
lines changed

3 files changed

+93
-17
lines changed

src/configuraion.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ configuration_t read_config(const char *filename) {
8484
result.scroll.horz_delta = (uint8_t) iniparser_getint(ini, "scroll:horizontaldelta", 30);
8585
result.vert_threshold_percentage = iniparser_getint(ini, "thresholds:vertical", 15);
8686
result.horz_threshold_percentage = iniparser_getint(ini, "thresholds:horizontal", 15);
87+
result.zoom.enabled = iniparser_getboolean(ini, "zoom:enabled", false);
8788

8889
uint8_t i, j;
8990
for (i = 0; i < MAX_FINGERS; i++) {

src/configuraion.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ typedef struct configuration {
4747
uint8_t vert_delta;
4848
uint8_t horz_delta;
4949
} scroll;
50+
struct zoom_options {
51+
bool enabled;
52+
} zoom;
5053
uint8_t vert_threshold_percentage;
5154
uint8_t horz_threshold_percentage;
5255
keys_array_t swipe_keys[MAX_FINGERS][DIRECTIONS_COUNT];

src/gesture_detection.c

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#include "gesture_detection.h"
3737

3838
// FIXME use 2 for SCROLL_FINGER_COUNT as soon as possible
39-
#define SCROLL_FINGER_COUNT 4
39+
#define SCROLL_FINGER_COUNT 2
4040
#define SCROLL_SLOW_DOWN_FACTOR -0.006
4141

4242
typedef struct point {
@@ -47,6 +47,7 @@ typedef struct point {
4747
typedef struct mt_slots {
4848
uint8_t active;
4949
point_t points[2];
50+
point_t last_points[2];
5051
} mt_slots_t;
5152

5253
typedef struct scroll {
@@ -69,10 +70,13 @@ typedef struct scroll_thread_params {
6970
void (*callback)(input_event_array_t*);
7071
} scroll_thread_params_t;
7172

73+
typedef enum gesture { NO_GESTURE, SCROLL, ZOOM, SWIPE } gesture_t;
74+
7275
mt_slots_t mt_slots;
7376
gesture_start_t gesture_start;
7477
uint8_t finger_count;
7578
volatile scroll_t scroll;
79+
gesture_t current_gesture;
7680

7781
static int test_grab(int fd) {
7882
int rc;
@@ -83,19 +87,23 @@ static int test_grab(int fd) {
8387
return rc;
8488
}
8589

86-
static void init_gesture() {
90+
static uint8_t calculate_distance(point_t p1, point_t p2) {
8791
int32_t x_distance, y_distance;
88-
gesture_start.point.x = mt_slots.points[0].x;
89-
gesture_start.point.y = mt_slots.points[0].y;
92+
x_distance = p1.x - p2.x;
93+
y_distance = p1.y - p2.y;
94+
return (uint32_t) sqrt((x_distance * x_distance) + (y_distance * y_distance));
95+
}
96+
97+
static void init_gesture() {
98+
gesture_start.point = mt_slots.points[0];
9099

91100
if (finger_count == SCROLL_FINGER_COUNT) {
92-
x_distance = mt_slots.points[0].x - mt_slots.points[1].x;
93-
y_distance = mt_slots.points[0].y - mt_slots.points[1].y;
94-
gesture_start.distance = (uint32_t) sqrt((x_distance * x_distance) + (y_distance * y_distance));
101+
gesture_start.distance = calculate_distance(mt_slots.points[0], mt_slots.points[1]);
95102
scroll.width = 0;
96103
scroll.last_point = mt_slots.points[0];
97104
scroll.x_velocity = 0;
98105
scroll.y_velocity = 0;
106+
current_gesture = NO_GESTURE;
99107
}
100108
}
101109

@@ -159,6 +167,7 @@ static void process_abs_event(struct input_event event) {
159167
scroll.last_x_abs_event = event;
160168
scroll.last_point.x = mt_slots.points[0].x;
161169
}
170+
mt_slots.last_points[mt_slots.active].x = mt_slots.points[mt_slots.active].x;
162171
// store the current x position for the current mt_slot
163172
mt_slots.points[mt_slots.active].x = event.value;
164173
break;
@@ -173,6 +182,7 @@ static void process_abs_event(struct input_event event) {
173182
scroll.last_y_abs_event = event;
174183
scroll.last_point.y = mt_slots.points[0].y;
175184
}
185+
mt_slots.last_points[mt_slots.active].y = mt_slots.points[mt_slots.active].y;
176186
// store the current y position for the current mt_slot
177187
mt_slots.points[mt_slots.active].y = event.value;
178188
break;
@@ -207,6 +217,22 @@ static input_event_array_t *do_scroll(double distance, int32_t delta, int rel_co
207217
return result;
208218
}
209219

220+
/*
221+
* @return a vector that can only have the following values for x and y: -1, 0, 1
222+
*/
223+
static point_t create_direction_vector(point_t p1, point_t p2) {
224+
point_t result;
225+
result.x = p1.x - p2.x;
226+
result.y = p1.y - p2.y;
227+
if (result.x != 0) {
228+
result.x /= fabs(result.x);
229+
}
230+
if (result.y != 0) {
231+
result.y /= fabs(result.y);
232+
}
233+
return result;
234+
}
235+
210236
static input_event_array_t *process_syn_event(struct input_event event,
211237
configuration_t config,
212238
point_t thresholds) {
@@ -218,28 +244,66 @@ static input_event_array_t *process_syn_event(struct input_event event,
218244
x_distance = gesture_start.point.x - mt_slots.points[0].x;
219245
y_distance = gesture_start.point.y - mt_slots.points[0].y;
220246
if (fabs(x_distance) > fabs(y_distance)) {
221-
// only check for the finger_count LEFT and RIGHT gestures if horizontal scrolling is
222-
// disabled and the the finger_count doesn't match SCROLL_FINGER_COUNT
223-
if (!(config.scroll.horz && finger_count == SCROLL_FINGER_COUNT)) {
247+
if (current_gesture == NO_GESTURE) {
248+
point_t v1 = create_direction_vector(mt_slots.last_points[0], mt_slots.points[0]);
249+
point_t v2 = create_direction_vector(mt_slots.last_points[1], mt_slots.points[1]);
250+
// if horizontal scrolling is enable, the finger_count matches SCROLL_FINGER_COUNT and
251+
// the x direction of the direction vectors for both fingers is equal the current_gesture
252+
// will be SCROLL
253+
if (config.scroll.horz && finger_count == SCROLL_FINGER_COUNT && v1.x != 0 && v1.x == v2.x) {
254+
current_gesture = SCROLL;
255+
// if zooming is enable, the finger_count matches SCROLL_FINGER_COUNT and the direction
256+
// vectors for both fingers are opposed to each other the current_gesture will be ZOOM
257+
} else if (config.zoom.enabled && finger_count == SCROLL_FINGER_COUNT && (v1.x != v2.x || v1.y != v2.y)) {
258+
current_gesture = ZOOM;
259+
// if no scrolling and zooming is enabled or the finger_count does not match
260+
// SCROLL_FINGER_COUNT the current_gesture will be SWIPE
261+
} else if ((!config.scroll.horz && !config.zoom.enabled) || finger_count != SCROLL_FINGER_COUNT) {
262+
current_gesture = SWIPE;
263+
}
264+
}
265+
266+
if (current_gesture == SWIPE) {
224267
if (x_distance > thresholds.x) {
225268
direction = LEFT;
226269
} else if (x_distance < -thresholds.x) {
227270
direction = RIGHT;
228271
}
229-
} else {
230-
result = do_scroll(scroll.last_point.x - mt_slots.points[0].x, config.scroll.horz_delta, REL_HWHEEL);
272+
} else if (current_gesture == SCROLL) {
273+
result = do_scroll(scroll.last_point.x - mt_slots.points[0].x, config.scroll.horz_delta, REL_HWHEEL);
274+
} else if (current_gesture == ZOOM) {
275+
printf("zoom\n");
231276
}
232277
} else {
233-
// only check for the finger_count UP and DOWN gestures if horizontal scrolling is
234-
// disabled and the the finger_count doesn't match SCROLL_FINGER_COUNT
235-
if (!(config.scroll.vert && finger_count == SCROLL_FINGER_COUNT)) {
278+
if (current_gesture == NO_GESTURE) {
279+
point_t v1 = create_direction_vector(mt_slots.last_points[0], mt_slots.points[0]);
280+
point_t v2 = create_direction_vector(mt_slots.last_points[1], mt_slots.points[1]);
281+
// if vertical scrolling is enable, the finger_count matches SCROLL_FINGER_COUNT and
282+
// the y direction of the direction vectors for both fingers is equal the current_gesture
283+
// will be SCROLL
284+
if (config.scroll.vert && finger_count == SCROLL_FINGER_COUNT && v1.y != 0 && v1.y == v2.y) {
285+
current_gesture = SCROLL;
286+
// if zooming is enable, the finger_count matches SCROLL_FINGER_COUNT and the direction
287+
// vectors for both fingers are opposed to each other the current_gesture will be ZOOM
288+
} else if (config.zoom.enabled && finger_count == SCROLL_FINGER_COUNT && (v1.x != v2.x || v1.y != v2.y)) {
289+
current_gesture = ZOOM;
290+
// if no scrolling and zooming is enabled or the finger_count does not match
291+
// SCROLL_FINGER_COUNT the current_gesture will be SWIPE
292+
} else if ((!config.scroll.vert && !config.zoom.enabled) || finger_count != SCROLL_FINGER_COUNT) {
293+
current_gesture = SWIPE;
294+
}
295+
}
296+
297+
if (current_gesture == SWIPE) {
236298
if (y_distance > thresholds.y) {
237299
direction = UP;
238300
} else if (y_distance < -thresholds.y) {
239301
direction = DOWN;
240302
}
241-
} else {
303+
} else if (current_gesture == SCROLL) {
242304
result = do_scroll(mt_slots.points[0].y - scroll.last_point.y, config.scroll.vert_delta, REL_WHEEL);
305+
} else if (current_gesture == ZOOM) {
306+
printf("zoom\n");
243307
}
244308
}
245309
if (direction != NONE) {
@@ -317,6 +381,8 @@ void process_events(int fd, configuration_t config, void (*callback)(input_event
317381

318382
pthread_t scroll_thread = NULL;
319383

384+
uint8_t syn_event_skip_counter = 0;
385+
320386
if (thresholds.x < 0 || thresholds.y < 0) {
321387
return;
322388
}
@@ -342,6 +408,7 @@ void process_events(int fd, configuration_t config, void (*callback)(input_event
342408
pthread_cancel(scroll_thread);
343409
}
344410
init_gesture();
411+
syn_event_skip_counter = 0;
345412
} else if (scroll.x_velocity != 0 || scroll.y_velocity != 0) {
346413
scroll_thread_params_t params = {
347414
.callback = callback
@@ -361,7 +428,12 @@ void process_events(int fd, configuration_t config, void (*callback)(input_event
361428
case EV_ABS:
362429
process_abs_event(ev[i]);
363430
break;
364-
case EV_SYN: {
431+
case EV_SYN:
432+
// skip the first 3 EV_SYN events to get enough data for mt_slots.last_points and .points
433+
// to calculate the direction vectors correctly
434+
if (syn_event_skip_counter < 3) {
435+
syn_event_skip_counter++;
436+
} else {
365437
input_event_array_t *input_events = process_syn_event(ev[i], config, thresholds);
366438
callback(input_events);
367439
free(input_events);

0 commit comments

Comments
 (0)