From 9169a787b057e1f933c8a9084d9fa5d414d98a25 Mon Sep 17 00:00:00 2001 From: Johannes Bensmann Date: Sat, 14 Dec 2019 20:13:05 +0100 Subject: added scroll bindings --- README.md | 28 +++++++++++++------- config.h | 31 ++++++++++++++++------- xmouseless.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 114 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 00d0389..1ad5b8c 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ This program is a replacement for the physical mouse in X11. -It aims to be simple and efficient. - Features: - move the mouse with different speeds - click and grab +- scroll - execute shell commands -## Installation +## Installation ``` make sudo make install @@ -22,14 +21,25 @@ Debian based distros: sudo apt-get install libx11-dev libxtst-dev ``` -## Configuration - -Edit config.h and reinstall. The configuration file should be self explaining. - ## Usage When starting xmouseless, it grabs the keyboard and all defined bindings are available. When pressing an exit key, the program exits. -You probably want to define a key binding for xmouseless in your desktop -environment or window manager. +The usage is quite intuitive and with some practice, you can move the pointer to +a specific location very fast. Basically, you move the pointer by pressing some +keys (the defaults are i, k, j and l for up, down, left and right) +and change the speed by pressing modifier keys. +The keys f, d and s (by default) are used to simulate mouse clicks and grabbing. +With some other keys, you can scroll up, down, left and right and execute +previously defined shell commands. + +You probably want to define a key binding to start xmouseless. + + +## Configuration + +The configuration is done in config.h, which is a C header file, +but you don't need any programming knowledge to edit it. +After you edited the file, you have to run make again. + diff --git a/config.h b/config.h index bd8b941..7164980 100644 --- a/config.h +++ b/config.h @@ -1,11 +1,14 @@ -/* the rate at which the mouse moves in Hz */ +/* the rate at which the mouse moves in Hz + * does not change its speed */ static const unsigned int move_rate = 50; -/* the speed with no modifier (pixels per second) */ +/* the default speed of the mouse pointer + * in pixels per second */ static const unsigned int default_speed = 500; -static SpeedBindings speed_bindings[] = { +/* changes the speed of the mouse pointer */ +static SpeedBinding speed_bindings[] = { /* key speed */ { XK_Super_L, 3000 }, { XK_Alt_L, 1500 }, @@ -13,7 +16,8 @@ static SpeedBindings speed_bindings[] = { { XK_Control_L, 10 }, }; -/* you can also add any other direction (e.g. diagonals) */ +/* moves the mouse pointer + * you can also add any other direction (e.g. diagonals) */ static MoveBinding move_bindings[] = { /* key x y */ { XK_j, -1, 0 }, @@ -24,19 +28,28 @@ static MoveBinding move_bindings[] = { /* 1: left * 2: middle - * 3: right - * 4: scroll up - * 5: scroll down */ + * 3: right */ static ClickBinding click_bindings[] = { /* key button */ { XK_space, 1 }, { XK_f, 1 }, { XK_d, 2 }, { XK_s, 3 }, - { XK_plus, 4 }, - { XK_minus, 5 }, }; +/* scrolls up, down, left and right + * a higher value scrolls faster */ +static ScrollBinding scroll_bindings[] = { + /* key x y */ + { XK_n, 0 , 25 }, + { XK_p, 0 , -25 }, + { XK_plus, 0 , 80 }, + { XK_minus, 0 , -80 }, + { XK_h, 25, 0 }, + { XK_g, -25, 0 }, +}; + +/* executes shell commands */ static ShellBinding shell_bindings[] = { /* key command */ { XK_b, "wmctrl -a firefox" }, diff --git a/xmouseless.c b/xmouseless.c index 8a52bc3..a187890 100644 --- a/xmouseless.c +++ b/xmouseless.c @@ -25,10 +25,16 @@ typedef struct { unsigned int button; } ClickBinding; +typedef struct { + KeySym keysym; + float x; + float y; +} ScrollBinding; + typedef struct { KeySym keysym; unsigned int speed; -} SpeedBindings; +} SpeedBinding; typedef struct { KeySym keysym; @@ -52,10 +58,19 @@ struct { float speed_y; } mouseinfo; +struct { + float x; + float y; + float speed_x; + float speed_y; +} scrollinfo; + void get_pointer(); -void moverelative(float x, float y); +void move_relative(float x, float y); void click(unsigned int button, Bool is_press); +void click_full(unsigned int button); +void scroll(float x, float y); void handle_key(XKeyEvent event); void init_x(); void close_x(); @@ -71,7 +86,7 @@ void get_pointer() { mouseinfo.y = y; } -void moverelative(float x, float y) { +void move_relative(float x, float y) { mouseinfo.x += x; mouseinfo.y += y; XWarpPointer(dpy, None, root, 0, 0, 0, 0, @@ -80,10 +95,37 @@ void moverelative(float x, float y) { } void click(unsigned int button, Bool is_press) { - XTestFakeButtonEvent(dpy, button, is_press, 0); + XTestFakeButtonEvent(dpy, button, is_press, CurrentTime); + XFlush(dpy); +} + +void click_full(unsigned int button) { + XTestFakeButtonEvent(dpy, button, 1, CurrentTime); + XTestFakeButtonEvent(dpy, button, 0, CurrentTime); XFlush(dpy); } +void scroll(float x, float y) { + scrollinfo.x += x; + scrollinfo.y += y; + while (scrollinfo.y <= -0.51) { + scrollinfo.y += 1; + click_full(4); + } + while (scrollinfo.y >= 0.51) { + scrollinfo.y -= 1; + click_full(5); + } + while (scrollinfo.x <= -0.51) { + scrollinfo.x += 1; + click_full(6); + } + while (scrollinfo.x >= 0.51) { + scrollinfo.x -= 1; + click_full(7); + } +} + void init_x() { int i; int screen; @@ -101,8 +143,9 @@ void init_x() { /* grab keys until success */ for (i = 0; i < 100; i++) { if (XGrabKeyboard(dpy, root, False, GrabModeAsync, - GrabModeAsync, CurrentTime) == GrabSuccess) + GrabModeAsync, CurrentTime) == GrabSuccess) { return; + } usleep(10000); } @@ -118,12 +161,18 @@ void close_x(int exit_status) { exit(exit_status); } -void *moveforever(void *val) { +void *move_forever(void *val) { /* this function is executed in a seperate thread */ while (1) { + /* move mouse? */ if (mouseinfo.speed_x != 0 || mouseinfo.speed_y != 0) { - moverelative((float) mouseinfo.speed_x * speed / move_rate, - (float) mouseinfo.speed_y * speed / move_rate); + move_relative((float) mouseinfo.speed_x * speed / move_rate, + (float) mouseinfo.speed_y * speed / move_rate); + } + /* scroll? */ + if (scrollinfo.speed_x != 0 || scrollinfo.speed_y != 0) { + scroll((float) scrollinfo.speed_x / move_rate, + (float) scrollinfo.speed_y / move_rate); } usleep(1000000 / move_rate); } @@ -162,6 +211,15 @@ void handle_key(XKeyEvent event) { } } + /* scroll bindings */ + for (i = 0; i < LENGTH(scroll_bindings); i++) { + if (scroll_bindings[i].keysym == keysym) { + int sign = is_press ? 1 : -1; + scrollinfo.speed_x += sign * scroll_bindings[i].x; + scrollinfo.speed_y += sign * scroll_bindings[i].y; + } + } + /* shell and exit bindings only on key release */ if (!is_press) { /* shell bindings */ @@ -195,8 +253,13 @@ int main () { mouseinfo.speed_y = 0; speed = default_speed; - // start the thread for mouse movement - rc = pthread_create(&movethread, NULL, &moveforever, NULL); + scrollinfo.x = 0; + scrollinfo.y = 0; + scrollinfo.speed_x = 0; + scrollinfo.speed_y = 0; + + /* start the thread for mouse movement and scrolling */ + rc = pthread_create(&movethread, NULL, &move_forever, NULL); if( rc != 0 ) { printf("Unable to start thread.\n"); return EXIT_FAILURE; -- cgit v1.2.3