You are not logged in.
I've spent 4 days trying to figure out how to map RAlt+additional keys to have arrow keys, text navigation/selection/deletion etc. in programs that don't support Vim or Emacs style keybindings, which are many.
We all know how time consuming and uncomfortable it is to reach for arrow keys, but what makes the situation worse is that I've got an HP Zbook, so my arrow keys be like:
The keys I'm trying to map while holding down RAlt are:
hjkl to Arrow keys
HJKL to Shift+Arrow keys
f to Ctrl+Right
b to Ctrl+Left
F to Ctrl+Shift+Right
B to Ctrl+Shift+Left
x to Delete
d to Ctrl+Delete
w to Ctrl+Backspace
e to End
a to Home
I've tried mapping RAlt scancode to rightmeta, but I displays as Alt_R in xev.
Then I tried to bind RAlt+keys in AutoKey, but it doesn't allow to choose between left and right Alt, and I'm using the left alt for other purposes.
So I tried mapping RAlt to Hyper_L using xkbcomp:
xkb_symbols {
key <RALT> { [ Hyper_L ] };
};And binding Hyper+keys in AutoKey. That worked in chromium, but in my terminal emulator (I'm using Alacritty), it just outputs the keys I'm pressing, so I made a hack for each key (e.g. for Hyper+j that's bound to the Down arrow key, I bound Alt+j to... Alt+j).
That worked for a while, but then I decided to map Alt+f (left alt) to Shift+F6 in chromium only, to switch focus from address bar to the page, but it didn't let me, because I had Alt+f as a hack for Hyper+f, even though I specified chromium's window class, so it could still use the other script for other programs? And if I disable the hack for this, I can't use Alt+f in Alacritty (nothing happens when I press it).
Then I tried to make RAlt modify the Mod3 bit with:
xmodmap -e 'add mod3 = Alt_R'And binding Mod3+keys in Awesome WM, but it's such a hack I had to do something like this (unpress all the keys before sending fake input):
awful.key({ "Mod3" }, "j",
function()
root.fake_input("key_release", "j")
root.fake_input("key_release", "Alt_R")
root.fake_input("key_press", "Down")
root.fake_input("key_release", "Down")
end,
{description = "simulate down arrow key", group = "fake_input"})And it only works for 1 key stroke, if I hold down the Alt key and press j twice, the second time it just outputs "j". Adding
root.fake_input("key_press", "Alt_R")At the end of the function doesn't work.
I'm starting to lose faith... Is this even possible in X? In Windows I would just use LowLevelKeyboardProc for this kind of thing. I would completely hide the right Alt from the system and all of the keys I'm pressing while holding it down, and send back completely different key strokes.
So, is there a way to make this work, in all programs?
Last edited by sooqua (2019-07-29 21:16:35)
Offline
Well that wasn't hard. Just made one script for Alt+f and did the class checking in there:
winClass = window.get_active_class()
if winClass == "chromium.Chromium":
keyboard.send_keys("<shift>+<f6>")
else:
keyboard.send_keys("<alt>+f")Offline
...So I was messing around with xmodmap until I got this result:
xmodmap: up to 3 keys per modifier, (keycodes in parentheses):
shift Shift_L (0x32), Shift_R (0x3e)
lock Caps_Lock (0x42)
control Control_L (0x25), Control_R (0x69)
mod1 Alt_L (0x40), Meta_L (0xcd)
mod2 Num_Lock (0x4d)
mod3 Hyper_R (0x6c)
mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce)
mod5 ISO_Level3_Shift (0x5c), Mode_switch (0xcb)Now everything works in all programs without any Alt+ hacks in AutoKey!
Finally a clean solution. Now I have to find a way to do this with xkbcomp...
Offline
...Sooo I was messing around with my ~/.xkb directory I made because I wanted to do everything with snippet files (i.e. don't just xkbcomp -xkb $DISPLAY xkbdump and re-import the whole file, instead use setxkbmap -print's output and add my snippet files in include`s.
It was a problem that there is a modifier_map "function", but no "clear_modifier" like in xmodmap.
So after adding
default partial modifier_keys
xkb_symbols "hyper" {
key <RALT> { [ Hyper_R ] };
};to my ~/.xkb/symbols/ralt I had this in my Mod1:
$xmodmap
mod1 Alt_L (0x40), Hyper_R (0x6c), Meta_L (0xcd) Note the Hyper_R with a keycode of Alt_R is still in there. This broke all Alt+ shortcuts in chromium, even though Alt_L is still there?
And also Hyper_L is by default in Mod4 (which makes e.g. Awesome WM shortcuts also trigger on remapped RAlt)
mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf)because of this line in /usr/share/X11/xkb/symbols/pc that is obviously included in setxkbmap -print's output if you are on a PC:
modifier_map Mod4 { <HYPR> };And again, I didn't want to modify it directly, instead, override it with snippet files.
Then I noticed that /usr/share/X11/xkb/symbols/pc includes the altwin file. So I took a look at it and I still just can't understand what is happening here:
key <LALT> { [ Alt_L, Meta_L ] };
key <RALT> { type[Group1] = "TWO_LEVEL",
symbols[Group1] = [ Alt_R, Meta_R ] };
modifier_map Mod1 { Alt_L, Alt_R, Meta_L, Meta_R };Why is RALT defined differently? What is the difference here?
Anyway here is the version of my ~/.xkb that just works (same xmodmap output as in my previous post):
~/.xkb/keymap/mykbd
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)+ralt(hyper)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+us:2+inet(evdev)+capslock(escape)+ralt(hyper)" };
xkb_geometry { include "pc(pc105)" };
};~/.xkb/keycodes/ralt
default partial
xkb_keycodes "hyper" {
<HYPR> = 108;
};~/.xkb/symbols/ralt
default partial modifier_keys
xkb_symbols "hyper" {
key <HYPR> { type[Group1] = "TWO_LEVEL",
symbols[Group1] = [ Hyper_R, Hyper_R ] };
modifier_map Mod3 { <HYPR> };
};Invoke it with
xkbcomp -I$HOME/.xkb ~/.xkb/keymap/mykbd $DISPLAYI have no idea how this works (I just got lucky) so if you know plz let me know.
I am now reading xkb manuals because I'm planning to port all the keybindings to xkb and not use AutoKey for that. Maybe I will understand what I just did at some point.
Offline
RAlt is now Hyper_R, a Mod3 key, and can activate Level3 with preserved Shift, or Level4 when the Shift key is pressed, depending on the type you choose.
CapsLock indicator is now showing Mod3 state (Hyper), since it's mapped to Escape.
~/.xkb/keymap/custom
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)+ralt(hyper)" };
xkb_types { include "complete+hyper+hyper(4lvl)" };
xkb_compat { include "complete+indicator-capslock(mod3)" };
xkb_symbols { include "pc+us+us:2+inet(evdev)+capslock(escape)+group(rctrl_toggle)+ralt(hyper)+hyper" };
xkb_geometry { include "pc(pc105)" };
};~/.xkb/compat/indicator-capslock
partial
xkb_compat "mod3" {
indicator "Caps Lock" {
whichModState= base;
modifiers= Mod3;
};
};~/.xkb/keycodes/ralt
partial
xkb_keycodes "hyper" {
<HYPR> = 108;
};~/.xkb/symbols/hyper
default partial alphanumeric_keys modifier_keys
xkb_symbols "hyper" {
key <LatW> {
type = "HYPER",
actions[Group1] = [NoAction(), NoAction(), RedirectKey(key=<BKSP>,modifiers=Control)],
actions[Group2] = [NoAction(), NoAction(), RedirectKey(key=<BKSP>,modifiers=Control)]
};
key <LatE> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, End]
};
key <LatI> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Next]
};
key <LatO> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Prior]
};
key <LatA> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Home]
};
key <LatD> {
type = "HYPER",
actions[Group1] = [NoAction(), NoAction(), RedirectKey(key=<DELE>,modifiers=Control)],
actions[Group2] = [NoAction(), NoAction(), RedirectKey(key=<DELE>,modifiers=Control)]
};
key <LatF> {
type = "HYPER",
actions[Group1] = [NoAction(), NoAction(), RedirectKey(key=<RGHT>,modifiers=Control)],
actions[Group2] = [NoAction(), NoAction(), RedirectKey(key=<RGHT>,modifiers=Control)]
};
key <LatH> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Left]
};
key <LatJ> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Down]
};
key <LatK> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Up]
};
key <LatL> {
type = "HYPER",
symbols[Group1] = [NoSymbol, NoSymbol, Right]
};
key <LatX> {
type = "HYPER4LVL",
symbols[Group1] = [NoSymbol, NoSymbol, Delete, BackSpace]
};
key <LatB> {
type = "HYPER",
actions[Group1] = [NoAction(), NoAction(), RedirectKey(key=<LEFT>,modifiers=Control)],
actions[Group2] = [NoAction(), NoAction(), RedirectKey(key=<LEFT>,modifiers=Control)]
};
};~/.xkb/symbols/ralt
partial modifier_keys
xkb_symbols "hyper" {
key <HYPR> { [ Hyper_R ] };
modifier_map none { <HYPR> };
modifier_map Mod3 { <HYPR> };
};~/.xkb/types/hyper
default partial
xkb_types "3lvl" {
virtual_modifiers LevelThree,Alt,Hyper;
type "HYPER" {
modifiers= LevelThree+Shift+Control+Alt+Hyper;
map[Shift]= Level2;
map[Control]= Level1;
preserve[Control]= Control;
map[Shift+Control]= Level2;
preserve[Shift+Control]= Control;
map[Alt]= Level1;
preserve[Alt]= Alt;
map[Shift+Alt]= Level2;
preserve[Shift+Alt]= Alt;
map[Control+Alt]= Level1;
preserve[Control+Alt]= Control+Alt;
map[Shift+Control+Alt]= Level2;
preserve[Shift+Control+Alt]= Control+Alt;
map[Hyper]= Level3;
map[Shift+Hyper] = Level3;
preserve[Shift+Hyper] = Shift;
map[Control+Hyper] = Level3;
preserve[Control+Hyper] = Control;
map[Shift+Control+Hyper] = Level3;
preserve[Shift+Control+Hyper] = Shift+Control;
map[Alt+Hyper] = Level3;
preserve[Alt+Hyper] = Alt;
map[Shift+Alt+Hyper] = Level3;
preserve[Shift+Alt+Hyper] = Shift+Alt;
map[Control+Alt+Hyper] = Level3;
preserve[Control+Alt+Hyper] = Control+Alt;
map[Shift+Control+Alt+Hyper] = Level3;
preserve[Shift+Control+Alt+Hyper] = Shift+Control+Alt;
map[LevelThree] = Level4;
level_name[Level1]= "Base";
level_name[Level2]= "Shift";
level_name[Level3]= "Hyper";
level_name[Level4]= "AltGr";
};
};
partial
xkb_types "4lvl" {
virtual_modifiers Alt,Hyper;
type "HYPER4LVL" {
modifiers= Shift+Control+Alt+Hyper;
map[Shift]= Level2;
preserve[Shift]= Shift;
map[Control]= Level1;
preserve[Control]= Control;
map[Shift+Control]= Level2;
preserve[Shift+Control]= Shift+Control;
map[Alt]= Level1;
preserve[Alt]= Alt;
map[Shift+Alt]= Level2;
preserve[Shift+Alt]= Shift+Alt;
map[Control+Alt]= Level1;
preserve[Control+Alt]= Control+Alt;
map[Shift+Control+Alt]= Level2;
preserve[Shift+Control+Alt]= Shift+Alt;
map[Hyper]= Level3;
map[Shift+Hyper]= Level4;
map[Control+Hyper] = Level3;
preserve[Control+Hyper] = Control;
map[Shift+Control+Hyper] = Level4;
preserve[Shift+Control+Hyper] = Control;
map[Alt+Hyper] = Level3;
preserve[Alt+Hyper] = Alt;
map[Shift+Alt+Hyper] = Level4;
preserve[Shift+Alt+Hyper] = Alt;
map[Control+Alt+Hyper] = Level3;
preserve[Control+Alt+Hyper] = Control+Alt;
map[Shift+Control+Alt+Hyper] = Level4;
preserve[Shift+Control+Alt+Hyper] = Control+Alt;
level_name[Level1]= "Normal";
level_name[Level2]= "Shift";
level_name[Level3]= "Hyper";
level_name[Level4]= "Shift+Hyper";
};
};Last edited by sooqua (2019-08-03 02:22:36)
Offline