blob: 68d25ba1d2f4f029fdf630981eaf0bcad336e407 [file] [log] [blame]
/*
Copyright 1985, 1998 The Open Group
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of The Open Group shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from The Open Group.
*/
/* Modified by Stephen so keyboard rate is set using XKB extensions */
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <X11/Xos.h>
#include <X11/Xfuncs.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/Xmu/Error.h>
#include <X11/XKBlib.h>
#define ON 1
#define OFF 0
#define SERVER_DEFAULT (-1)
#define DONT_CHANGE -2
#define ALL -1
#define XKBDDELAY_DEFAULT 660
#define XKBDRATE_DEFAULT (1000/40)
static char *progName;
static int error_status = 0;
static int is_number(char *arg, int maximum);
static void set_mouse(Display *dpy, int acc_num, int acc_denom, int threshold);
static void set_repeat(Display *dpy, int key, int auto_repeat_mode);
static void usage(char *fmt, ...) _X_NORETURN;
static int local_xerror(Display *dpy, XErrorEvent *rep);
static void xkbset_repeatrate(Display *dpy, int delay, int rate);
int
main(int argc, char *argv[])
{
register char *arg;
register int i;
int acc_num, acc_denom, threshold;
int key, auto_repeat_mode;
char *disp = NULL;
Display *dpy;
int miscpresent = 0;
int xkbpresent = 0;
int xkbmajor = XkbMajorVersion, xkbminor = XkbMinorVersion;
int xkbopcode, xkbevent, xkberror;
progName = argv[0];
if (argc < 2) {
usage(NULL, NULL); /* replace with window interface */
}
dpy = XOpenDisplay(disp); /* Open display and check for success */
if (dpy == NULL) {
fprintf(stderr, "%s: unable to open display \"%s\"\n",
argv[0], XDisplayName(disp));
exit(EXIT_FAILURE);
}
XSetErrorHandler(local_xerror);
for (i = 1; i < argc;) {
arg = argv[i++];
/* Set pointer (mouse) settings: Acceleration and Threshold. */
if (strcmp(arg, "m") == 0 || strcmp(arg, "mouse") == 0) {
acc_num = SERVER_DEFAULT; /* restore server defaults */
acc_denom = SERVER_DEFAULT;
threshold = SERVER_DEFAULT;
if (i >= argc) {
set_mouse(dpy, acc_num, acc_denom, threshold);
break;
}
arg = argv[i];
if (strcmp(arg, "default") == 0) {
i++;
} else if (*arg >= '0' && *arg <= '9') {
acc_denom = 1;
sscanf(arg, "%d/%d", &acc_num, &acc_denom);
i++;
if (i >= argc) {
set_mouse(dpy, acc_num, acc_denom, threshold);
break;
}
arg = argv[i];
if (*arg >= '0' && *arg <= '9') {
threshold = atoi(arg); /* Set threshold as user specified. */
i++;
}
}
set_mouse(dpy, acc_num, acc_denom, threshold);
} else if (strcmp(arg, "-r") == 0) { /* Turn off one or
all autorepeats */
auto_repeat_mode = OFF;
key = ALL; /* None specified */
arg = argv[i];
if (i < argc)
if (is_number(arg, 255)) {
key = atoi(arg);
i++;
}
set_repeat(dpy, key, auto_repeat_mode);
} else if (strcmp(arg, "r") == 0) { /* Turn on one or
all autorepeats */
auto_repeat_mode = ON;
key = ALL; /* None specified */
arg = argv[i];
if (i < argc) {
if (strcmp(arg, "on") == 0) {
i++;
} else if (strcmp(arg, "off") == 0) { /* ...except in
this case */
auto_repeat_mode = OFF;
i++;
}
else if (strcmp(arg, "rate") == 0) { /* ...or this one. */
int delay = 0, rate = 0;
if (XkbQueryExtension(dpy, &xkbopcode, &xkbevent,
&xkberror, &xkbmajor, &xkbminor)) {
delay = XKBDDELAY_DEFAULT;
rate = XKBDRATE_DEFAULT;
xkbpresent = 1;
}
if (!xkbpresent && !miscpresent)
fprintf(stderr,
"server does not have extension for \"r rate\" option\n");
i++;
arg = argv[i];
if (i < argc) {
if (is_number(arg, 10000) && atoi(arg) > 0) {
delay = atoi(arg);
i++;
arg = argv[i];
if (i < argc) {
if (is_number(arg, 255) && atoi(arg) > 0) {
rate = atoi(arg);
i++;
}
}
}
}
if (xkbpresent) {
xkbset_repeatrate(dpy, delay, 1000 / rate);
}
}
else if (is_number(arg, 255)) {
key = atoi(arg);
i++;
}
}
set_repeat(dpy, key, auto_repeat_mode);
} else
usage("unknown option %s", arg);
}
XCloseDisplay(dpy);
exit(error_status); /* Done. We can go home now. */
}
static int
is_number(char *arg, int maximum)
{
register char *p;
if (arg[0] == '-' && arg[1] == '1' && arg[2] == '\0')
return (1);
for (p = arg; isdigit(*p); p++) ;
if (*p || atoi(arg) > maximum)
return (0);
return (1);
}
static void
set_mouse(Display *dpy, int acc_num, int acc_denom, int threshold)
{
int do_accel = True, do_threshold = True;
if (acc_num == DONT_CHANGE) /* what an incredible crock... */
do_accel = False;
if (threshold == DONT_CHANGE)
do_threshold = False;
if (acc_num < 0) /* shouldn't happen */
acc_num = SERVER_DEFAULT;
if (acc_denom <= 0) /* prevent divide by zero */
acc_denom = SERVER_DEFAULT;
if (threshold < 0)
threshold = SERVER_DEFAULT;
XChangePointerControl(dpy, do_accel, do_threshold, acc_num,
acc_denom, threshold);
return;
}
static void
set_repeat(Display *dpy, int key, int auto_repeat_mode)
{
XKeyboardControl values;
values.auto_repeat_mode = auto_repeat_mode;
if (key != ALL) {
values.key = key;
XChangeKeyboardControl(dpy, KBKey | KBAutoRepeatMode, &values);
} else {
XChangeKeyboardControl(dpy, KBAutoRepeatMode, &values);
}
return;
}
static void
xkbset_repeatrate(Display *dpy, int delay, int interval)
{
XkbDescPtr xkb = XkbAllocKeyboard();
if (!xkb)
return;
XkbGetControls(dpy, XkbRepeatKeysMask, xkb);
xkb->ctrls->repeat_delay = delay;
xkb->ctrls->repeat_interval = interval;
XkbSetControls(dpy, XkbRepeatKeysMask, xkb);
XkbFreeKeyboard(xkb, 0, True);
}
/* This is the usage function */
static void
usage(char *fmt, ...)
{
va_list ap;
if (fmt) {
fprintf(stderr, "%s: ", progName);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n\n");
}
fprintf(stderr, "usage: %s option ...\n", progName);
fprintf(stderr, " To set mouse acceleration and threshold:\n");
fprintf(stderr, "\t m [acc_mult[/acc_div] [thr]] m default\n");
fprintf(stderr, " To set pixel colors:\n");
fprintf(stderr, "\t-r [keycode] r off\n");
fprintf(stderr, "\t r [keycode] r on\n");
fprintf(stderr, "\t r rate [delay [rate]]\n");
exit(EXIT_SUCCESS);
}
static int
local_xerror(Display *dpy, XErrorEvent *rep)
{
if (rep->request_code == X_SetFontPath && rep->error_code == BadValue) {
fprintf(stderr,
"%s: bad font path element (#%ld), possible causes are:\n",
progName, rep->resourceid);
fprintf(stderr,
" Directory does not exist or has wrong permissions\n");
fprintf(stderr, " Directory missing fonts.dir\n");
fprintf(stderr, " Incorrect font server address or syntax\n");
} else if (rep->request_code == X_StoreColors) {
switch (rep->error_code) {
case BadAccess:
fprintf(stderr,
"%s: pixel not allocated read/write\n", progName);
break;
case BadValue:
fprintf(stderr,
"%s: cannot store in pixel 0x%lx, invalid pixel number\n",
progName, rep->resourceid);
break;
default:
XmuPrintDefaultErrorMessage(dpy, rep, stderr);
}
} else
XmuPrintDefaultErrorMessage(dpy, rep, stderr);
error_status = -1;
return (0);
}