From: Mark Wooding Date: Sun, 24 Apr 2022 11:19:36 +0000 (+0100) Subject: Add new program `xwarpptr'. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/xtoys/commitdiff_plain/7f25aae9e167bb416be95d25ea916b64a16f8a23 Add new program `xwarpptr'. --- diff --git a/Makefile.am b/Makefile.am index 825e8fd..dcba780 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/debian/control b/debian/control index 743330a..3d3e2e6 100644 --- a/debian/control +++ b/debian/control @@ -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 diff --git a/debian/xtoys.install b/debian/xtoys.install index 445435a..600a2f4 100644 --- a/debian/xtoys.install +++ b/debian/xtoys.install @@ -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 index 0000000..3c35a9c --- /dev/null +++ b/xwarpptr.1 @@ -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 index 0000000..92cd5c6 --- /dev/null +++ b/xwarpptr.c @@ -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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/*----- 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 -------------------------------------------------*/