From 879695cb5fbec0aca094d029119fcbfa1f7d1cc5 Mon Sep 17 00:00:00 2001 From: Adam Kankovsky Date: Tue, 14 Jan 2025 10:28:32 +0100 Subject: [PATCH] Adding dbus interface for loading locale keyboards --- pyanaconda/localization.py | 72 +++++++++++++++++++ .../localization/localization_interface.py | 13 ++++ 2 files changed, 85 insertions(+) diff --git a/pyanaconda/localization.py b/pyanaconda/localization.py index 3e44ebb462a..a5126a49834 100644 --- a/pyanaconda/localization.py +++ b/pyanaconda/localization.py @@ -389,6 +389,78 @@ def get_territory_locales(territory): """ return langtable.list_locales(territoryId=territory) +def normalize_language(lang): + """Normalize the language string to extract the relevant part.""" + parts = lang.split(".")[0].split("_") + return parts[1].lower() if len(parts) > 1 else parts[0] + + +def get_locale_keyboard_layouts(lang): + """Get keyboard layouts for the specified language. + + :param lang: Language code string (e.g., "en_US.UTF-8") + :return: List of keyboard layout dictionaries + :raises: Exception if the file cannot be read or processed + """ + normalized_lang = normalize_language(lang) + file_path = "/usr/share/X11/xkb/rules/evdev.lst" + + try: + with open(file_path, "r") as file: + content = file.read() + lines = content.strip().split("\n") + + layouts = [] + layout_map = {} + in_variant_section = False + + # Parse the base layout IDs and store them in a map + for line in lines: + if line.startswith("! layout"): + in_variant_section = False + continue + elif line.startswith("! variant"): + in_variant_section = True + continue + elif line.startswith("! "): + in_variant_section = False + + if not in_variant_section: + parts = re.split(r"\s+", line.strip()) + if len(parts) >= 2: + layout_id = parts[0] + layout_name = " ".join(parts[1:]).strip() + layout_map[layout_id] = layout_name + + # Parse the variant section and associate with layout IDs + in_variant_section = False + for line in lines: + if line.startswith("! variant"): + in_variant_section = True + continue + elif line.startswith("! "): + in_variant_section = False + + if in_variant_section: + parts = re.split(r"\s+", line.strip()) + if len(parts) > 1 and parts[1].startswith(f"{normalized_lang}:"): + variant_id = parts[0] + description = " ".join(parts[1:]).replace(f"{normalized_lang}:", "").strip() + + # Find the base layout ID associated with this variant + base_layout_id = next((layout_id for layout_id in layout_map.keys() if parts[1].startswith(f"{normalized_lang}:") and layout_id in parts[1]), "unknown") + + layouts.append({ + "description": description, + "layoutId": base_layout_id, + "variantId": variant_id, + }) + + return layouts if layouts else [{"description": "Default US layout", "layoutId": "us", "variantId": "us"}] + except Exception as error: + log.error(f"Failed to process keyboard layouts for language {lang}: {error}") + raise + def get_locale_keyboards(locale): """Function returning preferred keyboard layouts for the given locale. diff --git a/pyanaconda/modules/localization/localization_interface.py b/pyanaconda/modules/localization/localization_interface.py index 0b46702583c..8ae9f21c358 100644 --- a/pyanaconda/modules/localization/localization_interface.py +++ b/pyanaconda/modules/localization/localization_interface.py @@ -91,6 +91,19 @@ def GetLocaleData(self, locale_id: Str) -> Structure: locale_data = self.implementation.get_locale_data(locale_id) return LocaleData.to_structure(locale_data) + def GetLocaleKeyboardLayouts(self, lang: Str) -> List[Structure]: + """Get keyboard layouts for the specified language. + + For example: [ + {"description": "US layout", "layoutId": "us", "variantId": ""}, + {"description": "Czech QWERTY", "layoutId": "cz", "variantId": "qwerty"} + ] + + :param lang: Language code string (e.g., "en_US.UTF-8") + :return: List of keyboard layout dictionaries + """ + return self.implementation.get_locale_keyboard_layouts(lang) + @property def Language(self) -> Str: """The language the system will use."""