* gnu/packages/patches/kmscon-runtime-keymap-switch.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/terminals.scm (kmscon)[source]: Add patch.
		
			
				
	
	
		
			229 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 360d44d67e7be46108bec982ff2e79b89f04a9a3 Mon Sep 17 00:00:00 2001
 | 
						|
From: Mathieu Othacehe <m.othacehe@gmail.com>
 | 
						|
Date: Thu, 15 Nov 2018 14:34:40 +0900
 | 
						|
Subject: [PATCH] add runtime keymap switch support.
 | 
						|
 | 
						|
---
 | 
						|
 src/pty.c                  | 23 ++++++++++-
 | 
						|
 src/uterm_input.c          |  2 +
 | 
						|
 src/uterm_input_internal.h |  5 +++
 | 
						|
 src/uterm_input_uxkb.c     | 83 ++++++++++++++++++++++++++++++++++++++
 | 
						|
 4 files changed, 111 insertions(+), 2 deletions(-)
 | 
						|
 | 
						|
diff --git a/src/pty.c b/src/pty.c
 | 
						|
index 1443f4a..f64cb5b 100644
 | 
						|
--- a/src/pty.c
 | 
						|
+++ b/src/pty.c
 | 
						|
@@ -46,6 +46,8 @@
 | 
						|
 
 | 
						|
 #define KMSCON_NREAD 16384
 | 
						|
 
 | 
						|
+#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
 | 
						|
