| 1 | Make kmscon listen to a FIFO in /tmp that clients can write to
|
| 2 | to request a keymap change.
|
| 3 |
|
| 4 | Patch by Mathieu Othacehe <[email protected]>.
|
| 5 | Modified by Florian Pelz <[email protected]>
|
| 6 | and Ludovic Courtès <[email protected]>.
|
| 7 |
|
| 8 | diff --git a/src/pty.c b/src/pty.c
|
| 9 | index 1443f4a..f64cb5b 100644
|
| 10 | |
| 11 | |
| 12 | @@ -46,6 +46,8 @@
|
| 13 |
|
| 14 | #define KMSCON_NREAD 16384
|
| 15 |
|
| 16 | +#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
|
| 17 | +
|
| 18 | struct kmscon_pty {
|
| 19 | unsigned long ref;
|
| 20 | struct ev_eloop *eloop;
|
| 21 | @@ -241,9 +243,22 @@ static bool pty_is_open(struct kmscon_pty *pty)
|
| 22 | return pty->fd >= 0;
|
| 23 | }
|
| 24 |
|
| 25 | +static int kmscon_keymap_update(pid_t pid)
|
| 26 | +{
|
| 27 | + char *file;
|
| 28 | + int ret;
|
| 29 | +
|
| 30 | + ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
|
| 31 | + if (ret < 0)
|
| 32 | + return ret;
|
| 33 | +
|
| 34 | + return setenv("KEYMAP_UPDATE", file, 1);
|
| 35 | +}
|
| 36 | +
|
| 37 | static void __attribute__((noreturn))
|
| 38 | exec_child(const char *term, const char *colorterm, char **argv,
|
| 39 | - const char *seat, const char *vtnr, bool env_reset)
|
| 40 | + const char *seat, const char *vtnr, bool env_reset,
|
| 41 | + pid_t kmscon_pid)
|
| 42 | {
|
| 43 | char **env;
|
| 44 | char **def_argv;
|
| 45 | @@ -277,6 +292,8 @@ exec_child(const char *term, const char *colorterm, char **argv,
|
| 46 | if (vtnr)
|
| 47 | setenv("XDG_VTNR", vtnr, 1);
|
| 48 |
|
| 49 | + kmscon_keymap_update(kmscon_pid);
|
| 50 | +
|
| 51 | execve(argv[0], argv, environ);
|
| 52 |
|
| 53 | log_err("failed to exec child %s: %m", argv[0]);
|
| 54 | @@ -383,12 +400,14 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
|
| 55 | unsigned short width, unsigned short height)
|
| 56 | {
|
| 57 | pid_t pid;
|
| 58 | + pid_t kmscon_pid;
|
| 59 | struct winsize ws;
|
| 60 |
|
| 61 | memset(&ws, 0, sizeof(ws));
|
| 62 | ws.ws_col = width;
|
| 63 | ws.ws_row = height;
|
| 64 |
|
| 65 | + kmscon_pid = getpid();
|
| 66 | pid = fork();
|
| 67 | switch (pid) {
|
| 68 | case -1:
|
| 69 | @@ -397,7 +416,7 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
|
| 70 | case 0:
|
| 71 | setup_child(master, &ws);
|
| 72 | exec_child(pty->term, pty->colorterm, pty->argv, pty->seat,
|
| 73 | - pty->vtnr, pty->env_reset);
|
| 74 | + pty->vtnr, pty->env_reset, kmscon_pid);
|
| 75 | exit(EXIT_FAILURE);
|
| 76 | default:
|
| 77 | log_debug("forking child %d", pid);
|
| 78 | diff --git a/src/uterm_input.c b/src/uterm_input.c
|
| 79 | index 6fcbc4b..990a09d 100644
|
| 80 | |
| 81 | |
| 82 | @@ -178,6 +178,10 @@ static void input_new_dev(struct uterm_input *input,
|
| 83 | if (ret)
|
| 84 | goto err_rcodepoints;
|
| 85 |
|
| 86 | + /* Add the FIFO fd only to the first input poll loop. */
|
| 87 | + if (shl_dlist_empty(&input->devices))
|
| 88 | + uxkb_dev_keymap_update(dev);
|
| 89 | +
|
| 90 | if (input->awake > 0) {
|
| 91 | ret = input_wake_up_dev(dev);
|
| 92 | if (ret)
|
| 93 | diff --git a/src/uterm_input_internal.h b/src/uterm_input_internal.h
|
| 94 | index 04e6cc9..ec44459 100644
|
| 95 | |
| 96 | |
| 97 | @@ -39,6 +39,8 @@
|
| 98 | #include "shl_misc.h"
|
| 99 | #include "uterm_input.h"
|
| 100 |
|
| 101 | +#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
|
| 102 | +
|
| 103 | enum uterm_input_device_capability {
|
| 104 | UTERM_DEVICE_HAS_KEYS = (1 << 0),
|
| 105 | UTERM_DEVICE_HAS_LEDS = (1 << 1),
|
| 106 | @@ -62,6 +64,8 @@ struct uterm_input_dev {
|
| 107 |
|
| 108 | bool repeating;
|
| 109 | struct ev_timer *repeat_timer;
|
| 110 | + struct ev_fd *fd_update;
|
| 111 | + int rupdate_fd;
|
| 112 | };
|
| 113 |
|
| 114 | struct uterm_input {
|
| 115 | @@ -95,6 +99,7 @@ void uxkb_desc_destroy(struct uterm_input *input);
|
| 116 |
|
| 117 | int uxkb_dev_init(struct uterm_input_dev *dev);
|
| 118 | void uxkb_dev_destroy(struct uterm_input_dev *dev);
|
| 119 | +int uxkb_dev_keymap_update(struct uterm_input_dev *dev);
|
| 120 | int uxkb_dev_process(struct uterm_input_dev *dev,
|
| 121 | uint16_t key_state,
|
| 122 | uint16_t code);
|
| 123 | diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c
|
| 124 | index 925c755..8fe08f8 100644
|
| 125 | |
| 126 | |
| 127 | @@ -31,6 +31,9 @@
|
| 128 | #include <stdlib.h>
|
| 129 | #include <string.h>
|
| 130 | #include <unistd.h>
|
| 131 | +#include <sys/types.h>
|
| 132 | +#include <sys/stat.h>
|
| 133 | +#include <fcntl.h>
|
| 134 | #include <xkbcommon/xkbcommon.h>
|
| 135 | #include "shl_hook.h"
|
| 136 | #include "shl_llog.h"
|
| 137 | @@ -178,6 +181,106 @@ static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
|
| 138 | shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event);
|
| 139 | }
|
| 140 |
|
| 141 | +static void uxkb_keymap_update_handler(struct ev_fd *fd, int mask, void *data)
|
| 142 | +{
|
| 143 | + struct uterm_input_dev *dev = data;
|
| 144 | + char in;
|
| 145 | + char keymap[4][255];
|
| 146 | + int pos = 0;
|
| 147 | + int curr_keymap = 0;
|
| 148 | + int ret;
|
| 149 | + char *model, *layout, *variant, *options;
|
| 150 | +
|
| 151 | + if (!(mask & EV_READABLE))
|
| 152 | + return;
|
| 153 | +
|
| 154 | + memset(keymap, 0, sizeof(keymap));
|
| 155 | +
|
| 156 | + model = keymap[0];
|
| 157 | + layout = keymap[1];
|
| 158 | + variant = keymap[2];
|
| 159 | + options = keymap[3];
|
| 160 | +
|
| 161 | + do {
|
| 162 | + ret = read(dev->rupdate_fd, &in, sizeof(in));
|
| 163 | + if (ret <= 0)
|
| 164 | + break;
|
| 165 | +
|
| 166 | + keymap[curr_keymap][pos++] = in;
|
| 167 | +
|
| 168 | + if (in == '\0') {
|
| 169 | + curr_keymap++;
|
| 170 | + pos = 0;
|
| 171 | + }
|
| 172 | + } while (1);
|
| 173 | +
|
| 174 | + llog_info(dev->input, "HANDLER CALLED %s|%s|%s\n",
|
| 175 | + model, layout, variant);
|
| 176 | +
|
| 177 | + struct uterm_input *input = dev->input;
|
| 178 | + struct shl_dlist *iter;
|
| 179 | +
|
| 180 | + /* Apply the new layout to all the inputs. */
|
| 181 | + shl_dlist_for_each(iter, &input->devices) {
|
| 182 | + struct uterm_input_dev *dev;
|
| 183 | + dev = shl_dlist_entry(iter,
|
| 184 | + struct uterm_input_dev,
|
| 185 | + list);
|
| 186 | + uxkb_desc_init(dev->input, model, layout, variant, options, NULL);
|
| 187 | + dev->state = xkb_state_new(dev->input->keymap);
|
| 188 | + if (!dev->state) {
|
| 189 | + llog_error(dev->input, "cannot create XKB state");
|
| 190 | + return;
|
| 191 | + }
|
| 192 | + }
|
| 193 | +
|
| 194 | + /* The client will now close the FIFO. Close it too, and re-create a
|
| 195 | + * FIFO so other clients can eventually connect. */
|
| 196 | + ev_eloop_rm_fd(fd);
|
| 197 | + close(dev->rupdate_fd);
|
| 198 | + dev->rupdate_fd = -1;
|
| 199 | + uxkb_dev_keymap_update(dev);
|
| 200 | +
|
| 201 | +}
|
| 202 | +
|
| 203 | +int uxkb_dev_keymap_update(struct uterm_input_dev *dev)
|
| 204 | +{
|
| 205 | + int ret;
|
| 206 | + char *file;
|
| 207 | + int pid = getpid();
|
| 208 | +
|
| 209 | + ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
|
| 210 | + if (ret < 0)
|
| 211 | + return ret;
|
| 212 | +
|
| 213 | + (void) unlink(file);
|
| 214 | + ret = mkfifo(file, S_IRWXU);
|
| 215 | + if (ret < 0) {
|
| 216 | + llog_warn(dev->input, "could not open fifo");
|
| 217 | + return -EFAULT;
|
| 218 | + }
|
| 219 | + dev->rupdate_fd = open(file, O_RDONLY | O_NONBLOCK);
|
| 220 | + if (dev->rupdate_fd < 0) {
|
| 221 | + llog_warn(dev->input, "cannot open file %s (%d): %m",
|
| 222 | + file, errno);
|
| 223 | + return -EFAULT;
|
| 224 | + }
|
| 225 | +
|
| 226 | + setenv("KEYMAP_UPDATE", file, 1);
|
| 227 | +
|
| 228 | + ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd_update,
|
| 229 | + dev->rupdate_fd, EV_READABLE,
|
| 230 | + uxkb_keymap_update_handler, dev);
|
| 231 | + if (ret) {
|
| 232 | + llog_error(dev->input, "could not init keymap update");
|
| 233 | + close(dev->rupdate_fd);
|
| 234 | + dev->rupdate_fd = -1;
|
| 235 | + return ret;
|
| 236 | + }
|
| 237 | +
|
| 238 | + return 0;
|
| 239 | +}
|
| 240 | +
|
| 241 | int uxkb_dev_init(struct uterm_input_dev *dev)
|
| 242 | {
|
| 243 | int ret;
|