Tap & Hold keymaps - OBSD

OBSD-6.8-cur Gaanu/Linux X11 xcape


I have made a previous post living fullest - home row workflow by remapping keys to behave differently on tapping. (works regardless of X11 or wayland)

It was based on interception-tools which uses libudev and libevdev these are not *BSD-specific (there's an interesting libudev-devd implementation for FreeBSD though)

The only way AFAIK to achieve on OBSD is using xcape (happy puffer noises, it's in ports hearty thanks edd and sthen!) along with xmodmap(1)


xcape adds only extra keysym on tapping with certain timeout so holding a key longer than the timeout, functions same. In order for key, say semicolon to generate control on holding it should mapped to that first using xmodmap (with some extra bits since control mod1 mod2 .. are special keys)

Running xmodmap will list all the modifiers.

general syntax xmodmap+xcape

First, remove the useless key (guessed it right) - Caps_Lock

xmodmap -e "remove Lock = Caps_Lock"

To avoid confusions, I'm using keycodes (it's a code representing physical keys so it won't change no matter what the key is generating)

using xev(1), the keycode of caps is 66

xmodmap -e "keycode 66 = Contrl_L"

xmodmap should be informed that newly mapped 66 is needed to function as control ie when Ctrl+C Ctrl+some_key is pressed

xmodmap -e "add Control = Contrl_L"  

To generate Escape when tapped

xcape -e "Control_L=Escape"

Pseudo Keycode - for extra modifier

Holding Tab key should generate alt, the keycode being 23

xmodmap -e "keycode 23 = Alt_L"

appending 23 to mod1 list

xmodmap -e "add mod1 = Alt_L"

all done?

xcape -e "Alt_L=Tab"

This throws error, complaining keysym Tab isn't mapped to any keycodes. To avoid, map it to random keycode then run above

xmodmap -e "keycode any = Tab"
xcape -e "Alt_L=Tab"

Workaround for Shift+key lag

Similar can be done for semicolon (keycode 47)

xmodmap -e "keycode 47 = Control_R colon"
xmodmap -e "add Control = Control_R"
xmodmap -e "keycode any = semicolon"

xcape for generating semicolon on tap

xcape -e "Control_R=semicolon"

Problem with above, xcape cannot differentiate states (state 0x1 for shifted) so Shift+semicolon generates :;

Decreasing tap timing with xcape -t 95 is not reliable, sometimes ; gets missed. I have tinkered with xset delay and frequency
xset r rate 1200 12 nothing useful, it's how xcape

For colon I have to hold left_shift and press semicolon (2 key strokes), since tapping shift_l remaining usued, it felt the most intuitive way (overcomes the lag + saving a key stroke)

xmodmap -e "keycode any = colon"
xcape -e "Shift_l=colon"

Conf Persist on Startup

xmodmap's config file

remove Lock = Caps_Lock

! keycode 66 Caps_Lock
! to control & esc on tap
keycode 66 = Control_L
add Control = Control_L
! xcape -e "Control_L=Escape"

! keycode 66 Caps_Lock
! to super (logo key) & esc on tap
! keycode 66 = Super_L
! add mod4 = Super_L
! xcape -e "Super_L=Escape"

! keycode 47 semicolon
! to control, semicolon on tap 
keycode 47 = Control_R
add Control = Control_R
keycode any = semicolon
! xcape -e "Control_R=semicolon"

! keycode 50 Shift_L
! tap as colon
keycode any = colon
! xcape -e "Shift_L=colon"

! keycode 23 tab
! as alt, tab on tap
keycode 23 = Alt_L
keycode any = Tab 
add mod1 = Alt_L
! xcape -e "Alt_L=Tab"

Adding before wm startup on ~/.xsession

# xinput essentials

# keymaps 
xmodmap ~/.xmodmap_conf &
xcape -e " Control_L=Escape;Control_R=semicolon;Alt_L=Tab;Shift_L=colon" &

# bg term wm

funky X

I'm confused by different ways other than xmodmap.. xkbcomp(1), setxkbmap(1), wsconsctl(1). I cannot keep track of all, the worst experience I had was with wsconsctl - none worked even the annoying keyboard bell (there's only one hotplugged keyboard it's supposed to work, no dice)

setxkbmap is (supposed) successor of xmodmap but they differ in usecase, it's easier if inbuilt option is present

# caps as control and escape on tapping 
setxkbmap -option "caps:ctrl_modifier"
xcape -e "Caps_Lock=Escape"

# caps as super and escape on tapping 
setxkbmap -option "caps:super"
xcape -e "Caps_Lock=Escape"

more -option on xkeyboard-config(7)

clearly XKB looks simple compared to xmodmap but I failed at making config for other keys following convoluted docs (=_=)

If someone want to experience the pain, I highly recommend

Evil Tip

For some reason if you want to revert back to RSI causing vanilla layout, setxkbmap can override xmodmap

# with no option present it maps to pre-defined layout
setxkbmap -option
# and kill xcape 
pkill xcape 

End notes

Even with the limitations, xcape is highly usuable I'm happy how it turned. Now that I have filled gaps of OBSD being my daily driver, what's left is figuring FVWM(2?)