From 354d8234f177bca65eddf1451b180772cdbf7611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 18 Nov 2013 13:42:57 -0500 Subject: [PATCH] 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/[-].map[.gz] exists, [-] 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 Conflicts: src/locale/localed.c src/shared/def.h --- src/locale/localectl.c | 8 +-- src/locale/localed.c | 189 ++++++++++++++++++++++++++++--------------------- src/shared/def.h | 13 ++++ 3 files changed, 126 insertions(+), 84 deletions(-) diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 8259c0a..d3c6152 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -38,6 +38,7 @@ #include "set.h" #include "path-util.h" #include "utf8.h" +#include "def.h" static bool arg_no_pager = false; static enum transport { @@ -533,15 +534,14 @@ static int nftw_cb( static int list_vconsole_keymaps(DBusConnection *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) { diff --git a/src/locale/localed.c b/src/locale/localed.c index e160c04..b9b98f4 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -792,105 +792,135 @@ static int convert_vconsole_to_x11(DBusConnection *connection) { return 0; } -static int convert_x11_to_vconsole(DBusConnection *connection) { - bool modified = false; +static int find_converted_keymap(char **new_keymap) { + const char *dir; + _cleanup_free_ char *n; + + if (state.x11_variant) + n = strjoin(state.x11_layout, "-", state.x11_variant, NULL); + else + n = strdup(state.x11_layout); + if (!n) + return -ENOMEM; - assert(connection); + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + _cleanup_free_ char *p = NULL, *pz = NULL; - if (isempty(state.x11_layout)) { + p = strjoin(dir, "xkb/", n, ".map", NULL); + pz = strjoin(dir, "xkb/", n, ".map.gz", NULL); + if (!p || !pz) + return -ENOMEM; - modified = - !isempty(state.vc_keymap) || - !isempty(state.vc_keymap_toggle); + if (access(p, F_OK) == 0 || access(pz, F_OK) == 0) { + *new_keymap = n; + n = NULL; + return 1; + } + } - free_data_x11(); - } else { - FILE *f; - unsigned n = 0; - unsigned best_matching = 0; - char *new_keymap = NULL; + return 0; +} - f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); - if (!f) - return -errno; +static int find_legacy_keymap(char **new_keymap) { + _cleanup_fclose_ FILE *f; + unsigned n = 0; + unsigned best_matching = 0; - for (;;) { - char **a; - unsigned matching = 0; - int r; - r = read_next_mapping(f, &n, &a); - if (r < 0) { - fclose(f); - return r; - } + f = fopen(SYSTEMD_KBD_MODEL_MAP, "re"); + if (!f) + return -errno; - if (r == 0) - break; + for (;;) { + _cleanup_strv_free_ char **a = NULL; + unsigned matching = 0; + int r; - /* Determine how well matching this entry is */ - if (streq_ptr(state.x11_layout, a[1])) - /* If we got an exact match, this is best */ - matching = 10; - else { - size_t x; - - x = strcspn(state.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(state.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(state.x11_layout, a[1], x) == 0) - matching = 1; - } + 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(state.x11_layout, a[1])) + /* If we got an exact match, this is best */ + matching = 10; + else { + size_t x; + + x = strcspn(state.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(state.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(state.x11_layout, a[1], x) == 0) + matching = 1; } + } + + if (matching > 0 && + streq_ptr(state.x11_model, a[2])) { + matching++; - if (matching > 0 && - streq_ptr(state.x11_model, a[2])) { + if (streq_ptr(state.x11_variant, a[3])) { matching++; - if (streq_ptr(state.x11_variant, a[3])) { + if (streq_ptr(state.x11_options, a[4])) matching++; - - if (streq_ptr(state.x11_options, a[4])) - matching++; - } } + } - /* The best matching entry so far, then let's - * save that */ - if (matching > best_matching) { - best_matching = 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]); + free(*new_keymap); + *new_keymap = strdup(a[0]); + if (!*new_keymap) + return -ENOMEM; + } + } - if (!new_keymap) { - strv_free(a); - fclose(f); - return -ENOMEM; - } - } + return 0; +} - strv_free(a); - } +static int convert_x11_to_vconsole(DBusConnection *connection) { + bool modified = false; + int r; - fclose(f); + assert(connection); + + if (isempty(state.x11_layout)) { + + modified = + !isempty(state.vc_keymap) || + !isempty(state.vc_keymap_toggle); + + free_data_x11(); + } else { + char *new_keymap = NULL; + + r = find_converted_keymap(&new_keymap); + if (r < 0) + return r; + else if (r == 0) { + r = find_legacy_keymap(&new_keymap); + if (r < 0) + return r; + } if (!streq_ptr(state.vc_keymap, new_keymap)) { free(state.vc_keymap); @@ -907,7 +937,6 @@ static int convert_x11_to_vconsole(DBusConnection *connection) { if (modified) { dbus_bool_t b; DBusMessage *changed; - int r; r = write_data_vconsole(); if (r < 0) diff --git a/src/shared/def.h b/src/shared/def.h index e4ef735..58c834c 100644 --- a/src/shared/def.h +++ b/src/shared/def.h @@ -41,3 +41,16 @@ #define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS + +#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