virt-manager/virtinst/hostkeymap.py

201 lines
4.9 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 os
import re
from .logger import log
_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:
log.debug("Found keymap=%s in %s", kt, path)
break
log.debug("Didn't find keymap in '%s'", path)
except Exception as e:
log.debug("Error parsing '%s': %s", path, str(e))
if kt is None:
log.debug("Did not parse any usable keymapping.")
return default
kt = kt.lower()
keymap = sanitize_keymap(kt)
if not keymap:
log.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
clean_kt = kt.replace("-", "").replace("_", "")
sorted_keys = sorted(list(keytable.keys()), key=len)
for key in sorted_keys:
origkey = key
key = key.replace("-", "").replace("_", "")
if clean_kt.startswith(key):
return keytable[origkey]
return None