microsoft / wslg

Enabling the Windows Subsystem for Linux to include support for Wayland and X server related scenarios
MIT License
10.22k stars 305 forks source link

Swapping modifier keys with xmodmap or setxkbmap does not work #418

Open camsaul opened 3 years ago

camsaul commented 3 years ago

Not sure if this is a WSLg bug specifically or something upstream but I ran in to this today after switching to WSLg. I was previously using X410 and it worked without issue.

I can use xmodmap, xkbcomp, or setxkbmap to remap keys on my keyboard; this works perfectly fine for normal, non-modifier keys; however, when remapping modifier keys, it only remaps the keysym, and not the modifier bits. It seems like the modifier bits are hardcoded, because nothing I have tried will change them.

steps to repro:

Use the built-in option to swap left alt and left control

setxkbmap -option ctrl:swap_lalt_lctl

Then run

xev -event keyboard

and press Left Alt and Left Control to see what you get:

Left Control:
KeyRelease event, serial 49, synthetic NO, window 0xa00001,
    root 0x22e, subw 0x0, time 472407, (96,118), root:(6191,3567),
    state 0x4, keycode 37 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False
Left Alt:
KeyRelease event, serial 49, synthetic NO, window 0xa00001,
    root 0x22e, subw 0x0, time 473915, (96,118), root:(6191,3567),
    state 0x8, keycode 64 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

Note that the keysyms are remapped as expected, but the modifier states are not; left control still has the modifier state 0x4 (Control) while left alt still has the state 0x8 (Mod1, which is Meta on my system). Thus various X applications such as Emacs still treat these keys as their original keys, not the remapped ones.

I've been able to reassign non-modifier keys such as KP_Divide to modifiers (e.g. Hyper_R) using xkbcomp, and that works perfectly; I can also use setxkbmap -option caps:escape to make Caps Lock work as Escape, but it still sets the the 0x2 (Lock) bit -- so it's actually working as both Caps Lock and Escape at the same time.

I've tried everything under the sun to tweak the modifier bits that modifier key presses generate, but nothing seems to affect them -- I'm left to conclude maybe they're hardcoded somewhere in WSLg, or an upstream component?

Other things I tried:

Using xmodmap

This was my old config that was working fine with X410. I had my right alt key mapped to `Alt_R` (**not** Meta) and my right Ctrl key mapped to `Hyper_R`, like this: ``` cat $~/.Xmodmap ! Set left alt = Meta_L keycode 64 = Meta_L ! Set right alt = Alt_R keycode 108 = Alt_R ! Set right control = right hyper keycode 105 = Hyper_R clear control clear mod1 clear mod2 clear mod3 clear mod4 clear mod5 add control = Control_L add mod1 = Meta_L add mod2 = Scroll_Lock add mod3 = Alt_R add mod4 = Super_R add mod5 = Hyper_R ``` As you can see it's returning the correct keysym (`Hyper_R`) but the state is `0x4` (Control) whereas it _should_ be `0x80` (Mod5/Hyper). ``` KeyRelease event, serial 28, synthetic NO, window 0xc00001, root 0x254, subw 0x0, time 6383137, (131,102), root:(5524,3131), state 0x4, keycode 105 (keysym 0xffee, Hyper_R), same_screen YES, XLookupString gives 0 bytes: XFilterEvent returns: False ```

Using xkbcomp

I generated file called `.Xkeymap` file with `xkbcomp $DISPLAY .Xkeymap`, then made the following tweaks to map Numpad Divide and Right Control to `Hyper_R`, and make `Hyper_R` `Mod5`, and loaded it with `xkbcomp .Xkeymap $DISPLAY`: ``` xkb_keymap { ... xkb_symbols { .... key { [ Hyper_R ] }; key { [ Hyper_R ] }; .... modifier_map Mod5 { Hyper_R }; }; } ``` Numpad Divide now works perfectly as Hyper -- the keysym is `Hyper_R` and the modifier state is `0x80` (`Mod5`); however Right Control has keysym `Hyper_R` but still has modifier state `0x4` (`Control`).

Version info/logs

