Mini Shell

Direktori : /proc/thread-self/root/lib64/python3.6/site-packages/pyanaconda/
Upload File :
Current File : //proc/thread-self/root/lib64/python3.6/site-packages/pyanaconda/keyboard.py

#
# Copyright (C) 2012  Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#

"""
This module provides functions for dealing with keyboard layouts/keymaps in Anaconda.
"""

import re
import langtable

from pyanaconda.core.configuration.anaconda import conf
from pyanaconda import localization
from pyanaconda.core.constants import DEFAULT_KEYBOARD
from pyanaconda.modules.common.task import sync_run_task
from pyanaconda.modules.common.constants.services import LOCALIZATION

from pyanaconda.anaconda_loggers import get_module_logger
log = get_module_logger(__name__)


# should match and parse strings like 'cz' or 'cz (qwerty)' regardless of white
# space
LAYOUT_VARIANT_RE = re.compile(r'^\s*([/\w]+)\s*'  # layout plus
                               r'(?:(?:\(\s*([-\w]+)\s*\))'  # variant in parentheses
                               r'|(?:$))\s*')  # or nothing


class KeyboardConfigError(Exception):
    """Exception class for keyboard configuration related problems"""

    pass


class InvalidLayoutVariantSpec(Exception):
    """
    Exception class for errors related to parsing layout and variant specification strings.

    """

    pass


def parse_layout_variant(layout_variant_str):
    """
    Parse layout and variant from the string that may look like 'layout' or
    'layout (variant)'.

    :param layout_variant_str: keyboard layout and variant string specification
    :type layout_variant_str: str
    :return: the (layout, variant) pair, where variant can be ""
    :rtype: tuple
    :raise InvalidLayoutVariantSpec: if the given string isn't a valid layout
                                     and variant specification string

    """

    match = LAYOUT_VARIANT_RE.match(layout_variant_str)
    if not match:
        msg = "'%s' is not a valid keyboard layout and variant specification" % layout_variant_str
        raise InvalidLayoutVariantSpec(msg)

    layout, variant = match.groups()

    # groups may be (layout, None) if no variant was specified
    return (layout, variant or "")


def join_layout_variant(layout, variant=""):
    """
    Join layout and variant to form the commonly used 'layout (variant)'
    or 'layout' (if variant is missing) format.

    :type layout: string
    :type variant: string
    :return: 'layout (variant)' or 'layout' string
    :rtype: string

    """

    if variant:
        return "%s (%s)" % (layout, variant)
    else:
        return layout


def normalize_layout_variant(layout_str):
    """
    Normalize keyboard layout and variant specification given as a single
    string. E.g. for a 'layout(variant) string missing the space between the
    left parenthesis return 'layout (variant)' which is a proper layout and
    variant specification we use.

    :param layout_str: a string specifying keyboard layout and its variant
    :type layout_str: string

    """

    layout, variant = parse_layout_variant(layout_str)
    return join_layout_variant(layout, variant)


def populate_missing_items(localization_proxy=None):
    """
    Function that populates virtual console keymap and X layouts if they
    are missing. By invoking systemd-localed methods this function READS AND
    WRITES CONFIGURATION FILES (but tries to keep their content unchanged).

    :param localization_proxy: DBus proxy of the localization module or None

    """
    task_path = localization_proxy.PopulateMissingKeyboardConfigurationWithTask()
    task_proxy = LOCALIZATION.get_proxy(task_path)
    sync_run_task(task_proxy)


def activate_keyboard(localization_proxy):
    """
    Try to setup VConsole keymap and X11 layouts as specified in kickstart.

    :param localization_proxy: DBus proxy of the localization module or None

    """
    task_path = localization_proxy.ApplyKeyboardWithTask()
    task_proxy = LOCALIZATION.get_proxy(task_path)
    sync_run_task(task_proxy)


def set_x_keyboard_defaults(localization_proxy, xkl_wrapper):
    """
    Set default keyboard settings (layouts, layout switching).

    :param localization_proxy: DBus proxy of the localization module or None
    :type ksdata: object instance
    :param xkl_wrapper: XklWrapper instance
    :type xkl_wrapper: object instance
    :raise InvalidLocaleSpec: if an invalid locale is given (see
                              localization.is_valid_langcode)
    """
    x_layouts = localization_proxy.XLayouts
    # remove all X layouts that are not valid X layouts (unsupported)
    valid_layouts = []
    for layout in x_layouts:
        if xkl_wrapper.is_valid_layout(layout):
            valid_layouts.append(layout)
    localization_proxy.SetXLayouts(valid_layouts)

    if valid_layouts:
        # do not add layouts if there are any specified in the kickstart
        # (the x_layouts list comes from kickstart)
        return

    locale = localization_proxy.Language
    layouts = localization.get_locale_keyboards(locale)
    if layouts:
        # take the first locale (with highest rank) from the list and
        # store it normalized
        new_layouts = [normalize_layout_variant(layouts[0])]
        if not langtable.supports_ascii(layouts[0]):
            # does not support typing ASCII chars, append the default layout
            new_layouts.append(DEFAULT_KEYBOARD)
    else:
        log.error("Failed to get layout for chosen locale '%s'", locale)
        new_layouts = [DEFAULT_KEYBOARD]

    localization_proxy.SetXLayouts(new_layouts)
    if conf.system.can_configure_keyboard:
        xkl_wrapper.replace_layouts(new_layouts)

    if len(new_layouts) >= 2 and not localization_proxy.LayoutSwitchOptions:
        # initialize layout switching if needed
        localization_proxy.SetLayoutSwitchOptions(["grp:alt_shift_toggle"])

        if conf.system.can_configure_keyboard:
            xkl_wrapper.set_switching_options(["grp:alt_shift_toggle"])
            # activate the language-default layout instead of the additional
            # one
            xkl_wrapper.activate_default_layout()