Mapping CapsLock to semicolon

My 5-year-old MBP has busted semicolon key. It’s in a state where I’m not able to use it anymore.

I’m planning to replace MBP with something newer, yet it won’t happen in the next few weeks. For that time I need a replacement. In my case, there is one key which I’m not using. This can be safely remapped to act as a semicolon. It’s CapsLock.

The plan is simple - remap key bindings so that CapsLock will start acting as the semicolon.

Word of warning - my knowledge of keyboards and key bindings, in general, is pretty vague. I won’t even try to describe what happens. Here’s you’ll find rather a full recipe which worked in my case.

Identifying the keys

Each key has a keycode. If you want to remap keys, you need to know their codes.

This can be done using xev, a simple utility printing X events.

xev -event keyboard

It should pop up a small window. When typing in it you should see some output in the console.

For CapsLock it was:

KeyPress event, serial 28, synthetic NO, window 0x5a00001,
    root 0x113, subw 0x0, time 2723623, (2,160), root:(892,623),
    state 0x0, keycode 66 (keysym 0x3b, semicolon), same_screen YES,
    XKeysymToKeycode returns keycode: 47
    XLookupString gives 1 bytes: (3b) ";"
    XmbLookupString gives 1 bytes: (3b) ";"
    XFilterEvent returns: False

For semicolon:

KeyPress event, serial 28, synthetic NO, window 0x5a00001,
    root 0x113, subw 0x0, time 2728863, (2,160), root:(892,623),
    state 0x0, keycode 47 (keysym 0x3b, semicolon), same_screen YES,
    XLookupString gives 1 bytes: (3b) ";"
    XmbLookupString gives 1 bytes: (3b) ";"
    XFilterEvent returns: False

The thing we’re looking for is keycode XX (where XX is a decimal number).

Xmodmap

xmodmap allows rebinding keys using simple expressions.

xmodmap -e "keycode 66 = semicolon colon"

That’s it! This will remap CapsLock to the semicolon (or colon when used with Shift).

This is not persistent - works only for current session.
If you want to keep this mapping you should create ~/.Xmodmap file with expression passed as -e argument.

There’s one problem - those settings are reset by Xkb. If you happen to use it (which will be true for most of the current Linx distributions), you should go to the next paragraph.

Xkb

Now, the wizardry part. Know one thing - Xkb is something I was not able (or willing) to understand it fully. I used my intuition, it worked.

Find /usr/share/X11/xkb/symbols/capslock and add this lines:

xkb_symbols "colon" {
    key <CAPS> { [ semicolon, colon ] };
};

Find /usr/share/X11/xkb/rules/evdev and open it. Find lines:

caps:capslock         =>      +capslock(capslock)
caps:numlock          =>      +capslock(numlock)
caps:shiftlock        =>      +capslock(shiftlock)
caps:swapescape       =>      +capslock(swapescape)
caps:escape           =>      +capslock(escape)
caps:backspace        =>      +capslock(backspace)
caps:super            =>      +capslock(super)
caps:hyper            =>      +capslock(hyper)
caps:menu             =>      +capslock(menu)
caps:none             =>      +capslock(none)

Add after them:

caps:colon             =>      +capslock(colon)

Having this set won’t change anything. Now, you need to adjust keyboard options in WM of your choice.

KDE

Edit file ~/.config/kxkbrc, change Options so it looks something like this:

Options=,caps:colon

In my case, the whole file looks like this:

[Layout]
DisplayNames=
LayoutList=
LayoutLoopCount=-1
Model=pc101
Options=,caps:colon,altwin:ctrl_win
ResetOldOptions=true
ShowFlag=false
ShowLabel=true
ShowLayoutIndicator=true
ShowSingle=false
SwitchMode=Global
Use=false

Gnome

Use Dconf. Go to: /org/gnome/desktop/input-sources/xkb-options. In Custom value add caps:colon to the array.

In my case, it looks like this:

['altwin:ctrl_win', 'caps:colon']

End

Sorry for rough instructions with a little word of explanation. As I said, sometimes this blog will be used as my tech notes. They may look like this.

Hopefully, you’ll find them useful.