Blame src/libkeymap/ksyms.c

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