Blame src/libkeymap/loadkeys.c

Packit Service 50ad14
#include "config.h"
Packit Service 50ad14
Packit Service 50ad14
#include <errno.h>
Packit Service 50ad14
#include <stdlib.h>
Packit Service 50ad14
#include <string.h>
Packit Service 50ad14
#include <sys/ioctl.h>
Packit Service 50ad14
#include <linux/kd.h>
Packit Service 50ad14
#include <linux/keyboard.h>
Packit Service 50ad14
#include <unistd.h>
Packit Service 50ad14
Packit Service 50ad14
#include "keymap.h"
Packit Service 50ad14
Packit Service 50ad14
#include "nls.h"
Packit Service 50ad14
#include "kbd.h"
Packit Service 50ad14
#include "contextP.h"
Packit Service 50ad14
#include "ksyms.h"
Packit Service 50ad14
Packit Service 50ad14
static int
Packit Service 50ad14
defkeys(struct lk_ctx *ctx, int fd, int kbd_mode)
Packit Service 50ad14
{
Packit Service 50ad14
	struct kbentry ke;
Packit Service 50ad14
	int ct = 0;
Packit Service 50ad14
	int i, j, fail;
Packit Service 50ad14
Packit Service 50ad14
	if (ctx->flags & LK_FLAG_UNICODE_MODE) {
Packit Service 50ad14
		/* temporarily switch to K_UNICODE while defining keys */
Packit Service 50ad14
		if (ioctl(fd, KDSKBMODE, K_UNICODE)) {
Packit Service 50ad14
			ERR(ctx, _("KDSKBMODE: %s: could not switch to Unicode mode"),
Packit Service 50ad14
			    strerror(errno));
Packit Service 50ad14
			goto fail;
Packit Service 50ad14
		}
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	for (i = 0; i < MAX_NR_KEYMAPS; i++) {
Packit Service 50ad14
		unsigned int exist = lk_map_exists(ctx, i);
Packit Service 50ad14
Packit Service 50ad14
		if (exist) {
Packit Service 50ad14
			for (j = 0; j < NR_KEYS; j++) {
Packit Service 50ad14
				if (!lk_key_exists(ctx, i, j))
Packit Service 50ad14
					continue;
Packit Service 50ad14
Packit Service 50ad14
				ke.kb_index = j;
Packit Service 50ad14
				ke.kb_table = i;
Packit Service 50ad14
				ke.kb_value = lk_get_key(ctx, i, j);
Packit Service 50ad14
Packit Service 50ad14
				fail = ioctl(fd, KDSKBENT, (unsigned long)&ke;;
Packit Service 50ad14
Packit Service 50ad14
				if (fail) {
Packit Service 50ad14
					if (errno == EPERM) {
Packit Service 50ad14
						ERR(ctx, _("Keymap %d: Permission denied"), i);
Packit Service 50ad14
						j = NR_KEYS;
Packit Service 50ad14
						continue;
Packit Service 50ad14
					}
Packit Service 50ad14
					ERR(ctx, "%s", strerror(errno));
Packit Service 50ad14
				} else
Packit Service 50ad14
					ct++;
Packit Service 50ad14
Packit Service 50ad14
				INFO(ctx, _("keycode %d, table %d = %d%s"),
Packit Service 50ad14
				     j, i, lk_get_key(ctx, i, j), fail ? _("    FAILED") : "");
Packit Service 50ad14
Packit Service 50ad14
				if (fail)
Packit Service 50ad14
					WARN(ctx, _("failed to bind key %d to value %d"),
Packit Service 50ad14
					     j, lk_get_key(ctx, i, j));
Packit Service 50ad14
			}
Packit Service 50ad14
Packit Service 50ad14
		} else if ((ctx->keywords & LK_KEYWORD_KEYMAPS) && !exist) {
Packit Service 50ad14
			/* deallocate keymap */
Packit Service 50ad14
			ke.kb_index = 0;
Packit Service 50ad14
			ke.kb_table = i;
Packit Service 50ad14
			ke.kb_value = K_NOSUCHMAP;
Packit Service 50ad14
Packit Service 50ad14
			DBG(ctx, _("deallocate keymap %d"), i);
Packit Service 50ad14
Packit Service 50ad14
			if (ioctl(fd, KDSKBENT, (unsigned long)&ke)) {
Packit Service 50ad14
				if (errno != EINVAL) {
Packit Service 50ad14
					ERR(ctx, _("KDSKBENT: %s: could not deallocate keymap %d"),
Packit Service 50ad14
					    strerror(errno), i);
Packit Service 50ad14
					goto fail;
Packit Service 50ad14
				}
Packit Service 50ad14
				/* probably an old kernel */
Packit Service 50ad14
				/* clear keymap by hand */
Packit Service 50ad14
				for (j = 0; j < NR_KEYS; j++) {
Packit Service 50ad14
					ke.kb_index = j;
Packit Service 50ad14
					ke.kb_table = i;
Packit Service 50ad14
					ke.kb_value = K_HOLE;
Packit Service 50ad14
Packit Service 50ad14
					if (ioctl(fd, KDSKBENT, (unsigned long)&ke)) {
Packit Service 50ad14
						if (errno == EINVAL && i >= 16)
Packit Service 50ad14
							break; /* old kernel */
Packit Service 50ad14
Packit Service 50ad14
						ERR(ctx, _("KDSKBENT: %s: cannot deallocate or clear keymap"),
Packit Service 50ad14
						    strerror(errno));
Packit Service 50ad14
						goto fail;
Packit Service 50ad14
					}
Packit Service 50ad14
				}
Packit Service 50ad14
			}
Packit Service 50ad14
		}
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	if ((ctx->flags & LK_FLAG_UNICODE_MODE) && ioctl(fd, KDSKBMODE, kbd_mode)) {
Packit Service 50ad14
		ERR(ctx, _("KDSKBMODE: %s: could not return to original keyboard mode"),
Packit Service 50ad14
		    strerror(errno));
Packit Service 50ad14
		goto fail;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	return ct;
Packit Service 50ad14
Packit Service 50ad14
fail:
Packit Service 50ad14
	return -1;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
static char *
Packit Service 50ad14
ostr(struct lk_ctx *ctx, char *s)
Packit Service 50ad14
{
Packit Service 50ad14
	int lth   = strlen(s);
Packit Service 50ad14
	char *ns0 = malloc(4 * lth + 1);
Packit Service 50ad14
	char *ns  = ns0;
Packit Service 50ad14
Packit Service 50ad14
	if (ns == NULL) {
Packit Service 50ad14
		ERR(ctx, _("out of memory"));
Packit Service 50ad14
		return NULL;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	while (*s) {
Packit Service 50ad14
		switch (*s) {
Packit Service 50ad14
			case '\n':
Packit Service 50ad14
				*ns++ = '\\';
Packit Service 50ad14
				*ns++ = 'n';
Packit Service 50ad14
				break;
Packit Service 50ad14
			case '\033':
Packit Service 50ad14
				*ns++ = '\\';
Packit Service 50ad14
				*ns++ = '0';
Packit Service 50ad14
				*ns++ = '3';
Packit Service 50ad14
				*ns++ = '3';
Packit Service 50ad14
				break;
Packit Service 50ad14
			default:
Packit Service 50ad14
				*ns++ = *s;
Packit Service 50ad14
		}
Packit Service 50ad14
		s++;
Packit Service 50ad14
	}
Packit Service 50ad14
	*ns = 0;
Packit Service 50ad14
	return ns0;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
static int
Packit Service 50ad14
deffuncs(struct lk_ctx *ctx, int fd)
Packit Service 50ad14
{
Packit Service 50ad14
	int i, ct = 0;
Packit Service 50ad14
	char *ptr, *s;
Packit Service 50ad14
	struct kbsentry kbs;
Packit Service 50ad14
Packit Service 50ad14
	for (i = 0; i < MAX_NR_FUNC; i++) {
Packit Service 50ad14
		kbs.kb_func = i;
Packit Service 50ad14
Packit Service 50ad14
		ptr = lk_array_get_ptr(ctx->func_table, i);
Packit Service 50ad14
Packit Service 50ad14
		if (ptr) {
Packit Service 50ad14
			strcpy((char *)kbs.kb_string, ptr);
Packit Service 50ad14
			if (ioctl(fd, KDSKBSENT, (unsigned long)&kbs)) {
Packit Service 50ad14
				s = ostr(ctx, (char *)kbs.kb_string);
Packit Service 50ad14
				if (s == NULL)
Packit Service 50ad14
					return -1;
Packit Service 50ad14
				ERR(ctx, _("failed to bind string '%s' to function %s"),
Packit Service 50ad14
				    s, get_sym(ctx, KT_FN, kbs.kb_func));
Packit Service 50ad14
				free(s);
Packit Service 50ad14
			} else {
Packit Service 50ad14
				ct++;
Packit Service 50ad14
			}
Packit Service 50ad14
		} else if (ctx->flags & LK_FLAG_CLEAR_STRINGS) {
Packit Service 50ad14
			kbs.kb_string[0] = 0;
Packit Service 50ad14
Packit Service 50ad14
			if (ioctl(fd, KDSKBSENT, (unsigned long)&kbs)) {
Packit Service 50ad14
				ERR(ctx, _("failed to clear string %s"),
Packit Service 50ad14
				    get_sym(ctx, KT_FN, kbs.kb_func));
Packit Service 50ad14
			} else {
Packit Service 50ad14
				ct++;
Packit Service 50ad14
			}
Packit Service 50ad14
		}
Packit Service 50ad14
	}
Packit Service 50ad14
	return ct;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
static int
Packit Service 50ad14
defdiacs(struct lk_ctx *ctx, int fd)
Packit Service 50ad14
{
Packit Service 50ad14
	unsigned int i, j, count;
Packit Service 50ad14
	struct lk_kbdiacr *ptr;
Packit Service 50ad14
Packit Service 50ad14
	count = ctx->accent_table->count;
Packit Service 50ad14
	if (count > MAX_DIACR) {
Packit Service 50ad14
		count = MAX_DIACR;
Packit Service 50ad14
		ERR(ctx, _("too many compose definitions"));
Packit Service 50ad14
	}
Packit Service 50ad14
#ifdef KDSKBDIACRUC
Packit Service 50ad14
	if (ctx->flags & LK_FLAG_PREFER_UNICODE) {
Packit Service 50ad14
		struct kbdiacrsuc kdu;
Packit Service 50ad14
Packit Service 50ad14
		kdu.kb_cnt = count;
Packit Service 50ad14
Packit Service 50ad14
		for (i = 0, j = 0; i < ctx->accent_table->total && j < count; i++) {
Packit Service 50ad14
			ptr = lk_array_get_ptr(ctx->accent_table, i);
Packit Service 50ad14
			if (!ptr)
Packit Service 50ad14
				continue;
Packit Service 50ad14
Packit Service 50ad14
			kdu.kbdiacruc[j].diacr  = ptr->diacr;
Packit Service 50ad14
			kdu.kbdiacruc[j].base   = ptr->base;
Packit Service 50ad14
			kdu.kbdiacruc[j].result = ptr->result;
Packit Service 50ad14
			j++;
Packit Service 50ad14
		}
Packit Service 50ad14
Packit Service 50ad14
		if (ioctl(fd, KDSKBDIACRUC, (unsigned long)&kdu)) {
Packit Service 50ad14
			ERR(ctx, "KDSKBDIACRUC: %s", strerror(errno));
Packit Service 50ad14
			return -1;
Packit Service 50ad14
		}
Packit Service 50ad14
	} else
Packit Service 50ad14
#endif
Packit Service 50ad14
	{
Packit Service 50ad14
		struct kbdiacrs kd;
Packit Service 50ad14
Packit Service 50ad14
		kd.kb_cnt = count;
Packit Service 50ad14
Packit Service 50ad14
		for (i = 0, j = 0; i < ctx->accent_table->total && j < count; i++) {
Packit Service 50ad14
			ptr = lk_array_get_ptr(ctx->accent_table, i);
Packit Service 50ad14
			if (!ptr)
Packit Service 50ad14
				continue;
Packit Service 50ad14
Packit Service 50ad14
			kd.kbdiacr[j].diacr  = ptr->diacr;
Packit Service 50ad14
			kd.kbdiacr[j].base   = ptr->base;
Packit Service 50ad14
			kd.kbdiacr[j].result = ptr->result;
Packit Service 50ad14
			j++;
Packit Service 50ad14
		}
Packit Service 50ad14
Packit Service 50ad14
		if (ioctl(fd, KDSKBDIACR, (unsigned long)&kd)) {
Packit Service 50ad14
			ERR(ctx, "KDSKBDIACR: %s", strerror(errno));
Packit Service 50ad14
			return -1;
Packit Service 50ad14
		}
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	return count;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
int lk_load_keymap(struct lk_ctx *ctx, int fd, int kbd_mode)
Packit Service 50ad14
{
Packit Service 50ad14
	int keyct, funcct, diacct;
Packit Service 50ad14
Packit Service 50ad14
	if (lk_add_constants(ctx) < 0)
Packit Service 50ad14
		return -1;
Packit Service 50ad14
Packit Service 50ad14
	if ((keyct = defkeys(ctx, fd, kbd_mode)) < 0 || (funcct = deffuncs(ctx, fd)) < 0)
Packit Service 50ad14
		return -1;
Packit Service 50ad14
Packit Service 50ad14
	INFO(ctx, P_("\nChanged %d key", "\nChanged %d keys", keyct), keyct);
Packit Service 50ad14
	INFO(ctx, P_("Changed %d string", "Changed %d strings", funcct), funcct);
Packit Service 50ad14
Packit Service 50ad14
	if (ctx->accent_table->count > 0 || ctx->flags & LK_FLAG_CLEAR_COMPOSE) {
Packit Service 50ad14
		diacct = defdiacs(ctx, fd);
Packit Service 50ad14
Packit Service 50ad14
		if (diacct < 0)
Packit Service 50ad14
			return -1;
Packit Service 50ad14
Packit Service 50ad14
		INFO(ctx, P_("Loaded %d compose definition",
Packit Service 50ad14
		             "Loaded %d compose definitions", diacct),
Packit Service 50ad14
		     diacct);
Packit Service 50ad14
Packit Service 50ad14
	} else {
Packit Service 50ad14
		INFO(ctx, _("(No change in compose definitions)"));
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	return 0;
Packit Service 50ad14
}