chiark / gitweb /
Add new program `xwarpptr'.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 24 Apr 2022 11:19:36 +0000 (12:19 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 24 Apr 2022 11:25:08 +0000 (12:25 +0100)
Makefile.am
debian/control
debian/xtoys.install
xwarpptr.1 [new file with mode: 0644]
xwarpptr.c [new file with mode: 0644]

index 825e8fd953d161cfe42b30fd761c1c4a8cf19946..dcba7801d6b45c1230461d64567e3fe2bfe2d5fa 100644 (file)
@@ -58,6 +58,11 @@ dist_man_MANS                += xatom.1
 xatom_SOURCES           = xatom.c
 xatom_SOURCES          += libxatom.h libxatom.c
 
+## xwarpptr.
+bin_PROGRAMS           += xwarpptr
+dist_man_MANS          += xwarpptr.1
+xwarpptr_SOURCES        = xwarpptr.c
+
 ## xrepaint.
 bin_PROGRAMS           += xrepaint
 dist_man_MANS          += xrepaint.1
index 743330a9b3abb09a366834fc2f12dc52647fc80f..3d3e2e6efea2cd2b5ee3dffca8c218308b22fdd1 100644 (file)
@@ -16,6 +16,7 @@ Description: A collection of small X11 tools
  xscsize -- reports the display size as shell variables
  xatom -- inspect properties on windows, and wait for changes
  xrepaint -- repaint the display, or just a single screen
+ xwarpptr -- move mouse pointer to a given location
 
 Package: xtoys-gtk
 Architecture: all
index 445435a838f5599497f676918558f1ecbdf87979..600a2f4a22ab3c9e94f6f04b87cceceefe2ebee3 100644 (file)
@@ -4,3 +4,5 @@ debian/tmp/usr/bin/xscsize
 debian/tmp/usr/share/man/man1/xscsize.1
 debian/tmp/usr/bin/xrepaint
 debian/tmp/usr/share/man/man1/xrepaint.1
+debian/tmp/usr/bin/xwarpptr
+debian/tmp/usr/share/man/man1/xwarpptr.1
diff --git a/xwarpptr.1 b/xwarpptr.1
new file mode 100644 (file)
index 0000000..3c35a9c
--- /dev/null
@@ -0,0 +1,60 @@
+.\" -*-nroff-*-
+.TH xwarpptr 1 "22 April 2022" "Straylight/Edgeware" "xtoys"
+.SH NAME
+xwarpptr \- warp pointer to a given location
+.SH SYNOPSIS
+.B xwarpptr
+.RB [ \-r ]
+.RB [ \-d
+.IR display ]
+.I x
+.I y
+.SH DESCRIPTION
+The
+.B xwarpptr
+warps (moves) the mouse pointer to position
+.RI ( x ,
+.IR y )
+on the screen.
+.PP
+Coordinates use the usual (left-handed) X11 convention: the origin in in
+the top left, with
+.IR x -
+and
+.IR y -coordinates
+increasing rightwards and downwards respectively.
+.PP
+If
+.I x
+or
+.I y
+is negative, then it is instead considered relative to the right or
+bottom edge, respectively.  Usually, a negative number would need to be
+preceded by a
+.RB ` \-\- '
+marker to prevent it from being misinterpreted as an option, but
+.B xwarpptr
+takes special care to handle this situation correctly.
+.PP
+With the
+.B \-r
+option,
+.I x
+and
+.I y
+are instead considered relative to the pointer's current position;
+coordinates still increase rightwards and downwards.
+.SS Options
+.TP 5
+.BI "\-d, \-\-display " display
+Choose which display to connect to.
+.TP 5
+.B \-r, \-\-relative
+Move the pointer relative to its current position, rather than to an
+absolute position.  (See above.)
+.SH BUGS
+Hopefully none.
+.SH SEE ALSO
+.BR XWarpPointer (3x).
+.SH AUTHOR
+Mark Wooding (mdw@distorted.org.uk).
diff --git a/xwarpptr.c b/xwarpptr.c
new file mode 100644 (file)
index 0000000..92cd5c6
--- /dev/null
@@ -0,0 +1,173 @@
+/* -*-c-*-
+ *
+ * Warp pointer to a specific location
+ *
+ * (c) 2022 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Edgeware X tools collection.
+ *
+ * X tools is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * X tools is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with X tools.  If not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+
+#include <mLib/alloc.h>
+#include <mLib/macros.h>
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+/*----- Help and version information --------------------------------------*/
+
+static void version(void)
+  { pquis(stdout, "$ version " VERSION "\n"); }
+
+static void usage(FILE *fp)
+  { pquis(fp, "Usage: $ [-d DISPLAY] X Y\n"); }
+
+static void help(void)
+{
+  version(); putchar('\n');
+  usage(stdout);
+  fputs("\n\
+Warp mouse pointer to position X, Y on the screen.\n\
+\n\
+Command-line options:\n\
+\n\
+-h, --help                     Display this help.\n\
+-v, --version                  Display program's version number.\n\
+-u, --usage                    Display short usage summary.\n\
+\n\
+-d, --display=DISPLAY          Connect to X DISPLAY.\n",
+       stdout);
+}
+
+/*----- Main program ------------------------------------------------------*/
+
+static int parse_int(const char *p)
+{
+  char *q;
+  int err;
+  long i;
+
+  err = errno; errno = 0;
+  if (!*p || ISSPACE(*p)) goto bad;
+  i = strtol(p, &q, 0);
+  if (err || *q || i < INT_MIN || i > INT_MAX) goto bad;
+  return ((int)i);
+
+bad:
+  die(1, "bad integer `%s'", p);
+}
+
+int main(int argc, char *argv[])
+{
+  const char *display = 0;
+  Display *dpy = 0;
+  int sc;
+  Window w;
+  char **fixups; int nfixups, i;
+  int x, y, xmin, xmax, ymin, ymax, wd, ht;
+
+  unsigned f = 0;
+#define f_bogus 1u
+#define f_relative 2u
+#define f_neg 4u
+
+  ego(argv[0]);
+
+  /* An initial pass over the argument vector.
+   *
+   * Negative numbers look like options, but we don't want them treated that
+   * way.  So we're going to hide them from the option parser for a bit.
+   */
+  fixups = xmalloc(argc*sizeof(char *));
+  for (i = 0, nfixups = 0; i < argc; i++)
+    if (argv[i][0] == '-' && ISDIGIT(argv[i][1]))
+      { fixups[nfixups++] = argv[i]; argv[i][0] = '?'; }
+
+  /* Parse arguments. */
+  for (;;) {
+    static struct option opt[] = {
+      { "help",                0,                      0,      'h' },
+      { "usage",       0,                      0,      'u' },
+      { "version",     0,                      0,      'v' },
+      { "display",     OPTF_ARGREQ,            0,      'd' },
+      { "relative",    0,                      0,      'r' },
+      {        0,              0,                      0,      0 }
+    };
+
+    i = mdwopt(argc, argv, "huvd:r", opt, 0, 0, 0); if (i < 0) break;
+    switch (i) {
+      case 'h': help(); exit(0);
+      case 'u': usage(stdout); exit(0);
+      case 'v': version(); exit(0);
+      case 'd': display = optarg; break;
+      case 'r': f |= f_relative; break;
+      default: f |= f_bogus; break;
+    }
+  }
+  if ((f&f_bogus) || argc - optind != 2) {
+    usage(stderr);
+    exit(EXIT_FAILURE);
+  }
+
+  /* Undo the fixups and fish out the numbers. */
+  for (i = 0; i < nfixups; i++) *fixups[i] = '-';
+  x = parse_int(argv[optind]);
+  y = parse_int(argv[optind + 1]);
+
+  /* Open the display and the screen size. */
+  if ((dpy = XOpenDisplay(display)) == 0)
+    die(EXIT_FAILURE, "couldn't open display");
+  sc = DefaultScreen(dpy);
+  wd = DisplayWidth(dpy, sc);
+  ht = DisplayHeight(dpy, sc);
+
+  /* Interpret the coordinates and check that they're in range. */
+  if (f&f_relative) {
+    w = None;
+    xmin = -wd + 1; ymin = -ht + 1; xmax = wd - 1; ymax = ht - 1;
+  } else {
+    if (x < 0) x += wd;
+    if (y < 0) y += ht;
+    w = RootWindow(dpy, sc);
+    xmin = ymin = 0; xmax = wd - 1; ymax = ht - 1;
+  }
+  if (x < xmin || x > xmax || y < ymin || y > ymax)
+    die(1, "coordinates out of range");
+
+  /* Do the work. */
+  XWarpPointer(dpy, None, w, 0, 0, 0, 0, x, y);
+
+  /* Done. */
+  XCloseDisplay(dpy);
+  return (0);
+
+#undef f_bogus
+#undef f_relative
+}
+
+/*----- That's all, folks -------------------------------------------------*/