• You are not logged in.

    Dual-role modifiers in XKB

    • Started by 39aldo39
    • 2 Replies:
    • Reputation: 15
    • Registered: 12-Sep-2016
    • Posts: 45

    Disclaimer: I don't recommend using this method for dual-role modifiers, since it is very buggy. It is better to use dedicated programs like xcape for it. However, it is an implementation in just XKB.

    In XKB, dead keys are implemented using a Compose file, which contains entries like

    <dead_acute> <space> : "'" apostrophe
    <dead_acute> <A> : "Á" Aacute
    <dead_acute> <a> : "á" aacute

    The part before the colon is a list of keysyms, which must be typed to activate the part after the colon. This is a string and/or a keysym. See `man Compose` for more details.
    Compose sequences are also implemented this way. For example, with `<Multi_key> <minus> <greater> : "→"` an arrow → is printed when "Compose - >" is typed.

    Since the list before the colon consists of arbitrary keysyms, we can abuse the format and use modifier keysyms. By trying this, the resulting string and/or keysym is only activated when the modifier is tapped on its own, not when it is used with a different key. This is exactly a dual-role modifier! However, there are some limitations:

    • The modifier is still active when it is released. This is no problem when a string is needed as output, but it does affect the behavior of keys like BackSpace and movement keys.

    • Not all applications recognize the keysym in the action. For example, movement keys do work in xterm, but don't work in Firefox. This can partially be solved by using non-printable ASCII codes for some actions (e.g. BackSpace as 0x08, Return as 0x0d and Escape as 0x1b), but those aren't recognized very well as well. (Also, the escaping should be done it in octal as \123 instead of hexadecimal as \0x123a, as the hexadecimal version doesn't seem to work.)

    Despite these limitations, it is still possible to implement useful dual-role modifiers. For example, to use the left control (mapped to the CapsLock position) as escape when tapped and Extend (mapped to the space bar) as space when tapped, one could use:

    <Control_L> : "\033" Escape
    <ISO_Level5_Shift> : " " Space

    (The Escape and Space parts aren't necessary.) The escape might not be recognized by all applications. However, VIM recognizes it, which is the most important application for this binding.

    To use custom compose sequences, you should add your custom entries to ~/.XCompose. This file should start with

    include "%L"

    to include the default sequences. Otherwise, the dead keys and the compose key stop working. Furthermore, changes in this file become active in an application when the application is restarted. Also, GTK apps use a hard coded Compose file by default. To disable this, you should add

    export GTK_IM_MODULE="xim"

    to ~/.profile. This will disable the Control+Shift+u method to input Unicode characters.

    Last edited by 39aldo39 (10-Feb-2018 22:54:33)

    Create advanced keyboard layouts in various formats using my Keyboard Layout Files Creator!

    • 0
    • Reputation: 1
    • Registered: 15-Apr-2014
    • Posts: 107

    This is relevant to my interests, but I have never bothered learning xkb.  Would it be straightforward to make the spacebar Ctrl when held and another key is typed, and Spc when tapped? This makes life in Emacs so much better, but every implementation I've seen on any platform is buggy/hacky in some way.

    • 0
    • Reputation: 15
    • Registered: 12-Sep-2016
    • Posts: 45

    Well, I wouldn't say that this method isn't hacky, but you can try it.

    First, you need to map Space to Control_L. I recommend mapping Shift+Space to plain space, so you still have a backup space.

    You could use my KLFC to generate XKB files. This way, editing is easier and you can use advanced features. In that case you can take an example layout (e.g. examples/colemak.json) and add the key

    { "pos": "Space", "letters": [ "Control_L", " " ] }

    Then, by executing

    klfc path/to/layout.json --xkb xkb

    your XKB files will be generated in the folder xkb. This folder also contains a script "run-session.sh" to use the new layout once and a script "install-system.sh" to install the new layout. In the latter case, you should be able to select your layout in the settings after a reboot.

    Alternatively, you could make a folder for your XKB configurations and create a file "symbols/fn" with

    default partial
    xkb_symbols "basic" {
        key <SPCE> { [ Control_L, space ],
                     actions[Group1] = [ SetMods(mods=Control) ] };

    in it. To use this layout in the current session, you should execute

    setxkbmap -layout "us(colemak)+fn" -print | xkbcomp -I"your/xkb/folder" - "$DISPLAY"

    If everything went well, your space should act as Control and as space when pressed with Shift active. Now we need to say that it should act as space when it is pressed on its own. This can be done by creating a ~/.XCompose file with

    include "%L"
    <Control_L> : " " space

    in it. This file should be reloaded each time an application is restarted, although a reboot doesn't hurt. You can try it with xterm.
    However, GTK apps use a hard coded Compose file by default. So, it doesn't work in there. To disable this, you should add

    export GTK_IM_MODULE="xim"

    to ~/.profile (or ~/.bash_profile) and reboot.

    Create advanced keyboard layouts in various formats using my Keyboard Layout Files Creator!

    • 0