xkbcommon / libxkbcommon

keymap handling library for toolkits and window systems
https://xkbcommon.org
Other
286 stars 125 forks source link

Should we recommend compose state to be global, per-seat, per-device? #254

Open crater2150 opened 3 years ago

crater2150 commented 3 years ago

Hi, I filed a bug against kitty today, because my user XCompose was ignored (see kovidgoyal/kitty#3827). According to its developer, this is an issue with libxkbcommon and should be filed here.

Since reporting the bug there, I ran an strace to see if the file is read and just now noticed, that it actually reads ~/.config/XCompose instead of ~/.XCompose (the latter being a symlink to the former on my system), which means that it didn't use my minimal version in the previous test, so I tried again replacing the correct file. The results are mostly the same, except that the system locale's compose was also not loaded until adding include "%L".

The sample configuration that I used is a ~/.config/XCompose with just a single line:

<Multi_key> <asterisk> <a>      : "α"  U03B1       # GREEK SMALL LETTER ALPHA

When typing Compose, * in kitty, a * will be inserted immediately, pressing a afterwards will also just insert it instead of producing α. When adding include "%L" before or after that line, system compose sequences will work as expected, but inserting α still won't.

The same XCompose file works in other applications (e.g. Qt-based apps, GTK-based apps if exporting GTK_IM_MODULE=xim).

Please let me know, if there is other debug information I can provide.

bluetech commented 3 years ago

The following should work:

include "%L"
<Multi_key> <asterisk> <a>      : "α"  U03B1       # GREEK SMALL LETTER ALPHA

In XCompose, when there's an exact conflict, the latter wins. I just tested it and it works for me. If it indeed doesn't work for you, please run the following command in your terminal, try to insert the sequence (I configured right Alt to be the Compose key), and paste the output.

XKB_LOG_LEVEL=debug sudo -E xkbcli interactive-evdev --enable-compose --options compose:ralt
crater2150 commented 3 years ago

The config you posted was already one of the variants I tried, sadly it doesn't work.

My keyboard doesn't have a right alt, so I used the above command, but with compose:102 as with my normal layout. The output:

% XKB_LOG_LEVEL=debug sudo -E xkbcli interactive-evdev --enable-compose --options compose:102
xkbcommon: DEBUG: Include path failed: /home/crater2150/.config/xkb (No such file or directory)
xkbcommon: DEBUG: Include path failed: /home/crater2150/.xkb (No such file or directory)
xkbcommon: DEBUG: Include path failed: /etc/xkb (No such file or directory)
xkbcommon: DEBUG: Include path added: /usr/share/X11/xkb
xkbcommon: DEBUG: Compiling from RMLVO: rules 'evdev', model 'pc105', layout 'us', variant '(null)', options 'compose:102'
xkbcommon: DEBUG: Compiling from KcCGST: keycodes 'evdev+aliases(qwerty)', types 'complete', compat 'complete', symbols 'pc+us+inet(evdev)+compose(102)'
xkbcommon: DEBUG: Compiling xkb_keycodes "(unnamed)"
xkbcommon: DEBUG: Compiling xkb_types "(unnamed)"
xkbcommon: DEBUG: Compiling xkb_compatibility "(unnamed)"
xkbcommon: DEBUG: The "group" statement in compat is unsupported; Ignored
xkbcommon: DEBUG: The "group" statement in compat is unsupported; Ignored
xkbcommon: DEBUG: The "group" statement in compat is unsupported; Ignored
xkbcommon: DEBUG: The "allowExplicit" field in indicator statements is unsupported; Ignored
xkbcommon: DEBUG: The "allowExplicit" field in indicator statements is unsupported; Ignored
xkbcommon: DEBUG: The "allowExplicit" field in indicator statements is unsupported; Ignored
xkbcommon: DEBUG: The "allowExplicit" field in indicator statements is unsupported; Ignored
xkbcommon: DEBUG: The "indicatorDrivesKeyboard" field in indicator statements is unsupported; Ignored
xkbcommon: DEBUG: The "allowExplicit" field in indicator statements is unsupported; Ignored
xkbcommon: DEBUG: Indicator name "Shift Lock" was not declared in the keycodes section; Adding new indicator
xkbcommon: DEBUG: Indicator name "Group 2" was not declared in the keycodes section; Adding new indicator
xkbcommon: DEBUG: Indicator name "Mouse Keys" was not declared in the keycodes section; Adding new indicator
xkbcommon: DEBUG: Compiling xkb_symbols "(unnamed)"
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5089:46: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5091:48: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5093:48: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5097:47: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5099:46: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5107:48: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5111:46: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5113:46: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5117:45: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /usr/share/X11/locale/en_US.UTF-8/Compose:5120:46: this compose sequence is a duplicate of another; skipping line
xkbcommon: WARNING: /home/crater2150/.config/XCompose:2:41: this compose sequence already exists; overriding
xkbcommon: DEBUG: created compose table from locale en_US.UTF-8 with path /home/crater2150/.config/XCompose
keysyms [ 8                ] unicode [ 8 ] layout [ English (US) (0) ] level [ 0 ] mods [ ] leds [ ] 
keysyms [ aring            ] unicode [ å ] layout [ English (US) (0) ] level [ 0 ] mods [ ] leds [ ]

When pressing the compose key, there is no output. The line with keysym 8 appears when pressing * (Shift + 8), while the one with å appears after pressing a twice. There is no output on the first key press.

I ran the program in kitty and in xterm with the same results, if this makes any difference.

bluetech commented 3 years ago

I can't reproduce this, so something must be going on here.

xkbcommon: WARNING: /home/crater2150/.config/XCompose:2:41: this compose sequence already exists; overriding

This looks good.

When pressing the compose key, there is no output.

This too.

The line with keysym 8 appears when pressing * (Shift + 8)

That should not happen.

Which libxkbcommon version is this?

Can you think of anything else unusual?

crater2150 commented 3 years ago

My system uses libxkbcommon 1.3.0 (Void Linux). But I think I may have found the issue, and it probably is indeed my unusual hardware setup. I have a split keyboard, and both halfes are connected via separate USB cables, so they are seen as two separate keyboards. With normal X input, like e.g. Xterm, compose works across those halfs, but it seems with libxkbcommon-based input it doesn't.

My Compose key and a are on the left keyboard, while 8/* is on the right one. I added another entry with <exclam> (left half) instead of <asterisk>, and it works, which confirms my suspicion.

bluetech commented 3 years ago

Huh that's interesting. This is beyond the scope of libxkbcommon itself -- the library user decides how the keyboard devices map to xkb_state and xkb_compose_state objects.

It's interesting that you say that in X the compose state is not per-device but global. I'll need to refresh my memory on how it (X input methods) really works there, and we might amend our recommendations accordingly.

bluetech commented 3 years ago

(I've edited the title to the new question)

fooishbar commented 3 years ago

Most X11 clients will receive a unified stream of key events (as well as unified keymap) through a single master device, usually the Virtual core keyboard. So this might be a GLFW bug for not doing that.

crater2150 commented 3 years ago

So this might be a GLFW bug for not doing that.

The behaviour and output of xkbcli I described above is the same in xterm and in urxvt, AFAIK both of them don't use GLFW.

Another thing, which might be relevant to this issue: modifier keys (Ctrl, Shift, etc.) do work across keyboards without problem.

bluetech commented 3 years ago

@crater2150 Are you using kitty under X or Wayland?

If X, can you show the output of xinput?

If Wayland, which compositor?

And for both, can you show the output of sudo libinput list-devices?

The behaviour and output of xkbcli I described above is the same in xterm and in urxvt, AFAIK both of them don't use GLFW.

That's right, xkbcli interactive-evdev currently creates a compose state per device. This is probably the wrong thing to do.

Another thing, which might be relevant to this issue: modifier keys (Ctrl, Shift, etc.) do work across keyboards without problem.

Hmm I know some compositors like sway have the concept of a "keyboard group" to allow multiple devices to use the same keymap/state/repeat info etc. But I'm not sure how prevalent this is.

crater2150 commented 3 years ago

@bluetech I'm using X. Output of xinput:

⎡ Virtual core pointer                      id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ UGTABLET 13.3 inch PenDisplay Mouse       id=9    [slave  pointer  (2)]
⎜   ↳ ROCCAT ROCCAT Nyth Consumer Control       id=14   [slave  pointer  (2)]
⎜   ↳ ROCCAT ROCCAT Nyth Mouse                  id=16   [slave  pointer  (2)]
⎜   ↳ Valve Software Steam Controller           id=18   [slave  pointer  (2)]
⎣ Virtual core keyboard                     id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Power Button                              id=7    [slave  keyboard (3)]
    ↳ UGTABLET 13.3 inch PenDisplay Keyboard    id=10   [slave  keyboard (3)]
    ↳ UGTABLET 13.3 inch PenDisplay             id=11   [slave  keyboard (3)]
    ↳ bareminimum bareminimum keys              id=12   [slave  keyboard (3)]
    ↳ bareminimum bareminimum keys              id=13   [slave  keyboard (3)]
    ↳ ROCCAT ROCCAT Nyth System Control         id=15   [slave  keyboard (3)]
    ↳ ROCCAT ROCCAT Nyth                        id=17   [slave  keyboard (3)]
    ↳ ROCCAT ROCCAT Nyth Consumer Control       id=19   [slave  keyboard (3)]
    ↳ Valve Software Steam Controller           id=20   [slave  keyboard (3)]

The split keyboard is the bareminimum bareminimum keys, id 12 and 13.

Output of sudo libinput list-devices for relevant devices (full output. Group is different for other devices):

Device:           bareminimum bareminimum keys
Kernel:           /dev/input/event6
Group:            4
Seat:             seat0, default
Capabilities:     keyboard 
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      n/a
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   n/a
Rotation:         n/a

Device:           bareminimum bareminimum keys
Kernel:           /dev/input/event7
Group:            4
Seat:             seat0, default
Capabilities:     keyboard 
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      n/a
Nat.scrolling:    n/a
Middle emulation: n/a
Calibration:      n/a
Scroll methods:   none
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   n/a
Rotation:         n/a
whot commented 3 years ago

That's right, xkbcli interactive-evdev currently creates a compose state per device. This is probably the wrong thing to do.

unless you want to have to deal with seats and device groups etc. I'd argue it's the best thing to do for a debugging tool.

Hmm I know some compositors like sway have the concept of a "keyboard group" to allow multiple devices to use the same keymap/state/repeat info etc. But I'm not sure how prevalent this is

From the libinput side which all compositors use: libinput_event_keyboard_get_seat_key_count() returns the number of times the given key is down for all devices attached to the seat. So two keyboards on the same seat (e.g. laptop + USB), you press space on both, you get a count of 1, then 2 for the events. Compositors usually only toggle actions on the transition between 0 and 1, all other events have no effect on state.

It's interesting that you say that in X the compose state is not per-device but global.

X didn't have a per device-state until XI came along and that wasn't used for keyboards until XI2. Anything handling XI2 would probably handle compose per master device but since there's only one in 99.99% of all case, it's effectively a single global state :)