# # Copyright (C) 2019 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. # from pyanaconda.core.util import execWithRedirect from pyanaconda.core.configuration.anaconda import conf from pyanaconda.modules.common.errors.configuration import KeyboardConfigurationError from pyanaconda.modules.common.task import Task from pyanaconda.modules.localization.utils import get_missing_keyboard_configuration from pyanaconda.anaconda_loggers import get_module_logger from pyanaconda.modules.localization.installation import write_vc_configuration log = get_module_logger(__name__) class AssignGenericKeyboardSettingTask(Task): """Task for assignment of generic keyboard specification to a specific configuration.""" def __init__(self, keyboard): """Create a new task. :param keyboard: generic system keyboard specification :type keyboard: str """ super().__init__() self._keyboard = keyboard @property def name(self): return "Assign generic keyboard setting value." def run(self): """Run assignment of generic keyboard setting value. :returns: tuple of X layouts and VC keyboard settings :rtype: (list(str), str)) """ x_layouts = [] vc_keymap = "" if conf.system.can_activate_keyboard: is_keymap = try_to_load_keymap(self._keyboard) if is_keymap: vc_keymap = self._keyboard else: x_layouts.append(self._keyboard) else: vc_keymap = self._keyboard return x_layouts, vc_keymap class GetMissingKeyboardConfigurationTask(Task): """Task for getting missing keyboard settings by conversion and default values.""" def __init__(self, localed_wrapper, x_layouts, vc_keymap): """Create a new task. :param localed_wrapper: instance of systemd-localed service wrapper :type localed_wrapper: LocaledWrapper :param x_layouts: list of x layout specifications :type x_layouts: list(str) :param vc_keymap: virtual console keyboard mapping name :type vc_keymap: str """ super().__init__() self._localed_wrapper = localed_wrapper self._x_layouts = x_layouts self._vc_keymap = vc_keymap @property def name(self): return "Get missing keyboard settings." def run(self): """Run getting of missing keyboard settings. :returns: tuple of X layouts and VC keyboard settings :rtype: (list(str), str)) """ return get_missing_keyboard_configuration(self._localed_wrapper, self._x_layouts, self._vc_keymap) class ApplyKeyboardTask(Task): """Task for applying keyboard settings to current system.""" def __init__(self, localed_wrapper, x_layouts, vc_keymap, switch_options): """Create a new task. :param localed_wrapper: instance of systemd-localed service wrapper :type localed_wrapper: LocaledWrapper :param x_layouts: list of x layout specifications :type x_layouts: list(str) :param vc_keymap: virtual console keyboard mapping name :type vc_keymap: str :param switch_options: list of options for layout switching :type switch_options: list(str) """ super().__init__() self._localed_wrapper = localed_wrapper self._x_layouts = x_layouts self._vc_keymap = vc_keymap self._switch_options = switch_options @property def name(self): return "Apply keyboard configuration." def run(self): """Run application of keyboard settings. :returns: tuple of X layouts and VC keyboard settings after application :rtype: (list(str), str)) """ if not conf.system.can_activate_keyboard: log.debug("Activating of keyboard configuration is disabled on this system.") return self._x_layouts, self._vc_keymap if not self._vc_keymap and not self._x_layouts: log.debug("Not applying keyboard configuration:" "neither VConsole not X Layouts are set.") return self._x_layouts, self._vc_keymap vc_keymap = self._vc_keymap x_layouts = self._x_layouts x_layouts_from_conversion = None if vc_keymap: valid_keymap = try_to_load_keymap(vc_keymap) if not valid_keymap: log.error("'%s' is not a valid VConsole keymap, not loading", vc_keymap) vc_keymap = "" else: # activate VConsole keymap and get converted layout and variant x_layouts_from_conversion = self._localed_wrapper.set_and_convert_keymap(vc_keymap) if not x_layouts: if x_layouts_from_conversion: # suggested by systemd-localed for a requested VConsole keymap x_layouts += x_layouts_from_conversion elif vc_keymap: # nothing suggested by systemd-localed, but we may try to use the # same string for both VConsole keymap and X layout (will fail # safely if it doesn't work) x_layouts.append(vc_keymap) if x_layouts: if not vc_keymap: vc_keymap = self._localed_wrapper.set_and_convert_layouts(x_layouts) self._localed_wrapper.set_layouts(x_layouts, self._switch_options) # FIXME: is this really needed? # Only because of configuration of the FONT, if at all. write_vc_configuration(vc_keymap, root="/") return x_layouts, vc_keymap def try_to_load_keymap(keymap): """ Method that tries to load keymap and returns boolean indicating if it was successfull or not. It can be used to test if given string is VConsole keymap or not, but in case it is given valid keymap, IT REALLY LOADS IT!. :type keymap: string :raise KeyboardConfigurationError: if loadkeys command is not available :return: True if given string was a valid keymap and thus was loaded, False otherwise """ # BUG: systemd-localed should be able to tell us if we are trying to # activate invalid keymap. Then we will be able to get rid of this # fuction ret = 0 try: ret = execWithRedirect("loadkeys", [keymap]) except OSError as oserr: msg = "'loadkeys' command not available (%s)" % oserr.strerror raise KeyboardConfigurationError(msg) from oserr return ret == 0