home *** CD-ROM | disk | FTP | other *** search
- /* ta=4 tabs set at 4*/
- /*
- kbmap.c
-
- Kbmap reads a text file containg keyboard mapping information and
- set the keyboard to the selected mapping. It can also create
- a map file with the -g option.
-
- Only root may use this programme from the console.
- It cannot be run from an rc2.d/xxx file or cron.
-
- Then true-meta keys cannot be used with X11R2 - which uses its own map.
- VTLMGR tends to modify a couple of keys. The -q option (query_map())
- tries to detect a vtlmgr modification.
-
- This works for AT&T Unix 3.2.2 - other systems not tested.
-
- AUTHOR: Tony Field (tony%ajfcal@cpsc.ucalgary.ca)
-
- NOTES:
-
- Structure of keyboard translation table (from /usr/include/sys/kd.h)
-
- #define NUM_KEYS 256 Maximum number of keys
- #define NUM_STATES 8 Number of key states
- #pragma pack(2)
- typedef struct {
- short n_keys ; Number of entries in table
- struct key_t {
- unsigned char map[NUM_STATES]; Key code for each state
- unsigned char spcl; Bits marking states as special
- unsigned char flgs; Flags
- } key[NUM_KEYS+1]; One entry for each key
- } keymap_t;
-
- (note: NUM_KEYS is specified as 256, however n_keys only
- describes 128 keys... kbmap only updates the first
- 128 keys. The remainder are unmodified.)
-
- Each key has 8 (NUM_STATES) possible scan states honoured if
- set in the "spcl" field:
-
- spcl map[i]
- bit 7 i=0 = normal
- 6 1 = shifted
- 5 2 = control
- 4 3 = shift-control
- 3 4 = alt
- 2 5 = alt-shift
- 1 6 = alt-control
- 0 7 = alt-shift-control
-
- If the corresponding bit is set, then the feature is enabled. For
- example, if bit 3 is set, then the keyboard driver will translate
- the scan code into the "<esc>Nx" escape sequence. If the 3ed bit is
- NOT set, then the driver will use the character as specified in
- map[4] as the returned value.
-
- The "flgs" field needs no modification: it allows the "numlok",
- "caploc" and "control" keys to be used with specific keys:
-
- 0x8000 allow numlock
- 0x4000 allow caps lock
- 0x2000 allow control
- 0x1000 locking is off
-
- At leaset that is what <sys/kd.h> indicates. But that is not
- what is indicated in the actual dump of the tables... Alphabetic
- characters contain 0x01, the numeric keypad contains 0x02, and
- verything else contains 0x00. Oh well... A more reasonable
- interpretation is that these meanings are assigned to the
- high order 4 bits of "spcl", but that is only a guess.
-
- In addition, the default value for the map[4] entry for most codes
- that can be translated into the <esc>Nx sequence is 0x7d.
- The 7x numbers are used for function key translation. They mean
- (of course i am guessing):
-
- 7d = use <esc>Nx where 'x' is the un-alted value
- 7e = use <esc>Ox of the scan code (funny that 7e
- 7f = use <esc>Lx and 7f do not appear in the table
- nor are visible in keyboard(7))
-
- Conversion of the table to emacs "meta" bits is done as follows:
-
- 1. read the entire keyboard mapping structure with ioctl().
- 2. if the base key (map[0]) is between ' ' & 0x7f and not uppercase
- then remove bit 3 from the spcl field and
- set map[4] = map[0] | 0x80. The creates the
- meta-mapping of the keys for lower case letters.
- 3. if the shifted key (map[1]) is between ' ' & 0x7f and the
- map[0] value is not an upper case character,
- then remove bit 2 from the spcl field and
- set map[5] = map[1] | 0x80. The creates the
- meta-mapping of the keys for upper case letters.
- 4. write the new keyboard mapping with ioctl().
-
- Similar conversion is make for the "normal" emacs <esc>N prefix
- sequence. This requires forcing the 0x7d code into all <alt>x slots.
-
- The map structure contains map[0] entries for both lower and upper
- case letters. The lower case entries "seem" to be the only ones
- used. No explanation is offered for the upper case entries.
- */
-
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/at_ansi.h>
- #include <sys/kd.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
-
- /* where does kbmap expect to find the default map table */
-
- #ifndef DEFAULTMAP
- #define DEFAULTMAP "/local/lib/kbmap.table"
- #endif
-
- char progname[150];
- int vtlmgr;
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- extern char *optarg;
- extern int optind;
- int c;
- int select_map = -1;
- char use_file[200];
- int generate_file = 0;
- FILE *use_fp, *open_file();
- char tfile[100];
- int tn = -1;
- int index_only = 0;
- char line[200];
- int query_only = 0;
- int option_count = 0;
- int also_alt_ctl = 1;
-
- strcpy (progname, argv[0]);
- use_fp = NULL;
- use_file[0] = '\0';
- if (argc == 1 || strcmp (argv[1], "-") == 0 || strcmp (argv[1], "--") == 0)
- usage();
-
- while ((c = getopt(argc, argv, "aqgin:dmet:-?")) != -1)
- { option_count++;
- switch (c)
- {
- case 'a': also_alt_ctl = 0; /* disable alt+ctl expansion */
- break;
- case 'i': index_only = 1;
- break;
- case 'n': select_map = atoi (optarg); /* select by number */
- break;
- case 'd': select_map = 0; /* select default = 0 */
- if (use_file[0] == '\0')
- strcpy (use_file, DEFAULTMAP);
- break;
- case 'e': select_map = 2; /* select emacs = 2 */
- if (use_file[0] == '\0')
- strcpy (use_file, DEFAULTMAP);
- break;
- case 'm': select_map = 1; /* select emacs = 1 (meta) */
- if (use_file[0] == '\0')
- strcpy (use_file, DEFAULTMAP);
- break;
- case 't': strcpy (tfile, optarg); /* use terminal at /dev/xxxx */
- if ((tn = open (tfile, O_RDWR)) < 0)
- { fprintf (stderr, "%s: Cannot open %s\n", progname, tfile);
- exit (1);
- }
- break;
- case 'q': query_only = 1;
- break;
- case 'g': generate_file = 1; /* generate map file */
- if (use_file[0] == '\0')
- strcpy (use_file, DEFAULTMAP);
- break;
-
- default: usage ();
- }
- }
- if (optind < argc)
- { strcpy (use_file, argv[optind]); /* specify map file */
- if (option_count == 0)
- index_only = 1;
- }
-
- if (tn < 1)
- tn = 0;
-
- if (index_only) /* show index of maps */
- { use_fp = open_file (use_file, "r");
- c = 0;
- while (fgets (line, 190, use_fp) != NULL)
- if (strncmp (line, "...", 3) == 0)
- printf ("map %d = %s", c++, line + 3);
- fclose (use_fp);
- exit (0);
- }
-
- if (query_only) /* which map is in use */
- { use_fp = open_file (use_file, "r");
- if (query_map (use_fp) == 0)
- printf ("current map is not in %s\n", use_file);
- exit (0);
- }
-
- if (generate_file) /* create new kbmap.table file */
- { if (use_file[0])
- { use_fp = open_file (use_file, "w");
- create_table (use_fp, tn, also_alt_ctl);
- fclose (use_fp);
- }
- else
- create_table (stdout, tn, also_alt_ctl);
- }
-
- if (select_map >= 0)
- { use_fp = open_file (use_file, "r");
- update_map (use_fp, select_map);
- fclose (use_fp);
- }
-
- exit (0);
- }
-
- /****************************************************************************
- * create_table (fp) *
- * Get the existing keyboard mapping structure and write to file. *
- * Translate all alt and alt-shift keys to the meta-mapping. *
- * Write the meta-mapping structure to disk file. *
- ****************************************************************************/
-
- create_table (fp, tn, also_alt_ctl)
- FILE *fp; /* file containing the keyboard maps */
- int tn;
- int also_alt_ctl; /* convert ALT/CTL and ALT/SHIFT/CTL as well? */
- {
- int i, j, cb, cs;
- keymap_t kt;
- char title[200];
-
- /* get existing mapping */
-
- if (ioctl (tn, GIO_KEYMAP, &kt))
- ioctl_failure ('r');
-
- /* write the existing mapping to the disk file
-
- some potentiall useful keyboard scan numbers:
-
- 1 esc
- 14 bs
- 15 tab
- 28 cr
- 83 del
- 116 cr
- 119 break
- 121 del
-
- For example, if scan code 1 (esc) is specifically selected,
- then the <ALT><ESC> combination becomes available. This is
- not done because double-striking <esc> is quite easy.
-
- It might be useful to force full alt-decoding for cr and tab.
- Emacs would recognize such sequences by default (see comments
- in the code to make this modification)
-
- The variable sequence is:
- char scan scpl flgs NORMAL SHIFT CTRL SHFCTL ALT ALTSHF ALTCTL ALTSHFCTL
- */
-
- header (fp, "system default keyboard mapping", -1);
- for (i = 0; i < kt.n_keys; i++)
- {
- cb = kt.key[i].map[0];
- cs = kt.key[i].map[1];
- fprintf (fp, "%c%c %3d %02x %02x",
- cb > ' ' && cb < 127 ? cb : ' ',
- cs > ' ' && cs < 127 && cs != cb ? cs : ' ',
- i,
- kt.key[i].spcl & 0x0ff,
- kt.key[i].flgs & 0x0ff);
- for (j = 0; j < NUM_STATES; j++)
- fprintf (fp, " %02x", kt.key[i].map[j]);
- fprintf (fp, "\n");
- }
-
- /* convert the existing mapping to emacs-meta (8th bit set) conventions
- and write to file
- */
-
- fprintf (fp, "\n\n");
- strcpy (title, "emacs 8th bit set (<letter>|0x080) meta mapping");
- header (fp, title, also_alt_ctl);
- for (i = 0; i < kt.n_keys; i++)
- {
- cb = kt.key[i].map[NORMAL]; /* base char */
- cs = kt.key[i].map[SHIFT]; /* shifted char */
-
- if (1) /* things to ignore e,g, (i == 121) */
- {
- /* convert ALT key to meta. */
-
- /* add the following the various "if" statements below
- to enable full conversion of \t and \n:
-
- || (i == 15) || (i == 28)
- */
- if ((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb <= 127))
- { kt.key[i].map[ALT] = (kt.key[i].map[NORMAL] | 0x080);
- kt.key[i].spcl &= 0x0f7;
- }
-
- /* convert ALT-CTRL key to meta. (dont include <alt><ctl><del> */
-
- if (also_alt_ctl
- && ((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb < 127)))
- { kt.key[i].map[ALTCTL] = (kt.key[i].map[CTRL] | 0x080);
- kt.key[i].spcl &= 0x0fd;
- }
-
- /* convert ALT-SHIFT to meta */
-
- if (((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb <= 127))
- && (cs >= ' ' && cs <= 127))
- { kt.key[i].map[ALTSHF] = (kt.key[i].map[SHIFT] | 0x080);
- kt.key[i].spcl &= 0x0fb;
- }
-
- /* convert ALT-SHIFT-CTL to meta */
-
- if (also_alt_ctl
- && ((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb <= 127))
- && (cs >= ' ' && cs <= 127))
- { kt.key[i].map[ALTSHFCTL] = (kt.key[i].map[SHFCTL] | 0x080);
- kt.key[i].spcl &= 0x0fe;
- }
- }
- fprintf (fp, "%c%c %3d %02x %02x",
- cb > ' ' && cb < 127 ? cb : ' ',
- cs > ' ' && cs < 127 && cs != cb ? cs : ' ',
- i,
- kt.key[i].spcl & 0x0ff,
- kt.key[i].flgs & 0x0ff);
- for (j = 0; j < NUM_STATES; j++)
- fprintf (fp, " %02x", kt.key[i].map[j]);
- fprintf (fp, "\n");
- }
-
- /* re-get existing mapping to remove the above meta-conversion
-
- Set the k.key[i].map[xx] values to 0x7d. This seems to be
- the code that forces the <esc>N sequence durning translation
- */
-
- if (ioctl (tn, GIO_KEYMAP, &kt))
- ioctl_failure('r');
-
- fprintf (fp, "\n\n");
- strcpy (title, "emacs normal (<esc>N<letter>) meta mapping");
- header (fp, title, also_alt_ctl);
- for (i = 0; i < kt.n_keys; i++)
- {
- cb = kt.key[i].map[NORMAL]; /* base char */
- cs = kt.key[i].map[SHIFT]; /* shifted char */
-
- if (1) /* things to ignore */
- { /* make ALT converssion available */
-
- if ((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb <= 127))
- { kt.key[i].map[ALT] = 0x7d;
- kt.key[i].spcl |= 0x08;
- }
-
- /* make ALT-CTL conversion available (dont include <alt><ctl><del> */
-
- if (also_alt_ctl
- && ((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb < 127)))
- { kt.key[i].map[ALTCTL] = 0x7d;
- kt.key[i].spcl |= 0x02;
- }
-
- /* make ALT-SHIFT available */
-
- if (((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb <= 127))
- && (cs >= ' ' && cs <= 127))
- { kt.key[i].map[ALTSHF] = 0x7d;
- kt.key[i].spcl |= 0x04;
- }
-
- /* make ALT-SHIFT-CTL available */
-
- if (also_alt_ctl
- && ((cb >= ' ' && cb < 'A') || (cb > 'Z' && cb <= 127))
- && (cs >= ' ' && cs <= 127))
- { kt.key[i].map[ALTSHFCTL] = 0x7d;
- kt.key[i].spcl |= 0x01;
- }
- }
- fprintf (fp, "%c%c %3d %02x %02x",
- cb > ' ' && cb < 127 ? cb : ' ',
- cs > ' ' && cs < 127 && cs != cb ? cs : ' ',
- i,
- kt.key[i].spcl & 0x0ff,
- kt.key[i].flgs & 0x0ff);
- for (j = 0; j < NUM_STATES; j++)
- fprintf (fp, " %02x", kt.key[i].map[j]);
- fprintf (fp, "\n");
- }
-
- }
-
- /****************************************************************************
- * header () *
- * Standard table header generation *
- ****************************************************************************/
-
- header (fp, title, also_alt_ctl)
- FILE *fp;
- char *title;
- { fprintf (fp, "...%s", title);
- if (also_alt_ctl == -1)
- fprintf (fp, "\n");
- else if (also_alt_ctl)
- fprintf (fp, " -- full alt/ctl\n");
- else
- fprintf (fp, " -- no alt/ctl\n");
- fprintf (fp, " alt\n");
- fprintf (fp, " shif alt alt shif\n");
- fprintf (fp, " key spcl flgs norm shif ctrl ctrl alt shif ctrl ctrl\n");
- fprintf (fp, "------ ---- ---- ---- ---- ---- ---- ---- ---- ---- ----\n");
- }
-
-
- /****************************************************************************
- * update_map (fp, which_map) *
- * Read the specified mapping table from the map file. Send the new map *
- * to key keyboard driver. *
- ****************************************************************************/
-
- update_map (fp, which_map)
- FILE *fp; /* file containing keyboard maps */
- int which_map; /* select this table from the file (0..n) */
- {
- int i, j, how;
- keymap_t kt;
-
- /* find the desired map in the file and read it into the keytable */
-
- if (ioctl (1, GIO_KEYMAP, &kt)) /* read current map */
- ioctl_failure ('r');
-
- for (i = 0; i <= which_map; i++)
- how = read_map (i == which_map, fp, &kt, NULL);
- if (how)
- { fprintf (stderr, "%s: map %d not found\n", progname, which_map);
- exit (1);
- }
- if (ioctl (1, PIO_KEYMAP, &kt)) /* send found map to driver */
- ioctl_failure ('w');
- }
-
- /****************************************************************************
- * query_map (fp) *
- * Identifiy which table file map matches the keyboard map in use. *
- ****************************************************************************/
-
- query_map (fp)
- FILE *fp; /* file containing keyboard maps */
- {
- int i, j, k;
- char text[200];
- keymap_t kt, inuse;
- int found;
- int vtlmgr;
-
- if (ioctl (1, GIO_KEYMAP, &inuse)) /* read current map */
- ioctl_failure ('r');
-
- vtlmgr = 0;
- found = 0;
- kt = inuse;
- for (k = 0; ; k++)
- { if (read_map (1, fp, &kt, text))
- return (found);
- for (i = 0; i < inuse.n_keys; i++)
- { for (j = 0; j < NUM_STATES; j++) /* compare all keys */
- { if (inuse.key[i].map[j] != kt.key[i].map[j])
- { /* detect minor mod made by vtlmgr in line 3 for "1!" */
- if (i == 2 && (j == ALTSHF || j == ALTSHFCTL))
- vtlmgr = 1;
- else
- goto next_map;
- }
- }
- }
- printf ("using map %d: %s\n", k, text);
- if (vtlmgr)
- printf (" (modified by vtlmgr)\n");
- found = 1;
- break;
- next_map: ;
- }
- return (found);
- }
-
- /****************************************************************************
- * read_map (fp, kt, title) *
- * Read the nextd mapping table from the map file. *
- ****************************************************************************/
-
- read_map (getit, fp, kt, title)
- int getit; /* 1 = update kt, 0 = get title only */
- FILE *fp; /* file containing keyboard maps */
- keymap_t *kt; /* read structure into this */
- char *title; /* read title line into this buffer */
- {
- int i, j, cc;
- char key_line[200], *c;
- int a0,a1,a2,a3,a4,a5,a6,a7,a8,a9;
- int good_read;
-
- /* find the next map in the file and read it into the keytable */
-
- while (good_read = (fgets (key_line, 199, fp) != NULL))
- { if (title != NULL && strncmp (key_line, "...", 3) == 0)
- { strcpy (title, key_line + 3);
- c = title;
- while (*c)
- { if (*c < ' ')
- { *c = '\0';
- break;
- }
- c++;
- }
- }
- else if (strncmp (key_line, "------ -", 8) == 0)
- break;
- }
- if (good_read == 0)
- return (-1);
- if (strncmp (key_line, "------ -", 8) != 0)
- bad_file ();
-
- if (getit == 0)
- return (1);
- for (i = 0; i < kt->n_keys; i++)
- { if (fgets (key_line, 199, fp) == NULL)
- bad_file ();
- if (atoi (key_line + 2) != i)
- bad_file ();
- sscanf (key_line + 7, "%x %x %x %x %x %x %x %x %x %x",
- &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9);
- kt->key[i].spcl = a0;
- kt->key[i].flgs = a1;
- kt->key[i].map[0] = a2;
- kt->key[i].map[1] = a3;
- kt->key[i].map[2] = a4;
- kt->key[i].map[3] = a5;
- kt->key[i].map[4] = a6;
- kt->key[i].map[5] = a7;
- kt->key[i].map[6] = a8;
- kt->key[i].map[7] = a9;
-
- }
- return (0);
- }
-
- /****************************************************************************
- * open_file (use_file, how) *
- * Open a table file. If there is a problem, quit now. *
- ****************************************************************************/
-
- FILE *open_file (use_file, how)
- char *use_file;
- char *how;
- { FILE *use_fp;
- char *strchr();
-
- if (*use_file == '\0')
- strcpy (use_file, DEFAULTMAP);
-
- if ((use_fp = fopen (use_file, how)) == NULL)
- { fprintf (stderr, "%s: cannot open file %s\n", progname, use_file);
- exit (1);
- }
- return (use_fp);
- }
-
- /****************************************************************************
- * bad_file () *
- ****************************************************************************/
-
- bad_file ()
- {
- fprintf (stderr, "%s: invalid key map file format\n", progname);
- exit (2);
- }
-
- ioctl_failure (how)
- int how;
- {
- fprintf (stderr, "%s: ioctl failure, %s\n",
- progname, how == 'r' ? "cannot read, possibly using X11???" : "must be root?");
- exit (2);
- }
-
- /****************************************************************************
- * usage () *
- ****************************************************************************/
-
- usage ()
- {
- printf ("Usage: kbmap [-i] [-q] [-g] [-n n] [-d] [-e] [-m] [-1] [-t /dev/xxx] [file]\n");
- printf (" where: -i = show index of available maps\n");
- printf (" -q = identify map currenly in use\n");
- printf (" -g = generate a key map table\n");
- printf (" -n n = set keyboard to map 'n' mapping\n");
- printf (" -d = set keyboard to default mapping\n");
- printf (" -e = set keyboard to emacs mapping (<esc>N)\n");
- printf (" -m = set keyboard to emacs meta-mapping (8bit)\n");
- printf (" -a = disable <alt><ctl> & <alt><shf><ctl>\n");
- printf (" -t /dev/xxx = apply map to this device (default stdin)\n");
- printf (" file = use specified key map file\n");
- printf (" default = %s\n", DEFAULTMAP);
- exit (0);
- }
-