| /* |
| * loadkeys.y |
| * |
| * For history, see older versions. |
| */ |
| |
| %token EOL NUMBER LITERAL CHARSET KEYMAPS KEYCODE EQUALS |
| %token PLAIN SHIFT CONTROL ALT ALTGR SHIFTL SHIFTR CTRLL CTRLR |
| %token COMMA DASH STRING STRLITERAL COMPOSE TO CCHAR ERROR PLUS |
| %token UNUMBER ALT_IS_META STRINGS AS USUAL ON FOR |
| |
| %{ |
| #include <errno.h> |
| #include <stdio.h> |
| #include <getopt.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <linux/kd.h> |
| #include <linux/keyboard.h> |
| #include <sys/ioctl.h> |
| #include <ctype.h> |
| #include "paths.h" |
| #include "getfd.h" |
| #include "findfile.h" |
| #include "modifiers.h" |
| #include "nls.h" |
| #include "version.h" |
| |
| #ifndef KT_LETTER |
| #define KT_LETTER KT_LATIN |
| #endif |
| |
| #undef NR_KEYS |
| #define NR_KEYS 256 |
| |
| /* What keymaps are we defining? */ |
| char defining[MAX_NR_KEYMAPS]; |
| char keymaps_line_seen = 0; |
| int max_keymap = 0; /* from here on, defining[] is false */ |
| int alt_is_meta = 0; |
| |
| /* the kernel structures we want to set or print */ |
| u_short *key_map[MAX_NR_KEYMAPS]; |
| char *func_table[MAX_NR_FUNC]; |
| struct kbdiacr accent_table[MAX_DIACR]; |
| unsigned int accent_table_size = 0; |
| |
| char key_is_constant[NR_KEYS]; |
| char *keymap_was_set[MAX_NR_KEYMAPS]; |
| char func_buf[4096]; /* should be allocated dynamically */ |
| char *fp = func_buf; |
| |
| #define U(x) ((x) ^ 0xf000) |
| |
| #undef ECHO |
| |
| static void addmap(int map, int explicit); |
| static void addkey(int index, int table, int keycode); |
| static void addfunc(struct kbsentry kbs_buf); |
| static void killkey(int index, int table); |
| static void compose(int diacr, int base, int res); |
| static void do_constant(void); |
| static void do_constant_key (int, u_short); |
| static void loadkeys(void); |
| static void mktable(void); |
| static void strings_as_usual(void); |
| static void keypad_as_usual(char *keyboard); |
| static void function_keys_as_usual(char *keyboard); |
| static void consoles_as_usual(char *keyboard); |
| static void compose_as_usual(char *charset); |
| static void lkfatal0(const char *, int); |
| extern int set_charset(const char *charset); |
| extern char *xstrdup(char *); |
| int key_buf[MAX_NR_KEYMAPS]; |
| int mod; |
| extern int unicode_used; |
| int private_error_ct = 0; |
| |
| extern int rvalct; |
| extern struct kbsentry kbs_buf; |
| extern void lkfatal(const char *s); |
| extern void lkfatal1(const char *s, const char *s2); |
| |
| #include "ksyms.h" |
| %} |
| |
| %% |
| keytable : |
| | keytable line |
| ; |
| line : EOL |
| | charsetline |
| | altismetaline |
| | usualstringsline |
| | usualcomposeline |
| | keymapline |
| | fullline |
| | singleline |
| | strline |
| | compline |
| ; |
| charsetline : CHARSET STRLITERAL EOL |
| { |
| set_charset(kbs_buf.kb_string); |
| } |
| ; |
| altismetaline : ALT_IS_META EOL |
| { |
| alt_is_meta = 1; |
| } |
| ; |
| usualstringsline: STRINGS AS USUAL EOL |
| { |
| strings_as_usual(); |
| } |
| ; |
| usualcomposeline: COMPOSE AS USUAL FOR STRLITERAL EOL |
| { |
| compose_as_usual(kbs_buf.kb_string); |
| } |
| | COMPOSE AS USUAL EOL |
| { |
| compose_as_usual(0); |
| } |
| ; |
| keymapline : KEYMAPS range EOL |
| { |
| keymaps_line_seen = 1; |
| } |
| ; |
| range : range COMMA range0 |
| | range0 |
| ; |
| range0 : NUMBER DASH NUMBER |
| { |
| int i; |
| for (i = $1; i<= $3; i++) |
| addmap(i,1); |
| } |
| | NUMBER |
| { |
| addmap($1,1); |
| } |
| ; |
| strline : STRING LITERAL EQUALS STRLITERAL EOL |
| { |
| if (KTYP($2) != KT_FN) |
| lkfatal1(_("'%s' is not a function key symbol"), |
| syms[KTYP($2)].table[KVAL($2)]); |
| kbs_buf.kb_func = KVAL($2); |
| addfunc(kbs_buf); |
| } |
| ; |
| compline : COMPOSE CCHAR CCHAR TO CCHAR EOL |
| { |
| compose($2, $3, $5); |
| } |
| | COMPOSE CCHAR CCHAR TO rvalue EOL |
| { |
| compose($2, $3, $5); |
| } |
| ; |
| singleline : { mod = 0; } |
| modifiers KEYCODE NUMBER EQUALS rvalue EOL |
| { |
| addkey($4, mod, $6); |
| } |
| | PLAIN KEYCODE NUMBER EQUALS rvalue EOL |
| { |
| addkey($4, 0, $6); |
| } |
| ; |
| modifiers : modifiers modifier |
| | modifier |
| ; |
| modifier : SHIFT { mod |= M_SHIFT; } |
| | CONTROL { mod |= M_CTRL; } |
| | ALT { mod |= M_ALT; } |
| | ALTGR { mod |= M_ALTGR; } |
| | SHIFTL { mod |= M_SHIFTL; } |
| | SHIFTR { mod |= M_SHIFTR; } |
| | CTRLL { mod |= M_CTRLL; } |
| | CTRLR { mod |= M_CTRLR; } |
| ; |
| fullline : KEYCODE NUMBER EQUALS rvalue0 EOL |
| { |
| int i, j; |
| |
| if (rvalct == 1) { |
| /* Some files do not have a keymaps line, and |
| we have to wait until all input has been read |
| before we know which maps to fill. */ |
| key_is_constant[$2] = 1; |
| |
| /* On the other hand, we now have include files, |
| and it should be possible to override lines |
| from an include file. So, kill old defs. */ |
| for (j = 0; j < max_keymap; j++) |
| if (defining[j]) |
| killkey($2, j); |
| } |
| if (keymaps_line_seen) { |
| i = 0; |
| for (j = 0; j < max_keymap; j++) |
| if (defining[j]) { |
| if (rvalct != 1 || i == 0) |
| addkey($2, j, (i < rvalct) ? key_buf[i] : K_HOLE); |
| i++; |
| } |
| if (i < rvalct) |
| lkfatal0(_("too many (%d) entries on one line"), rvalct); |
| } else |
| for (i = 0; i < rvalct; i++) |
| addkey($2, i, key_buf[i]); |
| } |
| ; |
| |
| rvalue0 : |
| | rvalue1 rvalue0 |
| ; |
| rvalue1 : rvalue |
| { |
| if (rvalct >= MAX_NR_KEYMAPS) |
| lkfatal(_("too many keydefinitions on one line")); |
| key_buf[rvalct++] = $1; |
| } |
| ; |
| rvalue : NUMBER |
| {$$=$1;} |
| | UNUMBER |
| {$$=($1 ^ 0xf000); unicode_used=1;} |
| | PLUS NUMBER |
| {$$=add_capslock($2);} |
| | LITERAL |
| {$$=$1;} |
| | PLUS LITERAL |
| {$$=add_capslock($2);} |
| ; |
| %% |
| |
| #include "analyze.c" |
| |
| void |
| usage(void) { |
| fprintf(stderr, _("loadkeys version %s\n" |
| "\n" |
| "Usage: loadkeys [option...] [mapfile...]\n" |
| "\n" |
| "valid options are:\n" |
| "\n" |
| " -c --clearcompose clear kernel compose table\n" |
| " -d --default load \"" DEFMAP "\"\n" |
| " -h --help display this help text\n" |
| " -m --mktable output a \"defkeymap.c\" to stdout\n" |
| " -s --clearstrings clear kernel string table\n" |
| " -u --unicode implicit conversion to Unicode\n" |
| " -v --verbose report the changes\n"), VERSION); |
| exit(1); |
| } |
| |
| char **args; |
| int optd = 0; |
| int optm = 0; |
| int opts = 0; |
| int verbose = 0; |
| int quiet = 0; |
| int nocompose = 0; |
| |
| int |
| main(unsigned int argc, char *argv[]) { |
| const char *short_opts = "cdhmsuqvV"; |
| const struct option long_opts[] = { |
| { "clearcompose", no_argument, NULL, 'c' }, |
| { "default", no_argument, NULL, 'd' }, |
| { "help", no_argument, NULL, 'h' }, |
| { "mktable", no_argument, NULL, 'm' }, |
| { "clearstrings", no_argument, NULL, 's' }, |
| { "unicode", no_argument, NULL, 'u' }, |
| { "quiet", no_argument, NULL, 'q' }, |
| { "verbose", no_argument, NULL, 'v' }, |
| { "version", no_argument, NULL, 'V' }, |
| { NULL, 0, NULL, 0 } |
| }; |
| int c; |
| |
| set_progname(argv[0]); |
| |
| while ((c = getopt_long(argc, argv, |
| short_opts, long_opts, NULL)) != -1) { |
| switch (c) { |
| case 'c': |
| nocompose = 1; |
| break; |
| case 'd': |
| optd = 1; |
| break; |
| case 'm': |
| optm = 1; |
| break; |
| case 's': |
| opts = 1; |
| break; |
| case 'u': |
| set_charset("unicode"); |
| break; |
| case 'q': |
| quiet = 1; |
| break; |
| case 'v': |
| verbose++; |
| break; |
| case 'V': |
| print_version_and_exit(); |
| case 'h': |
| case '?': |
| usage(); |
| } |
| } |
| |
| args = argv + optind - 1; |
| unicode_used = 0; |
| yywrap(); /* set up the first input file, if any */ |
| if (yyparse() || private_error_ct) { |
| fprintf(stderr, _("syntax error in map file\n")); |
| if(!optm) |
| fprintf(stderr, _("key bindings not changed\n")); |
| exit(1); |
| } |
| do_constant(); |
| if(optm) |
| mktable(); |
| else |
| loadkeys(); |
| exit(0); |
| } |
| |
| extern char pathname[]; |
| char *filename; |
| int line_nr = 1; |
| |
| int |
| yyerror(const char *s) { |
| fprintf(stderr, "%s:%d: %s\n", filename, line_nr, s); |
| private_error_ct++; |
| return(0); |
| } |
| |
| /* fatal errors - change to varargs next time */ |
| void |
| lkfatal(const char *s) { |
| fprintf(stderr, "%s: %s:%d: %s\n", progname, filename, line_nr, s); |
| exit(1); |
| } |
| |
| void |
| lkfatal0(const char *s, int d) { |
| fprintf(stderr, "%s: %s:%d: ", progname, filename, line_nr); |
| fprintf(stderr, s, d); |
| fprintf(stderr, "\n"); |
| exit(1); |
| } |
| |
| void |
| lkfatal1(const char *s, const char *s2) { |
| fprintf(stderr, "%s: %s:%d: ", progname, filename, line_nr); |
| fprintf(stderr, s, s2); |
| fprintf(stderr, "\n"); |
| exit(1); |
| } |
| |
| /* Include file handling - unfortunately flex-specific. */ |
| #define MAX_INCLUDE_DEPTH 20 |
| struct infile { |
| int linenr; |
| char *filename; |
| YY_BUFFER_STATE bs; |
| } infile_stack[MAX_INCLUDE_DEPTH]; |
| int infile_stack_ptr = 0; |
| |
| void |
| lk_push(void) { |
| if (infile_stack_ptr >= MAX_INCLUDE_DEPTH) |
| lkfatal(_("includes nested too deeply")); |
| |
| /* preserve current state */ |
| infile_stack[infile_stack_ptr].filename = filename; |
| infile_stack[infile_stack_ptr].linenr = line_nr; |
| infile_stack[infile_stack_ptr++].bs = |
| YY_CURRENT_BUFFER; |
| } |
| |
| int |
| lk_pop(void) { |
| if (--infile_stack_ptr >= 0) { |
| filename = infile_stack[infile_stack_ptr].filename; |
| line_nr = infile_stack[infile_stack_ptr].linenr; |
| yy_delete_buffer(YY_CURRENT_BUFFER); |
| yy_switch_to_buffer(infile_stack[infile_stack_ptr].bs); |
| return 0; |
| } |
| return 1; |
| } |
| |
| /* |
| * Where shall we look for an include file? |
| * Current strategy (undocumented, may change): |
| * |
| * 1. Look for a user-specified LOADKEYS_INCLUDE_PATH |
| * 2. Try . and ../include and ../../include |
| * 3. Try D and D/../include and D/../../include |
| * where D is the directory from where we are loading the current file. |
| * 4. Try KD/include and KD/#/include where KD = DATADIR/KEYMAPDIR. |
| * |
| * Expected layout: |
| * KD has subdirectories amiga, atari, i386, mac, sun, include |
| * KD/include contains architecture-independent stuff |
| * like strings and iso-8859-x compose tables. |
| * KD/i386 has subdirectories qwerty, ... and include; |
| * this latter include dir contains stuff with keycode=... |
| * |
| * (Of course, if the present setup turns out to be reasonable, |
| * then later also the other architectures will grow and get |
| * subdirectories, and the hard-coded i386 below will go again.) |
| * |
| * People that dislike a dozen lookups for loadkeys |
| * can easily do "loadkeys file_with_includes; dumpkeys > my_keymap" |
| * and afterwards use only "loadkeys /fullpath/mykeymap", where no |
| * lookups are required. |
| */ |
| char *include_dirpath0[] = { "", 0 }; |
| char *include_dirpath1[] = { "", "../include/", "../../include/", 0 }; |
| char *include_dirpath2[] = { 0, 0, 0, 0 }; |
| char *include_dirpath3[] = { DATADIR "/" KEYMAPDIR "/include/", |
| DATADIR "/" KEYMAPDIR "/i386/include/", |
| DATADIR "/" KEYMAPDIR "/mac/include/", 0 }; |
| char *include_suffixes[] = { "", ".inc", 0 }; |
| |
| FILE *find_incl_file_near_fn(char *s, char *fn) { |
| FILE *f = NULL; |
| char *t, *te, *t1, *t2; |
| int len; |
| |
| if (!fn) |
| return NULL; |
| |
| t = xstrdup(fn); |
| te = rindex(t, '/'); |
| if (te) { |
| te[1] = 0; |
| include_dirpath2[0] = t; |
| len = strlen(t); |
| include_dirpath2[1] = t1 = xmalloc(len + 12); |
| include_dirpath2[2] = t2 = xmalloc(len + 15); |
| strcpy(t1, t); |
| strcat(t1, "../include/"); |
| strcpy(t2, t); |
| strcat(t2, "../../include/"); |
| f = findfile(s, include_dirpath2, include_suffixes); |
| if (f) |
| return f; |
| } |
| return f; |
| } |
| |
| FILE *find_standard_incl_file(char *s) { |
| FILE *f; |
| |
| f = findfile(s, include_dirpath1, include_suffixes); |
| if (!f) |
| f = find_incl_file_near_fn(s, filename); |
| |
| /* If filename is a symlink, also look near its target. */ |
| if (!f) { |
| char buf[1024], path[1024], *p; |
| int n; |
| |
| n = readlink(filename, buf, sizeof(buf)); |
| if (n > 0 && n < sizeof(buf)) { |
| buf[n] = 0; |
| if (buf[0] == '/') |
| f = find_incl_file_near_fn(s, buf); |
| else if (strlen(filename) + n < sizeof(path)) { |
| strcpy(path, filename); |
| path[sizeof(path)-1] = 0; |
| p = rindex(path, '/'); |
| if (p) |
| p[1] = 0; |
| strcat(path, buf); |
| f = find_incl_file_near_fn(s, path); |
| } |
| } |
| } |
| |
| if (!f) |
| f = findfile(s, include_dirpath3, include_suffixes); |
| return f; |
| } |
| |
| FILE *find_incl_file(char *s) { |
| FILE *f; |
| char *ev; |
| if (!s || !*s) |
| return NULL; |
| if (*s == '/') /* no path required */ |
| return (findfile(s, include_dirpath0, include_suffixes)); |
| |
| if((ev = getenv("LOADKEYS_INCLUDE_PATH")) != NULL) { |
| /* try user-specified path */ |
| char *user_dir[2] = { 0, 0 }; |
| while(ev) { |
| char *t = index(ev, ':'); |
| char sv; |
| if (t) { |
| sv = *t; |
| *t = 0; |
| } |
| user_dir[0] = ev; |
| if (*ev) |
| f = findfile(s, user_dir, include_suffixes); |
| else /* empty string denotes system path */ |
| f = find_standard_incl_file(s); |
| if (f) |
| return f; |
| if (t) |
| *t++ = sv; |
| ev = t; |
| } |
| return NULL; |
| } |
| return find_standard_incl_file(s); |
| } |
| |
| void |
| open_include(char *s) { |
| char *t, *te; |
| |
| if (verbose) |
| /* start reading include file */ |
| fprintf(stderr, _("switching to %s\n"), s); |
| |
| lk_push(); |
| |
| yyin = find_incl_file(s); |
| if (!yyin) |
| lkfatal1(_("cannot open include file %s"), s); |
| filename = xstrdup(pathname); |
| line_nr = 1; |
| yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); |
| } |
| |
| /* String file handling - flex-specific. */ |
| int in_string = 0; |
| |
| void |
| lk_scan_string(char *s) { |
| lk_push(); |
| in_string = 1; |
| yy_scan_string(s); |
| } |
| |
| void |
| lk_end_string(void) { |
| lk_pop(); |
| in_string = 0; |
| } |
| |
| char *dirpath[] = { "", DATADIR "/" KEYMAPDIR "/**", KERNDIR "/", 0 }; |
| char *suffixes[] = { "", ".map", 0 }; |
| extern FILE *findfile(char *fnam, char **dirpath, char **suffixes); |
| |
| #undef yywrap |
| int |
| yywrap(void) { |
| FILE *f; |
| static int first_file = 1; /* ugly kludge flag */ |
| |
| if (in_string) { |
| lk_end_string(); |
| return 0; |
| } |
| |
| if (infile_stack_ptr > 0) { |
| lk_pop(); |
| return 0; |
| } |
| |
| line_nr = 1; |
| if (optd) { |
| /* first read default map - search starts in . */ |
| optd = 0; |
| if((f = findfile(DEFMAP, dirpath, suffixes)) == NULL) { |
| fprintf(stderr, _("Cannot find %s\n"), DEFMAP); |
| exit(1); |
| } |
| goto gotf; |
| } |
| if (*args) |
| args++; |
| if (!*args) |
| return 1; |
| if (!strcmp(*args, "-")) { |
| f = stdin; |
| strcpy(pathname, "<stdin>"); |
| } else if ((f = findfile(*args, dirpath, suffixes)) == NULL) { |
| fprintf(stderr, _("cannot open file %s\n"), *args); |
| exit(1); |
| } |
| /* |
| Can't use yyrestart if this is called before entering yyparse() |
| I think assigning directly to yyin isn't necessarily safe in |
| other situations, hence the flag. |
| */ |
| gotf: |
| filename = xstrdup(pathname); |
| if (!quiet) |
| fprintf(stderr, _("Loading %s\n"), pathname); |
| if (first_file) { |
| yyin = f; |
| first_file = 0; |
| } else |
| yyrestart(f); |
| return 0; |
| } |
| |
| static void |
| addmap(int i, int explicit) { |
| if (i < 0 || i >= MAX_NR_KEYMAPS) |
| lkfatal0(_("addmap called with bad index %d"), i); |
| |
| if (!defining[i]) { |
| if (keymaps_line_seen && !explicit) |
| lkfatal0(_("adding map %d violates explicit keymaps line"), i); |
| |
| defining[i] = 1; |
| if (max_keymap <= i) |
| max_keymap = i+1; |
| } |
| } |
| |
| /* unset a key */ |
| static void |
| killkey(int index, int table) { |
| /* roughly: addkey(index, table, K_HOLE); */ |
| |
| if (index < 0 || index >= NR_KEYS) |
| lkfatal0(_("killkey called with bad index %d"), index); |
| if (table < 0 || table >= MAX_NR_KEYMAPS) |
| lkfatal0(_("killkey called with bad table %d"), table); |
| if (key_map[table]) |
| (key_map[table])[index] = K_HOLE; |
| if (keymap_was_set[table]) |
| (keymap_was_set[table])[index] = 0; |
| } |
| |
| static void |
| addkey(int index, int table, int keycode) { |
| int i; |
| |
| if (keycode == -1) |
| return; |
| if (index < 0 || index >= NR_KEYS) |
| lkfatal0(_("addkey called with bad index %d"), index); |
| if (table < 0 || table >= MAX_NR_KEYMAPS) |
| lkfatal0(_("addkey called with bad table %d"), table); |
| |
| if (!defining[table]) |
| addmap(table, 0); |
| if (!key_map[table]) { |
| key_map[table] = (u_short *)xmalloc(NR_KEYS * sizeof(u_short)); |
| for (i = 0; i < NR_KEYS; i++) |
| (key_map[table])[i] = K_HOLE; |
| } |
| if (!keymap_was_set[table]) { |
| keymap_was_set[table] = (char *) xmalloc(NR_KEYS); |
| for (i = 0; i < NR_KEYS; i++) |
| (keymap_was_set[table])[i] = 0; |
| } |
| |
| if (alt_is_meta && keycode == K_HOLE && (keymap_was_set[table])[index]) |
| return; |
| |
| (key_map[table])[index] = keycode; |
| (keymap_was_set[table])[index] = 1; |
| |
| if (alt_is_meta) { |
| int alttable = table | M_ALT; |
| int type = KTYP(keycode); |
| int val = KVAL(keycode); |
| char *p; |
| if (alttable != table && defining[alttable] && |
| (!keymap_was_set[alttable] || |
| !(keymap_was_set[alttable])[index]) && |
| (type == KT_LATIN || type == KT_LETTER) && val < 128) |
| addkey(index, alttable, K(KT_META, val)); |
| } |
| } |
| |
| static void |
| addfunc(struct kbsentry kbs) { |
| int sh, i, x; |
| char *p, *q, *r; |
| |
| x = kbs.kb_func; |
| |
| if (x >= MAX_NR_FUNC) { |
| fprintf(stderr, _("%s: addfunc called with bad func %d\n"), |
| progname, kbs.kb_func); |
| exit(1); |
| } |
| |
| q = func_table[x]; |
| if (q) { /* throw out old previous def */ |
| sh = strlen(q) + 1; |
| p = q + sh; |
| while (p < fp) |
| *q++ = *p++; |
| fp -= sh; |
| |
| for (i = x + 1; i < MAX_NR_FUNC; i++) |
| if (func_table[i]) |
| func_table[i] -= sh; |
| } |
| |
| p = func_buf; /* find place for new def */ |
| for (i = 0; i < x; i++) |
| if (func_table[i]) { |
| p = func_table[i]; |
| while(*p++); |
| } |
| func_table[x] = p; |
| sh = strlen(kbs.kb_string) + 1; |
| if (fp + sh > func_buf + sizeof(func_buf)) { |
| fprintf(stderr, |
| _("%s: addfunc: func_buf overflow\n"), progname); |
| exit(1); |
| } |
| q = fp; |
| fp += sh; |
| r = fp; |
| while (q > p) |
| *--r = *--q; |
| strcpy(p, kbs.kb_string); |
| for (i = x + 1; i < MAX_NR_FUNC; i++) |
| if (func_table[i]) |
| func_table[i] += sh; |
| } |
| |
| static void |
| compose(int diacr, int base, int res) { |
| struct kbdiacr *p; |
| if (accent_table_size == MAX_DIACR) { |
| fprintf(stderr, _("compose table overflow\n")); |
| exit(1); |
| } |
| p = &accent_table[accent_table_size++]; |
| p->diacr = diacr; |
| p->base = base; |
| p->result = res; |
| } |
| |
| static int |
| defkeys(int fd) { |
| struct kbentry ke; |
| int ct = 0; |
| int i,j,fail; |
| int oldm; |
| |
| if (unicode_used) { |
| /* Switch keyboard mode for a moment - |
| do not complain about errors. |
| Do not attempt a reset if the change failed. */ |
| if (ioctl(fd, KDGKBMODE, &oldm) |
| || (oldm != K_UNICODE && ioctl(fd, KDSKBMODE, K_UNICODE))) |
| oldm = K_UNICODE; |
| } |
| |
| for(i=0; i<MAX_NR_KEYMAPS; i++) { |
| if (key_map[i]) { |
| for(j=0; j<NR_KEYS; j++) { |
| if ((keymap_was_set[i])[j]) { |
| ke.kb_index = j; |
| ke.kb_table = i; |
| ke.kb_value = (key_map[i])[j]; |
| |
| fail = ioctl(fd, KDSKBENT, (unsigned long)&ke); |
| if (fail) { |
| if (errno == EPERM) { |
| fprintf(stderr, |
| _("Keymap %d: Permission denied\n"), i); |
| j = NR_KEYS; |
| continue; |
| } |
| perror("KDSKBENT"); |
| } else |
| ct++; |
| if(verbose) |
| printf("keycode %d, table %d = %d%s\n", j, i, |
| (key_map[i])[j], fail ? _(" FAILED") : ""); |
| else if (fail) |
| fprintf(stderr, |
| _("failed to bind key %d to value %d\n"), |
| j, (key_map[i])[j]); |
| } |
| } |
| } else if (keymaps_line_seen && !defining[i]) { |
| /* deallocate keymap */ |
| ke.kb_index = 0; |
| ke.kb_table = i; |
| ke.kb_value = K_NOSUCHMAP; |
| |
| if (verbose > 1) |
| printf(_("deallocate keymap %d\n"), i); |
| |
| if(ioctl(fd, KDSKBENT, (unsigned long)&ke)) { |
| if (errno != EINVAL) { |
| perror("KDSKBENT"); |
| fprintf(stderr, |
| _("%s: could not deallocate keymap %d\n"), |
| progname, i); |
| exit(1); |
| } |
| /* probably an old kernel */ |
| /* clear keymap by hand */ |
| for (j = 0; j < NR_KEYS; j++) { |
| ke.kb_index = j; |
| ke.kb_table = i; |
| ke.kb_value = K_HOLE; |
| if(ioctl(fd, KDSKBENT, (unsigned long)&ke)) { |
| if (errno == EINVAL && i >= 16) |
| break; /* old kernel */ |
| perror("KDSKBENT"); |
| fprintf(stderr, |
| _("%s: cannot deallocate or clear keymap\n"), |
| progname); |
| exit(1); |
| } |
| } |
| } |
| } |
| } |
| |
| if(unicode_used && oldm != K_UNICODE) { |
| if (ioctl(fd, KDSKBMODE, oldm)) { |
| fprintf(stderr, _("%s: failed to restore keyboard mode\n"), |
| progname); |
| } |
| fprintf(stderr, _("%s: warning: this map uses Unicode symbols\n" |
| " (perhaps you want to do `kbd_mode -u'?)\n"), |
| progname); |
| } |
| return ct; |
| } |
| |
| static char * |
| ostr(char *s) { |
| int lth = strlen(s); |
| char *ns0 = xmalloc(4*lth + 1); |
| char *ns = ns0; |
| |
| while(*s) { |
| switch(*s) { |
| case '\n': |
| *ns++ = '\\'; |
| *ns++ = 'n'; |
| break; |
| case '\033': |
| *ns++ = '\\'; |
| *ns++ = '0'; |
| *ns++ = '3'; |
| *ns++ = '3'; |
| break; |
| default: |
| *ns++ = *s; |
| } |
| s++; |
| } |
| *ns = 0; |
| return ns0; |
| } |
| |
| static int |
| deffuncs(int fd){ |
| int i, ct = 0; |
| char *p; |
| |
| for (i = 0; i < MAX_NR_FUNC; i++) { |
| kbs_buf.kb_func = i; |
| if ((p = func_table[i])) { |
| strcpy(kbs_buf.kb_string, p); |
| if (ioctl(fd, KDSKBSENT, (unsigned long)&kbs_buf)) |
| fprintf(stderr, _("failed to bind string '%s' to function %s\n"), |
| ostr(kbs_buf.kb_string), syms[KT_FN].table[kbs_buf.kb_func]); |
| else |
| ct++; |
| } else if (opts) { |
| kbs_buf.kb_string[0] = 0; |
| if (ioctl(fd, KDSKBSENT, (unsigned long)&kbs_buf)) |
| fprintf(stderr, _("failed to clear string %s\n"), |
| syms[KT_FN].table[kbs_buf.kb_func]); |
| else |
| ct++; |
| } |
| } |
| return ct; |
| } |
| |
| static int |
| defdiacs(int fd){ |
| struct kbdiacrs kd; |
| int i; |
| |
| kd.kb_cnt = accent_table_size; |
| if (kd.kb_cnt > MAX_DIACR) { |
| kd.kb_cnt = MAX_DIACR; |
| fprintf(stderr, _("too many compose definitions\n")); |
| } |
| for (i = 0; i < kd.kb_cnt; i++) |
| kd.kbdiacr[i] = accent_table[i]; |
| |
| if(ioctl(fd, KDSKBDIACR, (unsigned long) &kd)) { |
| perror("KDSKBDIACR"); |
| exit(1); |
| } |
| return kd.kb_cnt; |
| } |
| |
| void |
| do_constant_key (int i, u_short key) { |
| int typ, val, j; |
| |
| typ = KTYP(key); |
| val = KVAL(key); |
| if ((typ == KT_LATIN || typ == KT_LETTER) && |
| ((val >= 'a' && val <= 'z') || |
| (val >= 'A' && val <= 'Z'))) { |
| 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<max_keymap; j++) { |
| if (!defining[j]) |
| continue; |
| if (j > 0 && |
| keymap_was_set[j] && (keymap_was_set[j])[i]) |
| continue; |
| addkey(i, j, defs[j%16]); |
| } |
| } else { |
| /* do this also for keys like Escape, |
| as promised in the man page */ |
| for (j=1; j<max_keymap; j++) |
| if(defining[j] && |
| (!(keymap_was_set[j]) || !(keymap_was_set[j])[i])) |
| addkey(i, j, key); |
| } |
| } |
| |
| static void |
| do_constant (void) { |
| int i, r0 = 0; |
| |
| if (keymaps_line_seen) |
| while (r0 < max_keymap && !defining[r0]) |
| r0++; |
| |
| for (i=0; i<NR_KEYS; i++) { |
| if (key_is_constant[i]) { |
| u_short key; |
| if (!key_map[r0]) |
| lkfatal(_("impossible error in do_constant")); |
| key = (key_map[r0])[i]; |
| do_constant_key (i, key); |
| } |
| } |
| } |
| |
| static void |
| loadkeys (void) { |
| int fd; |
| int keyct, funcct, diacct; |
| |
| fd = getfd(NULL); |
| keyct = defkeys(fd); |
| funcct = deffuncs(fd); |
| if (accent_table_size > 0 || nocompose) |
| diacct = defdiacs(fd); |
| if (verbose) { |
| printf(_("\nChanged %d %s and %d %s.\n"), |
| keyct, (keyct == 1) ? _("key") : _("keys"), |
| funcct, (funcct == 1) ? _("string") : _("strings")); |
| if (accent_table_size > 0 || nocompose) |
| printf(_("Loaded %d compose %s.\n"), diacct, |
| (diacct == 1) ? _("definition") : _("definitions")); |
| else |
| printf(_("(No change in compose definitions.)\n")); |
| } |
| } |
| |
| static void strings_as_usual(void) { |
| /* |
| * 26 strings, mostly inspired by the VT100 family |
| */ |
| char *stringvalues[30] = { |
| /* F1 .. F20 */ |
| "\033[[A", "\033[[B", "\033[[C", "\033[[D", "\033[[E", |
| "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~", |
| "\033[23~", "\033[24~", "\033[25~", "\033[26~", |
| "\033[28~", "\033[29~", |
| "\033[31~", "\033[32~", "\033[33~", "\033[34~", |
| /* Find, Insert, Remove, Select, Prior */ |
| "\033[1~", "\033[2~", "\033[3~", "\033[4~", "\033[5~", |
| /* Next, Macro, Help, Do, Pause */ |
| "\033[6~", 0, 0, 0, 0 |
| }; |
| int i; |
| for (i=0; i<30; i++) if(stringvalues[i]) { |
| struct kbsentry ke; |
| ke.kb_func = i; |
| strncpy(ke.kb_string, stringvalues[i], sizeof(ke.kb_string)); |
| ke.kb_string[sizeof(ke.kb_string)-1] = 0; |
| addfunc(ke); |
| } |
| } |
| |
| static void |
| compose_as_usual(char *charset) { |
| if (charset && strcmp(charset, "iso-8859-1")) { |
| fprintf(stderr, _("loadkeys: don't know how to compose for %s\n"), |
| charset); |
| exit(1); |
| } else { |
| struct ccc { |
| char c1, c2, c3; |
| } def_latin1_composes[68] = { |
| { '`', 'A', 0300 }, { '`', 'a', 0340 }, |
| { '\'', 'A', 0301 }, { '\'', 'a', 0341 }, |
| { '^', 'A', 0302 }, { '^', 'a', 0342 }, |
| { '~', 'A', 0303 }, { '~', 'a', 0343 }, |
| { '"', 'A', 0304 }, { '"', 'a', 0344 }, |
| { 'O', 'A', 0305 }, { 'o', 'a', 0345 }, |
| { '0', 'A', 0305 }, { '0', 'a', 0345 }, |
| { 'A', 'A', 0305 }, { 'a', 'a', 0345 }, |
| { 'A', 'E', 0306 }, { 'a', 'e', 0346 }, |
| { ',', 'C', 0307 }, { ',', 'c', 0347 }, |
| { '`', 'E', 0310 }, { '`', 'e', 0350 }, |
| { '\'', 'E', 0311 }, { '\'', 'e', 0351 }, |
| { '^', 'E', 0312 }, { '^', 'e', 0352 }, |
| { '"', 'E', 0313 }, { '"', 'e', 0353 }, |
| { '`', 'I', 0314 }, { '`', 'i', 0354 }, |
| { '\'', 'I', 0315 }, { '\'', 'i', 0355 }, |
| { '^', 'I', 0316 }, { '^', 'i', 0356 }, |
| { '"', 'I', 0317 }, { '"', 'i', 0357 }, |
| { '-', 'D', 0320 }, { '-', 'd', 0360 }, |
| { '~', 'N', 0321 }, { '~', 'n', 0361 }, |
| { '`', 'O', 0322 }, { '`', 'o', 0362 }, |
| { '\'', 'O', 0323 }, { '\'', 'o', 0363 }, |
| { '^', 'O', 0324 }, { '^', 'o', 0364 }, |
| { '~', 'O', 0325 }, { '~', 'o', 0365 }, |
| { '"', 'O', 0326 }, { '"', 'o', 0366 }, |
| { '/', 'O', 0330 }, { '/', 'o', 0370 }, |
| { '`', 'U', 0331 }, { '`', 'u', 0371 }, |
| { '\'', 'U', 0332 }, { '\'', 'u', 0372 }, |
| { '^', 'U', 0333 }, { '^', 'u', 0373 }, |
| { '"', 'U', 0334 }, { '"', 'u', 0374 }, |
| { '\'', 'Y', 0335 }, { '\'', 'y', 0375 }, |
| { 'T', 'H', 0336 }, { 't', 'h', 0376 }, |
| { 's', 's', 0337 }, { '"', 'y', 0377 }, |
| { 's', 'z', 0337 }, { 'i', 'j', 0377 } |
| }; |
| int i; |
| for(i=0; i<68; i++) { |
| struct ccc p = def_latin1_composes[i]; |
| compose(p.c1, p.c2, p.c3); |
| } |
| } |
| } |
| |
| /* |
| * mktable.c |
| * |
| */ |
| static char *modifiers[8] = { |
| "shift", "altgr", "ctrl", "alt", "shl", "shr", "ctl", "ctr" |
| }; |
| |
| static char *mk_mapname(char mod) { |
| static char buf[60]; |
| int i; |
| |
| if (!mod) |
| return "plain"; |
| buf[0] = 0; |
| for (i=0; i<8; i++) |
| if (mod & (1<<i)) { |
| if (buf[0]) |
| strcat(buf, "_"); |
| strcat(buf, modifiers[i]); |
| } |
| return buf; |
| } |
| |
| |
| static void |
| outchar (unsigned char c, int comma) { |
| printf("'"); |
| printf((c == '\'' || c == '\\') ? "\\%c" : isgraph(c) ? "%c" |
| : "\\%03o", c); |
| printf(comma ? "', " : "'"); |
| } |
| |
| static void |
| mktable () { |
| int i, imax, j; |
| |
| struct kbsentry kbs; |
| u_char *p; |
| int maxfunc; |
| unsigned int keymap_count = 0; |
| |
| printf( |
| /* not to be translated... */ |
| "/* Do not edit this file! It was automatically generated by */\n"); |
| printf( |
| "/* loadkeys --mktable defkeymap.map > defkeymap.c */\n\n"); |
| printf("#include <linux/types.h>\n"); |
| printf("#include <linux/keyboard.h>\n"); |
| printf("#include <linux/kd.h>\n\n"); |
| |
| for (i = 0; i < MAX_NR_KEYMAPS; i++) |
| if (key_map[i]) { |
| keymap_count++; |
| if (i) |
| printf("static "); |
| printf("u_short %s_map[NR_KEYS] = {", mk_mapname(i)); |
| for (j = 0; j < NR_KEYS; j++) { |
| if (!(j % 8)) |
| printf("\n"); |
| printf("\t0x%04x,", U((key_map[i])[j])); |
| } |
| printf("\n};\n\n"); |
| } |
| |
| for (imax = MAX_NR_KEYMAPS-1; imax > 0; imax--) |
| if (key_map[imax]) |
| break; |
| printf("ushort *key_maps[MAX_NR_KEYMAPS] = {"); |
| for (i = 0; i <= imax; i++) { |
| printf((i%4) ? " " : "\n\t"); |
| if (key_map[i]) |
| printf("%s_map,", mk_mapname(i)); |
| else |
| printf("0,"); |
| } |
| if (imax < MAX_NR_KEYMAPS-1) |
| printf("\t0"); |
| printf("\n};\n\nunsigned int keymap_count = %d;\n\n", keymap_count); |
| |
| /* uglified just for xgettext - it complains about nonterminated strings */ |
| printf( |
| "/*\n" |
| " * Philosophy: most people do not define more strings, but they who do\n" |
| " * often want quite a lot of string space. So, we statically allocate\n" |
| " * the default and allocate dynamically in chunks of 512 bytes.\n" |
| " */\n" |
| "\n"); |
| for (maxfunc = MAX_NR_FUNC; maxfunc; maxfunc--) |
| if(func_table[maxfunc-1]) |
| break; |
| |
| printf("char func_buf[] = {\n"); |
| for (i = 0; i < maxfunc; i++) { |
| p = func_table[i]; |
| if (p) { |
| printf("\t"); |
| for ( ; *p; p++) |
| outchar(*p, 1); |
| printf("0, \n"); |
| } |
| } |
| if (!maxfunc) |
| printf("\t0\n"); |
| printf("};\n\n"); |
| |
| printf( |
| "char *funcbufptr = func_buf;\n" |
| "int funcbufsize = sizeof(func_buf);\n" |
| "int funcbufleft = 0; /* space left */\n" |
| "\n"); |
| |
| printf("char *func_table[MAX_NR_FUNC] = {\n"); |
| for (i = 0; i < maxfunc; i++) { |
| if (func_table[i]) |
| printf("\tfunc_buf + %d,\n", func_table[i] - func_buf); |
| else |
| printf("\t0,\n"); |
| } |
| if (maxfunc < MAX_NR_FUNC) |
| printf("\t0,\n"); |
| printf("};\n"); |
| |
| printf("\nstruct kbdiacr accent_table[MAX_DIACR] = {\n"); |
| for (i = 0; i < accent_table_size; i++) { |
| printf("\t{"); |
| outchar(accent_table[i].diacr, 1); |
| outchar(accent_table[i].base, 1); |
| outchar(accent_table[i].result, 0); |
| printf("},"); |
| if(i%2) printf("\n"); |
| } |
| if(i%2) printf("\n"); |
| printf("};\n\n"); |
| printf("unsigned int accent_table_size = %d;\n", |
| accent_table_size); |
| |
| exit(0); |
| } |