mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-25 23:21:33 +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 "set.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
static bool arg_no_pager = false;
|
static bool arg_no_pager = false;
|
||||||
static bool arg_ask_password = true;
|
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) {
|
static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
const char *dir;
|
||||||
|
|
||||||
keymaps = set_new(string_hash_func, string_compare_func);
|
keymaps = set_new(string_hash_func, string_compare_func);
|
||||||
if (!keymaps)
|
if (!keymaps)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
nftw("/usr/share/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS)
|
||||||
nftw("/usr/share/kbd/keymaps/", nftw_cb, 20, FTW_MOUNT|FTW_PHYS);
|
nftw(dir, 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);
|
|
||||||
|
|
||||||
l = set_get_strv(keymaps);
|
l = set_get_strv(keymaps);
|
||||||
if (!l) {
|
if (!l) {
|
||||||
|
@ -633,8 +633,114 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
|
|||||||
return 0;
|
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) {
|
static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(bus);
|
assert(bus);
|
||||||
|
|
||||||
@ -646,79 +752,15 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
|
|||||||
|
|
||||||
context_free_x11(c);
|
context_free_x11(c);
|
||||||
} else {
|
} else {
|
||||||
_cleanup_fclose_ FILE *f;
|
|
||||||
unsigned n = 0;
|
|
||||||
unsigned best_matching = 0;
|
|
||||||
char *new_keymap = NULL;
|
char *new_keymap = NULL;
|
||||||
|
|
||||||
f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
|
r = find_converted_keymap(c, &new_keymap);
|
||||||
if (!f)
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
else if (r == 0) {
|
||||||
for (;;) {
|
r = find_legacy_keymap(c, &new_keymap);
|
||||||
_cleanup_strv_free_ char **a = NULL;
|
|
||||||
unsigned matching = 0;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = read_next_mapping(f, &n, &a);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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)) {
|
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) {
|
if (modified) {
|
||||||
int r;
|
|
||||||
|
|
||||||
r = vconsole_write_data(c);
|
r = vconsole_write_data(c);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error("Failed to set virtual console keymap: %s", strerror(-r));
|
log_error("Failed to set virtual console keymap: %s", strerror(-r));
|
||||||
|
@ -43,3 +43,16 @@
|
|||||||
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
|
||||||
|
|
||||||
#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
|
#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