Combining Accents do not work with KeyboardEvent on Linux
Categories
(Core :: DOM: Events, defect, P5)
Tracking
()
People
(Reporter: mozilla, Unassigned)
References
()
Details
(Keywords: testcase)
Comment 1•8 years ago
|
||
Comment 3•8 years ago
|
||
Comment 4•8 years ago
|
||
Updated•6 years ago
|
Comment 5•4 years ago
|
||
Is anyone looking at all at this? Is it something that has been discussed in whatwg? I would guess this needs some standardisation.
In an effort to get some collaboration I've also informed the other parties of this deficiency:
https://bugs.chromium.org/p/chromium/issues/detail?id=1135952
https://github.com/whatwg/dom/issues/900
Comment 6•4 years ago
|
||
This bug is also affecting text input in WASM-based games and other app which, for portability reasons, do not use DOM but implement their own UI, typically on top of WebGL.
Comment 7•4 years ago
|
||
Regarding the links above, I think that there are two different issues:
- One is that the keypress event does not contain the accentuated composed character, Firefox on Linux has this problem but not on Windows and Chrome works everywhere.
- The other is that when a dead key is sent, the associated character is not mentioned, that is the issue linked above that seems to affect everyone.
Comment 8•3 years ago
|
||
In my environment (Ubuntu 21.04), dead keys are handled as composition of IME. So no keypress event is fired. Which environment can reproduce this?
Comment 9•3 years ago
|
||
Composition events don't seem to solve this unfortunately. From the whatwg issue:
The standard currently refers to using composition events, but they are not a replacement as they only give you the current composed state, not the symbol that was just included to update the state.
Composition events also only work on input fields, not other keyboard event targets such as a canvas. So even if they did contain the proper information, they would still not be a valid replacement.
I'm not sure why you aren't seeing keypress events though. Are you using a more "full" IME, e.g. for Japanese? I've been testing with no IME (on Linux) and any western layout with dead keys (e.g. US International or Swedish).
Comment 10•3 years ago
|
||
Ah, is this a case when no editor has focus? If so, I reproduce the symptom.
And the KeyboardEvent.key
values are set as you expected only when IME works. Otherwise, the dead key state is not managed by Linux (meaning GTK nor X). Therefore, only the raw characters are exposed to the web when you type base character (a
, e
, etc). Additionally, there is no way to get composed character at least via GDK. Therefore, it seems that it's impossible to expose composed character via KeyboardEvent.key
with dead keys.
Comment 11•3 years ago
|
||
I don't suppose you can get the raw X event somewhere? What we (noVNC) would ideally like is something like XK_dead_acute
to "DeadAcute"
or similar. I'm afraid I'm not too familiar with GDK's event handling.
And base X11, without any IME, has some basic IME-like behaviour for the dead keys. It hides the real event using XFilterEvent()
and then injects a fake new event with the raw keysym swapped out for the combined on (and also a keycode of 0
). E.g.:
KeyPress event, serial 37, synthetic NO, window 0x3200001,
root 0x754, subw 0x0, time 1206484575, (408,-145), root:(1514,153),
state 0x10, keycode 21 (keysym 0xfe51, dead_acute), same_screen YES,
XLookupString gives 2 bytes: (c2 b4) "´"
XmbLookupString gives 0 bytes:
XFilterEvent returns: True
KeyRelease event, serial 37, synthetic NO, window 0x3200001,
root 0x754, subw 0x0, time 1206484647, (408,-145), root:(1514,153),
state 0x10, keycode 21 (keysym 0xfe51, dead_acute), same_screen YES,
XLookupString gives 2 bytes: (c2 b4) "´"
XFilterEvent returns: False
KeyPress event, serial 37, synthetic NO, window 0x3200001,
root 0x754, subw 0x0, time 1206485039, (408,-145), root:(1514,153),
state 0x10, keycode 38 (keysym 0x61, a), same_screen YES,
XLookupString gives 1 bytes: (61) "a"
XmbLookupString gives 1 bytes: (61) "a"
XFilterEvent returns: True
KeyPress event, serial 37, synthetic NO, window 0x3200001,
root 0x754, subw 0x0, time 1206485039, (408,-145), root:(1514,153),
state 0x10, keycode 0 (keysym 0xe1, aacute), same_screen YES,
XKeysymToKeycode returns keycode: 38
XLookupString gives 0 bytes:
XmbLookupString gives 2 bytes: (c3 a1) "á"
XFilterEvent returns: False
KeyRelease event, serial 37, synthetic NO, window 0x3200001,
root 0x754, subw 0x0, time 1206485135, (408,-145), root:(1514,153),
state 0x10, keycode 38 (keysym 0x61, a), same_screen YES,
XLookupString gives 1 bytes: (61) "a"
XFilterEvent returns: False
On Windows things get much messier as they don't seem to have a standardised way of doing things. For reference, this is the mess we've had to come up with for TigerVNC:
https://github.com/TigerVNC/tigervnc/blob/468687f5d7f036b3e78e767b32d3b9b14a4b3b17/vncviewer/win32.c#L349
https://github.com/TigerVNC/tigervnc/blob/468687f5d7f036b3e78e767b32d3b9b14a4b3b17/vncviewer/keysym2ucs.c#L841
TL;DR; We repeat the dead key until we get a character back from Windows. We then have a lookup table where we can map that key back to the expected Unicode combining character, and then from that to the X11 keysym (that VNC needs).
Comment 12•3 years ago
|
||
I/KeymapWrapperWidgets HandleKeyPressEvent(aWindow=7f4ac1d86800, aGdkKeyEvent={ type=GDK_KEY_PRESS, keyval=dead_grave(0xFE50), state=0x00002010, hardware_keycode=0x00000022, time=4515613, is_modifier=FALSE })
D/KeymapWrapperWidgets 7f4ac1d24a60 InitInputEvent, aModifierState=0x00002010, aInputEvent={ mMessage=eKeyDown, mModifiers=0x0080 (Shift: FALSE, Control: FALSE, Alt: FALSE, Meta: FALSE, OS: FALSE, AltGr: FALSE, CapsLock: FALSE, NumLock: TRUE, ScrollLock: FALSE })
I/KeymapWrapperWidgets 7f4ac1d24a60 InitKeyEvent, modifierState=0x00002010 aKeyEvent={ mMessage=eKeyDown, isShift=FALSE, isControl=FALSE, isAlt=FALSE, isMeta=FALSE , mKeyCode=0x00, mCharCode=NULL (0x0000), mKeyNameIndex=Dead, mKeyValue="", mCodeNameIndex=BracketLeft, mCodeValue="", mLocation=KEY_LOCATION_STANDARD, mIsRepeat=FALSE }
I/KeymapWrapperWidgets HandleKeyPressEvent(), dispatched eKeyDown event and it wasn't consumed
D/KeymapWrapperWidgets 7f4ac1d24a60 InitInputEvent, aModifierState=0x00002010, aInputEvent={ mMessage=eKeyPress, mModifiers=0x0080 (Shift: FALSE, Control: FALSE, Alt: FALSE, Meta: FALSE, OS: FALSE, AltGr: FALSE, CapsLock: FALSE, NumLock: TRUE, ScrollLock: FALSE })
I/KeymapWrapperWidgets 7f4ac1d24a60 InitKeyEvent, modifierState=0x00002010 aKeyEvent={ mMessage=eKeyPress, isShift=FALSE, isControl=FALSE, isAlt=FALSE, isMeta=FALSE , mKeyCode=0x00, mCharCode=NULL (0x0000), mKeyNameIndex=Dead, mKeyValue="", mCodeNameIndex=BracketLeft, mCodeValue="", mLocation=KEY_LOCATION_STANDARD, mIsRepeat=FALSE }
I/KeymapWrapperWidgets HandleKeyPressEvent(), didn't dispatch eKeyPress event (status=nsEventStatus_eIgnore)
<snip>
I/KeymapWrapperWidgets FilterEvents(aXEvent={ type=KeyPress, xkey={ keycode=0x00000026, state=0x00002010, time=4518957 } }, aGdkEvent={ state=0x00000000 }), detected first keypress
I/KeymapWrapperWidgets HandleKeyPressEvent(aWindow=7f4ac1d86800, aGdkKeyEvent={ type=GDK_KEY_PRESS, keyval=a(0x61), state=0x00002010, hardware_keycode=0x00000026, time=4518957, is_modifier=FALSE })
D/KeymapWrapperWidgets 7f4ac1d24a60 InitInputEvent, aModifierState=0x00002010, aInputEvent={ mMessage=eKeyDown, mModifiers=0x0080 (Shift: FALSE, Control: FALSE, Alt: FALSE, Meta: FALSE, OS: FALSE, AltGr: FALSE, CapsLock: FALSE, NumLock: TRUE, ScrollLock: FALSE })
I/KeymapWrapperWidgets 7f4ac1d24a60 InitKeyEvent, modifierState=0x00002010 aKeyEvent={ mMessage=eKeyDown, isShift=FALSE, isControl=FALSE, isAlt=FALSE, isMeta=FALSE , mKeyCode=0x41, mCharCode=NULL (0x0000), mKeyNameIndex=USE_STRING, mKeyValue="'a' (0x0061)", mCodeNameIndex=KeyA, mCodeValue="", mLocation=KEY_LOCATION_STANDARD, mIsRepeat=FALSE }
I/KeymapWrapperWidgets HandleKeyPressEvent(), dispatched eKeyDown event and it wasn't consumed
D/KeymapWrapperWidgets 7f4ac1d24a60 InitInputEvent, aModifierState=0x00002010, aInputEvent={ mMessage=eKeyPress, mModifiers=0x0080 (Shift: FALSE, Control: FALSE, Alt: FALSE, Meta: FALSE, OS: FALSE, AltGr: FALSE, CapsLock: FALSE, NumLock: TRUE, ScrollLock: FALSE })
I/KeymapWrapperWidgets 7f4ac1d24a60 InitKeyEvent, modifierState=0x00002010 aKeyEvent={ mMessage=eKeyPress, isShift=FALSE, isControl=FALSE, isAlt=FALSE, isMeta=FALSE , mKeyCode=0x00, mCharCode=NULL (0x0000), mKeyNameIndex=USE_STRING, mKeyValue="'a' (0x0061)", mCodeNameIndex=KeyA, mCodeValue="", mLocation=KEY_LOCATION_STANDARD, mIsRepeat=FALSE }
I/KeymapWrapperWidgets HandleKeyPressEvent(), dispatched eKeyPress event (status=nsEventStatus_eIgnore)
Unfortunately, there is no last KeyPress
event of your log in GDK level...
Comment 13•3 years ago
|
||
I think we might be misunderstanding each other here, since that looks like precisely what we want. :)
I/KeymapWrapperWidgets HandleKeyPressEvent(aWindow=7f4ac1d86800, aGdkKeyEvent={ type=GDK_KEY_PRESS, keyval=dead_grave(0xFE50), state=0x00002010, hardware_keycode=0x00000022, time=4515613, is_modifier=FALSE })
I'd like the keyval
and hardware_keycode
values here exposed in JavaScript.
I/KeymapWrapperWidgets 7f4ac1d24a60 InitKeyEvent, modifierState=0x00002010 aKeyEvent={ mMessage=eKeyDown, isShift=FALSE, isControl=FALSE, isAlt=FALSE, isMeta=FALSE , mKeyCode=0x00, mCharCode=NULL (0x0000), mKeyNameIndex=Dead, mKeyValue="", mCodeNameIndex=BracketLeft, mCodeValue="", mLocation=KEY_LOCATION_STANDARD, mIsRepeat=FALSE }
The problem is that keyval
gets translated to the ambiguous "Dead"
here.
I/KeymapWrapperWidgets HandleKeyPressEvent(aWindow=7f4ac1d86800, aGdkKeyEvent={ type=GDK_KEY_PRESS, keyval=a(0x61), state=0x00002010, hardware_keycode=0x00000026, time=4518957, is_modifier=FALSE })
Same thing here. I'd like keyval
and hardware_keycode
values to propagate to JavaScript since this event contains the uncomposed "a"
rather than the composed "á"
.
The strange thing about your log is that the composed event is missing. So I wonder if we are looking at the right thing...
Can I enable that debug output easily and try here?
Updated•2 years ago
|
Description
•