You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

230 lines
5.7 KiB

  1. From 360d44d67e7be46108bec982ff2e79b89f04a9a3 Mon Sep 17 00:00:00 2001
  2. From: Mathieu Othacehe <m.othacehe@gmail.com>
  3. Date: Thu, 15 Nov 2018 14:34:40 +0900
  4. Subject: [PATCH] add runtime keymap switch support.
  5. ---
  6. src/pty.c | 23 ++++++++++-
  7. src/uterm_input.c | 2 +
  8. src/uterm_input_internal.h | 5 +++
  9. src/uterm_input_uxkb.c | 83 ++++++++++++++++++++++++++++++++++++++
  10. 4 files changed, 111 insertions(+), 2 deletions(-)
  11. diff --git a/src/pty.c b/src/pty.c
  12. index 1443f4a..f64cb5b 100644
  13. --- a/src/pty.c
  14. +++ b/src/pty.c
  15. @@ -46,6 +46,8 @@
  16. #define KMSCON_NREAD 16384
  17. +#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
  18. +
  19. struct kmscon_pty {
  20. unsigned long ref;
  21. struct ev_eloop *eloop;
  22. @@ -241,9 +243,22 @@ static bool pty_is_open(struct kmscon_pty *pty)
  23. return pty->fd >= 0;
  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. + kmscon_keymap_update(kmscon_pid);
  49. +
  50. execve(argv[0], argv, environ);
  51. log_err("failed to exec child %s: %m", argv[0]);
  52. @@ -383,12 +400,14 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
  53. unsigned short width, unsigned short height)
  54. {
  55. pid_t pid;
  56. + pid_t kmscon_pid;
  57. struct winsize ws;
  58. memset(&ws, 0, sizeof(ws));
  59. ws.ws_col = width;
  60. ws.ws_row = height;
  61. + kmscon_pid = getpid();
  62. pid = fork();
  63. switch (pid) {
  64. case -1:
  65. @@ -397,7 +416,7 @@ static int pty_spawn(struct kmscon_pty *pty, int master,
  66. case 0:
  67. setup_child(master, &ws);
  68. exec_child(pty->term, pty->colorterm, pty->argv, pty->seat,
  69. - pty->vtnr, pty->env_reset);
  70. + pty->vtnr, pty->env_reset, kmscon_pid);
  71. exit(EXIT_FAILURE);
  72. default:
  73. log_debug("forking child %d", pid);
  74. diff --git a/src/uterm_input.c b/src/uterm_input.c
  75. index 6fcbc4b..990a09d 100644
  76. --- a/src/uterm_input.c
  77. +++ b/src/uterm_input.c
  78. @@ -178,6 +178,8 @@ static void input_new_dev(struct uterm_input *input,
  79. if (ret)
  80. goto err_rcodepoints;
  81. + uxkb_dev_keymap_update(dev);
  82. +
  83. if (input->awake > 0) {
  84. ret = input_wake_up_dev(dev);
  85. if (ret)
  86. diff --git a/src/uterm_input_internal.h b/src/uterm_input_internal.h
  87. index 04e6cc9..ec44459 100644
  88. --- a/src/uterm_input_internal.h
  89. +++ b/src/uterm_input_internal.h
  90. @@ -39,6 +39,8 @@
  91. #include "shl_misc.h"
  92. #include "uterm_input.h"
  93. +#define INPUT_KEYMAP_UPDATE_FILE "/tmp/kmscon-%d-keymap-update"
  94. +
  95. enum uterm_input_device_capability {
  96. UTERM_DEVICE_HAS_KEYS = (1 << 0),
  97. UTERM_DEVICE_HAS_LEDS = (1 << 1),
  98. @@ -62,6 +64,8 @@ struct uterm_input_dev {
  99. bool repeating;
  100. struct ev_timer *repeat_timer;
  101. + struct ev_fd *fd_update;
  102. + int rupdate_fd;
  103. };
  104. struct uterm_input {
  105. @@ -95,6 +99,7 @@ void uxkb_desc_destroy(struct uterm_input *input);
  106. int uxkb_dev_init(struct uterm_input_dev *dev);
  107. void uxkb_dev_destroy(struct uterm_input_dev *dev);
  108. +int uxkb_dev_keymap_update(struct uterm_input_dev *dev);
  109. int uxkb_dev_process(struct uterm_input_dev *dev,
  110. uint16_t key_state,
  111. uint16_t code);
  112. diff --git a/src/uterm_input_uxkb.c b/src/uterm_input_uxkb.c
  113. index 925c755..4760972 100644
  114. --- a/src/uterm_input_uxkb.c
  115. +++ b/src/uterm_input_uxkb.c
  116. @@ -31,6 +31,9 @@
  117. #include <stdlib.h>
  118. #include <string.h>
  119. #include <unistd.h>
  120. +#include <sys/types.h>
  121. +#include <sys/stat.h>
  122. +#include <fcntl.h>
  123. #include <xkbcommon/xkbcommon.h>
  124. #include "shl_hook.h"
  125. #include "shl_llog.h"
  126. @@ -178,6 +181,86 @@ static void timer_event(struct ev_timer *timer, uint64_t num, void *data)
  127. shl_hook_call(dev->input->hook, dev->input, &dev->repeat_event);
  128. }
  129. +static void uxkb_keymap_update_handler(struct ev_fd *fd, int mask, void *data)
  130. +{
  131. + struct uterm_input_dev *dev = data;
  132. + char in;
  133. + char keymap[3][255];
  134. + int pos = 0;
  135. + int curr_keymap = 0;
  136. + int ret;
  137. + char *model, *layout, *variant;
  138. +
  139. + if (!(mask & EV_READABLE))
  140. + return;
  141. +
  142. + memset(keymap, 0, sizeof(keymap));
  143. +
  144. + model = keymap[0];
  145. + layout = keymap[1];
  146. + variant = keymap[2];
  147. +
  148. + do {
  149. + ret = read(dev->rupdate_fd, &in, sizeof(in));
  150. + if (ret <= 0)
  151. + break;
  152. +
  153. + keymap[curr_keymap][pos++] = in;
  154. +
  155. + if (in == '\0') {
  156. + curr_keymap++;
  157. + pos = 0;
  158. + }
  159. + } while (1);
  160. +
  161. + llog_info(dev->input, "HANDLER CALLED %s|%s|%s\n",
  162. + model, layout, variant);
  163. + uxkb_desc_init(dev->input, model, layout, variant, NULL, NULL);
  164. +
  165. + dev->state = xkb_state_new(dev->input->keymap);
  166. + if (!dev->state) {
  167. + llog_error(dev->input, "cannot create XKB state");
  168. + return;
  169. + }
  170. +}
  171. +
  172. +int uxkb_dev_keymap_update(struct uterm_input_dev *dev)
  173. +{
  174. + int ret;
  175. + char *file;
  176. + int pid = getpid();
  177. +
  178. + ret = asprintf(&file, INPUT_KEYMAP_UPDATE_FILE, pid);
  179. + if (ret < 0)
  180. + return ret;
  181. +
  182. + ret = mkfifo(file, S_IRWXU);
  183. + if (ret < 0) {
  184. + llog_warn(dev->input, "could not open fifo");
  185. + return -EFAULT;
  186. + }
  187. + dev->rupdate_fd = open(file, O_RDONLY | O_NONBLOCK);
  188. + if (dev->rupdate_fd < 0) {
  189. + llog_warn(dev->input, "cannot open file %s (%d): %m",
  190. + file, errno);
  191. + return -EFAULT;
  192. + }
  193. +
  194. + setenv("KEYMAP_UPDATE", file, 1);
  195. +
  196. + ret = ev_eloop_new_fd(dev->input->eloop, &dev->fd_update,
  197. + dev->rupdate_fd, EV_READABLE,
  198. + uxkb_keymap_update_handler, dev);
  199. + if (ret) {
  200. + llog_error(dev->input, "could not init keymap update");
  201. + close(dev->rupdate_fd);
  202. + dev->rupdate_fd = -1;
  203. + return ret;
  204. + }
  205. +
  206. + return 0;
  207. +}
  208. +
  209. int uxkb_dev_init(struct uterm_input_dev *dev)
  210. {
  211. int ret;
  212. --
  213. 2.17.1