`versions.txt`: ``` WSLg ( x86_64 ): 1.0.26+Branch.main.Sha.26ce2c09b86442f3c7f4f6462f770ed2afa76a25 Mariner: VERSION="1.0.20210224" FreeRDP: b05321cd4e6a862aef76163a69db4e1910245736 weston: 46756d0e77e5c01b5995fbbee6f3ab0db9b30612 pulseaudio: 2f0f0b8c3872780f15e275fc12899f4564f01bd5 mesa: ``` `weston.log`: https://gist.github.com/camsaul/4d47d67fc468bed34cba8b9cfa0fc88e
camsaul commented 3 years ago

@hideyukn88 any idea how I can fix this?

ggray00 commented 2 years ago

Did you make any progress on this? I have the same issue, except that, in addition, non-modifier keys also do not change. It also extends beyond app like emacs and intellij, the command line itself displays the original key value/symbol. The values displayed in xev and an outputted keymap for xmodmap are both changed to no effect.

camsaul commented 2 years ago

Still trying to figure out how to get it to work...

From reading https://github.com/microsoft/wslg/issues/173 I think the correct approach is to do things with xkb and edit the weston.ini config in the WSLg instance, and restart the Weston server.

I edited /home/wslg/.config/weston.ini/ in the WSLg instance to look like this:

[xwayland]
disable_access_control=true

[input-method]
path=

[keyboard]
keymap_layout=us
keymap_options=ctrl:swap_rctrl_ralt

(based on the weston.ini reference here: https://www.mankier.com/5/weston.ini)

and restarted Weston with pkill -HUP weston but that doesn't seem to have any effect either... in weston.log I see

[11:33:31.032] Using config file '/home/wslg/.config/weston.ini'
...
[11:34:02.962] convert_rdp_keyboard_to_xkb_rule_names: matching layout=us variant=(null) options=(null)

According to https://github.com/microsoft/wslg/issues/173#issuecomment-849894177

| actually weston should be trying to "sync" the keyboard layout based on what Windows client software (RDP client) reports.

So it seems like RDP is possibly syncing and stomping on the options I tried to specify. Not sure how to prevent that yet (@hideyukn88 do you have any ideas?)

ggray00 commented 2 years ago

I'm about to give up and buy a new Linux box. The only ideas I had where:

  1. Trying different set keyboard layouts
  2. Buying a new custom keyboard with better mappings
  3. Software that codes its own hotkeys (Actiona or Key Mapper) and try to replace mod keys with something else
  4. Contact Microsoft support and let them know xmodmap doesn't work at all.

Each of these has its own problems and I am not optimistic. I'll let you know if anything works out. Your approach sounds promising but is beyond me. I can't even get ultra simple commands like this one to work on the command line: xmodmap -e "Keycode 24 = u U u U"

camsaul commented 2 years ago

FWIW Xmodmap with an X server (e.g. Vcxsrv or X410) works just fine. I really want to use WSLg but I might have to go back to using X410 until I can figure out how to make this work

camsaul commented 2 years ago

To use X410 or Vcxsrv instead of WSLg you can just do

export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
unset WAYLAND_DISPLAY
export GDK_BACKEND=x11

and then xmodmap works without issue for me

ggray00 commented 2 years ago

Sorry for the late reply. Thank you for the suggestion, but on my environment (Windows 11, WSL2 fresh install), it was pretty catastrophic. The keyboard output was completely unpredictable.

I made some progress with autohotkey, but it was sluggish and randomly didn't work about 3% of the time. It's a shame because it felt close to being a great product, but enough went wrong for me to go back to pure linux. Thanks for reaching out though.

On Mon, Jan 3, 2022 at 1:20 PM Cam Saul @.***> wrote:

To use X410 or Vcxsrv instead of WSLg you can just do

export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0 unset WAYLAND_DISPLAY export GDK_BACKEND=x11

and then xmodmap works without issue for me

— Reply to this email directly, view it on GitHub https://github.com/microsoft/wslg/issues/418#issuecomment-1004303212, or unsubscribe https://github.com/notifications/unsubscribe-auth/AXDFR6QRQBE3CPSRPIKIZQDUUHZJTANCNFSM5CNKIXVA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

hideyukn88 commented 2 years ago

While I mark this as "weston-upstream-bug" since upstream reference has same issue (state bit is not swapped), but given same issue is also observed with mutter compositor on native Ubuntu desktop running in Wayland mode, I personally feel the Xwayland (X server for Wayland compositor) is not honoring that, thus the issue seems common in X app support in Wayland compositor.