Fixes <https://bugs.gnu.org/40493>. * gnu/installer/newt/keymap.scm (%non-latin-layouts): New variable. (%non-latin-variants): New variable. (%latin-layout+variants): New variable. (toggleable-latin-layout): New procedure to compute combined layouts. (run-keymap-page): Use it. (keyboard-layout->configuration): Apply it in config.scm. (run-layout-page): Mention Alt+Shift. * gnu/installer/keymap.scm (kmscon-update-keymap): Pass on XKB options. * gnu/installer/record.scm (<installer>): Adjust code comments. * gnu/installer.scm (apply-keymap): Pass on XKB options. (installer-steps): Adjust code comments. * gnu/packages/patches/kmscon-runtime-keymap-switch.patch: Apply XKB options.
		
			
				
	
	
		
			218 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| By Mathieu Othacehe <m.othacehe@gmail.com>.
 | |
| Modified by Florian Pelz <pelzflorian@pelzflorian.de>.
 | |
| 
 | |
| 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..5d5c22e 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,87 @@ 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[4][255];
 | |
| +	int pos = 0;
 | |
| +	int curr_keymap = 0;
 | |
| +	int ret;
 | |
| +	char *model, *layout, *variant, *options;
 | |
| +
 | |
| +	if (!(mask & EV_READABLE))
 | |
| +		return;
 | |
| +
 | |
| +	memset(keymap, 0, sizeof(keymap));
 | |
| +
 | |
| +	model = keymap[0];
 | |
| +	layout = keymap[1];
 | |
| +	variant = keymap[2];
 | |
| +	options = keymap[3];
 | |
| +
 | |
| +	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, options, 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;
 |