예제 #1
0
def set_all_keycodes(xkbmap_x11_keycodes, xkbmap_keycodes, preserve_server_keycodes, modifiers):
    """
        Clients that have access to raw x11 keycodes should provide
        an xkbmap_x11_keycodes map, we otherwise fallback to using
        the xkbmap_keycodes gtk keycode list.
        We try to preserve the initial keycodes if asked to do so,
        we retrieve them from the current server keymap and combine
        them with the given keycodes.
        The modifiers dict can be obtained by calling
        get_modifiers_from_meanings or get_modifiers_from_keycodes.
        We use it to ensure that two modifiers are not
        mapped to the same keycode (which is not allowed).
        We return a translation map for keycodes after setting them up,
        the key is (keycode, keysym) and the value is the server keycode.
    """
    debug("set_all_keycodes(%s.., %s.., %s.., %s)", str(xkbmap_x11_keycodes)[:60], str(xkbmap_keycodes)[:60], str(preserve_server_keycodes)[:60], modifiers)

    #so we can validate entries:
    keysym_to_modifier = {}
    for modifier, keysyms in modifiers.items():
        for keysym in keysyms:
            existing_mod = keysym_to_modifier.get(keysym)
            if existing_mod and existing_mod!=modifier:
                log.error("ERROR: keysym %s is mapped to both %s and %s !", keysym, modifier, existing_mod)
            else:
                keysym_to_modifier[keysym] = modifier
    debug("keysym_to_modifier=%s", keysym_to_modifier)

    def modifiers_for(entries):
        """ entries can only point to a single modifier - verify """
        modifiers = set()
        for keysym, _ in entries:
            modifier = keysym_to_modifier.get(keysym)
            if modifier:
                modifiers.add(modifier)
        return modifiers

    def filter_mappings(mappings):
        filtered = {}
        for keycode, entries in mappings.items():
            mods = modifiers_for(entries)
            if len(mods)>1:
                log.warn("keymapping removed invalid keycode entry %s pointing to more than one modifier (%s): %s", keycode, mods, entries)
                continue
            #now remove entries for keysyms we don't have:
            f_entries = set([(keysym, index) for keysym, index in entries if parse_keysym(keysym) is not None])
            if len(f_entries)==0:
                log("keymapping removed invalid keycode entry %s pointing to only unknown keysyms: %s", keycode, entries)
                continue
            filtered[keycode] = f_entries
        return filtered

    #get the list of keycodes (either from x11 keycodes or gtk keycodes):
    if xkbmap_x11_keycodes and len(xkbmap_x11_keycodes)>0:
        debug("using x11 keycodes: %s", xkbmap_x11_keycodes)
        dump_dict(xkbmap_x11_keycodes)
        keycodes = indexed_mappings(xkbmap_x11_keycodes)
    else:
        debug("using gtk keycodes: %s", xkbmap_keycodes)
        keycodes = gtk_keycodes_to_mappings(xkbmap_keycodes)
    #filter to ensure only valid entries remain:
    debug("keycodes=%s", keycodes)
    keycodes = filter_mappings(keycodes)

    #now lookup the current keycodes (if we need to preserve them)
    preserve_keycode_entries = {}
    if preserve_server_keycodes:
        import gtk.gdk
        preserve_keycode_entries = get_keycode_mappings(gtk.gdk.get_default_root_window())
        debug("preserved mappings:")
        dump_dict(preserve_keycode_entries)
        debug("preserve_keycode_entries=%s", preserve_keycode_entries)
        preserve_keycode_entries = filter_mappings(indexed_mappings(preserve_keycode_entries))

    kcmin, kcmax = get_minmax_keycodes()
    for try_harder in (False, True):
        trans, new_keycodes, missing_keycodes = translate_keycodes(kcmin, kcmax, keycodes, preserve_keycode_entries, keysym_to_modifier, try_harder)
        if len(missing_keycodes)==0:
            break
    instructions = keymap_to_xmodmap(new_keycodes)
    unset = apply_xmodmap(instructions)
    debug("unset=%s", unset)
    return trans
