mirror of
https://github.com/systemd/systemd.git
synced 2024-10-30 23:21:22 +03:00
localed: match converted keymaps before legacy
Before, X11 keymap fr-pc105-oss would be converted to fr, even though fr-oss exists. Now, if /usr/lib/kbd/keymaps/xkb/<layout>[-<variant>].map[.gz] exists, <layout>[-<variant>] will be used as the console keymap, falling back to the legacy mappings otherwise. % sudo localectl set-x11-keymap pl pc105 % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: pl (was pl2 before) X11 Layout: pl X11 Model: pc105 % sudo localectl set-x11-keymap fr pc105 oss % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: fr-oss (was fr before) X11 Layout: fr X11 Model: pc105 X11 Variant: oss % sudo localectl set-x11-keymap fr pc105 % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: fr X11 Layout: fr X11 Model: pc105 % sudo localectl set-x11-keymap gb % localectl System Locale: LANG=en_US.UTF-8 VC Keymap: gb (was uk before) X11 Layout: gb
This commit is contained in:
parent
98fce79dea
commit
0732ef7acf
@ -42,6 +42,7 @@
|
||||
#include "set.h"
|
||||
#include "path-util.h"
|
||||
#include "utf8.h"
|
||||
#include "def.h"
|
||||
|
||||
static bool arg_no_pager = false;
|
||||
static bool arg_ask_password = true;
|
||||
@ -437,15 +438,14 @@ static int nftw_cb(
|
||||
|
||||
static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
const char *dir;
|
||||
|
||||
keymaps = set_new(string_hash_func, string_compare_func);
|
||||
if (!keymaps)
|
||||
return log_oom();
|
||||
|
||||
nftw("/usr/share/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
||||
nftw("/usr/share/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
||||
nftw("/usr/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
||||
nftw("/lib/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
||||
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS)
|
||||
nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
||||
|
||||
l = set_get_strv(keymaps);
|
||||
if (!l) {
|
||||
|
@ -633,8 +633,114 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_converted_keymap(Context *c, char **new_keymap) {
|
||||
const char *dir;
|
||||
_cleanup_free_ char *n;
|
||||
|
||||
if (c->x11_variant)
|
||||
n = strjoin(c->x11_layout, "-", c->x11_variant, NULL);
|
||||
else
|
||||
n = strdup(c->x11_layout);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
|
||||
_cleanup_free_ char *p = NULL, *pz = NULL;
|
||||
|
||||
p = strjoin(dir, "xkb/", n, ".map", NULL);
|
||||
pz = strjoin(dir, "xkb/", n, ".map.gz", NULL);
|
||||
if (!p || !pz)
|
||||
return -ENOMEM;
|
||||
|
||||
if (access(p, F_OK) == 0 || access(pz, F_OK) == 0) {
|
||||
*new_keymap = n;
|
||||
n = NULL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_legacy_keymap(Context *c, char **new_keymap) {
|
||||
_cleanup_fclose_ FILE *f;
|
||||
unsigned n = 0;
|
||||
unsigned best_matching = 0;
|
||||
|
||||
|
||||
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
unsigned matching = 0;
|
||||
int r;
|
||||
|
||||
r = read_next_mapping(f, &n, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
/* Determine how well matching this entry is */
|
||||
if (streq_ptr(c->x11_layout, a[1]))
|
||||
/* If we got an exact match, this is best */
|
||||
matching = 10;
|
||||
else {
|
||||
size_t x;
|
||||
|
||||
x = strcspn(c->x11_layout, ",");
|
||||
|
||||
/* We have multiple X layouts, look for an
|
||||
* entry that matches our key with everything
|
||||
* but the first layout stripped off. */
|
||||
if (x > 0 &&
|
||||
strlen(a[1]) == x &&
|
||||
strneq(c->x11_layout, a[1], x))
|
||||
matching = 5;
|
||||
else {
|
||||
size_t w;
|
||||
|
||||
/* If that didn't work, strip off the
|
||||
* other layouts from the entry, too */
|
||||
w = strcspn(a[1], ",");
|
||||
|
||||
if (x > 0 && x == w &&
|
||||
memcmp(c->x11_layout, a[1], x) == 0)
|
||||
matching = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (matching > 0 &&
|
||||
streq_ptr(c->x11_model, a[2])) {
|
||||
matching++;
|
||||
|
||||
if (streq_ptr(c->x11_variant, a[3])) {
|
||||
matching++;
|
||||
|
||||
if (streq_ptr(c->x11_options, a[4]))
|
||||
matching++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The best matching entry so far, then let's save that */
|
||||
if (matching > best_matching) {
|
||||
best_matching = matching;
|
||||
|
||||
free(*new_keymap);
|
||||
*new_keymap = strdup(a[0]);
|
||||
if (!*new_keymap)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
|
||||
bool modified = false;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
|
||||
@ -646,79 +752,15 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
|
||||
|
||||
context_free_x11(c);
|
||||
} else {
|
||||
_cleanup_fclose_ FILE *f;
|
||||
unsigned n = 0;
|
||||
unsigned best_matching = 0;
|
||||
char *new_keymap = NULL;
|
||||
|
||||
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
unsigned matching = 0;
|
||||
int r;
|
||||
|
||||
r = read_next_mapping(f, &n, &a);
|
||||
r = find_converted_keymap(c, &new_keymap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else if (r == 0) {
|
||||
r = find_legacy_keymap(c, &new_keymap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
/* Determine how well matching this entry is */
|
||||
if (streq_ptr(c->x11_layout, a[1]))
|
||||
/* If we got an exact match, this is best */
|
||||
matching = 10;
|
||||
else {
|
||||
size_t x;
|
||||
|
||||
x = strcspn(c->x11_layout, ",");
|
||||
|
||||
/* We have multiple X layouts, look
|
||||
* for an entry that matches our key
|
||||
* with the everything but the first
|
||||
* layout stripped off. */
|
||||
if (x > 0 &&
|
||||
strlen(a[1]) == x &&
|
||||
strneq(c->x11_layout, a[1], x))
|
||||
matching = 5;
|
||||
else {
|
||||
size_t w;
|
||||
|
||||
/* If that didn't work, strip
|
||||
* off the other layouts from
|
||||
* the entry, too */
|
||||
w = strcspn(a[1], ",");
|
||||
|
||||
if (x > 0 && x == w &&
|
||||
memcmp(c->x11_layout, a[1], x) == 0)
|
||||
matching = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (matching > 0 &&
|
||||
streq_ptr(c->x11_model, a[2])) {
|
||||
matching++;
|
||||
|
||||
if (streq_ptr(c->x11_variant, a[3])) {
|
||||
matching++;
|
||||
|
||||
if (streq_ptr(c->x11_options, a[4]))
|
||||
matching++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The best matching entry so far, then let's
|
||||
* save that */
|
||||
if (matching > best_matching) {
|
||||
best_matching = matching;
|
||||
|
||||
free(new_keymap);
|
||||
new_keymap = strdup(a[0]);
|
||||
if (!new_keymap)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (!streq_ptr(c->vc_keymap, new_keymap)) {
|
||||
@ -730,8 +772,6 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
int r;
|
||||
|
||||
r = vconsole_write_data(c);
|
||||
if (r < 0)
|
||||
log_error("Failed to set virtual console keymap: %s", strerror(-r));
|
||||
|
@ -43,3 +43,16 @@
|
||||
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
||||
|
||||
#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
|
||||
|
||||
#ifdef HAVE_SPLIT_USR
|
||||
#define KBD_KEYMAP_DIRS \
|
||||
"/usr/share/keymaps/\0" \
|
||||
"/usr/share/kbd/keymaps/\0" \
|
||||
"/usr/lib/kbd/keymaps/\0" \
|
||||
"/lib/kbd/keymaps/\0"
|
||||
#else
|
||||
#define KBD_KEYMAP_DIRS \
|
||||
"/usr/share/keymaps/\0" \
|
||||
"/usr/share/kbd/keymaps/\0" \
|
||||
"/usr/lib/kbd/keymaps/\0"
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user