#include <ctype.h>
#include <fcntl.h>
#include <getopt.h>
+#include <unistd.h>
#include <linux/types.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include "nls.h"
#include "version.h"
-#ifdef COMPAT_HEADERS
-#include "compat/linux-keyboard.h"
-#endif
-
static int fd;
static int verbose;
-static int nr_keys = 0; /* probably 112, 128, 256 or 512 */
-
-int keymap_index[MAX_NR_KEYMAPS]; /* inverse of good_keymap */
-int good_keymap[MAX_NR_KEYMAPS], keymapnr, allocct;
-
-/* note: asking for n > 255 is not meaningful: ke.kb_index is uchar */
-static int
-has_key(int n) {
- struct kbentry ke;
-
- ke.kb_table = 0; /* plain map is always present */
- ke.kb_index = n;
- return !ioctl(fd, KDGKBENT, (unsigned long)&ke);
-}
-
-static void
-find_nr_keys(void) {
- nr_keys = (has_key(255) ? 256 : has_key(127) ? 128 : 112);
-}
-
-static void
-get_keymaps(void) {
- int i, j;
- struct kbentry ke;
-
- keymapnr = allocct = 0;
- for (i=0; i<MAX_NR_KEYMAPS; i++) {
- ke.kb_index = 0;
- ke.kb_table = i;
- j = ioctl(fd, KDGKBENT, (unsigned long)&ke);
- if (j && errno != EINVAL) {
- perror("KDGKBENT");
- fprintf(stderr,
- _("KDGKBENT error at index 0 in table %d\n"), i);
- exit(1);
- }
- if (!j && ke.kb_value != K_NOSUCHMAP) {
- keymap_index[i] = keymapnr;
- good_keymap[keymapnr++] = i;
- if (ke.kb_value == K_ALLOCATED)
- allocct++;
- } else {
- keymap_index[i] = -1;
- }
- }
- if (keymapnr == 0) {
- fprintf(stderr, _("%s: cannot find any keymaps?\n"), progname);
- exit(1);
- }
- if (good_keymap[0] != 0) {
- fprintf(stderr,
- _("%s: plain map not allocated? very strange ...\n"),
- progname);
- /* this is not fatal */
- }
-}
-
-static void
-print_keymaps(void) {
- int i,m0,m;
-
- printf("keymaps ");
- for (i=0; i<keymapnr; i++) {
- if (i)
- printf(",");
- m0 = m = good_keymap[i];
- while (i+1 < keymapnr && good_keymap[i+1] == m+1)
- i++, m++;
- if (m0 == m)
- printf("%d", m0);
- else
- printf("%d-%d", m0, m);
- }
- printf("\n");
-}
-
-static int
-get_bind(u_char kb_index, u_char kb_table) {
- struct kbentry ke;
-
- ke.kb_index = kb_index;
- ke.kb_table = kb_table;
- if (ioctl(fd, KDGKBENT, (unsigned long)&ke)) {
- if (kb_index < 128) {
- perror("KDGKBENT");
- fprintf(stderr, _("KDGKBENT error at index %d in table %d\n"),
- kb_index, kb_table);
- exit(1);
- } else
- return -1;
- }
- return ke.kb_value;
-}
-
-static void
-print_keysym(int code, char numeric) {
- unsigned int t;
- int v;
- const char *p;
- int plus;
-
- printf(" ");
- t = KTYP(code);
- v = KVAL(code);
- if (t >= syms_size) {
- if (!numeric && (p = codetoksym(code)) != NULL)
- printf("%-16s", p);
- else
- printf("U+%04x ", code ^ 0xf000);
- return;
- }
- plus = 0;
- if (t == KT_LETTER) {
- t = KT_LATIN;
- printf("+");
- plus++;
- }
- if (!numeric && t < syms_size && v < syms[t].size &&
- (p = syms[t].table[v])[0])
- printf("%-*s", 16 - plus, p);
- else if (!numeric && t == KT_META && v < 128 && v < syms[0].size &&
- (p = syms[0].table[v])[0])
- printf("Meta_%-11s", p);
- else
- printf("0x%04x %s", code, plus ? "" : " ");
-}
-
-static char
-valid_type(int t) {
- struct kbentry ke;
- char status;
-
- ke.kb_index = 0;
- ke.kb_table = 0;
- ke.kb_value = K(t, 0);
- status = (ioctl(fd, KDSKBENT, (unsigned long)&ke) == 0);
- return status;
-}
-
-static u_char
-maximum_val(int t) {
- struct kbentry ke, ke0;
- int i;
-
- ke.kb_index = 0;
- ke.kb_table = 0;
- ke.kb_value = K_HOLE;
- ke0 = ke;
- ioctl(fd, KDGKBENT, (unsigned long)&ke0);
-
- for (i = 0; i < 256; i++) {
- ke.kb_value = K(t, i);
- if (ioctl(fd, KDSKBENT, (unsigned long)&ke))
- break;
- }
- ke.kb_value = K_HOLE;
- ioctl(fd, KDSKBENT, (unsigned long)&ke0);
-
- return i - 1;
-}
-
-#define NR_TYPES 15
-int maxval[NR_TYPES];
-
-#ifdef KDGKBDIACR
-/* isgraph() does not know about iso-8859; printing the character
- unescaped makes the output easier to check. Maybe this should
- be an option. Use locale? */
-static void
-outchar (unsigned char c) {
- printf("'");
- printf((c == '\'' || c == '\\') ? "\\%c"
- : (isgraph(c) || c == ' ' || c >= 0200) ? "%c"
- : "\\%03o", c);
- printf("'");
-}
-
-#ifdef KDGKBDIACRUC
-static struct kbdiacrsuc kd;
-#else
-static struct kbdiacrs kd;
-#endif
-
-static void
-get_diacs(void) {
- static int got_diacs = 0;
-
-#ifdef KDGKBDIACRUC
- if(!got_diacs && ioctl(fd, KDGKBDIACRUC, (unsigned long)&kd)) {
- perror("KDGKBDIACRUC");
- exit(1);
- }
-#else
- if(!got_diacs && ioctl(fd, KDGKBDIACR, (unsigned long)&kd)) {
- perror("KDGKBDIACR");
- exit(1);
- }
-#endif
-
- got_diacs = 1;
-}
-
-static int
-nr_of_diacs(void) {
- get_diacs();
- return kd.kb_cnt;
-}
-
-static void
-_dump_diacs(void) {
- unsigned int i;
-
- get_diacs();
-#ifdef KDGKBDIACRUC
- for (i = 0; i < kd.kb_cnt; i++) {
- printf("compose ");
- outchar(kd.kbdiacruc[i].diacr & 0xff);
- printf(" ");
- outchar(kd.kbdiacruc[i].base & 0xff);
- printf(" to U+%04x\n", kd.kbdiacruc[i].result);
- }
-#else
- for (i = 0; i < kd.kb_cnt; i++) {
- printf("compose ");
- outchar(kd.kbdiacr[i].diacr);
- printf(" ");
- outchar(kd.kbdiacr[i].base);
- printf(" to ");
- outchar(kd.kbdiacr[i].result);
- printf("\n");
- }
-#endif
-}
-#endif
-
-static void
-show_short_info(void) {
- int i;
-
- printf(_("keycode range supported by kernel: 1 - %d\n"),
- nr_keys - 1);
- printf(_("max number of actions bindable to a key: %d\n"),
- MAX_NR_KEYMAPS);
- get_keymaps();
- printf(_("number of keymaps in actual use: %d\n"),
- keymapnr);
- if (allocct)
- printf(_("of which %d dynamically allocated\n"), allocct);
- printf(_("ranges of action codes supported by kernel:\n"));
- for (i = 0; i < NR_TYPES && valid_type(i); i++) {
- maxval[i] = maximum_val(i);
- printf(" 0x%04x - 0x%04x\n", K(i, 0), K(i, maxval[i]));
- }
- printf(_("number of function keys supported by kernel: %d\n"),
- MAX_NR_FUNC);
-
- printf(_("max nr of compose definitions: %d\n"),
- MAX_DIACR);
- printf(_("nr of compose definitions in actual use: %d\n"),
- nr_of_diacs());
-}
-
-static struct {
- char *name;
- int bit;
-} modifiers[] = {
- { "shift", KG_SHIFT },
- { "altgr", KG_ALTGR },
- { "control",KG_CTRL },
- { "alt", KG_ALT },
- { "shiftl", KG_SHIFTL },
- { "shiftr", KG_SHIFTR },
- { "ctrll", KG_CTRLL },
- { "ctrlr", KG_CTRLR },
- { "capsshift", KG_CAPSSHIFT }
-};
-
-static void
-_dump_symbols(void) {
- unsigned int t;
- int v;
- const char *p;
-
- printf(_("Symbols recognized by %s:\n(numeric value, symbol)\n\n"),
- progname);
- for (t = 0; t < syms_size; t++) {
- if (syms[t].size) {
- for (v = 0; v < syms[t].size; v++)
- if ((p = syms[t].table[v])[0])
- printf("0x%04x\t%s\n", K(t, v), p);
- } else if (t == KT_META) {
- for (v = 0; v < syms[0].size && v < 128; v++)
- if ((p = syms[0].table[v])[0])
- printf("0x%04x\tMeta_%s\n", K(t, v), p);
- }
- }
- printf(_("\nThe following synonyms are recognized:\n\n"));
- for (t = 0; t < syn_size; t++)
- printf(_("%-15s for %s\n"), synonyms[t].synonym,
- synonyms[t].official_name);
- printf(_("\nRecognized modifier names and their column numbers:\n"));
- for (t = 0; t < sizeof(modifiers)/sizeof(modifiers[0]); t++)
- printf("%s\t\t%3d\n", modifiers[t].name, 1 << modifiers[t].bit);
-}
-
-static void
-print_mod(int x) {
- unsigned int t;
-
- if (!x)
- printf("plain\t");
- else
- for (t = 0; t < sizeof(modifiers)/sizeof(modifiers[0]); t++)
- if (x & (1 << modifiers[t].bit))
- printf("%s\t", modifiers[t].name);
-}
-
-static void
-print_bind(int bufj, int i, int j, char numeric) {
- if(j)
- printf("\t");
- print_mod(j);
- printf("keycode %3d =", i);
- print_keysym(bufj, numeric);
- printf("\n");
-}
-
-#define DEFAULT 0
-#define FULL_TABLE 1 /* one line for each keycode */
-#define SEPARATE_LINES 2 /* one line for each (modifier,keycode) pair */
-#define UNTIL_HOLE 3 /* one line for each keycode, until 1st hole */
-
-static void
-_dump_keys(char table_shape, char numeric) {
- int i, j, k;
- int buf[MAX_NR_KEYMAPS];
- int isletter, islatin, isasexpected;
- int typ, val;
- int alt_is_meta = 0;
- int zapped[MAX_NR_KEYMAPS];
-
- get_keymaps();
- print_keymaps();
- if (!keymapnr)
- return;
-
- if (table_shape == FULL_TABLE || table_shape == SEPARATE_LINES)
- goto no_shorthands;
-
- /* first pass: determine whether to set alt_is_meta */
- for (j = 0; j < MAX_NR_KEYMAPS; j++) {
- int ja = (j | M_ALT);
- if (j != ja && keymap_index[j] >= 0 && keymap_index[ja] >= 0)
- for (i = 1; i < nr_keys; i++) {
- int buf0, buf1, type;
-
- buf0 = get_bind(i, j);
- if (buf0 == -1)
- break;
- type = KTYP(buf0);
- if ((type == KT_LATIN || type == KT_LETTER)
- && KVAL(buf0) < 128) {
- buf1 = get_bind(i, ja);
- if (buf1 != K(KT_META, KVAL(buf0))) {
- if (verbose) {
- printf(_("# not alt_is_meta: "
- "on keymap %d key %d is bound to"),
- ja, i);
- print_keysym(buf1, numeric);
- printf("\n");
- }
- goto not_alt_is_meta;
- }
- }
- }
- }
- alt_is_meta = 1;
- printf("alt_is_meta\n");
-not_alt_is_meta:
-
-no_shorthands:
- for (i = 1; i < nr_keys; i++) {
- for (j = 0; j < keymapnr; j++)
- buf[j] = get_bind(i, good_keymap[j]);
- if (buf[0] == -1)
- break;
-
- if (table_shape == FULL_TABLE) {
- printf("keycode %3d =", i);
- for (j = 0; j < keymapnr; j++)
- print_keysym(buf[j], numeric);
- printf("\n");
- continue;
- }
-
- if (table_shape == SEPARATE_LINES) {
- for (j = 0; j < keymapnr; j++)
- print_bind(buf[j], i, good_keymap[j], numeric);
- printf("\n");
- continue;
- }
-
- typ = KTYP(buf[0]);
- val = KVAL(buf[0]);
- islatin = (typ == KT_LATIN || typ == KT_LETTER);
- isletter = (islatin &&
- ((val >= 'A' && val <= 'Z') ||
- (val >= 'a' && val <= 'z')));
- isasexpected = 0;
- if (isletter) {
- u_short defs[16];
- defs[0] = K(KT_LETTER, val);
- defs[1] = K(KT_LETTER, val ^ 32);
- defs[2] = defs[0];
- defs[3] = defs[1];
- for(j=4; j<8; j++)
- defs[j] = K(KT_LATIN, val & ~96);
- for(j=8; j<16; j++)
- defs[j] = K(KT_META, KVAL(defs[j-8]));
-
- for(j = 0; j < keymapnr; j++) {
- k = good_keymap[j];
- if ((k >= 16 && buf[j] != K_HOLE) || (k < 16 && buf[j] != defs[k]))
- goto unexpected;
- }
- isasexpected = 1;
- }
- unexpected:
-
- /* wipe out predictable meta bindings */
- for (j = 0; j < keymapnr; j++)
- zapped[j] = 0;
- if (alt_is_meta) {
- for(j = 0; j < keymapnr; j++) {
- int ka, ja, ktyp;
- k = good_keymap[j];
- ka = (k | M_ALT);
- ja = keymap_index[ka];
- if (k != ka && ja >= 0
- && ((ktyp=KTYP(buf[j])) == KT_LATIN || ktyp == KT_LETTER)
- && KVAL(buf[j]) < 128) {
- if (buf[ja] != K(KT_META, KVAL(buf[j])))
- fprintf(stderr, _("impossible: not meta?\n"));
- buf[ja] = K_HOLE;
- zapped[ja] = 1;
- }
- }
- }
-
- printf("keycode %3d =", i);
- if (isasexpected) {
- /* print only a single entry */
- /* suppress the + for ordinary a-zA-Z */
- print_keysym(K(KT_LATIN, val), numeric);
- printf("\n");
- } else {
- /* choose between single entry line followed by exceptions,
- and long line followed by exceptions; avoid VoidSymbol */
- int bad = 0;
- int count = 0;
- for(j = 1; j < keymapnr; j++) if (!zapped[j]) {
- if (buf[j] != buf[0])
- bad++;
- if (buf[j] != K_HOLE)
- count++;
- }
- if (bad <= count && bad < keymapnr-1) {
- if (buf[0] != K_HOLE)
- print_keysym(buf[0], numeric);
- printf("\n");
- for (j = 1; j < keymapnr; j++)
- if (buf[j] != buf[0] && !zapped[j])
- print_bind(buf[j], i, good_keymap[j], numeric);
- } else {
- for (j = 0; j < keymapnr && buf[j] != K_HOLE &&
- (j == 0 || table_shape != UNTIL_HOLE ||
- good_keymap[j] == good_keymap[j-1]+1); j++)
- print_keysym(buf[j], numeric);
- printf("\n");
- for ( ; j < keymapnr; j++)
- if (buf[j] != K_HOLE)
- print_bind(buf[j], i, good_keymap[j], numeric);
- }
- }
- }
-}
-
-static void
-_dump_funcs(void) {
- int i;
- struct kbsentry fbuf;
- unsigned char *p;
-
- for (i = 0; i < MAX_NR_FUNC; i++) {
- fbuf.kb_func = i;
- if (ioctl(fd, KDGKBSENT, (unsigned long)&fbuf)) {
- if (errno == EINVAL && i > 0) /* an old kernel */
- break;
- perror("KDGKBSENT");
- fprintf(stderr, _("KDGKBSENT failed at index %d: "), i);
- exit(1);
- }
- if (!fbuf.kb_string[0])
- continue;
- printf("string %s = \"", syms[KT_FN].table[i]);
- for (p = fbuf.kb_string; *p; p++) {
- if (*p == '"' || *p == '\\') {
- putchar('\\'); putchar(*p);
- } else if (isgraph(*p) || *p == ' ')
- putchar(*p);
- else
- printf("\\%03o", *p);
- }
- printf("\"\n");
- }
-}
static void attr_noreturn
usage(void) {
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
- int c;
+ int c, rc;
+ int kbd_mode;
+
char long_info = 0;
char short_info = 0;
char numeric = 0;
char keys_only = 0;
char diac_only = 0;
+ struct keymap kmap;
+
set_progname(argv[0]);
setlocale(LC_ALL, "");
if (optind < argc)
usage();
+ keymap_init(&kmap);
+
fd = getfd(NULL);
- find_nr_keys();
+ /* check whether the keyboard is in Unicode mode */
+ if (ioctl(fd, KDGKBMODE, &kbd_mode)) {
+ fprintf(stderr, _("%s: error reading keyboard mode: %m\n"),
+ progname);
+ exit(EXIT_FAILURE);
+ }
+
+ if (kbd_mode == K_UNICODE) {
+ kmap.prefer_unicode = 1;
+ }
+
+ if ((rc = get_keymap(&kmap, fd)) < 0)
+ goto fail;
if (short_info || long_info) {
- show_short_info();
- if (long_info)
- _dump_symbols();
- exit(0);
+ dump_summary(&kmap, stdout, fd);
+
+ if (long_info) {
+ printf(_("Symbols recognized by %s:\n(numeric value, symbol)\n\n"),
+ progname);
+ dump_symbols(stdout);
+ }
+ exit(EXIT_SUCCESS);
}
#ifdef KDGKBDIACR
if (!diac_only) {
#endif
- if (!funcs_only)
- _dump_keys(table_shape, numeric);
- if (!keys_only)
- _dump_funcs();
+ if (!funcs_only) {
+ dump_keymap(&kmap, stdout, table_shape, numeric);
+ }
#ifdef KDGKBDIACR
}
+
if (!funcs_only && !keys_only)
- _dump_diacs();
+ dump_diacs(&kmap, stdout);
#endif
- exit(0);
+ fail: keymap_free(&kmap);
+ close(fd);
+
+ if (rc < 0)
+ exit(EXIT_FAILURE);
+
+ exit(EXIT_SUCCESS);
}