203 lines
5.0 KiB
Python
203 lines
5.0 KiB
Python
#
|
|
# Copyright 2006-2013 Red Hat, Inc.
|
|
#
|
|
# This work is licensed under the GNU GPLv2 or later.
|
|
# See the COPYING file in the top-level directory.
|
|
#
|
|
|
|
import logging
|
|
import os
|
|
import re
|
|
|
|
|
|
_ETC_VCONSOLE = "/etc/vconsole.conf"
|
|
_KEYBOARD_DIR = "/etc/sysconfig/keyboard"
|
|
_XORG_CONF = "/etc/X11/xorg.conf"
|
|
_CONSOLE_SETUP_CONF = "/etc/default/console-setup"
|
|
_KEYBOARD_DEFAULT = "/etc/default/keyboard"
|
|
|
|
|
|
def _find_xkblayout(f):
|
|
"""
|
|
Reads a keyboard layout from a file that defines an XKBLAYOUT
|
|
variable, e.g. /etc/default/{keyboard,console-setup}.
|
|
The format of these files is such that they can be 'sourced'
|
|
in a shell script.
|
|
|
|
Used for both /etc/default/keyboard and /etc/default/console-setup.
|
|
The former is used by Debian 6.0 (Squeeze) and later. The latter is
|
|
used by older versions of Debian, and Ubuntu.
|
|
"""
|
|
kt = None
|
|
keymap_re = re.compile(r'\s*XKBLAYOUT="(?P<kt>[a-z-]+)"')
|
|
for line in f:
|
|
m = keymap_re.match(line)
|
|
if m:
|
|
kt = m.group('kt')
|
|
break
|
|
return kt
|
|
|
|
|
|
def _xorg_keymap(f):
|
|
"""
|
|
Look in /etc/X11/xorg.conf for the host machine's keymap, and attempt to
|
|
map it to a keymap supported by qemu
|
|
"""
|
|
kt = None
|
|
keymap_re = re.compile(r'\s*Option\s+"XkbLayout"\s+"(?P<kt>[a-z-]+)"')
|
|
for line in f:
|
|
m = keymap_re.match(line)
|
|
if m:
|
|
kt = m.group('kt')
|
|
break
|
|
return kt
|
|
|
|
|
|
def _sysconfig_keyboard(f):
|
|
kt = None
|
|
while 1:
|
|
s = f.readline()
|
|
if s == "":
|
|
break
|
|
s = s.strip()
|
|
if s.startswith("#"):
|
|
continue
|
|
if (re.search("KEYMAP", s) is not None or
|
|
re.search("KEYTABLE", s) is not None or
|
|
(re.search("KEYBOARD", s) is not None and
|
|
re.search("KEYBOARDTYPE", s) is None)):
|
|
if '"' in s:
|
|
delim = '"'
|
|
elif '=' in s:
|
|
delim = '='
|
|
else:
|
|
continue
|
|
kt = s.split(delim)[1].strip()
|
|
break
|
|
return kt
|
|
|
|
|
|
def _default_keymap():
|
|
"""
|
|
Look in various config files for the host machine's keymap, and attempt
|
|
to map it to a keymap supported by qemu
|
|
"""
|
|
# Set keymap to same as hosts
|
|
default = "en-us"
|
|
keymap = None
|
|
|
|
kt = None
|
|
|
|
if "VIRTINST_TEST_SUITE" in os.environ:
|
|
return default
|
|
|
|
for path, cb in [
|
|
(_ETC_VCONSOLE, _sysconfig_keyboard),
|
|
(_KEYBOARD_DIR, _sysconfig_keyboard),
|
|
(_XORG_CONF, _xorg_keymap),
|
|
(_KEYBOARD_DEFAULT, _find_xkblayout),
|
|
(_CONSOLE_SETUP_CONF, _find_xkblayout)]:
|
|
if not os.path.exists(path):
|
|
continue
|
|
|
|
try:
|
|
f = open(path, "r")
|
|
kt = cb(f)
|
|
f.close()
|
|
if kt:
|
|
logging.debug("Found keymap=%s in %s", kt, path)
|
|
break
|
|
logging.debug("Didn't find keymap in '%s'", path)
|
|
except Exception as e:
|
|
logging.debug("Error parsing '%s': %s", path, str(e))
|
|
|
|
if kt is None:
|
|
logging.debug("Did not parse any usable keymapping.")
|
|
return default
|
|
|
|
kt = kt.lower()
|
|
keymap = sanitize_keymap(kt)
|
|
if not keymap:
|
|
logging.debug("Didn't match keymap '%s' in keytable!", kt)
|
|
return default
|
|
return keymap
|
|
|
|
|
|
##################
|
|
# Public helpers #
|
|
##################
|
|
|
|
# Host keytable entry : keymap name in qemu/xen
|
|
# Only use lower case entries: all lookups are .lower()'d
|
|
keytable = {
|
|
"ar": "ar",
|
|
"da": "da", "dk": "da",
|
|
"de": "de",
|
|
"de-ch": "de-ch",
|
|
"en-gb": "en-gb", "gb": "en-gb", "uk": "en-gb",
|
|
"en-us": "en-us", "us": "en-us",
|
|
"es": "es",
|
|
"et": "et",
|
|
"fi": "fi", "se_fi": "fi",
|
|
"fo": "fo",
|
|
"fr": "fr",
|
|
"fr-be": "fr-be", "be": "fr-be",
|
|
"fr-ca": "fr-ca", "ca": "fr-ca",
|
|
"fr-ch": "fr-ch", "fr_ch": "fr-ch",
|
|
"hr": "hr",
|
|
"hu": "hu",
|
|
"is": "is",
|
|
"it": "it",
|
|
"ja": "ja", "jp106": "ja", "jp": "ja",
|
|
"lt": "lt",
|
|
"lv": "lv",
|
|
"mk": "mk",
|
|
"nl": "nl",
|
|
"nl-be": "nl-be",
|
|
"no": "no",
|
|
"pl": "pl",
|
|
"pt": "pt",
|
|
"pt-br": "pt-br", "br": "pt-br", "br-abnt2": "pt-br",
|
|
"ru": "ru",
|
|
"sl": "sl",
|
|
"sv": "sv",
|
|
"th": "th",
|
|
"tr": "tr",
|
|
}
|
|
|
|
|
|
_cached_keymap = None
|
|
|
|
|
|
def default_keymap():
|
|
global _cached_keymap
|
|
if _cached_keymap is None:
|
|
_cached_keymap = _default_keymap()
|
|
return _cached_keymap
|
|
|
|
|
|
def sanitize_keymap(kt):
|
|
"""
|
|
Make sure the passed keymap roughly matches something in keytable
|
|
"""
|
|
if kt.lower() in keytable:
|
|
return keytable[kt]
|
|
|
|
# Try a more intelligent lookup: strip out all '-' and '_', sort
|
|
# the keytable keys putting the longest first, then compare
|
|
# by string prefix
|
|
def len_cmp(a, b):
|
|
return len(b) - len(a)
|
|
|
|
clean_kt = kt.replace("-", "").replace("_", "")
|
|
sorted_keys = sorted(list(keytable.keys()), len_cmp)
|
|
|
|
for key in sorted_keys:
|
|
origkey = key
|
|
key = key.replace("-", "").replace("_", "")
|
|
|
|
if clean_kt.startswith(key):
|
|
return keytable[origkey]
|
|
|
|
return None
|