(Updated: 2023-05-05 to fix some typos)

Remap “Caps Lock” key as left-hand ENTER

[ This post is relevant primarily to right-handed folks, and to left-handed folks who use a right-handed computer setup (you use the mouse with your right hand). ]

I found myself working on a one-off task that involved a fair amount of copy/paste work in my terminal emulator, building up command lines with little tidbits of data gathered from here and there, without any typing (except to hit the ENTER key to run the command).

I am using X11, so selecting the source text tidbits is enough to “copy” it, and clicking the middle mouse button pastes it in the target window at the location of the cursor. So far, so good. Once the command line was ready I pressed the ENTER key (with my right hand), and then moved on to the next one.

I found that moving my right hand from the mouse to the ENTER key and then back to the mouse again was slowing me down, and the motion was generally irritating.

It occurred to me that it would be nice if there were an ENTER key within reach of my left hand, and that the Caps Lock key would be a good candidate for remapping for that purpose.


TL;DR

To turn your Caps Lock key into an ENTER key, run these two commands in a shell within your X11 session. If you are happy with the result, then add the commands to your ~/.xsession file (or your local system equivalent) to have them take effect the next time you restart X.

    $ xmodmap -e 'clear Lock'

    $ xmodmap -e 'keycode  66 = Return NoSymbol Return'

For best results, read the rest of the article first, though; the Caps Lock key on your keyboard might not be mapped to keycode 66. If that is the case, the above will just disable your Caps Lock key and turn whatever key that is mapped to keycode 66 into an ENTER key. Also described below is an approach to preserving the mapping when keyboards are hotplugged to the system (e.g., USB keyboards).


Background

A typical 104- or 105-key US keyboard has two ENTER keys reachable with your right hand:

  1. one to the right side of the home row, and

  2. one on the right edge of the number pad.

However, there are not any reachable from your left hand.

Since the Caps Lock key is useless anyway, it is a good candidate to re-map as a left-hand ENTER key. Having that allows you to keep your right hand on the mouse and use your left hand to press the ENTER key, when needed.


Gather tools and data

In order to remap the keyboard Caps Lock key, you will need a couple of pieces of information and two programs: xev(1) and xmodmap(1). On Debian-based systems, the xev program is provided by the x11-utils package, and the xmodmap program is provided by the x11-xserver-utils package. You may have one or both of them already, but if not:

    # apt-get -u install x11-utils x11-xserver-utils

The pieces of information needed include the “keycodes” for the “Caps Lock” and “Enter” keys, as well as the mapping (to “keysyms”) in effect for the “Enter” key (so we can copy it for use with the “Caps Lock” key).

Use xev to obtain the keycodes. Here’s what I saw initially for my “Caps Lock” key:

KeyPress event, serial 31, synthetic NO, window 0xd400001,
    root 0x1ab, subw 0x0, time 4049429559, (169,-13), root:(309,938),
    state 0x10, keycode 66 (keysym 0xffe5, Caps_Lock), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyRelease event, serial 34, synthetic NO, window 0xd400001,
    root 0x1ab, subw 0x0, time 4049429670, (169,-13), root:(309,938),
    state 0x12, keycode 66 (keysym 0xffe5, Caps_Lock), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

So that tells us that our “Caps Lock” key is mapped to keycode 66. A similar query for the “Enter” key told me it was mapped to keycode 36.

Next we will use xmodmap to obtain the keycode to keysyms mapping, and also the current state of the Lock modifier (from the “modifier map”).

Since we will make reference below to clearing the lock modifier, it is useful to note the initial state of it:

    $ xmodmap -pm | grep '^lock'
    lock        Caps_Lock (0x42)

[ The -pm option causes xmodmap to show us the current modifier map. ]

The next thing to find out was what the xmodmap setting for the “Enter” key looked like. That was done by browsing the output of the command:

    $ xmodmap -pke | less

[ The -pke option causes xmodmap to print on stdout the current keymap table, in the form of expressions that can be fed back into to xmodmap. ]

The two lines in that output of interest here were:

    keycode  36 = Return NoSymbol Return

    keycode  66 = Caps_Lock NoSymbol Caps_Lock

The first shows the setting for the “Enter” key, and the second is the initial setting for the “Caps Lock” key.


Let’s do it

To turn our “Caps Lock” key into a left-hand “Enter” key, we need to do two things:

  1. Remove the lock modifier for the “Caps Lock” key.

  2. Re-map the “Caps Lock” key’s keycode to the “keysyms” appropriate for an “Enter” key.

Step (1) is accomplished on the live system by using the command1:

    $ xmodmap -e 'clear Lock'


Step (2) is accomplished on the live system by using the command:

    $ xmodmap -e 'keycode  66 = Return NoSymbol Return'

Congratulations, your “Caps Lock” key now functions as an “Enter” key. At this point, your “Caps Lock” should have stopped having any letter case-altering effect, and should have no locking (“toggle”) effect, either. If your keyboard has an LED light that used to turn on when your “Caps Lock” key was in the lock position, you will find that the LED is no longer lit when the “Caps Lock” key is pressed (or even held down).


Make permanent