예제 #2
0
def set_keycodes(keycodes, preserve_keycodes={}):
    """
        The keycodes given may not match the range that the server supports,
        so we return a translation map for those keycodes that have been
        remapped.
        The preserve_keycodes is a dict containing {keysym:keycode}
        for keys we want to preserve the keycode for.
    """
    kcmin, kcmax = get_minmax_keycodes()
    free_keycodes = []
    for i in range(kcmin, kcmax):
        if i not in keycodes.keys() and i not in preserve_keycodes.values():
            free_keycodes.append(i)
    log.debug("set_keycodes(..) min=%s, max=%s, free_keycodes=%s", kcmin,
              kcmax, free_keycodes)

    used = []
    trans = {}
    instructions = []
    for keycode, entries in keycodes.items():
        server_keycode = keycode
        if preserve_keycodes:
            for entry in entries:
                (_, name, _, group, level) = entry
                if group == 0 and level == 0 and name in preserve_keycodes:
                    server_keycode = preserve_keycodes.get(name)
                    if server_keycode != keycode:
                        log.debug(
                            "set_keycodes key %s(%s) mapped to keycode=%s",
                            keycode, entries, server_keycode)
        if server_keycode == 0 or server_keycode in used or server_keycode < kcmin or server_keycode > kcmax:
            if len(free_keycodes) > 0:
                server_keycode = free_keycodes[0]
                free_keycodes = free_keycodes[1:]
                log.debug(
                    "set_keycodes key %s(%s) out of range or already in use, using free keycode=%s",
                    keycode, entries, server_keycode)
            else:
                log.error(
                    "set_keycodes: no free keycodes!, cannot translate %s: %s",
                    keycode, entries)
                continue
        if server_keycode != keycode and keycode != 0:
            trans[keycode] = server_keycode
        used.append(server_keycode)
        keysyms = []

        #sort them by group then level
        def sort_key(entry):
            (_, _, _, group, level) = entry
            return group * 10 + level

        sentries = sorted(entries, key=sort_key)
        for (_, name, _keycode, _, _) in sentries:
            assert _keycode == keycode
            try:
                keysym = parse_keysym(name)
            except:
                keysym = None
            if keysym is None:
                log.error("cannot find keysym for %s", name)
            else:
                keysyms.append(keysym)
        if len(keysyms) >= 2 and len(keysyms) <= 6:
            keysyms = keysyms[:2] + keysyms
        if len(keysyms) > 0:
            instructions.append(("keycode", server_keycode, keysyms))
    log.debug("instructions=%s", instructions)
    unset = apply_xmodmap(instructions)
    log.debug("unset=%s", unset)
    log.debug("translated keycodes=%s", trans)
    log.debug("%s free keycodes=%s", len(free_keycodes), free_keycodes)
    return trans
예제 #3
0
파일: xkbhelper.py 프로젝트: jmesmon/xpra
def set_keycodes(keycodes, preserve_keycodes={}):
    """
        The keycodes given may not match the range that the server supports,
        so we return a translation map for those keycodes that have been
        remapped.
        The preserve_keycodes is a dict containing {keysym:keycode}
        for keys we want to preserve the keycode for.
    """
    kcmin,kcmax = get_minmax_keycodes()
    free_keycodes = []
    for i in range(kcmin, kcmax):
        if i not in keycodes.keys() and i not in preserve_keycodes.values():
            free_keycodes.append(i)
    log.debug("set_keycodes(..) min=%s, max=%s, free_keycodes=%s", kcmin, kcmax, free_keycodes)

    used = []
    trans = {}
    instructions = []
    for keycode, entries in keycodes.items():
        server_keycode = keycode
        if preserve_keycodes:
            for entry in entries:
                (_, name, _, group, level) = entry
                if group==0 and level==0 and name in preserve_keycodes:
                    server_keycode = preserve_keycodes.get(name)
                    if server_keycode!=keycode:
                        log.debug("set_keycodes key %s(%s) mapped to keycode=%s", keycode, entries, server_keycode)
        if server_keycode==0 or server_keycode in used or server_keycode<kcmin or server_keycode>kcmax:
            if len(free_keycodes)>0:
                server_keycode = free_keycodes[0]
                free_keycodes = free_keycodes[1:]
                log.debug("set_keycodes key %s(%s) out of range or already in use, using free keycode=%s", keycode, entries, server_keycode)
            else:
                log.error("set_keycodes: no free keycodes!, cannot translate %s: %s", keycode, entries)
                continue
        if server_keycode!=keycode and keycode!=0:
            trans[keycode] = server_keycode
        used.append(server_keycode)
        keysyms = []
        #sort them by group then level
        def sort_key(entry):
            (_, _, _, group, level) = entry
            return group*10+level
        sentries = sorted(entries, key=sort_key)
        for (_, name, _keycode, _, _) in sentries:
            assert _keycode == keycode
            keysym = parse_keysym(name)
            if keysym is None:
                log.error("cannot find keysym for %s", name)
            else:
                keysyms.append(keysym)
        if len(keysyms)>=2 and len(keysyms)<=6:
            keysyms = keysyms[:2]+keysyms
        if len(keysyms)>0:
            instructions.append(("keycode", server_keycode, keysyms))
    log.debug("instructions=%s", instructions)
    unset = apply_xmodmap(instructions)
    log.debug("unset=%s", unset)
    log.debug("translated keycodes=%s", trans)
    log.debug("%s free keycodes=%s", len(free_keycodes), free_keycodes)
    return  trans
