def do_set_keymap(xkbmap_layout, xkbmap_variant, xkbmap_options, xkbmap_print, xkbmap_query, xkbmap_query_struct={}): """ xkbmap_layout is the generic layout name (used on non posix platforms) xkbmap_variant is the layout variant (may not be set) xkbmap_print is the output of "setxkbmap -print" on the client xkbmap_query is the output of "setxkbmap -query" on the client xkbmap_query_struct is xkbmap_query parsed into a dictionary Use those to try to setup the correct keyboard map for the client so that all the keycodes sent will be mapped """ #First we try to use data from setxkbmap -query, #preferably as structured data: if xkbmap_query and not xkbmap_query_struct: from xpra.keyboard.layouts import parse_xkbmap_query xkbmap_query_struct = parse_xkbmap_query(xkbmap_query) if xkbmap_query_struct: log("do_set_keymap using xkbmap_query struct=%s", xkbmap_query_struct) """ The xkbmap_query_struct data will look something like this: { b"rules" : b"evdev", b"model" : b"pc105", b"layout" : b"gb", b"options" : b"grp:shift_caps_toggle", } """ #parse the data into a dict: rules = xkbmap_query_struct.get(b"rules") model = xkbmap_query_struct.get(b"model") layout = xkbmap_query_struct.get(b"layout") variant = xkbmap_query_struct.get(b"variant") options = xkbmap_query_struct.get(b"options") if layout: log.info("setting keymap: %s", csv("%s=%s" % (std(k), std(v)) for k,v in xkbmap_query_struct.items() if k in ("rules", "model", "layout") and v)) safe_setxkbmap(rules, model, layout, variant, options) else: safe_setxkbmap(rules, model, "", "", "") if xkbmap_print: #TODO: this is no longer used with any client, remove it log("do_set_keymap using xkbmap_print") #try to guess the layout by parsing "setxkbmap -print" try: sym_re = re.compile(r"\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)") for line in xkbmap_print.splitlines(): m = sym_re.match(line) if m: layout = std(m.group(1)) log.info("guessing keyboard layout='%s'" % layout) safe_setxkbmap("evdev", "pc105", layout, "", xkbmap_options) return except Exception as e: log.info("error setting keymap: %s" % e) #fallback for non X11 clients: layout = xkbmap_layout or "us" log.info("setting keyboard layout to '%s'", std(layout)) safe_setxkbmap("evdev", "pc105", layout, xkbmap_variant, xkbmap_options)
def do_set_keymap(xkbmap_layout, xkbmap_variant, xkbmap_print, xkbmap_query): """ xkbmap_layout is the generic layout name (used on non posix platforms) xkbmap_variant is the layout variant (may not be set) xkbmap_print is the output of "setxkbmap -print" on the client xkbmap_query is the output of "setxkbmap -query" on the client Use those to try to setup the correct keyboard map for the client so that all the keycodes sent will be mapped """ #First we try to use data from setxkbmap -query if xkbmap_query: log("do_set_keymap using xkbmap_query") """ The xkbmap_query data will look something like this: rules: evdev model: evdev layout: gb options: grp:shift_caps_toggle (we execute the options separately in case that fails..) """ #parse the data into a dict: settings = parse_xkbmap_query(xkbmap_query) rules = settings.get("rules") model = settings.get("model") layout = settings.get("layout") variant = settings.get("variant") options = settings.get("options") if layout: log.info("setting keymap: %s", ", ".join(["%s=%s" % (std(k), std(v)) for k,v in settings.items() if k in ["rules", "model", "layout"] and v])) try: X11Keyboard.setxkbmap(rules, model, layout, variant, options) return except: log.warn("failed to set exact keymap using %s", settings) if options: #try again with no options: try: X11Keyboard.setxkbmap(rules, model, layout, variant, "") except: log.error("failed to set exact keymap even without applying options") if xkbmap_print: log("do_set_keymap using xkbmap_print") #try to guess the layout by parsing "setxkbmap -print" try: sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)") for line in xkbmap_print.splitlines(): m = sym_re.match(line) if m: layout = std(m.group(1)) log.info("guessing keyboard layout='%s'" % layout) X11Keyboard.setxkbmap("", "pc104", layout, "", "") return except Exception as e: log.info("error setting keymap: %s" % e) #fallback: layout = xkbmap_layout or "us" log.info("setting keyboard layout to '%s'", std(layout)) X11Keyboard.setxkbmap("", "", layout, xkbmap_variant, "")
def test_parse_xkbmap_query(self): d = parse_xkbmap_query("""rules: evdev model: pc105 layout: gb,us,gb variant: ,, """) assert d.get("rules") == "evdev" assert d.get("layout") == "gb,us,gb" assert not d.get("variant")
def do_set_keymap(xkbmap_layout, xkbmap_variant, xkbmap_print, xkbmap_query): """ xkbmap_layout is the generic layout name (used on non posix platforms) xkbmap_variant is the layout variant (may not be set) xkbmap_print is the output of "setxkbmap -print" on the client xkbmap_query is the output of "setxkbmap -query" on the client Use those to try to setup the correct keyboard map for the client so that all the keycodes sent will be mapped """ #First we try to use data from setxkbmap -query if xkbmap_query: log("do_set_keymap using xkbmap_query") """ The xkbmap_query data will look something like this: rules: evdev model: evdev layout: gb options: grp:shift_caps_toggle And we want to call something like: setxkbmap -rules evdev -model evdev -layout gb setxkbmap -option "" -option grp:shift_caps_toggle (we execute the options separately in case that fails..) """ #parse the data into a dict: settings = parse_xkbmap_query(xkbmap_query) #construct the command line arguments for setxkbmap: args = ["setxkbmap"] used_settings = {} for setting in ["rules", "model", "layout"]: if setting in settings: value = settings.get(setting) args += ["-%s" % setting, value] used_settings[setting] = value if len(args)==1: log.warn("do_set_keymap could not find rules, model or layout in the xkbmap query string..") else: log.info("setting keymap: %s", ", ".join(["%s=%s" % (std(k), std(v)) for k,v in used_settings.items()])) exec_keymap_command(args) #try to set the options: if "options" in settings: log.info("setting keymap options: %s", std(str(settings.get("options")))) exec_keymap_command(["setxkbmap", "-option", "", "-option", settings.get("options")]) elif xkbmap_print: log("do_set_keymap using xkbmap_print") #try to guess the layout by parsing "setxkbmap -print" try: sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)") for line in xkbmap_print.splitlines(): m = sym_re.match(line) if m: layout = std(m.group(1)) log.info("guessing keyboard layout='%s'" % layout) exec_keymap_command(["setxkbmap", layout]) break except Exception, e: log.info("error setting keymap: %s" % e)
def do_set_keymap(xkbmap_layout, xkbmap_variant, xkbmap_print, xkbmap_query): """ xkbmap_layout is the generic layout name (used on non posix platforms) xkbmap_variant is the layout variant (may not be set) xkbmap_print is the output of "setxkbmap -print" on the client xkbmap_query is the output of "setxkbmap -query" on the client Use those to try to setup the correct keyboard map for the client so that all the keycodes sent will be mapped """ #First we try to use data from setxkbmap -query if xkbmap_query: log("do_set_keymap using xkbmap_query") """ The xkbmap_query data will look something like this: rules: evdev model: evdev layout: gb options: grp:shift_caps_toggle (we execute the options separately in case that fails..) """ #parse the data into a dict: settings = parse_xkbmap_query(xkbmap_query) rules = settings.get("rules") model = settings.get("model") layout = settings.get("layout") variant = settings.get("variant") options = settings.get("options") log.info("setting keymap: %s", ", ".join(["%s=%s" % (std(k), std(v)) for k,v in settings.items() if k in ["rules", "model", "layout"] and v])) try: X11Keyboard.setxkbmap(rules, model, layout, variant, options) except: log.warn("failed to set exact keymap using %s", settings) #try again with no options: try: X11Keyboard.setxkbmap(rules, model, layout, variant, "") except: log.error("failed to set exact keymap even without applying options") elif xkbmap_print: log("do_set_keymap using xkbmap_print") #try to guess the layout by parsing "setxkbmap -print" try: sym_re = re.compile("\s*xkb_symbols\s*{\s*include\s*\"([\w\+]*)") for line in xkbmap_print.splitlines(): m = sym_re.match(line) if m: layout = std(m.group(1)) log.info("guessing keyboard layout='%s'" % layout) X11Keyboard.setxkbmap("", "pc104", layout, "", "") except Exception as e: log.info("error setting keymap: %s" % e) else: layout = xkbmap_layout or "us" log.info("setting keyboard layout to '%s'", std(layout)) X11Keyboard.setxkbmap("", "", layout, xkbmap_variant, "")
def get_keymap_spec_using_setxkbmap(self): xkbmap_print = self.exec_get_keyboard_data(["setxkbmap", "-print"]) if xkbmap_print is None: log.error("your keyboard mapping will probably be incorrect unless you are using a 'us' layout") xkbmap_query = self.exec_get_keyboard_data(["setxkbmap", "-query"]) if xkbmap_query is None and xkbmap_print is not None: log.error("the server will try to guess your keyboard mapping, which works reasonably well in most cases") log.error("however, upgrading 'setxkbmap' to a version that supports the '-query' parameter is preferred") xkbmap_query_struct = parse_xkbmap_query(xkbmap_query) else: xkbmap_query_struct = {} return xkbmap_print, xkbmap_query, xkbmap_query_struct
def do_set_keymap(xkbmap_layout, xkbmap_variant, xkbmap_options, xkbmap_query, xkbmap_query_struct): """ xkbmap_layout is the generic layout name (used on non posix platforms) xkbmap_variant is the layout variant (may not be set) xkbmap_print is the output of "setxkbmap -print" on the client xkbmap_query is the output of "setxkbmap -query" on the client xkbmap_query_struct is xkbmap_query parsed into a dictionary Use those to try to setup the correct keyboard map for the client so that all the keycodes sent will be mapped """ #First we try to use data from setxkbmap -query, #preferably as structured data: if xkbmap_query and not xkbmap_query_struct: xkbmap_query_struct = parse_xkbmap_query(xkbmap_query) xkbmap_query_struct = typedict(xkbmap_query_struct) if xkbmap_query_struct: log("do_set_keymap using xkbmap_query struct=%s", xkbmap_query_struct) #The xkbmap_query_struct data will look something like this: # { # b"rules" : b"evdev", # b"model" : b"pc105", # b"layout" : b"gb", # b"options" : b"grp:shift_caps_toggle", # } #parse the data into a dict: rules = xkbmap_query_struct.strget("rules") model = xkbmap_query_struct.strget("model") layout = xkbmap_query_struct.strget("layout") variant = xkbmap_query_struct.strget("variant") options = xkbmap_query_struct.strget("options") if layout: log.info( "setting keymap: %s", csv("%s=%s" % (std(k), std(v)) for k, v in xkbmap_query_struct.items() if k in ("rules", "model", "layout", "variant", "options") and v)) safe_setxkbmap(rules, model, layout, variant, options) else: safe_setxkbmap(rules, model, "", "", "") #fallback for non X11 clients: layout = xkbmap_layout or "us" log.info("setting keyboard layout to '%s'", std(layout)) safe_setxkbmap("evdev", "pc105", layout, xkbmap_variant, xkbmap_options)
def log_keyboard_info(self): #show the user a summary of what we have detected: kb_info = {} if self.xkbmap_query_struct or self.xkbmap_query: xkbqs = self.xkbmap_query_struct if xkbqs: #parse query into a dict from xpra.keyboard.layouts import parse_xkbmap_query xkbqs = parse_xkbmap_query(self.xkbmap_query) for x in ["rules", "model", "layout"]: v = xkbqs.get(x) if v: kb_info[x] = v if self.xkbmap_layout: kb_info["layout"] = self.xkbmap_layout if len(kb_info)==0: log.info(" using default keyboard settings") else: log.info(" keyboard settings: %s", ", ".join(["%s=%s" % (std(k), std(v)) for k,v in kb_info.items()]))