2013-04-14 00:31:13 +04:00
#
# Copyright 2006-2013 Red Hat, Inc.
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2013-04-14 00:31:13 +04:00
#
import logging
2013-10-02 20:35:01 +04:00
import os
2013-04-14 00:31:13 +04:00
import re
2013-07-14 04:58:09 +04:00
2013-10-02 20:35:01 +04:00
_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
2017-10-12 00:13:26 +03:00
s = s . strip ( )
if s . startswith ( " # " ) :
continue
2013-10-02 20:35:01 +04:00
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 ) ) :
2018-02-14 03:04:08 +03:00
if ' " ' in s :
2013-10-02 20:35:01 +04:00
delim = ' " '
2018-02-14 03:04:08 +03:00
elif ' = ' in s :
2013-10-02 20:35:01 +04:00
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
2013-10-03 13:26:31 +04:00
if " VIRTINST_TEST_SUITE " in os . environ :
return default
2013-10-02 20:35:01 +04:00
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 )
2017-05-05 19:47:21 +03:00
except Exception as e :
2013-10-02 20:35:01 +04:00
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 #
##################
2013-07-14 04:58:09 +04:00
2013-04-14 00:31:13 +04:00
# 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 " ,
}
2013-10-02 20:35:01 +04:00
_cached_keymap = None
2013-04-14 00:31:13 +04:00
def default_keymap ( ) :
2013-07-14 04:58:09 +04:00
global _cached_keymap
if _cached_keymap is None :
_cached_keymap = _default_keymap ( )
return _cached_keymap
2013-04-14 00:31:13 +04:00
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 ( " _ " , " " )
2018-06-07 18:33:37 +03:00
sorted_keys = sorted ( list ( keytable . keys ( ) ) , key = len )
2013-04-14 00:31:13 +04:00
for key in sorted_keys :
origkey = key
key = key . replace ( " - " , " " ) . replace ( " _ " , " " )
if clean_kt . startswith ( key ) :
return keytable [ origkey ]
return None