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>
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
6162static 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
6265static int is_active = False ;
6366static int scrolls_since_active = 0 ;
6467static enum LogLevel log_level = LOG_INFO ;
68+ static struct timespec last_scroll_time ;
69+
6570#define CAPSLOCK_KEY_CODE 66
6671
6772void 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+
339360void 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