+
 | 
						|
 struct kmscon_pty {
 | 
						|
 	unsigned long ref;
 | 
						|
 	struct ev_eloop *eloop;
 | 
						|
@@ -241,9 +243,22 @@ static bool pty_is_open(struct kmscon_pty *pty)
 | 
						|
 	return pty->fd >= 0;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static int kmscon_keymap_update(pid_t pid)
 | 
						|
+{
 | 
						|
+	char *file;
 | 
						|
+	int ret;
 | 
						|
+
 | 
						|
+	ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
 | 
						|
+	if (ret < 0)
 | 
						|
+		return ret;
 | 
						|
+
 | 
						|
+	return setenv("KEYMAP_UPDATE", file, 1);
 | 
						|
+}
 | 
						|
+
 | 
						|
 static void __attribute__((noreturn))
 | 
						|
 exec_child(const char *term, const char *colorterm, char **argv,
 | 
						|
-	   const char *seat, const char *vtnr, bool env_reset)
 | 
						|
+	   const char *seat, const char *vtnr, bool env_reset,
 | 
						|
+	   pid_t kmscon_pid)
 | 
						|
 {
 | 
						|
 	char **env;
 | 
						|
 	char **def_argv;
 | 
						|
@@ -277,6 +292,8 @@ exec_child(const char *term, const char *colorterm, char **argv,
 | 
						|
 	if (vtnr)
 | 
						|
 		setenv("XDG_VTNR", vtnr, 1);
 | 
						|
 
 | 
						|
+	kmscon_keymap_update(kmscon_pid);
 | 
						|
+
 | 
						|
 	execve(argv[0], argv, environ);
 | 
						|
 
 | 
						|
 	log_err("failed to exec child %s: %m", argv[0]);
 | 
						|
@@ -383,12 +400,14 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
 | 
						|
 			unsigned short width, unsigned short height)
 | 
						|
 {
 | 
						|
 	pid_t pid;
 | 
						|
+	pid_t kmscon_pid;
 | 
						|
 	struct winsize ws;
 | 
						|
 
 | 
						|
 	memset(&ws, 0, sizeof(ws));
 | 
						|
 	ws.ws_col = width;
 | 
						|
 	ws.ws_row = height;
 | 
						|
 
 | 
						|
+	kmscon_pid = getpid();
 | 
						|
 	pid = fork();
 | 
						|
 	switch (pid) {
 | 
						|
 	case -1:
 | 
						|
@@ -397,7 +416,7 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
 | 
						|
 	case 0:
 | 
						|
 		setup_child(master, &ws);
 | 
						|
 		exec_child(pty->term, pty->colorterm, pty->argv, pty->seat,
 | 
						|
-			   pty->vtnr, pty->env_reset);
 | 
						|
+			   pty->vtnr, pty->env_reset, kmscon_pid);
 | 
						|
 		exit(EXIT_FAILURE);
 | 
						|
 	default:
 | 
						|
 		log_debug("forking child %d", pid);
 | 
						|
diff --git a/src/uterm_input.c b/src/uterm_input.c
 | 
						|
index 6fcbc4b..990a09d 100644
 | 
						|
--- a/src/uterm_input.c
 | 
						|
+++ b/src/uterm_input.c
 | 
						|
@@ -178,6 +178,8 @@ static void input_new_dev(struct uterm_input *input,
 | 
						|
 	if (ret)
 | 
						|
 		goto err_rcodepoints;
 | 
						|
 
 | 
						|
+	uxkb_dev_keymap_update(dev);
 | 
						|
+
 | 
						|
 	if (input->awake > 0) {
 | 
						|
 		ret = input_wake_up_dev(dev);
 | 
						|
 		if (ret)
 | 
						|
diff --git a/src/uterm_input_internal.h b/src/uterm_input_internal.h
 | 
						|
index 04e6cc9..ec44459 100644
 | 
						|
--- a/src/uterm_input_internal.h
 | 
						|
+++ b/src/uterm_input_internal.h
 | 
						|
@@ -39,6 +39,8 @@
 | 
						|
 #include "shl_misc.h"
 | 
						|
 #include "uterm_input.h"
 | 
						|
 
 | 
						|
+#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
 | 
						|
+
 | 
						|
 enum uterm_input_device_capability {
 | 
						|
 	UTERM_DEVICE_HAS_KEYS = (1 << 0),
 | 
						|
 	UTERM_DEVICE_HAS_LEDS = (1 << 1),
 | 
						|
@@ -62,6 +64,8 @@ struct uterm_input_dev {
 | 
						|
 
 | 
						|
 	bool repeating;
 | 
						|
 	struct ev_timer *repeat_timer;
 | 
						|
+	struct ev_fd *fd_update;
 | 
						|
+	int rupdate_fd;
 | 
						|
 };
 | 
						|
 
 | 
						|
 struct uterm_input {
 | 
						|
@@ -95,6 +99,7 @@ void uxkb_desc_destroy(struct uterm_input *input);
 | 
						|
 
 | 
						|
 int uxkb_dev_init(struct uterm_input_dev *dev);
 | 
						|
 void uxkb_dev_destroy(struct uterm_input_dev *dev);
 | 
						|
+int uxkb_dev_keymap_update(struct uterm_input_dev *dev);
 | 
						|
 int uxkb_dev_process(struct uterm_input_dev *dev,
 | 
						|
 		     uint16_t key_state,
 | 
						|
 		     uint16_t code);
 | 
						|
diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c
 | 
						|
index 925c755..4760972 100644
 | 
						|
--- a/src/uterm_input_uxkb.c
 | 
						|
+++ b/src/uterm_input_uxkb.c
 | 
						|
@@ -31,6 +31,9 @@
 | 
						|
 #include <stdlib.h>
 | 
						|
 #include <string.h>
 | 
						|
 #include <unistd.h>
 | 
						|
+#include <sys/types.h>
 | 
						|
+#include <sys/stat.h>
 | 
						|
+#include <fcntl.h>
 | 
						|
 #include <xkbcommon/xkbcommon.h>
 | 
						|
 #include "shl_hook.h"
 | 
						|
 #include "shl_llog.h"
 | 
						|
@@ -178,6 +181,86 @@ static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
 | 
						|
 	shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event);
 | 
						|
 }
 | 
						|
 
 | 
						|
+static void uxkb_keymap_update_handler(struct ev_fd *fd, int mask, void *data)
 | 
						|
+{
 | 
						|
+	struct uterm_input_dev *dev = data;
 | 
						|
+	char in;
 | 
						|
+	char keymap[3][255];
 | 
						|
+	int pos = 0;
 | 
						|
+	int curr_keymap = 0;
 | 
						|
+	int ret;
 | 
						|
+	char *model, *layout, *variant;
 | 
						|
+
 | 
						|
+	if (!(mask & EV_READABLE))
 | 
						|
+		return;
 | 
						|
+
 | 
						|
+	memset(keymap, 0, sizeof(keymap));
 | 
						|
+
 | 
						|
+	model = keymap[0];
 | 
						|
+	layout = keymap[1];
 | 
						|
+	variant = keymap[2];
 | 
						|
+
 | 
						|
+	do {
 | 
						|
+	  ret = read(dev->rupdate_fd, &in, sizeof(in));
 | 
						|
+	  if (ret <= 0)
 | 
						|
+	    break;
 | 
						|
+
 | 
						|
+	  keymap[curr_keymap][pos++] = in;
 | 
						|
+
 | 
						|
+	  if (in == '\0') {
 | 
						|
+	    curr_keymap++;
 | 
						|
+	    pos = 0;
 | 
						|
+	  }
 | 
						|
+	} while (1);
 | 
						|
+
 | 
						|
+	llog_info(dev->input, "HANDLER CALLED %s|%s|%s\n",
 | 
						|
+		  model, layout, variant);
 | 
						|
+	uxkb_desc_init(dev->input, model, layout, variant, NULL, NULL);
 | 
						|
+
 | 
						|
+	dev->state = xkb_state_new(dev->input->keymap);
 | 
						|
+	if (!dev->state) {
 | 
						|
+		llog_error(dev->input, "cannot create XKB state");
 | 
						|
+		return;
 | 
						|
+	}
 | 
						|
+}
 | 
						|
+
 | 
						|
+int uxkb_dev_keymap_update(struct uterm_input_dev *dev)
 | 
						|
+{
 | 
						|
+	int ret;
 | 
						|
+	char *file;
 | 
						|
+	int pid = getpid();
 | 
						|
+
 | 
						|
+	ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
 | 
						|
+	if (ret < 0)
 | 
						|
+		return ret;
 | 
						|
+
 | 
						|
+	ret = mkfifo(file, S_IRWXU);
 | 
						|
+	if (ret < 0) {
 | 
						|
+		llog_warn(dev->input, "could not open fifo");
 | 
						|
+		return -EFAULT;
 | 
						|
+	}
 | 
						|
+	dev->rupdate_fd = open(file, O_RDONLY | O_NONBLOCK);
 | 
						|
+	if (dev->rupdate_fd < 0) {
 | 
						|
+		llog_warn(dev->input, "cannot open file %s (%d): %m",
 | 
						|
+			  file, errno);
 | 
						|
+		return -EFAULT;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	setenv("KEYMAP_UPDATE", file, 1);
 | 
						|
+
 | 
						|
+	ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd_update,
 | 
						|
+			      dev->rupdate_fd, EV_READABLE,
 | 
						|
+			      uxkb_keymap_update_handler, dev);
 | 
						|
+	if (ret) {
 | 
						|
+		llog_error(dev->input, "could not init keymap update");
 | 
						|
+		close(dev->rupdate_fd);
 | 
						|
+		dev->rupdate_fd = -1;
 | 
						|
+		return ret;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
 int uxkb_dev_init(struct uterm_input_dev *dev)
 | 
						|
 {
 | 
						|
 	int ret;
 | 
						|
-- 
 | 
						|
2.17.1
 | 
						|
 |