Skip to content

Commit fe6773c

Browse files
committed
rate limit scrolls to prevent event queuing up and playback
1 parent 99fb36d commit fe6773c

1 file changed

Lines changed: 36 additions & 4 deletions

File tree

main.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// converts pointer (mouse, trackpad, ...) movements into scroll wheel events
2-
// uses XLib and XLib extension XInput2
2+
// uses XLib, XLib extensions XInput2, XTest, Xfixes
33
// cursor position tracking based on https://keithp.com/blogs/Cursor_tracking/
44

55
#include <stdio.h>
@@ -13,6 +13,7 @@
1313
#include <getopt.h>
1414
#include <sys/file.h>
1515
#include <stdarg.h>
16+
#include <time.h>
1617
#include <X11/Xlib.h>
1718
#include <X11/extensions/XInput2.h>
1819
#include <X11/extensions/XTest.h>
@@ -59,9 +60,13 @@ struct Config {
5960
};
6061

6162
static const char* PROGRAM_VERSION = "1.0";
63+
static const int NANOSECOND_TO_MILLISECOND_DIV = 1000000;
64+
static const int SCROLL_TRIGGER_SPEED_LIMIT_MS = 30; // don't allow scrolling in too quick succession, it can't handle them so fast, so they queue up an play back, also causing more CPU load
6265
static int is_active = False;
6366
static int scrolls_since_active = 0;
6467
static enum LogLevel log_level = LOG_INFO;
68+
static struct timespec last_scroll_time;
69+
6570
#define CAPSLOCK_KEY_CODE 66
6671

6772
void logg(enum LogLevel level, const char* fmt, ...)
@@ -208,10 +213,10 @@ static void request_to_receive_events(Display *dpy, Window win)
208213

209214
/* select for button and key events from all master devices */
210215
XISetMask(mask1, XI_RawMotion);
211-
// XISetMask(mask1, XI_ButtonPress);
212-
// XISetMask(mask1, XI_ButtonRelease);
213216
XISetMask(mask1, XI_KeyPress);
214217
XISetMask(mask1, XI_KeyRelease);
218+
// XISetMask(mask1, XI_ButtonPress);
219+
// XISetMask(mask1, XI_ButtonRelease);
215220

216221
evmasks[0].deviceid = XIAllDevices;
217222
evmasks[0].mask_len = sizeof(mask1);
@@ -336,6 +341,22 @@ void set_is_active(Bool active, Display* display, Window window)
336341
XFixesShowCursor(display, window);
337342
}
338343

344+
struct timespec diff_timespec(struct timespec start, struct timespec end)
345+
{
346+
struct timespec temp;
347+
if ((end.tv_nsec-start.tv_nsec) < 0)
348+
{
349+
temp.tv_sec = end.tv_sec-start.tv_sec - 1;
350+
temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
351+
}
352+
else
353+
{
354+
temp.tv_sec = end.tv_sec - start.tv_sec;
355+
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
356+
}
357+
return temp;
358+
}
359+
339360
void check_for_scroll_trigger(enum ScrollDirection scroll_direction, double* total_movement_delta, double delta, struct Config* cfg, Display* display)
340361
{
341362
logg(LOG_DEBUG, "check: dir: %s, total_movement_delta: %g, delta: %g, thres: %d\n",
@@ -347,9 +368,21 @@ void check_for_scroll_trigger(enum ScrollDirection scroll_direction, double* tot
347368
*total_movement_delta += delta;
348369
if (fabs(*total_movement_delta) > cfg->mouse_move_delta_to_scroll_threshold)
349370
{
371+
struct timespec now;
372+
clock_gettime(CLOCK_REALTIME, &now);
373+
374+
struct timespec time_since_last_scroll = diff_timespec(last_scroll_time, now);
375+
if (time_since_last_scroll.tv_sec == 0 && (time_since_last_scroll.tv_nsec / NANOSECOND_TO_MILLISECOND_DIV) < SCROLL_TRIGGER_SPEED_LIMIT_MS)
376+
{
377+
logg(LOG_DEBUG, "rate limited, last scroll was just %dms ago. \n", time_since_last_scroll.tv_nsec / NANOSECOND_TO_MILLISECOND_DIV);
378+
*total_movement_delta = 0; // reset total so we don't rate limit a bunch of time for the next pointer move events, it needs to build up the total again
379+
return;
380+
}
381+
350382
before_synthethic_scroll(display, cfg);
351383

352384
int scroll_amount = (int) (*total_movement_delta / cfg->mouse_move_delta_to_scroll_threshold);
385+
last_scroll_time = now;
353386
trigger_scroll(display, cfg, scroll_direction, scroll_amount);
354387

355388
// adjust accumulator: reduce for distance traveled that is 'used up' by scrolling
@@ -505,7 +538,6 @@ int main(int argc, char **argv)
505538
if (cfg.allow_horizontal_scroll)
506539
check_for_scroll_trigger(SCROLL_HORIZONTAL, &total_movement_x_delta, deltaX, &cfg, display);
507540

508-
XFlush(display); // may not be necessary, but it's here to ensure immediacy
509541
break;
510542
}
511543
fflush(stdout);

0 commit comments

Comments
 (0)