xmodmap.c revision a733a5bf
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*/ 28a733a5bfSmrg 29a733a5bfSmrg#ifdef HAVE_CONFIG_H 30a733a5bfSmrg# include "config.h" 31a733a5bfSmrg#endif 321a30de1fSmrg 331a30de1fSmrg#include <X11/Xos.h> 341a30de1fSmrg#include <X11/Xlib.h> 351a30de1fSmrg#include <stdio.h> 361a30de1fSmrg#include <stdlib.h> 371a30de1fSmrg#include <ctype.h> 38a733a5bfSmrg#include <stdarg.h> 391a30de1fSmrg#include "xmodmap.h" 401a30de1fSmrg 411a30de1fSmrgconst char *ProgramName; 421a30de1fSmrgDisplay *dpy = NULL; 431a30de1fSmrgint min_keycode, max_keycode; 441a30de1fSmrgBool verbose = False; 451a30de1fSmrgBool dontExecute = False; 461a30de1fSmrg 47a733a5bfSmrgvoid 48a733a5bfSmrg_X_NORETURN 491a30de1fSmrgExit(int status) 501a30de1fSmrg{ 511a30de1fSmrg if (dpy) { 521a30de1fSmrg XCloseDisplay (dpy); 531a30de1fSmrg dpy = NULL; 541a30de1fSmrg } 551a30de1fSmrg exit (status); 561a30de1fSmrg} 571a30de1fSmrg 58a733a5bfSmrgstatic void _X_NORETURN 59a733a5bfSmrgFatalError(const char *message) 60a733a5bfSmrg{ 61a733a5bfSmrg fprintf(stderr, "%s: %s\n", ProgramName, message); 62a733a5bfSmrg Exit(-1); 63a733a5bfSmrg} 64a733a5bfSmrg 65a733a5bfSmrg#ifndef HAVE_ASPRINTF 66a733a5bfSmrg/* sprintf variant found in newer libc's which allocates string to print to */ 67a733a5bfSmrgstatic int _X_ATTRIBUTE_PRINTF(2,3) 68a733a5bfSmrgasprintf(char ** ret, const char *format, ...) 691a30de1fSmrg{ 70a733a5bfSmrg char buf[256]; 71a733a5bfSmrg int len; 72a733a5bfSmrg va_list ap; 73a733a5bfSmrg 74a733a5bfSmrg va_start(ap, format); 75a733a5bfSmrg len = vsnprintf(buf, sizeof(buf), format, ap); 76a733a5bfSmrg va_end(ap); 77a733a5bfSmrg 78a733a5bfSmrg if (len < 0) 79a733a5bfSmrg return -1; 80a733a5bfSmrg 81a733a5bfSmrg if (len < sizeof(buf)) 82a733a5bfSmrg { 83a733a5bfSmrg *ret = strdup(buf); 841a30de1fSmrg } 85a733a5bfSmrg else 86a733a5bfSmrg { 87a733a5bfSmrg *ret = malloc(len + 1); /* snprintf doesn't count trailing '\0' */ 88a733a5bfSmrg if (*ret != NULL) 89a733a5bfSmrg { 90a733a5bfSmrg va_start(ap, format); 91a733a5bfSmrg len = vsnprintf(*ret, len + 1, format, ap); 92a733a5bfSmrg va_end(ap); 93a733a5bfSmrg if (len < 0) { 94a733a5bfSmrg free(*ret); 95a733a5bfSmrg *ret = NULL; 96a733a5bfSmrg } 97a733a5bfSmrg } 98a733a5bfSmrg } 99a733a5bfSmrg 100a733a5bfSmrg if (*ret == NULL) 101a733a5bfSmrg return -1; 102a733a5bfSmrg 103a733a5bfSmrg return len; 1041a30de1fSmrg} 105a733a5bfSmrg#endif /* HAVE_ASPRINTF */ 1061a30de1fSmrg 1071a30de1fSmrgstatic const char help_message[] = 1081a30de1fSmrg"\nwhere options include:\n" 1091a30de1fSmrg" -display host:dpy X server to use\n" 1101a30de1fSmrg" -verbose, -quiet turn logging on or off\n" 1111a30de1fSmrg" -n don't execute changes, just show like make\n" 1121a30de1fSmrg" -e expression execute string\n" 1131a30de1fSmrg" -pm print modifier map\n" 1141a30de1fSmrg" -pk print keymap table\n" 1151a30de1fSmrg" -pke print keymap table as expressions\n" 1161a30de1fSmrg" -pp print pointer map\n" 117a733a5bfSmrg" -help print this usage message\n" 1181a30de1fSmrg" -grammar print out short help on allowable input\n" 1191a30de1fSmrg" - read standard input\n" 1201a30de1fSmrg"\n"; 1211a30de1fSmrg 1221a30de1fSmrg 1231a30de1fSmrgstatic void 124a733a5bfSmrg_X_NORETURN 125a733a5bfSmrgusage(int exitcode) 1261a30de1fSmrg{ 1271a30de1fSmrg fprintf (stderr, "usage: %s [-options ...] [filename]\n", ProgramName); 1281a30de1fSmrg fprintf (stderr, "%s\n", help_message); 129a733a5bfSmrg Exit (exitcode); 1301a30de1fSmrg} 1311a30de1fSmrg 1321a30de1fSmrgstatic const char grammar_message[] = 1331a30de1fSmrg" pointer = default reset pointer buttons to default\n" 1341a30de1fSmrg" pointer = NUMBER ... set pointer button codes\n" 1351a30de1fSmrg" keycode NUMBER = [KEYSYM ...] map keycode to given keysyms\n" 1361a30de1fSmrg" keysym KEYSYM = [KEYSYM ...] look up keysym and do a keycode operation\n" 1371a30de1fSmrg" clear MODIFIER remove all keys for this modifier\n" 1381a30de1fSmrg" add MODIFIER = KEYSYM ... add the keysyms to the modifier\n" 1391a30de1fSmrg" remove MODIFIER = KEYSYM ... remove the keysyms from the modifier\n" 1401a30de1fSmrg"\n" 1411a30de1fSmrg"where NUMBER is a decimal, octal, or hex constant; KEYSYM is a valid\n" 1421a30de1fSmrg"Key Symbol name; and MODIFIER is one of the eight modifier names: Shift,\n" 1431a30de1fSmrg"Lock, Control, Mod1, Mod2, Mod3, Mod4, or Mod5. Lines beginning with\n" 1441a30de1fSmrg"an exclamation mark (!) are taken as comments. Case is significant except\n" 1451a30de1fSmrg"for MODIFIER names.\n" 1461a30de1fSmrg"\n" 1471a30de1fSmrg"Keysyms on the left hand side of the = sign are looked up before any changes\n" 1481a30de1fSmrg"are made; keysyms on the right are looked up after all of those on the left\n" 1491a30de1fSmrg"have been resolved. This makes it possible to swap modifier keys.\n" 1501a30de1fSmrg"\n"; 1511a30de1fSmrg 1521a30de1fSmrg 1531a30de1fSmrgstatic void 154a733a5bfSmrg_X_NORETURN 1551a30de1fSmrggrammar_usage(void) 1561a30de1fSmrg{ 1571a30de1fSmrg fprintf (stderr, "%s accepts the following input expressions:\n\n", 1581a30de1fSmrg ProgramName); 1591a30de1fSmrg fprintf (stderr, "%s\n", grammar_message); 1601a30de1fSmrg Exit (0); 1611a30de1fSmrg} 1621a30de1fSmrg 1631a30de1fSmrgint parse_errors = 0; 1641a30de1fSmrg 1651a30de1fSmrgint 1661a30de1fSmrgmain(int argc, char *argv[]) 1671a30de1fSmrg{ 1681a30de1fSmrg int i; 1691a30de1fSmrg char *displayname = NULL; 1701a30de1fSmrg int status; 1711a30de1fSmrg Bool printMap = False; 1721a30de1fSmrg Bool printKeyTable = False; 1731a30de1fSmrg Bool printKeyTableExprs = False; 1741a30de1fSmrg Bool printPointerMap = False; 1751a30de1fSmrg Bool didAnything = False; 1761a30de1fSmrg 1771a30de1fSmrg ProgramName = argv[0]; 1781a30de1fSmrg 1791a30de1fSmrg /* 1801a30de1fSmrg * scan the arg list once to find out which display to use 1811a30de1fSmrg */ 1821a30de1fSmrg 1831a30de1fSmrg for (i = 1; i < argc; i++) { 184a733a5bfSmrg const char *arg = argv[i]; 185a733a5bfSmrg 186a733a5bfSmrg if (arg[0] == '-') { 187a733a5bfSmrg switch (arg[1]) { 188a733a5bfSmrg case 'd': /* -display host:dpy */ 189a733a5bfSmrg if (++i >= argc) usage (1); 190a733a5bfSmrg displayname = argv[i]; 191a733a5bfSmrg break; 192a733a5bfSmrg case 'g': /* -grammar */ 193a733a5bfSmrg grammar_usage (); 194a733a5bfSmrg /*NOTREACHED*/ 195a733a5bfSmrg case 'h': /* -help */ 196a733a5bfSmrg case '?': 197a733a5bfSmrg usage(0); 198a733a5bfSmrg } 1991a30de1fSmrg } 2001a30de1fSmrg } 2011a30de1fSmrg 2021a30de1fSmrg dpy = XOpenDisplay (displayname); 2031a30de1fSmrg if (!dpy) { 2041a30de1fSmrg fprintf (stderr, "%s: unable to open display '%s'\n", 2051a30de1fSmrg ProgramName, XDisplayName (displayname)); 2061a30de1fSmrg Exit (1); 2071a30de1fSmrg } 2081a30de1fSmrg 2091a30de1fSmrg XDisplayKeycodes (dpy, &min_keycode, &max_keycode); 2101a30de1fSmrg 2111a30de1fSmrg initialize_map (); 2121a30de1fSmrg 2131a30de1fSmrg /* 2141a30de1fSmrg * scan the arg list again to do the actual work (since it requires 2151a30de1fSmrg * the display being open. 2161a30de1fSmrg */ 2171a30de1fSmrg 2181a30de1fSmrg for (i = 1; i < argc; i++) { 2191a30de1fSmrg char *arg = argv[i]; 2201a30de1fSmrg 2211a30de1fSmrg if (arg[0] == '-') { 2221a30de1fSmrg switch (arg[1]) { 2231a30de1fSmrg case 'd': /* -display host:dpy */ 2241a30de1fSmrg ++i; /* handled above */ 2251a30de1fSmrg continue; 2261a30de1fSmrg case 'v': /* -verbose */ 2271a30de1fSmrg verbose = True; 2281a30de1fSmrg continue; 2291a30de1fSmrg case 'q': /* -quiet */ 2301a30de1fSmrg verbose = False; 2311a30de1fSmrg continue; 2321a30de1fSmrg case 'n': /* -n (like make) */ 2331a30de1fSmrg dontExecute = True; 2341a30de1fSmrg continue; 2351a30de1fSmrg case 'e': /* -e expression */ 2361a30de1fSmrg didAnything = True; 237a733a5bfSmrg if (++i >= argc) usage (1); 2381a30de1fSmrg process_line (argv[i]); 2391a30de1fSmrg continue; 2401a30de1fSmrg case 'p': /* -p... */ 2411a30de1fSmrg switch (arg[2]) { 2421a30de1fSmrg case '\0': 2431a30de1fSmrg case 'm': /* -pm */ 2441a30de1fSmrg printMap = True; 2451a30de1fSmrg break; 2461a30de1fSmrg case 'k': /* -pk, -pke */ 2471a30de1fSmrg switch (arg[3]) { 2481a30de1fSmrg case '\0': 2491a30de1fSmrg printKeyTable = True; 2501a30de1fSmrg break; 2511a30de1fSmrg case 'e': 2521a30de1fSmrg printKeyTableExprs = True; 2531a30de1fSmrg break; 2541a30de1fSmrg default: 255a733a5bfSmrg usage (1); 2561a30de1fSmrg } 2571a30de1fSmrg break; 2581a30de1fSmrg case 'p': /* -pp */ 2591a30de1fSmrg printPointerMap = True; 2601a30de1fSmrg break; 2611a30de1fSmrg default: 262a733a5bfSmrg usage (1); 2631a30de1fSmrg /* NOTREACHED */ 2641a30de1fSmrg } 2651a30de1fSmrg didAnything = True; 2661a30de1fSmrg continue; 2671a30de1fSmrg case 'g': /* -grammar */ 2681a30de1fSmrg grammar_usage (); 2691a30de1fSmrg /*NOTREACHED*/ 2701a30de1fSmrg case '\0': /* - (use standard input) */ 2711a30de1fSmrg didAnything = True; 2721a30de1fSmrg process_file (NULL); 2731a30de1fSmrg continue; 2741a30de1fSmrg 2751a30de1fSmrg /* 2761a30de1fSmrg * provide old xmodmap args 2771a30de1fSmrg */ 2781a30de1fSmrg case 'S': 2791a30de1fSmrg didAnything = True; 2801a30de1fSmrg process_line ("clear shift"); 2811a30de1fSmrg continue; 2821a30de1fSmrg case 'L': 2831a30de1fSmrg didAnything = True; 2841a30de1fSmrg process_line ("clear lock"); 2851a30de1fSmrg continue; 2861a30de1fSmrg case 'C': 2871a30de1fSmrg didAnything = True; 2881a30de1fSmrg process_line ("clear control"); 2891a30de1fSmrg continue; 2901a30de1fSmrg case '1': 2911a30de1fSmrg case '2': 2921a30de1fSmrg case '3': 2931a30de1fSmrg case '4': 2941a30de1fSmrg case '5': { 2951a30de1fSmrg char cmd[11] = "clear modX"; 2961a30de1fSmrg cmd[9] = arg[1]; 2971a30de1fSmrg process_line (cmd); 2981a30de1fSmrg continue; 2991a30de1fSmrg } 3001a30de1fSmrg case 's': 3011a30de1fSmrg case 'l': 3021a30de1fSmrg case 'c': { 3031a30de1fSmrg char *cmd; 3041a30de1fSmrg didAnything = True; 305a733a5bfSmrg if (++i >= argc) usage (1); 306a733a5bfSmrg if (asprintf (&cmd, "remove %s = %s", 3071a30de1fSmrg ((arg[1] == 's') ? "shift" : 3081a30de1fSmrg ((arg[1] == 'l') ? "lock" : 309a733a5bfSmrg "control")), argv[i]) == -1) 310a733a5bfSmrg FatalError("Could not allocate memory for remove cmd"); 3111a30de1fSmrg process_line (cmd); 3121a30de1fSmrg continue; 3131a30de1fSmrg } 3141a30de1fSmrg default: 315a733a5bfSmrg usage (1); 3161a30de1fSmrg /*NOTREACHED*/ 3171a30de1fSmrg } 3181a30de1fSmrg } else if (arg[0] == '+') { /* old xmodmap args */ 3191a30de1fSmrg switch (arg[1]) { 3201a30de1fSmrg case '1': 3211a30de1fSmrg case '2': 3221a30de1fSmrg case '3': 3231a30de1fSmrg case '4': 3241a30de1fSmrg case '5': { 3251a30de1fSmrg char *cmd; 3261a30de1fSmrg didAnything = True; 327a733a5bfSmrg if (++i >= argc) usage (1); 328a733a5bfSmrg if (asprintf (&cmd, "add mod%c = %s", arg[1], argv[i]) == -1) 329a733a5bfSmrg FatalError("Could not allocate memory for add cmd"); 3301a30de1fSmrg process_line (cmd); 3311a30de1fSmrg continue; 3321a30de1fSmrg } 3331a30de1fSmrg case 'S': 3341a30de1fSmrg case 'L': 3351a30de1fSmrg case 'C': 3361a30de1fSmrg arg[1] = tolower (arg[1]); 3371a30de1fSmrg /* fall through to handler below */ 3381a30de1fSmrg case 's': 3391a30de1fSmrg case 'l': 3401a30de1fSmrg case 'c': { 3411a30de1fSmrg char *cmd; 3421a30de1fSmrg didAnything = True; 343a733a5bfSmrg if (++i >= argc) usage (1); 344a733a5bfSmrg if (asprintf (&cmd, "add %s = %s", 3451a30de1fSmrg ((arg[1] == 's') ? "shift" : 3461a30de1fSmrg ((arg[1] == 'l') ? "lock" : 347a733a5bfSmrg "control")), argv[i]) == -1) 348a733a5bfSmrg FatalError("Could not allocate memory for remove cmd"); 3491a30de1fSmrg process_line (cmd); 3501a30de1fSmrg continue; 3511a30de1fSmrg } 3521a30de1fSmrg default: 353a733a5bfSmrg usage (1); 3541a30de1fSmrg } 3551a30de1fSmrg } else { 3561a30de1fSmrg didAnything = True; 3571a30de1fSmrg process_file (arg); 3581a30de1fSmrg continue; 3591a30de1fSmrg } 3601a30de1fSmrg } /* end for loop */ 3611a30de1fSmrg 3621a30de1fSmrg /* for compatibility */ 3631a30de1fSmrg if (!didAnything) printMap = True; 3641a30de1fSmrg 3651a30de1fSmrg /* 3661a30de1fSmrg * at this point, the work list has been built and we can view it or 3671a30de1fSmrg * execute it 3681a30de1fSmrg */ 3691a30de1fSmrg 3701a30de1fSmrg if (dontExecute) { 3711a30de1fSmrg print_work_queue (); 3721a30de1fSmrg Exit (0); 3731a30de1fSmrg } 3741a30de1fSmrg 3751a30de1fSmrg if (parse_errors != 0) { 3761a30de1fSmrg fprintf (stderr, "%s: %d error%s encountered, aborting.\n", 3771a30de1fSmrg ProgramName, parse_errors, 3781a30de1fSmrg (parse_errors == 1 ? "" : "s")); 3791a30de1fSmrg status = -1; /* return an error condition */ 3801a30de1fSmrg } else { 3811a30de1fSmrg status = execute_work_queue (); 3821a30de1fSmrg } 3831a30de1fSmrg 3841a30de1fSmrg if (printMap) { 3851a30de1fSmrg print_modifier_map (); 3861a30de1fSmrg } 3871a30de1fSmrg 3881a30de1fSmrg if (printKeyTable) { 3891a30de1fSmrg print_key_table (False); 3901a30de1fSmrg } 3911a30de1fSmrg 3921a30de1fSmrg if (printKeyTableExprs) { 3931a30de1fSmrg print_key_table (True); 3941a30de1fSmrg } 3951a30de1fSmrg 3961a30de1fSmrg if (printPointerMap) { 3971a30de1fSmrg print_pointer_map (); 3981a30de1fSmrg } 3991a30de1fSmrg 4001a30de1fSmrg Exit (status < 0 ? 1 : 0); 4011a30de1fSmrg 4021a30de1fSmrg /* Muffle gcc */ 4031a30de1fSmrg return 0; 4041a30de1fSmrg} 4051a30de1fSmrg 406