The above settings are transient as currently configured. If you were to restart X or reboot your machine (or something similar) the old settings would come back when X gets reinitialized. To have the new settings take effect automatically in your next X session, there are two different approaches you might consider:

  1. The first (and simpler) approach would be to add the commands exactly as typed above to your ~/.xsession file (or local system equivalent). If your keyboard is always plugged into the machine (typical for a desktop) then that approach is good enough.

  2. The second, more elaborate, approach would be to take additional steps to allow the settings to take effect not only upon re-initializing X, but also when hotplugging the keyboard.


Make dynamic

If your keyboard is not always plugged into the machine (e.g., a USB keyboard plugged into a laptop machine, sometimes) then you will find that approach (1) above is not adequate. The reason is that, in X11, those keyboard setting overrides would applied only to the devices attached to the system at the time the settings are applied – that is, when initializing X.

If, for example, a USB keyboard is unplugged and then re-plugged, it will get default settings, not the override settings that we would have applied during X11 initialization.

One solution to this problem is the userspace inputplug(1) daemon, available in the ‘inputplug’ Debian package or from the GitHub repo andrewshadura/inputplug. Because inputplug monitors the system for a particular class of XInput2 events, it can determine when a new device has been (re)added to the system. When such an event is received, it invokes a user-provided program with the event metadata; that gives us a chance to (re)apply our override settings.

[ The approach described below is an adaptation of the technique presented by unix.stackexchange.com user mosvy in an answer in the discussion “Prevent keyboard layout reset when USB keyboard is plugged in”. ]

This approach uses four small pieces acting on concert.

  1. my-keyboard-setup – A script with the above xmodmap commands in it

  2. on-new-kbd – A script invoked by inputplug; calls my-keyboard-setup

  3. ~/.xsession (1st) – Modify to call my-keyboard-setup (at X init time)

  4. ~/.xsession (2nd) – Modify to launch inputplug daemon (at X init time)

Piece 1 of 4: my-keyboard-setup

The first is a small script that runs the xmodmap commands we have been using above. The reason for putting them in a dedicated script is that it will allow us to trigger the functionality from two different contexts.

    $ mkdir -p ~/bin/

    $ cat - <<EOF > ~/bin/my-keyboard-setup
    > #!/bin/bash -
    > xmodmap -e 'clear Lock'
    > xmodmap -e 'keycode  66 = Return NoSymbol Return'
    > EOF

    $ chmod 0755 ~/bin/my-keyboard-setup

Piece 2 of 4: on-new-kbd

The second is a script intended to be invoked by inputplug that will decide when to invoke the above command (basically, only when a new keyboard has been enabled). There is a more complete version in the on-new-kbd Gist, but the basic idea looks like this:

#!/bin/bash -
declare -r PROG='on-new-kbd'

# When invoked by 'inputplug', four command line parameters will be
# provided:
#
#     event-type device-id device-type device-name
#
# See inputplug(1) for details.

event_type=$1
device_id=$2
device_type=$3
device_name=$4

# Examples:
# =========
#
# Note that we get two different events when we unplug the keyboard, and
# two different events when we plug the keyboard back in.
#
# Unplug events:
#
# -----------------------------------------------
# event_type:  XIDeviceDisabled  XIDeviceDisabled
# device_id:   10   10
# device_type: XISlaveKeyboard XISlaveKeyboard
# device_name: is_unset_or_null 
# -----------------------------------------------
# event_type:  XISlaveRemoved  XISlaveRemoved
# device_id:   10   10
# device_type: is_unset_or_null 
# device_name: is_unset_or_null 
# -----------------------------------------------
#
#
# Plug event:
#
# -----------------------------------------------
# event_type:  XISlaveAdded  XISlaveAdded
# device_id:   10   10
# device_type: XIFloatingSlave XIFloatingSlave
# device_name: Microsoft Natural Keyboard Elite Microsoft Natural Keyboard Elite
# -----------------------------------------------
# event_type:  XIDeviceEnabled  XIDeviceEnabled
# device_id:   10   10
# device_type: XISlaveKeyboard XISlaveKeyboard
# device_name: Microsoft Natural Keyboard Elite Microsoft Natural Keyboard Elite
# -----------------------------------------------

case "${event_type} ${device_type}" in

    'XIDeviceEnabled XISlaveKeyboard') my-keyboard-setup ;;

    *)
        : uninteresting event -- ignore
        ;;
esac

Piece 3 of 4: ~/.xession call to my-keyboard-setup

To have our keyboard mapping overrides take effect during X11 initialization, add a line such as the following to your ~/.xsession file (or equivalent):

    "${HOME}/bin/my-keyboard-setup"

Piece 4 of 4: ~/.xession run inputplug(1) daemon

Also done during X11 initialization, arrange for the inputplug daemon to run and to invoke the on-new-kbd script for device add/remove and enable/disable events. To do so, add a line such as the following to ~/.xsession beneath the line we just added in the previous step:

    /usr/bin/inputplug -c "${HOME}/bin/on-new-kbd"

Summary

At this point you should have a working left-hand ENTER key that is both permanent and dynamic. Enjoy!