예제 #4
0
def set_all_keycodes(xkbmap_x11_keycodes, xkbmap_keycodes,
                     preserve_server_keycodes, modifiers):
    """
        Clients that have access to raw x11 keycodes should provide
        an xkbmap_x11_keycodes map, we otherwise fallback to using
        the xkbmap_keycodes gtk keycode list.
        We try to preserve the initial keycodes if asked to do so,
        we retrieve them from the current server keymap and combine
        them with the given keycodes.
        The modifiers dict can be obtained by calling
        get_modifiers_from_meanings or get_modifiers_from_keycodes.
        We use it to ensure that two modifiers are not
        mapped to the same keycode (which is not allowed).
        We return a translation map for keycodes after setting them up,
        the key is (keycode, keysym) and the value is the server keycode.
    """
    debug("set_all_keycodes(%s.., %s.., %s.., %s)",
          str(xkbmap_x11_keycodes)[:60],
          str(xkbmap_keycodes)[:60],
          str(preserve_server_keycodes)[:60], modifiers)

    #so we can validate entries:
    keysym_to_modifier = {}
    for modifier, keysyms in modifiers.items():
        for keysym in keysyms:
            existing_mod = keysym_to_modifier.get(keysym)
            if existing_mod and existing_mod != modifier:
                log.error("ERROR: keysym %s is mapped to both %s and %s !",
                          keysym, modifier, existing_mod)
            else:
                keysym_to_modifier[keysym] = modifier
    debug("keysym_to_modifier=%s", keysym_to_modifier)

    def modifiers_for(entries):
        """ entries can only point to a single modifier - verify """
        modifiers = set()
        for keysym, _ in entries:
            modifier = keysym_to_modifier.get(keysym)
            if modifier:
                modifiers.add(modifier)
        return modifiers

    def filter_mappings(mappings):
        filtered = {}
        for keycode, entries in mappings.items():
            mods = modifiers_for(entries)
            if len(mods) > 1:
                log.warn(
                    "keymapping removed invalid keycode entry %s pointing to more than one modifier (%s): %s",
                    keycode, mods, entries)
                continue
            #now remove entries for keysyms we don't have:
            f_entries = set([(keysym, index) for keysym, index in entries
                             if parse_keysym(keysym) is not None])
            if len(f_entries) == 0:
                log(
                    "keymapping removed invalid keycode entry %s pointing to only unknown keysyms: %s",
                    keycode, entries)
                continue
            filtered[keycode] = f_entries
        return filtered

    #get the list of keycodes (either from x11 keycodes or gtk keycodes):
    if xkbmap_x11_keycodes and len(xkbmap_x11_keycodes) > 0:
        debug("using x11 keycodes: %s", xkbmap_x11_keycodes)
        dump_dict(xkbmap_x11_keycodes)
        keycodes = indexed_mappings(xkbmap_x11_keycodes)
    else:
        debug("using gtk keycodes: %s", xkbmap_keycodes)
        keycodes = gtk_keycodes_to_mappings(xkbmap_keycodes)
    #filter to ensure only valid entries remain:
    debug("keycodes=%s", keycodes)
    keycodes = filter_mappings(keycodes)

    #now lookup the current keycodes (if we need to preserve them)
    preserve_keycode_entries = {}
    if preserve_server_keycodes:
        import gtk.gdk
        preserve_keycode_entries = get_keycode_mappings(
            gtk.gdk.get_default_root_window())
        debug("preserved mappings:")
        dump_dict(preserve_keycode_entries)
        debug("preserve_keycode_entries=%s", preserve_keycode_entries)
        preserve_keycode_entries = filter_mappings(
            indexed_mappings(preserve_keycode_entries))

    kcmin, kcmax = get_minmax_keycodes()
    for try_harder in (False, True):
        trans, new_keycodes, missing_keycodes = translate_keycodes(
            kcmin, kcmax, keycodes, preserve_keycode_entries,
            keysym_to_modifier, try_harder)
        if len(missing_keycodes) == 0:
            break
    instructions = keymap_to_xmodmap(new_keycodes)
    unset = apply_xmodmap(instructions)
    debug("unset=%s", unset)
    return trans