| #include "config.h" |
| |
| #include <linux/keyboard.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include "keymap.h" |
| |
| #include "contextP.h" |
| #include "ksyms.h" |
| #include "nls.h" |
| |
| #include "syms.cp1250.h" |
| #include "syms.ethiopic.h" |
| #include "syms.iso8859_15.h" |
| #include "syms.iso8859_5.h" |
| #include "syms.iso8859_7.h" |
| #include "syms.iso8859_8.h" |
| #include "syms.iso8859_9.h" |
| #include "syms.koi8.h" |
| #include "syms.latin1.h" |
| #include "syms.latin2.h" |
| #include "syms.latin3.h" |
| #include "syms.latin4.h" |
| #include "syms.mazovia.h" |
| #include "syms.sami.h" |
| #include "syms.thai.h" |
| |
| #include "syms.synonyms.h" |
| |
| #include "syms.ktyp.h" |
| |
| #define E(x) \ |
| { \ |
| x, sizeof(x) / sizeof(x[0]) \ |
| } |
| |
| const syms_entry syms[] = { |
| E(iso646_syms), /* KT_LATIN */ |
| E(fn_syms), /* KT_FN */ |
| E(spec_syms), /* KT_SPEC */ |
| E(pad_syms), /* KT_PAD */ |
| E(dead_syms), /* KT_DEAD */ |
| E(cons_syms), /* KT_CONS */ |
| E(cur_syms), /* KT_CUR */ |
| E(shift_syms), /* KT_SHIFT */ |
| { 0, 0 }, /* KT_META */ |
| E(ascii_syms), /* KT_ASCII */ |
| E(lock_syms), /* KT_LOCK */ |
| { 0, 0 }, /* KT_LETTER */ |
| E(sticky_syms), /* KT_SLOCK */ |
| { 0, 0 }, /* */ |
| E(brl_syms) /* KT_BRL */ |
| }; |
| |
| #undef E |
| |
| const unsigned int syms_size = sizeof(syms) / sizeof(syms_entry); |
| const unsigned int syn_size = sizeof(synonyms) / sizeof(synonyms[0]); |
| |
| const struct cs { |
| const char *charset; |
| const sym *charnames; |
| const int start; |
| } charsets[] = { |
| { "iso-8859-1", latin1_syms, 160 }, |
| { "iso-8859-2", latin2_syms, 160 }, |
| { "iso-8859-3", latin3_syms, 160 }, |
| { "iso-8859-4", latin4_syms, 160 }, |
| { "iso-8859-5", iso8859_5_syms, 160 }, |
| { "iso-8859-7", iso8859_7_syms, 160 }, |
| { "iso-8859-8", iso8859_8_syms, 160 }, |
| { "iso-8859-9", iso8859_9_syms, 160 }, |
| { "iso-8859-10", latin6_syms, 160 }, |
| { "iso-8859-15", iso8859_15_syms, 160 }, |
| { "mazovia", mazovia_syms, 128 }, |
| { "cp-1250", cp1250_syms, 128 }, |
| { "koi8-r", koi8_syms, 128 }, |
| { "koi8-u", koi8_syms, 128 }, |
| { "tis-620", tis_620_syms, 160 }, /* thai */ |
| { "iso-10646-18", iso10646_18_syms, 159 }, /* ethiopic */ |
| { "iso-ir-197", iso_ir_197_syms, 160 }, /* sami */ |
| { "iso-ir-209", iso_ir_209_syms, 160 }, /* sami */ |
| }; |
| |
| static const unsigned int charsets_size = sizeof(charsets) / sizeof(charsets[0]); |
| |
| /* Functions for both dumpkeys and loadkeys. */ |
| |
| void lk_list_charsets(FILE *f) |
| { |
| int lth, ct; |
| unsigned int i, j; |
| char *mm[] = { "iso-8859-", "koi8-" }; |
| |
| for (j = 0; j < sizeof(mm) / sizeof(mm[0]); j++) { |
| if (j) |
| fprintf(f, ","); |
| fprintf(f, "%s{", mm[j]); |
| ct = 0; |
| lth = strlen(mm[j]); |
| for (i = 1; i < charsets_size; i++) { |
| if (!strncmp(charsets[i].charset, mm[j], lth)) { |
| if (ct++) |
| fprintf(f, ","); |
| fprintf(f, "%s", charsets[i].charset + lth); |
| } |
| } |
| fprintf(f, "}"); |
| } |
| for (i = 0; i < charsets_size; i++) { |
| for (j = 0; j < sizeof(mm) / sizeof(mm[0]); j++) { |
| lth = strlen(mm[j]); |
| if (!strncmp(charsets[i].charset, mm[j], lth)) |
| goto nxti; |
| } |
| fprintf(f, ",%s", charsets[i].charset); |
| nxti:; |
| } |
| fprintf(f, "\n"); |
| } |
| |
| const char * |
| lk_get_charset(struct lk_ctx *ctx) |
| { |
| if (!ctx || ctx->charset >= charsets_size) |
| return NULL; |
| |
| return charsets[ctx->charset].charset; |
| } |
| |
| int lk_set_charset(struct lk_ctx *ctx, const char *charset) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < charsets_size; i++) { |
| if (!strcasecmp(charsets[i].charset, charset)) { |
| ctx->charset = i; |
| return 0; |
| } |
| } |
| return 1; |
| } |
| |
| unsigned int |
| get_sym_size(struct lk_ctx *ctx, unsigned int ktype) |
| { |
| if (ktype >= syms_size) { |
| ERR(ctx, _("unable to get symbol by wrong type: %d"), ktype); |
| return 0; |
| } |
| |
| return syms[ktype].size; |
| } |
| |
| const char * |
| get_sym(struct lk_ctx *ctx, unsigned int ktype, unsigned int index) |
| { |
| if (!get_sym_size(ctx, ktype)) |
| return NULL; |
| |
| if (index >= syms[ktype].size) { |
| ERR(ctx, _("unable to get symbol of %d type by wrong index: %d"), ktype, index); |
| return NULL; |
| } |
| |
| return syms[ktype].table[index]; |
| } |
| |
| char * |
| lk_get_sym(struct lk_ctx *ctx, unsigned int ktype, unsigned int index) |
| { |
| const char *ksym = get_sym(ctx, ktype, index); |
| return (ksym ? strdup(ksym) : NULL); |
| } |
| |
| const char * |
| codetoksym(struct lk_ctx *ctx, int code) |
| { |
| unsigned int i; |
| int j; |
| sym *p; |
| |
| if (code < 0) |
| return NULL; |
| |
| if (code < 0x1000) { /* "traditional" keysym */ |
| if (code < 0x80) |
| return get_sym(ctx, KT_LATIN, code); |
| |
| if (KTYP(code) == KT_META) |
| return NULL; |
| |
| if (KTYP(code) == KT_LETTER) |
| code = K(KT_LATIN, KVAL(code)); |
| |
| if (KTYP(code) > KT_LATIN) |
| return get_sym(ctx, KTYP(code), KVAL(code)); |
| |
| i = ctx->charset; |
| p = (sym *)charsets[i].charnames; |
| if (p && (KVAL(code) >= charsets[i].start)) { |
| p += KVAL(code) - charsets[i].start; |
| if (p->name[0]) |
| return p->name; |
| } |
| } |
| |
| else { /* Unicode keysym */ |
| code ^= 0xf000; |
| |
| if (code < 0x80) |
| return get_sym(ctx, KT_LATIN, code); |
| |
| for (i = 0; i < charsets_size; i++) { |
| p = (sym *)charsets[i].charnames; |
| if (p) { |
| for (j = charsets[i].start; j < 256; j++, p++) { |
| if (p->uni == code && p->name[0]) |
| return p->name; |
| } |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| char * |
| lk_code_to_ksym(struct lk_ctx *ctx, int code) |
| { |
| const char *s; |
| |
| s = codetoksym(ctx, code); |
| if (!s) |
| return NULL; |
| |
| return strdup(s); |
| } |
| |
| /* Functions for loadkeys. */ |
| |
| static int |
| kt_latin(struct lk_ctx *ctx, const char *s, int direction) |
| { |
| unsigned int i, max; |
| |
| sym *p = (sym *)charsets[ctx->charset].charnames; |
| |
| max = (direction == TO_UNICODE ? 128 : 256); // TODO(dmage): is 256 valid for ethiopic charset? |
| |
| for (i = charsets[ctx->charset].start; i < max; i++, p++) { |
| if (p->name[0] && !strcmp(s, p->name)) |
| return K(KT_LATIN, i); |
| } |
| |
| max = (direction == TO_UNICODE ? 128 : syms[KT_LATIN].size); |
| |
| for (i = 0; i < max; i++) { |
| if (!strcmp(s, get_sym(ctx, KT_LATIN, i))) |
| return K(KT_LATIN, i); |
| } |
| |
| return -1; |
| } |
| |
| int ksymtocode(struct lk_ctx *ctx, const char *s, int direction) |
| { |
| unsigned int i, j; |
| int n; |
| int keycode; |
| sym *p; |
| |
| if (direction == TO_AUTO) |
| direction = (ctx->flags & LK_FLAG_PREFER_UNICODE) |
| ? TO_UNICODE |
| : TO_8BIT; |
| |
| if (!strncmp(s, "Meta_", 5)) { |
| keycode = ksymtocode(ctx, s + 5, TO_8BIT); |
| if (KTYP(keycode) == KT_LATIN) |
| return K(KT_META, KVAL(keycode)); |
| |
| /* Avoid error messages for Meta_acute with UTF-8 */ |
| else if (direction == TO_UNICODE) |
| return (0); |
| |
| /* fall through to error printf */ |
| } |
| |
| if ((n = kt_latin(ctx, s, direction)) >= 0) { |
| return n; |
| } |
| |
| for (i = 1; i < syms_size; i++) { |
| for (j = 0; j < syms[i].size; j++) { |
| if (!strcmp(s, get_sym(ctx, i, j))) |
| return K(i, j); |
| } |
| } |
| |
| for (i = 0; i < syn_size; i++) |
| if (!strcmp(s, synonyms[i].synonym)) |
| return ksymtocode(ctx, synonyms[i].official_name, direction); |
| |
| if (direction == TO_UNICODE) { |
| i = ctx->charset; |
| p = (sym *)charsets[i].charnames; |
| if (p) { |
| for (j = charsets[i].start; j < 256; j++, p++) { |
| if (!strcmp(s, p->name)) |
| return (p->uni ^ 0xf000); |
| } |
| } |
| |
| /* not found in the current charset, maybe we'll have good luck in others? */ |
| for (i = 0; i < charsets_size; i++) { |
| if (i == ctx->charset) { |
| continue; |
| } |
| p = (sym *)charsets[i].charnames; |
| if (p) { |
| for (j = charsets[i].start; j < 256; j++, p++) { |
| if (!strcmp(s, p->name)) |
| return (p->uni ^ 0xf000); |
| } |
| } |
| } |
| } else /* if (!chosen_charset[0]) */ { |
| /* note: some keymaps use latin1 but with euro, |
| so set_charset() would fail */ |
| /* note: some keymaps with charset line still use |
| symbols from more than one character set, |
| so we cannot have the `if (!chosen_charset[0])' here */ |
| |
| for (i = 0; i < 256 - 160; i++) |
| if (!strcmp(s, latin1_syms[i].name)) { |
| INFO(ctx, _("assuming iso-8859-1 %s"), s); |
| return K(KT_LATIN, 160 + i); |
| } |
| |
| for (i = 0; i < 256 - 160; i++) |
| if (!strcmp(s, iso8859_15_syms[i].name)) { |
| INFO(ctx, _("assuming iso-8859-15 %s"), s); |
| return K(KT_LATIN, 160 + i); |
| } |
| |
| for (i = 0; i < 256 - 160; i++) |
| if (!strcmp(s, latin2_syms[i].name)) { |
| INFO(ctx, _("assuming iso-8859-2 %s"), s); |
| return K(KT_LATIN, 160 + i); |
| } |
| |
| for (i = 0; i < 256 - 160; i++) |
| if (!strcmp(s, latin3_syms[i].name)) { |
| INFO(ctx, _("assuming iso-8859-3 %s"), s); |
| return K(KT_LATIN, 160 + i); |
| } |
| |
| for (i = 0; i < 256 - 160; i++) |
| if (!strcmp(s, latin4_syms[i].name)) { |
| INFO(ctx, _("assuming iso-8859-4 %s"), s); |
| return K(KT_LATIN, 160 + i); |
| } |
| } |
| |
| ERR(ctx, _("unknown keysym '%s'\n"), s); |
| |
| return CODE_FOR_UNKNOWN_KSYM; |
| } |
| |
| int lk_ksym_to_unicode(struct lk_ctx *ctx, const char *s) |
| { |
| return ksymtocode(ctx, s, TO_UNICODE); |
| } |
| |
| int convert_code(struct lk_ctx *ctx, int code, int direction) |
| { |
| const char *ksym; |
| int unicode_forced = (direction == TO_UNICODE); |
| int input_is_unicode = (code >= 0x1000); |
| int result; |
| |
| if (direction == TO_AUTO) |
| direction = (ctx->flags & LK_FLAG_PREFER_UNICODE) |
| ? TO_UNICODE |
| : TO_8BIT; |
| |
| if (KTYP(code) == KT_META) |
| return code; |
| else if (!input_is_unicode && code < 0x80) |
| /* basic ASCII is fine in every situation */ |
| return code; |
| else if (input_is_unicode && (code ^ 0xf000) < 0x80) |
| /* so is Unicode "Basic Latin" */ |
| return code ^ 0xf000; |
| else if ((input_is_unicode && direction == TO_UNICODE) || |
| (!input_is_unicode && direction == TO_8BIT)) |
| /* no conversion necessary */ |
| result = code; |
| else { |
| /* depending on direction, this will give us either an 8-bit |
| * K(KTYP, KVAL) or a Unicode keysym xor 0xf000 */ |
| ksym = codetoksym(ctx, code); |
| if (ksym) |
| result = ksymtocode(ctx, ksym, direction); |
| else |
| result = code; |
| if (direction == TO_UNICODE && KTYP(code) == KT_LETTER && (result ^ 0xf000) < 0x100) { |
| /* Unicode Latin-1 Supplement */ |
| result = K(KT_LETTER, result ^ 0xf000); |
| } |
| } |
| |
| /* if direction was TO_UNICODE from the beginning, we return the true |
| * Unicode value (without the 0xf000 mask) */ |
| if (unicode_forced && result >= 0x1000) |
| return result ^ 0xf000; |
| else |
| return result; |
| } |
| |
| int add_capslock(struct lk_ctx *ctx, int code) |
| { |
| if (KTYP(code) == KT_LATIN && (!(ctx->flags & LK_FLAG_PREFER_UNICODE) || code < 0x80)) |
| return K(KT_LETTER, KVAL(code)); |
| else if ((code ^ 0xf000) < 0x100) |
| /* Unicode Latin-1 Supplement */ |
| /* a bit dirty to use KT_LETTER here, but it should work */ |
| return K(KT_LETTER, code ^ 0xf000); |
| else |
| return convert_code(ctx, code, TO_AUTO); |
| } |