aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2020-05-18 03:22:20 -0400
committerB. Watson <yalhcru@gmail.com>2020-05-18 03:22:20 -0400
commitc4afb1d2e5e9d1e819af0cb3615ba4642d0ece72 (patch)
treea1a3c1e69c9dc72a06717311118a3bb616b45ba9
parent3674b88a2985dd3e14f643c0e0ae44e4e0cd0954 (diff)
downloadunsaver-c4afb1d2e5e9d1e819af0cb3615ba4642d0ece72.tar.gz
add -m (mouse motion)
-rw-r--r--jsmond.c123
-rw-r--r--jsmond.rst24
2 files changed, 120 insertions, 27 deletions
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) {
diff --git a/jsmond.rst b/jsmond.rst
index 0f875d3..bf9f9c8 100644
--- a/jsmond.rst
+++ b/jsmond.rst
@@ -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: