Is there a way to use CapsLock + [j, k, l, semicolon] to simulate the arrow keys?

ator-dev

New Member
Credits
57
Hi - sorry if I'm not posting in a good format, I've only just joined this site. I've been having a lot of problems trying to simulate the [Left, Up, Down, Right] keys (no modifiers) using CapsLock + [j, k, l, semicolon], respectively.

I've got quite a long way remapping CapsLock to Hyper and mapping that from mod4 to mod3, but whatever it's mapped to causes apps to interpret the arrow keys differently. For example, Firefox refuses to scroll most webpages if a modifier key is currently pressed, meaning Hyper+Down (technically CapsLock+l) usually does nothing.

A possible way around this is to execute a script (already made and functional) that remaps the j,k,l,; keys when the Hyper key is depressed (and then marks it as 'released' so as not to confuse programs), then maps them back when the physical CapsLock key is actually released. However, I can't seem to find a way of executing a command on key down/release.

If there's a way of using the above solution by running my script when Hyper (CapsLock) is specifically depressed or released, that would be perfect. Any other method for simulating an arrow key press with no modifiers would be greatly appreciated as well though. Could someone give me some information about this please?

Thanks in advance!
 


Fanboi

Active Member
Credits
3,427
I think you may be over-complicating things. Xmodmap lets you permanently change keys while you xsession is running (so it won't affect your disconnected ttys).

Open a terminal window and enter:
xev
When the small white window pops up, drag it out the way of the terminal. Now press every single key you want to modify and note down the "keycode" and the "keysym" symbol, eg "x", "Caps_Lock".
Install Xmodmap (if it isn't already installed).
Now you can modify your keys such:
Code:
// Basic grammaer is:
// xmodmap -e "<keycode> = <keysym>"
// Example:
// This will make keycode 53 ("x" on my machine the left hand Super key, AKA the "Windows key):
xmodmap -e "keycode 53 = Super_L"
Obviously this is lost per-xsession. So you need to place it in the ~/.Xmodmap config file. This file uses "!" for comments instead of "#" for some reason.
Code:
! My basic setup:
keycode 53 = Super_L
keycode 171 = F14
keycode 192 = x

! And so on. You can also map mouse buttons
pointer = 1 2 3 4 5 6 7 10 11 12 13
! which I used to set my mouse buttons in the right order because a few were backwards.

! Or even bind keys to mouse actions:
keycode 50 = Pointer_Button4 NoSymbol Pointer_Button4
keycode 62 = Pointer_Button5 NoSymbol Pointer_Button5
! The above makes my Shift keys act like the scroll wheel
Then just save the file, logout and login again (or restart if you can't shutdown your xsession).

If you need to undo the changes, you can do so from another tty. Otherwise, you could write a script if you need to toggle this key functionality on/off.

Good luck.
 

ator-dev

New Member
Credits
57
I think you may be over-complicating things. Xmodmap lets you permanently change keys while you xsession is running (so it won't affect your disconnected ttys).

Open a terminal window and enter:
xev
When the small white window pops up, drag it out the way of the terminal. Now press every single key you want to modify and note down the "keycode" and the "keysym" symbol, eg "x", "Caps_Lock".
Install Xmodmap (if it isn't already installed).
Now you can modify your keys such:
Code:
// Basic grammaer is:
// xmodmap -e "<keycode> = <keysym>"
// Example:
// This will make keycode 53 ("x" on my machine the left hand Super key, AKA the "Windows key):
xmodmap -e "keycode 53 = Super_L"
Obviously this is lost per-xsession. So you need to place it in the ~/.Xmodmap config file. This file uses "!" for comments instead of "#" for some reason.
Code:
! My basic setup:
keycode 53 = Super_L
keycode 171 = F14
keycode 192 = x

! And so on. You can also map mouse buttons
pointer = 1 2 3 4 5 6 7 10 11 12 13
! which I used to set my mouse buttons in the right order because a few were backwards.

! Or even bind keys to mouse actions:
keycode 50 = Pointer_Button4 NoSymbol Pointer_Button4
keycode 62 = Pointer_Button5 NoSymbol Pointer_Button5
! The above makes my Shift keys act like the scroll wheel
Then just save the file, logout and login again (or restart if you can't shutdown your xsession).

If you need to undo the changes, you can do so from another tty. Otherwise, you could write a script if you need to toggle this key functionality on/off.

Good luck.
Thanks for the help! Unfortunately this works similarly to my previous attempt at doing this, and it doesn't quite behave how I need it to; I want to turn the [jkl;] keys into the arrow keys when the CapsLock key is pressed down (which I currently can't work out how to detect), then turn them back when the key's release; not change them permanently. Your answer has given me some useful information about the problem anyway though (;
If you happen to know how I could work out how to execute one script when CapsLock or Super is pressed down and a different one when it's released, please let me know - I've managed to work out almost everything, but I can't seem to get this theoretically simple last step.
 

Fanboi

Active Member
Credits
3,427
Okay, off my head.. Install sxhkd (" sudo apt-get install sxhkd") and read manpages. It's a very simple hotkey daemon ("man sxhkd").

Up to steam. Now you can use sxhdk to call your
script. This is basic idea for your script:
Code:
#! /bin/bash

# Hacky technique, lol
if [ -e "/tmp/myxkeys.on" ]
then
	# Make a cfg file for the default key settings
	xmodmap <my-normal-config>
	rm /tmp/myxkeys.on
	exit
fi

# Make a tmp file as a "lock" to let script know
# the state is on
echo > /tmp/myxkeys.on

# Load your custom mapping
xmodmap <my-custom-ijkl-cfg-file>
Name the script something sensible like "myxkeys-ijkl.sh" and chmod a+x it. Put it in your choice directory. Then as root/superuser create a softlink to it as usr/local/bin/myxkeys-ijkl. Done. You can call it from the shell so you can create an entry in sxhkd's cfg file (check Caps Lock keysym name with xev):
Code:
Caps_Lock
    myxkeys-ijkl
And then just restart your xsession (yes, you could achieve this without the script, but this is easier for my explanation coz it'll get messy otherwise and newcomers will struggle). That's it.

Estimated time: 10-20min depending on your reading/typing speed.

Have fun with sxhkd, it can be fun for creating shortcuts (wouldn't recommend it for events though).
 

ator-dev

New Member
Credits
57
Okay, off my head.. Install sxhkd (" sudo apt-get install sxhkd") and read manpages. It's a very simple hotkey daemon ("man sxhkd").

Up to steam. Now you can use sxhdk to call your
script. This is basic idea for your script:
Code:
#! /bin/bash

# Hacky technique, lol
if [ -e "/tmp/myxkeys.on" ]
then
    # Make a cfg file for the default key settings
    xmodmap <my-normal-config>
    rm /tmp/myxkeys.on
    exit
fi

# Make a tmp file as a "lock" to let script know
# the state is on
echo > /tmp/myxkeys.on

# Load your custom mapping
xmodmap <my-custom-ijkl-cfg-file>
Name the script something sensible like "myxkeys-ijkl.sh" and chmod a+x it. Put it in your choice directory. Then as root/superuser create a softlink to it as usr/local/bin/myxkeys-ijkl. Done. You can call it from the shell so you can create an entry in sxhkd's cfg file (check Caps Lock keysym name with xev):
Code:
Caps_Lock
    myxkeys-ijkl
And then just restart your xsession (yes, you could achieve this without the script, but this is easier for my explanation coz it'll get messy otherwise and newcomers will struggle). That's it.

Estimated time: 10-20min depending on your reading/typing speed.

Have fun with sxhkd, it can be fun for creating shortcuts (wouldn't recommend it for events though).
Sorry this is so late, I started working on a solution based on this meaning to message back once I got it working, and forgot to reply! As it turns out, sxhkd allows me to map things to keydown and keyup events which is exactly what I wanted - annoyingly though, it also steals the keyboard when the mapped key/s is pressed, so I can't actually type while the arrow keys are switched which is obviously useless ):
I've started messing with sxhkd's source to try to remove the keyboard-stealing functionality, but it seems to be built into this 'xkb' library it uses and I can't figure out a way to fix my problem still.
I'll try asking about xkb specifically in another thread as I think it's a bit offtopic for this one, but fundamentally I've found what I needed (keyup and keydown shortcut events). Thank you very much for the help! I'll make sure to update this thread if I work out xcb or find another solution.
 
Last edited:

Fanboi

Active Member
Credits
3,427
Glad it's starting to work out. You could always write a script to toggle sxhkd on/off using the DEs keybindings. Course this is inelegant. A better approach may be to setup 2 sxhkd config file, say "norm.cfg" and "ijkl.cfg". Then a toggle script, say "toggle-ijkl".
Code:
#! /bin/bash

# Toggle sxhkd
if [ "norm" = $(cat /tmp/sxhkd.state) ]
then
        # sxhkd has an on-the-fly update signal but
        # I don't remember, may be SIGHUP so I'll
        # just do it dirty, you can fix this later.
        killall sxhkd
        sxhkd ijkl.cfg &
elif [ "ijkl" = $(cat /tmp/sxhkd.state) ]
then
        killall sxhkd
        sxhkd norm.cfg &
else
        echo "Something broke!" >> /tmo/sxhkd.log
fi;
As I mentioned, it should have ab on-the-fly update (in which case you could cat file.cfg > sxhkd.cfg && killall -1 sxhkd). Otherwise, just use the script idea and throw it in each sxhkd config:
Code:
Super_L + Caps_Lock
        toggle-ijkl
Hopefully then it won't intrude as you're using Super (Windows key) as a modifier, thus removing potential conflicts. Seems easier than code-diving through lines of code that may be 20 years old.
 

ator-dev

New Member
Credits
57
Glad it's starting to work out. You could always write a script to toggle sxhkd on/off using the DEs keybindings. Course this is inelegant. A better approach may be to setup 2 sxhkd config file, say "norm.cfg" and "ijkl.cfg". Then a toggle script, say "toggle-ijkl".
Code:
#! /bin/bash

# Toggle sxhkd
if [ "norm" = $(cat /tmp/sxhkd.state) ]
then
        # sxhkd has an on-the-fly update signal but
        # I don't remember, may be SIGHUP so I'll
        # just do it dirty, you can fix this later.
        killall sxhkd
        sxhkd ijkl.cfg &
elif [ "ijkl" = $(cat /tmp/sxhkd.state) ]
then
        killall sxhkd
        sxhkd norm.cfg &
else
        echo "Something broke!" >> /tmo/sxhkd.log
fi;
As I mentioned, it should have ab on-the-fly update (in which case you could cat file.cfg > sxhkd.cfg && killall -1 sxhkd). Otherwise, just use the script idea and throw it in each sxhkd config:
Code:
Super_L + Caps_Lock
        toggle-ijkl
Hopefully then it won't intrude as you're using Super (Windows key) as a modifier, thus removing potential conflicts. Seems easier than code-diving through lines of code that may be 20 years old.
Hi again - I've tried a few times now to get it working, but I'm pretty sure at this point the keyboard-stealing/locking behaviour is unavoidable... If you kill sxhkd, it no longer has the keys grabbed and so doesn't respond to keyup events ):
I can at least make it halfway there by turning capslock into a kind of toggle for the arrow keys, so you press it once to activate the behaviour and once more to deactivate it. It's not perfect (mainly because I keep forgetting whether it's on or off) but I can improve that by toggling the capslock indicator as well.
It's possible that the only way to do this is by using a language with better libraries for detecting key events that don't require keyboard-grabbing, but I haven't really got the time for that right now; I've already lost enough time on my work trying to make the perfect behaviour for this functionality.
Thanks again, I know you didn't need to help me out with something that seems I'm basically the only one interested in doing, and I'm grateful for that (;
Hopefully in the future there'll be a less hacky way of going about this kind of thing.
 
Last edited:

Fanboi

Active Member
Credits
3,427
Well, at least it works. You might try placing the @ symbol for key release events above normal specifiers, eg:
Code:
@Caps_Lock
        xmessage CapsRelease
Caps_Lock
        xmessage CapsPressed
You could then try it from there. Maybe the sxhkd -c cfg-file and redstart via killall -SIGUSR1 sxhkd which should refresh it. Failing -c cfg file, you could cat cfg file > sxhkdrc file for each toggle.
 
$100 Digital Ocean Credit
Get a free VM to test out Linux!


Top