From c4afb1d2e5e9d1e819af0cb3615ba4642d0ece72 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Mon, 18 May 2020 03:22:20 -0400 Subject: add -m (mouse motion) --- jsmond.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 22 deletions(-) (limited to 'jsmond.c') diff --git a/jsmond.c b/jsmond.c index 3dd2578..d57f626 100644 --- a/jsmond.c +++ b/jsmond.c @@ -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) { -- cgit v1.2.3