diff options
author | B. Watson <yalhcru@gmail.com> | 2020-05-18 03:22:20 -0400 |
---|---|---|
committer | B. Watson <yalhcru@gmail.com> | 2020-05-18 03:22:20 -0400 |
commit | c4afb1d2e5e9d1e819af0cb3615ba4642d0ece72 (patch) | |
tree | a1a3c1e69c9dc72a06717311118a3bb616b45ba9 | |
parent | 3674b88a2985dd3e14f643c0e0ae44e4e0cd0954 (diff) | |
download | unsaver-c4afb1d2e5e9d1e819af0cb3615ba4642d0ece72.tar.gz |
add -m (mouse motion)
-rw-r--r-- | jsmond.c | 123 | ||||
-rw-r--r-- | jsmond.rst | 24 |
2 files changed, 120 insertions, 27 deletions
@@ -35,6 +35,10 @@ #define MIN_BUTTON 1 #define MAX_BUTTON 10 +typedef enum { + fm_auto_keycode, fm_keycode, fm_button, fm_motion +} fake_mode_t; + /* user options */ int interval = 250; /* -i */ int debug = 0; /* -D */ @@ -43,6 +47,7 @@ int button = -1; /* -b */ char *event_dir = EVENTDIR; /* -d */ char *js_node_name = JSNODE; /* -j */ int autodiscover = 1; /* cleared if user supplies joydev args */ +fake_mode_t fake_mode = fm_auto_keycode; /* -b, -m */ /* joystick stuff */ char *joynames[MAX_STICKS + 1]; @@ -63,7 +68,7 @@ void usage(void) { printf("jsmond v" VERSION " by B. Watson, WTFPL\n"); printf("Usage: %s [-i interval] [-b button | -k keycode] [-j name]\n", self); printf(" [-d dir] [-D] [joystick [...]]\n"); - printf("Built-in defaults: MAX_STICKS=%d, EVENTDIR=" EVENTDIR ", JSNODE=" JSNODE "\n", MAX_STICKS); + printf("Built-in defaults: MAX_STICKS=%d, -d " EVENTDIR ", -j " JSNODE "\n", MAX_STICKS); printf("See man page for details\n"); exit(0); } @@ -111,6 +116,73 @@ void send_fake_click(void) { XSync(xdisp, 0); } +/* XXX: the man page documents XTestFakeRelativeMotionEvent() + as taking 5 arguments (2nd one is screen_number), but Xtst.h + only has 4 (with no screen_number arg). */ +void send_fake_motion(void) { + int oldx, oldy, ignoreme; + Window win_ignoreme; + + if(debug) fprintf(stderr, "sending mouse motion\n"); + + XQueryPointer( + xdisp, + DefaultRootWindow(xdisp), + &win_ignoreme, + &win_ignoreme, + &oldx, + &oldy, + &ignoreme, + &ignoreme, + (unsigned int *)&ignoreme); + + if(debug) fprintf(stderr, "oldx %d, oldy %d\n", oldx, oldy); + + /* move... */ + XTestFakeRelativeMotionEvent(xdisp, 10, 10, 0L); + XSync(xdisp, 0); + + /* ...wait 1/10 sec... */ + usleep(EVENT_DELAY); + + /* ...move back */ + XTestFakeRelativeMotionEvent(xdisp, -10, -10, 0L); + XSync(xdisp, 0); + + /* we've moved all 4 directions now. but if were were too close + to an edge of the screen, the mouse pointer isn't where it + started. so: */ + XWarpPointer( + xdisp, + None, + DefaultRootWindow(xdisp), + 0, + 0, + 0, + 0, + oldx, oldy); + XSync(xdisp, 0); +} + +void send_fake_x_event(void) { + switch(fake_mode) { + case fm_keycode: + send_fake_key(); + break; + case fm_button: + send_fake_click(); + break; + case fm_motion: + send_fake_motion(); + break; + default: /* This Never Happens(tm) */ + fprintf(stderr, "%s: BUG: fake_mode %d isn't a valid fake_mode_t!\n", + self, fake_mode); + exit(1); + break; + } +} + void open_joysticks(void) { int fdcount, i; struct js_event e; @@ -209,10 +281,7 @@ void main_loop(void) { /* if we got any activity on any of the fds, do our thing */ if(active) { if(debug) fprintf(stderr, "*** got activity!\n"); - if(button > -1) - send_fake_click(); - else - send_fake_key(); + send_fake_x_event(); } else if(debug) fprintf(stderr, "no activity\n"); } } @@ -225,6 +294,12 @@ void set_exe_name(const char *argv0) { if(p[0] == '/' && p[1]) self = p + 1; } +char *make_joystick_name(int js) { + static char buf[PATH_MAX + 1]; + sprintf(buf, "%s/%s%d", event_dir, js_node_name, js); + return buf; +} + /* add a joystick by pathname or number. note this only gets called once, at startup: the list never gets modified after that. */ void add_joystick_name(const char *name) { @@ -237,9 +312,7 @@ void add_joystick_name(const char *name) { } if(*name >= '0' && *name <= '9') { - char buf[PATH_MAX + 1]; - sprintf(buf, "%s/%s%d", event_dir, js_node_name, atoi(name)); - add_joystick_name(buf); + add_joystick_name(make_joystick_name(atoi(name))); return; } @@ -254,14 +327,19 @@ void add_joystick_name(const char *name) { void populate_joynames(void) { int i; - char buf[PATH_MAX + 1]; for(i = 0; i < MAX_STICKS; i++) { - sprintf(buf, "%s/%s%d", event_dir, js_node_name, i); - add_joystick_name(buf); + add_joystick_name(make_joystick_name(i)); } } +void set_fake_mode(fake_mode_t newmode) { + if(fake_mode != fm_auto_keycode) + die("use only one of the -k -b -m options"); + else + fake_mode = newmode; +} + void parse_args(int argc, char **argv) { char *nextarg; @@ -273,12 +351,16 @@ void parse_args(int argc, char **argv) { die("spaces required between options and arguments, please"); nextarg = argv[1]; switch(argv[0][1]) { + case 'm': + set_fake_mode(fm_motion); + break; case 'k': if(nextarg && (keycode = atoi(nextarg)) && (keycode >= MIN_KEYCODE) && (keycode <= MAX_KEYCODE) ) { + set_fake_mode(fm_keycode); argv++, argc--; } else { fprintf(stderr, "%s: -k requires a keycode argument, %d-%d\n", @@ -289,6 +371,7 @@ void parse_args(int argc, char **argv) { case 'b': if(nextarg) button = atoi(nextarg); if ( (button >= MIN_BUTTON) && (button <= MAX_BUTTON) ) { + set_fake_mode(fm_button); argv++, argc--; } else { fprintf(stderr, "%s: -b requires a mouse button argument, %d-%d\n", @@ -330,9 +413,6 @@ void parse_args(int argc, char **argv) { autodiscover = 0; } } - - if((keycode > -1) && (button > -1)) - die("can't send both keycode and button events"); } /* make ourselves a daemon, double-fork technique. @@ -427,7 +507,10 @@ void find_keycode() { /* XXX: XKeycodeToKeysym() is deprecated. I must learn XKB. */ for(i = min_code; i <= max_code; i++) { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" KeySym ks = XKeycodeToKeysym(xdisp, i, 0); +#pragma GCC diagnostic pop if(ks == NoSymbol) { keycode = i; if(debug) fprintf(stderr, "using keycode %d\n", keycode); @@ -447,19 +530,15 @@ void find_keycode() { void init_x(void) { connect_to_x(); - if(keycode < 0 && button < 0) { + if(fake_mode == fm_auto_keycode) { find_keycode(); + fake_mode = fm_keycode; } - /* do this now, before daemonizing. if the keycode is invalid, Xlib + /* do this now, before daemonizing. if something's wrong, Xlib will kill us. we'd better let that happen while we still have a stderr, so the user can see what happened. */ - if(keycode > -1) - send_fake_key(); - - /* same for the mouse, just in case */ - if(button > -1) - send_fake_click(); + send_fake_x_event(); } int main(int argc, char **argv) { @@ -20,7 +20,7 @@ deactivate screensaver on joystick activity SYNOPSIS ======== -jsmond [**-i interval**] [**-k keycode** | **-b button**] [**-d dir**] [**-j name**] [**-D**] [**joydev [joydev ...]**] +jsmond [**-i interval**] [**-m** | **-k keycode** | **-b button**] [**-d dir**] [**-j name**] [**-D**] [**joydev [joydev ...]**] DESCRIPTION =========== @@ -35,7 +35,7 @@ as joysticks are plugged in and unplugged. Every *interval* milliseconds (250, or whatever **-i** is set to), jsmond checks to see if there's been any activity on any of the devices it's -monitoring. If so, it sends a fake keystroke or mouse button click, which +monitoring. If so, it sends a fake mouse movement, keystroke, or mouse button click, which the screen saver will see as activity. It's recommended to let jsmond find the joysticks itself. However, @@ -63,7 +63,14 @@ OPTIONS -b <button> Send a click of this button when activity is detected, rather than a keystroke. Should be a button that - applications don't normally respond to (6 or higher). + applications don't normally respond to (6 or higher), + but in some environments, the window manager responds to + all the 'extra' buttons as though they were button 1. + +-m Send mouse movements rather than a keystroke. This will + move the pointer 10 pixels to the right and down, then + 10 pixels to the left and up, then warp the pointer back + to its starting point. These options are intended for developers and *really* shouldn't be needed for normal use: @@ -100,9 +107,13 @@ jsmond will wait for devices to come into existence (e.g. as created by **udev**). If the screensaver is configured to lock the screen, and it has already -activated, pressing a joystick button/direction will just bring up the +done so, pressing a joystick button/direction will just bring up the password dialog, same as pressing a key or mouse button would. +jsmond depends on the XTest extension being present in the X server. If +you get a "X server doesn't support XTest extension" error, see your X +server documentation to find out how to enable XTest. + EXIT STATUS =========== @@ -124,7 +135,10 @@ names (better to autodetect). Normally once daemonized, jsmond is very robust. However, if something does go wrong, there's no way to find out what. Probably there should -be a log file, or use syslog. +be a log file, or use syslog (or is that overkill?). + +It should be (but currently isn't) possible to at least work in +mouse-motion mode even without the XTest extension, via XWarpPointer(). jsmond isn't portable. It only works on Linux, at least for now, for three reasons: |