• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-country / 15022004526

14 May 2025 01:29PM UTC coverage: 42.791% (-0.2%) from 43.025%
15022004526

Pull #328

github

web-flow
Merge f0e471a76 into 17e9fd3be
Pull Request #328: Load required "setxkbmap" package on demand (bsc#1243088)

1484 of 3468 relevant lines covered (42.79%)

12.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.69
/keyboard/src/lib/y2keyboard/strategies/kb_strategy.rb
1
# Copyright (c) [2019] SUSE LLC
2
#
3
# All Rights Reserved.
4
#
5
# This program is free software; you can redistribute it and/or modify it
6
# under the terms of version 2 of the GNU General Public License as published
7
# by the Free Software Foundation.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12
# more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with this program; if not, contact SUSE LLC.
16
#
17
# To contact SUSE LLC about this file by physical or electronic mail, you may
18
# find current contact information at www.suse.com.
19

20
require "yast"
1✔
21
require "yast2/execute"
1✔
22
require "shellwords"
1✔
23

24
module Y2Keyboard
1✔
25
  module Strategies
1✔
26
    Yast.import "Directory"
1✔
27
    Yast.import "Stage"
1✔
28

29
    # Class to deal with xkb and kbd keyboard configuration management.
30
    # Use this class only for temporary changes like changing keyboard
31
    # layout "on the fly" for example in the inst-sys.
32
    #
33
    # Use the systemd strategy for making keyboard changes permanent on
34
    # the installed system.
35
    #
36
    class KbStrategy
1✔
37
      include Yast::Logger
1✔
38

39
      # Writing rules in /etc/udev would result in those files being copied to
40
      # the installed system. That's not what we want. sys-int is temporary, so
41
      # writing in its /run is safe.
42
      UDEV_FILE = "/run/udev/rules.d/70-installation-keyboard.rules"
1✔
43
      UDEV_COMMENT = "# Generated by Yast to handle the layout of keyboards "\
1✔
44
                     "connected during installation\n"
45

46
      # Used to set keybaord layout in a running system.
47
      # @param keyboard_code [String] the keyboard layout (e.g. "us") to set
48
      # in the running the system (mostly temporary).
49
      def set_layout(keyboard_code)
1✔
50
        if keyboard_code.nil? || keyboard_code.empty?
11✔
51
          log.info "Keyboard has not been defined. Do not set it."
1✔
52
          return
1✔
53
        end
54

55
        if Yast::UI.TextMode
10✔
56
          begin
57
            Yast::Execute.on_target!("loadkeys", *loadkeys_devices("tty"), keyboard_code)
2✔
58
            # It could be that for seriell tty's the keyboard cannot be set. So it will
59
            # be done separately in order to ensure that setting console keyboard
60
            # will be done successfully in the previous call.
61
            Yast::Execute.on_target!("loadkeys", *loadkeys_devices("ttyS"), keyboard_code)
1✔
62
            Yast::Execute.on_target!("loadkeys", *loadkeys_devices("ttyAMA"), keyboard_code)
1✔
63
          rescue Cheetah::ExecutionFailed => e
64
            log.info(e.message)
1✔
65
            log.info("Error output:    #{e.stderr}")
1✔
66
          end
67
        else
68
          # X11 mode
69
          set_x11_layout(keyboard_code)
8✔
70
        end
71
      end
72

73
    private
1✔
74

75
      # set x11 keys on the fly.
76
      # @param keyboard_code [String] the keyboard to set.
77
      def set_x11_layout(keyboard_code)
1✔
78
        x11data = get_x11_data(keyboard_code)
7✔
79
        return if x11data.empty?
7✔
80

81
        Yast::Execute.locally("/usr/bin/setxkbmap", *x11data["Apply"].split(" "))
7✔
82

83
        # bnc#885271: set udev rule to handle incoming attached keyboards
84
        # While installation/update only.
85
        write_udev_rule(x11data) if Yast::Stage.initial
7✔
86
      end
87

88
      # String to specify all the relevant devices in a loadkeys command
89
      #
90
      # It includes all tty[0-9]* and ttyS[0-9]* devices (bsc#1010938).
91
      #
92
      # @param [String] kind of tty ("tty", "ttyS")
93
      # @return [Array<String>] array with params for the loadkeys command
94
      def loadkeys_devices(kind)
1✔
95
        tty_dev_names = Dir["/dev/#{kind}[0-9]*"]
4✔
96
        tty_dev_names.each_with_object([]) { |d,res| res << "-C" << d }
10✔
97
      end
98

99
      # GetX11KeyData()
100
      #
101
      # Get the keyboard info for X11 for the given keymap
102
      #
103
      # @param        name of the keymap
104
      #
105
      # @return  [Hash] containing the x11 config data
106
      #
107
      def get_x11_data(keymap)
1✔
108
        cmd = "/usr/sbin/xkbctrl"
6✔
109
        x11data = {}
6✔
110

111
        if File.executable?(cmd)
6✔
112
          xkbctrl = Yast::Execute.locally(cmd, keymap, stdout: :capture)
6✔
113
          x11data = read_ycp_string(xkbctrl)
6✔
114
        else
115
          log.warn("#{cmd} not found on system.")
×
116
        end
117
        x11data
6✔
118
      end
119

120
      # Creates an udev rule to manage the layout for keyboards that are
121
      # hotplugged during the installation process
122
      #
123
      # @param        [Hash] X11 settings
124
      def write_udev_rule(x11data)
1✔
125
        # Remove the file if present (needed to make udev aware of changes)
126
        File.delete(UDEV_FILE) if File.file?(UDEV_FILE)
×
127

128
        # Using an array of arrays instead of a hash to get a predictable and
129
        # ordered rule (even if it's not required by udev itself)
130
        udev_env = [["XKBLAYOUT", x11data["XkbLayout"] || ""],
×
131
                    ["XKBMODEL", x11data["XkbModel"] || ""],
132
                    ["XKBOPTIONS", x11data["XkbOptions"] || ""]]
133
        udev_env.delete_if {|key,value| value.nil? || value.empty? }
×
134
        if !udev_env.empty?
×
135
          rule = 'ENV{ID_INPUT_KEYBOARD}=="1", '
×
136
          rule << udev_env.map {|key,value| "ENV{#{key}}=\"#{value}\"" }.join(", ")
×
137
          Yast::SCR.Write(Yast::path(".target.string"), UDEV_FILE, UDEV_COMMENT + rule + "\n")
×
138
          Yast::SCR.Write(Yast::path(".target.string"), UDEV_FILE, nil)
×
139
        end
140
      end
141

142
      # Parses the given YCP data structure
143
      #
144
      # @param str [String] string containing a YCP data structure
145
      # @return [Hash]
146
      def read_ycp_string(str)
1✔
147
        file = File.join(Yast::Directory.tmpdir, "content.ycp")
6✔
148
        File.write(file, str)
6✔
149
        Yast::SCR.Read(Yast::path(".target.ycp"), file)
6✔
150
      end
151
    end
152
  end
153
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc