def set_gnome_input_sources(self, input_sources): self.debug( "Setting org.gnome.desktop.input-sources sources to %r", input_sources, ) gsettings.set_list("org.gnome.desktop.input-sources", "sources", input_sources)
def set_indicator_keymaps(lang): import libxml2 from gi.repository import Xkl, GdkX11 # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been # imported; possibly finer-grained than this, but anything using this # will already have imported Gtk anyway ... from gi.repository import Gtk from ubiquity import gsettings # pacify pyflakes Gtk xpath = "//iso_639_3_entry[@part1_code='%s']" gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts'] lang = lang.split('_')[0] variants = [] # Map inspired from that of gfxboot-theme-ubuntu that's itself # based on console-setup's. This one has been restricted to # language => keyboard layout not locale => keyboard layout as # we don't actually know the exact locale default_keymap = { 'ar': 'ara', 'bs': 'ba', 'de': 'de', 'el': 'gr', 'en': 'us', 'eo': 'epo', 'fr': 'fr_oss', 'gu': 'in_guj', 'hi': 'in', 'hr': 'hr', 'hy': 'am', 'ka': 'ge', 'kn': 'in_kan', 'lo': 'la', 'ml': 'in_mal', 'pa': 'in_guru', 'sr': 'rs', 'sv': 'se', 'ta': 'in_tam', 'te': 'in_tel', 'zh': 'cn', } def item_str(s): '''Convert a zero-terminated byte array to a proper str''' i = s.find(b'\x00') return s[:i].decode() def process_variant(*args): if hasattr(args[2], 'name'): variants.append('%s\t%s' % (item_str(args[1].name), item_str(args[2].name))) else: variants.append(item_str(args[1].name)) def restrict_list(variants): new_variants = [] # Start by looking by an explicit default layout in the keymap if lang in default_keymap: if default_keymap[lang] in variants: variants.remove(default_keymap[lang]) new_variants.append(default_keymap[lang]) else: tab_keymap = default_keymap[lang].replace('_', '\t') if tab_keymap in variants: variants.remove(tab_keymap) new_variants.append(tab_keymap) # Prioritize the layout matching the language (if any) if lang in variants: variants.remove(lang) new_variants.append(lang) # Uniquify our list (just in case) variants = list(set(variants)) if len(variants) > 4: # We have a problem, X only supports 4 # Add as many entry as we can that are layouts without variant country_variants = sorted( [entry for entry in variants if '\t' not in entry]) for entry in country_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # We can add some more simple_variants = sorted( [entry for entry in variants if '_' not in entry]) for entry in simple_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # Now just add anything left for entry in variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) else: new_variants += list(variants) # gsettings doesn't understand utf8 new_variants = [str(variant) for variant in new_variants] return new_variants def call_setxkbmap(variants): kb_layouts = [] kb_variants = [] for entry in variants: fields = entry.split('\t') if len(fields) > 1: kb_layouts.append(fields[0]) kb_variants.append(fields[1]) else: kb_layouts.append(fields[0]) kb_variants.append("") execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants)) fp = libxml2.parseFile('/usr/share/xml/iso-codes/iso_639_3.xml') context = fp.xpathNewContext() nodes = context.xpathEvalExpression(xpath % lang) display = GdkX11.x11_get_default_xdisplay() engine = Xkl.Engine.get_instance(display) if nodes: configreg = Xkl.ConfigRegistry.get_instance(engine) configreg.load(False) # Apparently part2_code doesn't always work (fails with French) for prop in ('part2_code', 'id', 'part1_code'): if nodes[0].hasProp(prop): code = nodes[0].prop(prop) configreg.foreach_language_variant(code, process_variant, None) if variants: restricted_variants = restrict_list(variants) call_setxkbmap(restricted_variants) gsettings.set_list(gsettings_key[0], gsettings_key[1], restricted_variants) break else: # Use the system default if no other keymaps can be determined. gsettings.set_list(gsettings_key[0], gsettings_key[1], []) engine.lock_group(0)
def set_indicator_keymaps(lang): import xml.etree.cElementTree as ElementTree from gi.repository import Xkl, GdkX11 # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been # imported; possibly finer-grained than this, but anything using this # will already have imported Gtk anyway ... from gi.repository import Gtk from ubiquity import gsettings gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts'] lang = lang.split('_')[0] variants = [] # Map inspired from that of gfxboot-theme-ubuntu that's itself # based on console-setup's. This one has been restricted to # language => keyboard layout not locale => keyboard layout as # we don't actually know the exact locale default_keymap = { 'ar': 'ara', 'bs': 'ba', 'de': 'de', 'el': 'gr', 'en': 'us', 'eo': 'epo', 'fr': 'fr_oss', 'gu': 'in_guj', 'hi': 'in', 'hr': 'hr', 'hy': 'am', 'ka': 'ge', 'kn': 'in_kan', 'lo': 'la', 'ml': 'in_mal', 'pa': 'in_guru', 'sr': 'rs', 'sv': 'se', 'ta': 'in_tam', 'te': 'in_tel', 'zh': 'cn', } def item_str(s): """ Convert a zero-terminated byte array to a proper str """ i = s.find(b'\x00') return s[:i].decode() def process_variant(*args): if hasattr(args[2], 'name'): variants.append('{0}\t{1}'.format((item_str(args[1].name), item_str(args[2].name)))) else: variants.append(item_str(args[1].name)) def restrict_list(variants): new_variants = [] # Start by looking by an explicit default layout in the keymap if lang in default_keymap: if default_keymap[lang] in variants: variants.remove(default_keymap[lang]) new_variants.append(default_keymap[lang]) else: tab_keymap = default_keymap[lang].replace('_', '\t') if tab_keymap in variants: variants.remove(tab_keymap) new_variants.append(tab_keymap) # Prioritize the layout matching the language (if any) if lang in variants: variants.remove(lang) new_variants.append(lang) # Uniquify our list (just in case) variants = list(set(variants)) if len(variants) > 4: # We have a problem, X only supports 4 # Add as many entry as we can that are layouts without variant country_variants = sorted( entry for entry in variants if '\t' not in entry) for entry in country_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # We can add some more simple_variants = sorted( entry for entry in variants if '_' not in entry) for entry in simple_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # Now just add anything left for entry in variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) else: new_variants = new_variants + list(variants) # gsettings doesn't understand utf8 new_variants = [str(variant) for variant in new_variants] return new_variants def call_setxkbmap(variants): kb_layouts = [] kb_variants = [] for entry in variants: fields = entry.split('\t') if len(fields) > 1: kb_layouts.append(fields[0]) kb_variants.append(fields[1]) else: kb_layouts.append(fields[0]) kb_variants.append("") execute( "setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants)) iso_639_3 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639_3.xml') nodes = [element for element in iso_639_3.findall('iso_639_3_entry') if element.get('part1_code') == lang] display = GdkX11.x11_get_default_xdisplay() engine = Xkl.Engine.get_instance(display) if nodes: configreg = Xkl.ConfigRegistry.get_instance(engine) configreg.load(False) # Apparently part2_code doesn't always work (fails with French) for prop in ('part2_code', 'id', 'part1_code'): code = nodes[0].get(prop) if code is not None: configreg.foreach_language_variant(code, process_variant, None) if variants: restricted_variants = restrict_list(variants) call_setxkbmap(restricted_variants) gsettings.set_list( gsettings_key[0], gsettings_key[1], restricted_variants) break else: # Use the system default if no other keymaps can be determined. gsettings.set_list(gsettings_key[0], gsettings_key[1], []) engine.lock_group(0)
def set_indicator_keymaps(lang): import xml.etree.cElementTree as ElementTree from gi.repository import Xkl, GdkX11 # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been # imported; possibly finer-grained than this, but anything using this # will already have imported Gtk anyway ... from gi.repository import Gtk from ubiquity import gsettings # pacify pyflakes Gtk gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts'] gsettings_sources = ('org.gnome.desktop.input-sources', 'sources') gsettings_options = ('org.gnome.desktop.input-sources', 'xkb-options') lang = lang.split('_')[0] variants = [] # Map inspired from that of gfxboot-theme-ubuntu that's itself # based on console-setup's. This one has been restricted to # language => keyboard layout not locale => keyboard layout as # we don't actually know the exact locale default_keymap = { 'ar': 'ara', 'bs': 'ba', 'de': 'de', 'el': 'gr', 'en': 'us', 'eo': 'epo', 'fr': 'fr_oss', 'gu': 'in_guj', 'hi': 'in', 'hr': 'hr', 'hy': 'am', 'ka': 'ge', 'kn': 'in_kan', 'lo': 'la', 'ml': 'in_mal', 'pa': 'in_guru', 'sr': 'rs', 'sv': 'se', 'ta': 'in_tam', 'te': 'in_tel', 'zh': 'cn', } def item_str(s): '''Convert a zero-terminated byte array to a proper str''' import array s = array.array('B', s).tobytes() i = s.find(b'\x00') return s[:i].decode() def process_variant(*args): if hasattr(args[2], 'name'): variants.append('%s\t%s' % (item_str(args[1].name), item_str(args[2].name))) else: variants.append(item_str(args[1].name)) def restrict_list(variants): new_variants = [] # Start by looking by an explicit default layout in the keymap if lang in default_keymap: if default_keymap[lang] in variants: variants.remove(default_keymap[lang]) new_variants.append(default_keymap[lang]) else: tab_keymap = default_keymap[lang].replace('_', '\t') if tab_keymap in variants: variants.remove(tab_keymap) new_variants.append(tab_keymap) # Prioritize the layout matching the language (if any) if lang in variants: variants.remove(lang) new_variants.append(lang) # Uniquify our list (just in case) variants = list(set(variants)) if len(variants) > 4: # We have a problem, X only supports 4 # Add as many entry as we can that are layouts without variant country_variants = sorted(entry for entry in variants if '\t' not in entry) for entry in country_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # We can add some more simple_variants = sorted(entry for entry in variants if '_' not in entry) for entry in simple_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # Now just add anything left for entry in variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) else: new_variants += list(variants) # gsettings doesn't understand utf8 new_variants = [str(variant) for variant in new_variants] return new_variants def call_setxkbmap(variants): kb_layouts = [] kb_variants = [] for entry in variants: fields = entry.split('\t') if len(fields) > 1: kb_layouts.append(fields[0]) kb_variants.append(fields[1]) else: kb_layouts.append(fields[0]) kb_variants.append("") execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants)) iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml') nodes = [ element for element in iso_639.findall('iso_639_entry') if element.get('iso_639_1_code') == lang ] display = GdkX11.x11_get_default_xdisplay() engine = Xkl.Engine.get_instance(display) if nodes: configreg = Xkl.ConfigRegistry.get_instance(engine) configreg.load(False) # Apparently iso_639_2B_code doesn't always work (fails with French) for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'): code = nodes[0].get(prop) if code is not None: configreg.foreach_language_variant(code, process_variant, None) if variants: restricted_variants = restrict_list(variants) call_setxkbmap(restricted_variants) gsettings.set_list(gsettings_key[0], gsettings_key[1], restricted_variants) break else: # Use the system default if no other keymaps can be determined. gsettings.set_list(gsettings_key[0], gsettings_key[1], []) # Gnome Shell only does keyboard layout conversion from old # gsettings_key once. Recently we started to launch keyboard plugin # during ubiquity-dm, hence if we change that key, we should purge the # state that gsd uses, to determine if it should run the # conversion. Which are a stamp file, and having the new key set. # Ideally, I think ubiquity should be more universal and set the new key # directly, instead of relying on gsd keeping the conversion code # around. But it's too late for 20.10 release. gsettings_stamp = os.path.join( '/home', os.getenv("SUDO_USER", os.getenv("USER", "root")), '.local/share/gnome-settings-daemon/input-sources-converted') if os.path.exists(gsettings_stamp): os.remove(gsettings_stamp) gsettings.unset(*gsettings_sources) gsettings.unset(*gsettings_options) engine.lock_group(0)
def set_indicator_keymaps(lang): import xml.etree.cElementTree as ElementTree from gi.repository import Xkl, GdkX11 # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been # imported; possibly finer-grained than this, but anything using this # will already have imported Gtk anyway ... from gi.repository import Gtk from ubiquity import gsettings # pacify pyflakes Gtk gsettings_key = ["org.gnome.libgnomekbd.keyboard", "layouts"] lang = lang.split("_")[0] variants = [] # Map inspired from that of gfxboot-theme-ubuntu that's itself # based on console-setup's. This one has been restricted to # language => keyboard layout not locale => keyboard layout as # we don't actually know the exact locale default_keymap = { "ar": "ara", "bs": "ba", "de": "de", "el": "gr", "en": "us", "eo": "epo", "fr": "fr_oss", "gu": "in_guj", "hi": "in", "hr": "hr", "hy": "am", "ka": "ge", "kn": "in_kan", "lo": "la", "ml": "in_mal", "pa": "in_guru", "sr": "rs", "sv": "se", "ta": "in_tam", "te": "in_tel", "zh": "cn", } def item_str(s): """Convert a zero-terminated byte array to a proper str""" i = s.find(b"\x00") return s[:i].decode() def process_variant(*args): if hasattr(args[2], "name"): variants.append("%s\t%s" % (item_str(args[1].name), item_str(args[2].name))) else: variants.append(item_str(args[1].name)) def restrict_list(variants): new_variants = [] # Start by looking by an explicit default layout in the keymap if lang in default_keymap: if default_keymap[lang] in variants: variants.remove(default_keymap[lang]) new_variants.append(default_keymap[lang]) else: tab_keymap = default_keymap[lang].replace("_", "\t") if tab_keymap in variants: variants.remove(tab_keymap) new_variants.append(tab_keymap) # Prioritize the layout matching the language (if any) if lang in variants: variants.remove(lang) new_variants.append(lang) # Uniquify our list (just in case) variants = list(set(variants)) if len(variants) > 4: # We have a problem, X only supports 4 # Add as many entry as we can that are layouts without variant country_variants = sorted(entry for entry in variants if "\t" not in entry) for entry in country_variants[: 4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # We can add some more simple_variants = sorted(entry for entry in variants if "_" not in entry) for entry in simple_variants[: 4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # Now just add anything left for entry in variants[: 4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) else: new_variants += list(variants) # gsettings doesn't understand utf8 new_variants = [str(variant) for variant in new_variants] return new_variants def call_setxkbmap(variants): kb_layouts = [] kb_variants = [] for entry in variants: fields = entry.split("\t") if len(fields) > 1: kb_layouts.append(fields[0]) kb_variants.append(fields[1]) else: kb_layouts.append(fields[0]) kb_variants.append("") execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants)) iso_639_3 = ElementTree.parse("/usr/share/xml/iso-codes/iso_639_3.xml") nodes = [element for element in iso_639_3.findall("iso_639_3_entry") if element.get("part1_code") == lang] display = GdkX11.x11_get_default_xdisplay() engine = Xkl.Engine.get_instance(display) if nodes: configreg = Xkl.ConfigRegistry.get_instance(engine) configreg.load(False) # Apparently part2_code doesn't always work (fails with French) for prop in ("part2_code", "id", "part1_code"): code = nodes[0].get(prop) if code is not None: configreg.foreach_language_variant(code, process_variant, None) if variants: restricted_variants = restrict_list(variants) call_setxkbmap(restricted_variants) gsettings.set_list(gsettings_key[0], gsettings_key[1], restricted_variants) break else: # Use the system default if no other keymaps can be determined. gsettings.set_list(gsettings_key[0], gsettings_key[1], []) engine.lock_group(0)
def set_indicator_keymaps(lang): import xml.etree.cElementTree as ElementTree from gi.repository import Xkl, GdkX11 # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been # imported; possibly finer-grained than this, but anything using this # will already have imported Gtk anyway ... from gi.repository import Gtk from ubiquity import gsettings # pacify pyflakes Gtk gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts'] lang = lang.split('_')[0] variants = [] # Map inspired from that of gfxboot-theme-ubuntu that's itself # based on console-setup's. This one has been restricted to # language => keyboard layout not locale => keyboard layout as # we don't actually know the exact locale default_keymap = { 'ar': 'ara', 'bs': 'ba', 'de': 'de', 'el': 'gr', 'en': 'us', 'eo': 'epo', 'fr': 'fr_oss', 'gu': 'in_guj', 'hi': 'in', 'hr': 'hr', 'hy': 'am', 'ka': 'ge', 'kn': 'in_kan', 'lo': 'la', 'ml': 'in_mal', 'pa': 'in_guru', 'sr': 'rs', 'sv': 'se', 'ta': 'in_tam', 'te': 'in_tel', 'zh': 'cn', } def item_str(s): '''Convert a zero-terminated byte array to a proper str''' import array s = array.array('B', s).tostring() i = s.find(b'\x00') return s[:i].decode() def process_variant(*args): if hasattr(args[2], 'name'): variants.append( '%s\t%s' % (item_str(args[1].name), item_str(args[2].name))) else: variants.append(item_str(args[1].name)) def restrict_list(variants): new_variants = [] # Start by looking by an explicit default layout in the keymap if lang in default_keymap: if default_keymap[lang] in variants: variants.remove(default_keymap[lang]) new_variants.append(default_keymap[lang]) else: tab_keymap = default_keymap[lang].replace('_', '\t') if tab_keymap in variants: variants.remove(tab_keymap) new_variants.append(tab_keymap) # Prioritize the layout matching the language (if any) if lang in variants: variants.remove(lang) new_variants.append(lang) # Uniquify our list (just in case) variants = list(set(variants)) if len(variants) > 4: # We have a problem, X only supports 4 # Add as many entry as we can that are layouts without variant country_variants = sorted( entry for entry in variants if '\t' not in entry) for entry in country_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # We can add some more simple_variants = sorted( entry for entry in variants if '_' not in entry) for entry in simple_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # Now just add anything left for entry in variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) else: new_variants += list(variants) # gsettings doesn't understand utf8 new_variants = [str(variant) for variant in new_variants] #Hack pt1 added for Bio-Linux to prefer gb keyboard over us if new_variants[0] == "us" and new_variants[2] == "gb" : new_variants[0] = str("gb") new_variants[2] = str("us") #end hack return new_variants def call_setxkbmap(variants): kb_layouts = [] kb_variants = [] for entry in variants: fields = entry.split('\t') if len(fields) > 1: kb_layouts.append(fields[0]) kb_variants.append(fields[1]) else: kb_layouts.append(fields[0]) kb_variants.append("") execute( "setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants)) #Hack pt2 added for Bio-Linux to actually make the keyboard settings stick #in 14.04. #It seems the upstream authors have attempted to get this fixed, but missed #the point that we need to preserve the DBUS address variable, which is lost #when Ubiquity gains root privileges. # os.environ['DBUS_SESSION_BUS_ADDRESS'] = "unix:abstract=/tmp/dbus-FaqRsE1MGY" #I tried signalling the keyboard indicator with "pkill -USR1", but that just #locks up the whole system. Meh, so frickin fragile. Hence this appalling #kludge instead. user = os.environ.get('PKEXEC_UID') user = '******' + user if user else '#999' try: if not os.environ.get('DBUS_SESSION_BUS_ADDRESS') : proc1 = subprocess.Popen('ps -p %i -o ppid=' % os.getppid(), shell=True, stdout=subprocess.PIPE, ) pppid = int(proc1.communicate()[0].rstrip()) proc2 = subprocess.Popen('sudo -u "%s" cat /proc/%i/environ' % (user, pppid), shell=True, stdout=subprocess.PIPE, ) os.environ['DBUS_SESSION_BUS_ADDRESS'] = [ x for x in proc2.communicate()[0].decode().split('\0') if x.startswith("DBUS_SESSION_BUS_ADDRESS=") ][0][25:] except: os.environ['DBUS_SESSION_BUS_ADDRESS'] = 'none' subprocess.call( ['sudo', '-E', '-u', user, 'gsettings', 'set', "org.gnome.desktop.input-sources", "sources", repr( [('xkb', l+'+'+v if v else l) for l,v in zip(kb_layouts, kb_variants)] ) ], preexec_fn=drop_all_privileges ) #subprocess.call(['sudo', '-u', user, 'pkill', '-USR1', 'indicator-keybo']) #end hack iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml') nodes = [element for element in iso_639.findall('iso_639_entry') if element.get('iso_639_1_code') == lang] display = GdkX11.x11_get_default_xdisplay() engine = Xkl.Engine.get_instance(display) if nodes: configreg = Xkl.ConfigRegistry.get_instance(engine) configreg.load(False) # Apparently iso_639_2B_code doesn't always work (fails with French) for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'): code = nodes[0].get(prop) if code is not None: configreg.foreach_language_variant(code, process_variant, None) if variants: restricted_variants = restrict_list(variants) call_setxkbmap(restricted_variants) gsettings.set_list( gsettings_key[0], gsettings_key[1], restricted_variants) break else: # Use the system default if no other keymaps can be determined. gsettings.set_list(gsettings_key[0], gsettings_key[1], []) engine.lock_group(0)
def set_indicator_keymaps(lang): import xml.etree.cElementTree as ElementTree from gi.repository import Xkl, GdkX11 # GdkX11.x11_get_default_xdisplay() segfaults if Gtk hasn't been # imported; possibly finer-grained than this, but anything using this # will already have imported Gtk anyway ... from gi.repository import Gtk from ubiquity import gsettings # pacify pyflakes Gtk gsettings_key = ['org.gnome.libgnomekbd.keyboard', 'layouts'] lang = lang.split('_')[0] variants = [] # Map inspired from that of gfxboot-theme-ubuntu that's itself # based on console-setup's. This one has been restricted to # language => keyboard layout not locale => keyboard layout as # we don't actually know the exact locale default_keymap = { 'ar': 'ara', 'bs': 'ba', 'de': 'de', 'el': 'gr', 'en': 'us', 'eo': 'epo', 'fr': 'fr_oss', 'gu': 'in_guj', 'hi': 'in', 'hr': 'hr', 'hy': 'am', 'ka': 'ge', 'kn': 'in_kan', 'lo': 'la', 'ml': 'in_mal', 'pa': 'in_guru', 'sr': 'rs', 'sv': 'se', 'ta': 'in_tam', 'te': 'in_tel', 'zh': 'cn', } def item_str(s): '''Convert a zero-terminated byte array to a proper str''' import array s = array.array('B', s).tostring() i = s.find(b'\x00') return s[:i].decode() def process_variant(*args): if hasattr(args[2], 'name'): variants.append('%s\t%s' % (item_str(args[1].name), item_str(args[2].name))) else: variants.append(item_str(args[1].name)) def restrict_list(variants): new_variants = [] # Start by looking by an explicit default layout in the keymap if lang in default_keymap: if default_keymap[lang] in variants: variants.remove(default_keymap[lang]) new_variants.append(default_keymap[lang]) else: tab_keymap = default_keymap[lang].replace('_', '\t') if tab_keymap in variants: variants.remove(tab_keymap) new_variants.append(tab_keymap) # Prioritize the layout matching the language (if any) if lang in variants: variants.remove(lang) new_variants.append(lang) # Uniquify our list (just in case) variants = list(set(variants)) if len(variants) > 4: # We have a problem, X only supports 4 # Add as many entry as we can that are layouts without variant country_variants = sorted(entry for entry in variants if '\t' not in entry) for entry in country_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # We can add some more simple_variants = sorted(entry for entry in variants if '_' not in entry) for entry in simple_variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) if len(new_variants) < 4: # Now just add anything left for entry in variants[:4 - len(new_variants)]: new_variants.append(entry) variants.remove(entry) else: new_variants += list(variants) # gsettings doesn't understand utf8 new_variants = [str(variant) for variant in new_variants] #Hack pt1 added for Bio-Linux to prefer gb keyboard over us if new_variants[0] == "us" and new_variants[2] == "gb": new_variants[0] = str("gb") new_variants[2] = str("us") #end hack return new_variants def call_setxkbmap(variants): kb_layouts = [] kb_variants = [] for entry in variants: fields = entry.split('\t') if len(fields) > 1: kb_layouts.append(fields[0]) kb_variants.append(fields[1]) else: kb_layouts.append(fields[0]) kb_variants.append("") execute("setxkbmap", "-layout", ",".join(kb_layouts), "-variant", ",".join(kb_variants)) #Hack pt2 added for Bio-Linux to actually make the keyboard settings stick #in 14.04. #It seems the upstream authors have attempted to get this fixed, but missed #the point that we need to preserve the DBUS address variable, which is lost #when Ubiquity gains root privileges. # os.environ['DBUS_SESSION_BUS_ADDRESS'] = "unix:abstract=/tmp/dbus-FaqRsE1MGY" #I tried signalling the keyboard indicator with "pkill -USR1", but that just #locks up the whole system. Meh, so frickin fragile. Hence this appalling #kludge instead. user = os.environ.get('PKEXEC_UID') user = '******' + user if user else '#999' try: if not os.environ.get('DBUS_SESSION_BUS_ADDRESS'): proc1 = subprocess.Popen( 'ps -p %i -o ppid=' % os.getppid(), shell=True, stdout=subprocess.PIPE, ) pppid = int(proc1.communicate()[0].rstrip()) proc2 = subprocess.Popen( 'sudo -u "%s" cat /proc/%i/environ' % (user, pppid), shell=True, stdout=subprocess.PIPE, ) os.environ['DBUS_SESSION_BUS_ADDRESS'] = [ x for x in proc2.communicate()[0].decode().split('\0') if x.startswith("DBUS_SESSION_BUS_ADDRESS=") ][0][25:] except: os.environ['DBUS_SESSION_BUS_ADDRESS'] = 'none' subprocess.call([ 'sudo', '-E', '-u', user, 'gsettings', 'set', "org.gnome.desktop.input-sources", "sources", repr([('xkb', l + '+' + v if v else l) for l, v in zip(kb_layouts, kb_variants)]) ], preexec_fn=drop_all_privileges) #subprocess.call(['sudo', '-u', user, 'pkill', '-USR1', 'indicator-keybo']) #end hack iso_639 = ElementTree.parse('/usr/share/xml/iso-codes/iso_639.xml') nodes = [ element for element in iso_639.findall('iso_639_entry') if element.get('iso_639_1_code') == lang ] display = GdkX11.x11_get_default_xdisplay() engine = Xkl.Engine.get_instance(display) if nodes: configreg = Xkl.ConfigRegistry.get_instance(engine) configreg.load(False) # Apparently iso_639_2B_code doesn't always work (fails with French) for prop in ('iso_639_2B_code', 'iso_639_2T_code', 'iso_639_1_code'): code = nodes[0].get(prop) if code is not None: configreg.foreach_language_variant(code, process_variant, None) if variants: restricted_variants = restrict_list(variants) call_setxkbmap(restricted_variants) gsettings.set_list(gsettings_key[0], gsettings_key[1], restricted_variants) break else: # Use the system default if no other keymaps can be determined. gsettings.set_list(gsettings_key[0], gsettings_key[1], []) engine.lock_group(0)