11a30de1fSmrg/*
21a30de1fSmrg
31a30de1fSmrgCopyright 1988, 1998  The Open Group
41a30de1fSmrg
51a30de1fSmrgPermission to use, copy, modify, distribute, and sell this software and its
61a30de1fSmrgdocumentation for any purpose is hereby granted without fee, provided that
71a30de1fSmrgthe above copyright notice appear in all copies and that both that
81a30de1fSmrgcopyright notice and this permission notice appear in supporting
91a30de1fSmrgdocumentation.
101a30de1fSmrg
111a30de1fSmrgThe above copyright notice and this permission notice shall be included
121a30de1fSmrgin all copies or substantial portions of the Software.
131a30de1fSmrg
141a30de1fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151a30de1fSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161a30de1fSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
171a30de1fSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
181a30de1fSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
191a30de1fSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
201a30de1fSmrgOTHER DEALINGS IN THE SOFTWARE.
211a30de1fSmrg
221a30de1fSmrgExcept as contained in this notice, the name of The Open Group shall
231a30de1fSmrgnot be used in advertising or otherwise to promote the sale, use or
241a30de1fSmrgother dealings in this Software without prior written authorization
251a30de1fSmrgfrom The Open Group.
261a30de1fSmrg
271a30de1fSmrg*/
281a30de1fSmrg
291a30de1fSmrg/*
30ce62200cSmrg * Copyright (c) 1987, Oracle and/or its affiliates. All rights reserved.
311a30de1fSmrg *
32ce62200cSmrg * Permission is hereby granted, free of charge, to any person obtaining a
33ce62200cSmrg * copy of this software and associated documentation files (the "Software"),
34ce62200cSmrg * to deal in the Software without restriction, including without limitation
35ce62200cSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
36ce62200cSmrg * and/or sell copies of the Software, and to permit persons to whom the
37ce62200cSmrg * Software is furnished to do so, subject to the following conditions:
381a30de1fSmrg *
39ce62200cSmrg * The above copyright notice and this permission notice (including the next
40ce62200cSmrg * paragraph) shall be included in all copies or substantial portions of the
41ce62200cSmrg * Software.
42ce62200cSmrg *
43ce62200cSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44ce62200cSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45ce62200cSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
46ce62200cSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47ce62200cSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
48ce62200cSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
49ce62200cSmrg * DEALINGS IN THE SOFTWARE.
50ce62200cSmrg */
51ce62200cSmrg
52ce62200cSmrg/*
531a30de1fSmrg * Author:  Jim Fulton, MIT X Consortium; derived from parts of the
541a30de1fSmrg * original xmodmap, written by David Rosenthal, of Sun Microsystems.
551a30de1fSmrg */
56a733a5bfSmrg
57a733a5bfSmrg#ifdef HAVE_CONFIG_H
58a733a5bfSmrg# include "config.h"
59a733a5bfSmrg#endif
60a733a5bfSmrg
61a733a5bfSmrg#ifdef WIN32
62a733a5bfSmrg#include <X11/Xwindows.h>
63a733a5bfSmrg#endif
641a30de1fSmrg
651a30de1fSmrg#include <X11/Xos.h>
661a30de1fSmrg#include <X11/Xlib.h>
671a30de1fSmrg#include <stdio.h>
681a30de1fSmrg#include "xmodmap.h"
691a30de1fSmrg#include "wq.h"
701a30de1fSmrg
711a30de1fSmrgstatic void
721a30de1fSmrgmapping_busy_key(int timeout)
731a30de1fSmrg{
741a30de1fSmrg    int i;
751a30de1fSmrg    unsigned char keymap[32];
761a30de1fSmrg    static unsigned int masktable[8] = {
771a30de1fSmrg	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
781a30de1fSmrg
791a30de1fSmrg    XQueryKeymap (dpy, (char *) keymap);
801a30de1fSmrg
811a30de1fSmrg    fprintf (stderr,
821a30de1fSmrg	     "%s:  please release the following keys within %d seconds:\n",
831a30de1fSmrg	     ProgramName, timeout);
841a30de1fSmrg    for (i = 0; i < 256; i++) {
851a30de1fSmrg	if (keymap[i >> 3] & masktable[i & 7]) {
861a30de1fSmrg	    KeySym ks = XKeycodeToKeysym (dpy, (KeyCode) i, 0);
871a30de1fSmrg	    char *cp = XKeysymToString (ks);
881a30de1fSmrg	    fprintf (stderr, "    %s (keysym 0x%x, keycode %d)\n",
891a30de1fSmrg		     cp ? cp : "UNNAMED", (unsigned int)ks, i);
901a30de1fSmrg	}
911a30de1fSmrg    }
921a30de1fSmrg    sleep (timeout);
931a30de1fSmrg    return;
941a30de1fSmrg}
951a30de1fSmrg
961a30de1fSmrgstatic void
971a30de1fSmrgmapping_busy_pointer(int timeout)
981a30de1fSmrg{
991a30de1fSmrg    int i;
1001a30de1fSmrg    Window root, child;			/* dummy variables */
1011a30de1fSmrg    int rx, ry, wx, wy;			/* dummy variables */
1021a30de1fSmrg    unsigned int mask;
1031a30de1fSmrg    static unsigned int masks[5] = {
1041a30de1fSmrg	Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask };
1051a30de1fSmrg
1061a30de1fSmrg    if (!XQueryPointer (dpy, RootWindow(dpy,DefaultScreen(dpy)),
1071a30de1fSmrg			&root, &child, &rx, &ry, &wx, &wy, &mask))
1081a30de1fSmrg      mask = 0;
1091a30de1fSmrg
1101a30de1fSmrg    fprintf (stderr,
1111a30de1fSmrg	     "%s:  please release the following buttons within %d seconds:\n",
1121a30de1fSmrg	     ProgramName, timeout);
1131a30de1fSmrg    for (i = 0; i < 5; i++) {
1141a30de1fSmrg	if (mask & masks[i])
1151a30de1fSmrg	  fprintf (stderr, "    Button%d\n", i+1);
1161a30de1fSmrg    }
1171a30de1fSmrg    sleep (timeout);
1181a30de1fSmrg    return;
1191a30de1fSmrg}
1201a30de1fSmrg
1211a30de1fSmrg
1221a30de1fSmrg/*
1231a30de1fSmrg * UpdateModifierMapping - this sends the modifier map to the server
1241a30de1fSmrg * and deals with retransmissions due to the keyboard being busy.
1251a30de1fSmrg */
1261a30de1fSmrg
1271a30de1fSmrgint
1281a30de1fSmrgUpdateModifierMapping(XModifierKeymap *map)
1291a30de1fSmrg{
1301a30de1fSmrg    int retries, timeout;
1311a30de1fSmrg
1321a30de1fSmrg    for (retries = 5, timeout = 2; retries > 0; retries--, timeout *= 2) {
1331a30de1fSmrg	int result;
1341a30de1fSmrg
1351a30de1fSmrg	result = XSetModifierMapping (dpy, map);
1361a30de1fSmrg	switch (result) {
1371a30de1fSmrg	  case MappingSuccess:	/* Success */
1381a30de1fSmrg	    return (0);
1391a30de1fSmrg	  case MappingBusy:		/* Busy */
1401a30de1fSmrg	    mapping_busy_key (timeout);
1411a30de1fSmrg	    continue;
1421a30de1fSmrg	  case MappingFailed:
1431a30de1fSmrg	    fprintf (stderr, "%s: bad set modifier mapping.\n",
1441a30de1fSmrg		     ProgramName);
1451a30de1fSmrg	    return (-1);
1461a30de1fSmrg	  default:
1471a30de1fSmrg	    fprintf (stderr, "%s:  bad return %d from XSetModifierMapping\n",
1481a30de1fSmrg		     ProgramName, result);
1491a30de1fSmrg	    return (-1);
1501a30de1fSmrg	}
1511a30de1fSmrg    }
1521a30de1fSmrg    fprintf (stderr,
1531a30de1fSmrg	     "%s:  unable to set modifier mapping, keyboard problem\n",
1541a30de1fSmrg	     ProgramName);
1551a30de1fSmrg    return (-1);
1561a30de1fSmrg}
1571a30de1fSmrg
1581a30de1fSmrg
1591a30de1fSmrg/*
1601a30de1fSmrg * AddModifier - this adds a keycode to the modifier list
1611a30de1fSmrg */
1621a30de1fSmrg
1631a30de1fSmrgint
1641a30de1fSmrgAddModifier(XModifierKeymap **mapp, KeyCode keycode, int modifier)
1651a30de1fSmrg{
1661a30de1fSmrg    if (keycode) {
1671a30de1fSmrg	*mapp = XInsertModifiermapEntry (*mapp, keycode, modifier);
1681a30de1fSmrg	return (0);
1691a30de1fSmrg    } else {
1701a30de1fSmrg	return (-1);
1711a30de1fSmrg    }
1721a30de1fSmrg    /*NOTREACHED*/
1731a30de1fSmrg}
1741a30de1fSmrg
1751a30de1fSmrg
1761a30de1fSmrg/*
1771a30de1fSmrg * DeleteModifier - this removes a keycode from the modifier list
1781a30de1fSmrg */
1791a30de1fSmrg
1801a30de1fSmrgint
1811a30de1fSmrgRemoveModifier(XModifierKeymap **mapp, KeyCode keycode, int modifier)
1821a30de1fSmrg{
1831a30de1fSmrg    if (keycode) {
1841a30de1fSmrg	*mapp = XDeleteModifiermapEntry (*mapp, keycode, modifier);
1851a30de1fSmrg	return (0);
1861a30de1fSmrg    } else {
1871a30de1fSmrg	return (-1);
1881a30de1fSmrg    }
1891a30de1fSmrg    /*NOTREACHED*/
1901a30de1fSmrg}
1911a30de1fSmrg
1921a30de1fSmrg
1931a30de1fSmrg/*
1941a30de1fSmrg * ClearModifier - this removes all entries from the modifier list
1951a30de1fSmrg */
1961a30de1fSmrg
1971a30de1fSmrgint
1981a30de1fSmrgClearModifier(XModifierKeymap **mapp, int modifier)
1991a30de1fSmrg{
2001a30de1fSmrg    int i;
2011a30de1fSmrg    XModifierKeymap *map = *mapp;
2021a30de1fSmrg    KeyCode *kcp;
2031a30de1fSmrg
2041a30de1fSmrg    kcp = &map->modifiermap[modifier * map->max_keypermod];
2051a30de1fSmrg    for (i = 0; i < map->max_keypermod; i++) {
2061a30de1fSmrg	*kcp++ = (KeyCode) 0;
2071a30de1fSmrg    }
2081a30de1fSmrg    return (0);
2091a30de1fSmrg}
2101a30de1fSmrg
2116eaa481cSmrgstatic int
2126eaa481cSmrgGetKeysymsPerKeycode(void)
2136eaa481cSmrg{
2146eaa481cSmrg    int min_keycode, max_keycode, keysyms_per_keycode = 0;
2156eaa481cSmrg    KeySym *m;
2166eaa481cSmrg
2176eaa481cSmrg    XDisplayKeycodes(dpy, &min_keycode, &max_keycode);
2186eaa481cSmrg    m = XGetKeyboardMapping(dpy, min_keycode, (max_keycode - min_keycode + 1),
2196eaa481cSmrg                            &keysyms_per_keycode);
2206eaa481cSmrg    XFree(m);
2216eaa481cSmrg    return keysyms_per_keycode;
2226eaa481cSmrg}
2231a30de1fSmrg
2241a30de1fSmrg/*
2251a30de1fSmrg * print the contents of the map
2261a30de1fSmrg */
2271a30de1fSmrgvoid
2281a30de1fSmrgPrintModifierMapping(XModifierKeymap *map, FILE *fp)
2291a30de1fSmrg{
2306eaa481cSmrg    int k = 0;
2316eaa481cSmrg    int keysyms_per_keycode = GetKeysymsPerKeycode();
2321a30de1fSmrg
2331a30de1fSmrg    fprintf (fp,
2341a30de1fSmrg    	     "%s:  up to %d keys per modifier, (keycodes in parentheses):\n\n",
2351a30de1fSmrg    	     ProgramName, map->max_keypermod);
2366eaa481cSmrg    for (int i = 0; i < 8; i++) {
2371a30de1fSmrg	fprintf(fp, "%-10s", modifier_table[i].name);
2386eaa481cSmrg
2396eaa481cSmrg	for (int j = 0; j < map->max_keypermod; j++) {
2401a30de1fSmrg	    if (map->modifiermap[k]) {
2411a30de1fSmrg		KeySym ks;
2421a30de1fSmrg		int index = 0;
2431a30de1fSmrg		char *nm;
2441a30de1fSmrg		do {
2451a30de1fSmrg		    ks = XKeycodeToKeysym(dpy, map->modifiermap[k], index);
2461a30de1fSmrg		    index++;
2471a30de1fSmrg		} while ( !ks && index < keysyms_per_keycode);
2481a30de1fSmrg		nm = XKeysymToString(ks);
2491a30de1fSmrg
2501a30de1fSmrg		fprintf (fp, "%s  %s (0x%0x)", (j > 0 ? "," : ""),
2511a30de1fSmrg			 (nm ? nm : "BadKey"), map->modifiermap[k]);
2521a30de1fSmrg	    }
2531a30de1fSmrg	    k++;
2541a30de1fSmrg	}
2551a30de1fSmrg	fprintf(fp, "\n");
2561a30de1fSmrg    }
2571a30de1fSmrg    fprintf (fp, "\n");
2581a30de1fSmrg    return;
2591a30de1fSmrg}
2601a30de1fSmrg
2611a30de1fSmrgvoid
2621a30de1fSmrgPrintKeyTable(Bool exprs, FILE *fp)
2631a30de1fSmrg{
2641a30de1fSmrg    int         i;
2651a30de1fSmrg    int min_keycode, max_keycode, keysyms_per_keycode;
2661a30de1fSmrg    KeySym *keymap, *origkeymap;
2671a30de1fSmrg
2681a30de1fSmrg    XDisplayKeycodes (dpy, &min_keycode, &max_keycode);
2691a30de1fSmrg    origkeymap = XGetKeyboardMapping (dpy, min_keycode,
2701a30de1fSmrg				      (max_keycode - min_keycode + 1),
2711a30de1fSmrg				      &keysyms_per_keycode);
2721a30de1fSmrg
2731a30de1fSmrg    if (!origkeymap) {
2741a30de1fSmrg	fprintf (stderr, "%s:  unable to get keyboard mapping table.\n",
2751a30de1fSmrg		 ProgramName);
2761a30de1fSmrg	return;
2771a30de1fSmrg    }
2781a30de1fSmrg    if (!exprs) {
2791a30de1fSmrg	fprintf (fp,
2801a30de1fSmrg		 "There are %d KeySyms per KeyCode; KeyCodes range from %d to %d.\n\n",
2811a30de1fSmrg		 keysyms_per_keycode, min_keycode, max_keycode);
2821a30de1fSmrg	fprintf (fp, "    KeyCode\tKeysym (Keysym)\t...\n");
2831a30de1fSmrg	fprintf (fp, "    Value  \tValue   (Name) \t...\n\n");
2841a30de1fSmrg    }
2851a30de1fSmrg    keymap = origkeymap;
2861a30de1fSmrg    for (i = min_keycode; i <= max_keycode; i++) {
2871a30de1fSmrg	int  j, max;
2881a30de1fSmrg
2891a30de1fSmrg	if (exprs)
2901a30de1fSmrg	    fprintf(fp, "keycode %3d =", i);
2911a30de1fSmrg	else
2921a30de1fSmrg	    fprintf(fp, "    %3d    \t", i);
2931a30de1fSmrg	max = keysyms_per_keycode - 1;
2941a30de1fSmrg	while ((max >= 0) && (keymap[max] == NoSymbol))
2951a30de1fSmrg	    max--;
2961a30de1fSmrg	for (j = 0; j <= max; j++) {
2971a30de1fSmrg	    register KeySym ks = keymap[j];
298a733a5bfSmrg	    const char *s;
2991a30de1fSmrg	    if (ks != NoSymbol)
3001a30de1fSmrg		s = XKeysymToString (ks);
3011a30de1fSmrg	    else
3021a30de1fSmrg		s = "NoSymbol";
3031a30de1fSmrg	    if (!exprs)
3041a30de1fSmrg		fprintf (fp, "0x%04x (%s)\t",
3051a30de1fSmrg			 (unsigned int)ks, s ? s : "no name");
3061a30de1fSmrg	    else if (s)
3071a30de1fSmrg		fprintf (fp, " %s", s);
3081a30de1fSmrg	    else
3091a30de1fSmrg		fprintf (fp, " 0x%04x", (unsigned int)ks);
3101a30de1fSmrg	}
3111a30de1fSmrg	keymap += keysyms_per_keycode;
3121a30de1fSmrg	fprintf (fp, "\n");
3131a30de1fSmrg    }
3141a30de1fSmrg
3151a30de1fSmrg    XFree ((char *) origkeymap);
3161a30de1fSmrg    return;
3171a30de1fSmrg}
3181a30de1fSmrg
3191a30de1fSmrgvoid
3201a30de1fSmrgPrintPointerMap(FILE *fp)
3211a30de1fSmrg{
3221a30de1fSmrg    unsigned char pmap[256];		/* there are 8 bits of buttons */
3231a30de1fSmrg    int count, i;
3241a30de1fSmrg
3251a30de1fSmrg    count = XGetPointerMapping (dpy, pmap, 256);
3261a30de1fSmrg
3271a30de1fSmrg    fprintf (fp, "There are %d pointer buttons defined.\n\n", count);
3281a30de1fSmrg    fprintf (fp, "    Physical        Button\n");
3291a30de1fSmrg    fprintf (fp, "     Button          Code\n");
3301a30de1fSmrg/*               "      ###            ###\n"               */
3311a30de1fSmrg    for (i = 0; i < count; i++) {
3321a30de1fSmrg	fprintf (fp, "      %3u            %3u\n",
3331a30de1fSmrg		 i+1, (unsigned int) pmap[i]);
3341a30de1fSmrg    }
3351a30de1fSmrg    fprintf (fp, "\n");
3361a30de1fSmrg    return;
3371a30de1fSmrg}
3381a30de1fSmrg
3391a30de1fSmrg
3401a30de1fSmrg/*
3411a30de1fSmrg * SetPointerMap - set the pointer map
3421a30de1fSmrg */
3431a30de1fSmrg
3441a30de1fSmrgint
3451a30de1fSmrgSetPointerMap(unsigned char *map, int n)
3461a30de1fSmrg{
3471a30de1fSmrg    unsigned char defmap[MAXBUTTONCODES];
3481a30de1fSmrg    int j;
3491a30de1fSmrg    int retries, timeout;
3501a30de1fSmrg
3511a30de1fSmrg    if (n == 0) {				/* reset to default */
3521a30de1fSmrg	n = XGetPointerMapping (dpy, defmap, MAXBUTTONCODES);
3531a30de1fSmrg	for (j = 0; j < n; j++) defmap[j] = (unsigned char) (j + 1);
3541a30de1fSmrg	map = defmap;
3551a30de1fSmrg    }
3561a30de1fSmrg
3571a30de1fSmrg    for (retries = 5, timeout = 2; retries > 0; retries--, timeout *= 2) {
3581a30de1fSmrg	int result;
3591a30de1fSmrg
3601a30de1fSmrg	switch (result = XSetPointerMapping (dpy, map, n)) {
3611a30de1fSmrg	  case MappingSuccess:
3621a30de1fSmrg	    return 0;
3631a30de1fSmrg	  case MappingBusy:
3641a30de1fSmrg	    mapping_busy_pointer (timeout);
3651a30de1fSmrg	    continue;
3661a30de1fSmrg	  case MappingFailed:
3671a30de1fSmrg	    fprintf (stderr, "%s:  bad pointer mapping\n", ProgramName);
3681a30de1fSmrg	    return -1;
3691a30de1fSmrg	  default:
3701a30de1fSmrg	    fprintf (stderr, "%s:  bad return %d from XSetPointerMapping\n",
3711a30de1fSmrg		     ProgramName, result);
3721a30de1fSmrg	    return -1;
3731a30de1fSmrg	}
3741a30de1fSmrg    }
3751a30de1fSmrg    fprintf (stderr, "%s:  unable to set pointer mapping\n", ProgramName);
3761a30de1fSmrg    return -1;
3771a30de1fSmrg}
378