Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to write accented characters using Spanish keyboard with HTML5 client #1

Closed
totaam opened this issue Jan 18, 2021 · 8 comments
Closed

Comments

@totaam
Copy link
Collaborator

totaam commented Jan 18, 2021

Issue migrated from trac ticket # 3005

component: html5 | priority: major

2021-01-18 09:47:10: alv982 created the issue


Hi,

The problem is that it's impossible to write any accented character (á, é, etc) using the HTML5 client. Using the desktop client works fine.

I'm using Chrome on Windows to connect to an Ubuntu server using the last beta version xpra v4.1-r28309, but the problem also reproduces using the last stable version and using Firefox. I'm using a Spanish keyboard (as reference, this is the layout: https://commons.wikimedia.org/wiki/File:KB_Spanish.svg).

The procedure to write for example á is to press [[']] and then [a]. The first key is the key to the right to [ñ] in the keyboard.

At the beggining the HTML5 client doesn't send the accent key code and writes an apostrophe, so looking at other issues I added CHARCODE_TO_NAME[222] = "dead_acute" in Keycodes.js.

Then it recognizes the ['] key, but it doesn't write the á character. To write it, I have to press ['] [any other key] [a]. Pressing ['] [a] doesn't generate any output.

This is the output when pressing ['] [a] (no character is written).

2021-01-18 10:23:38,051 client   1 keyboard last keycode pressed= 0 , keycode= 222 , pressed= true , str= Dead
2021-01-18 10:23:38,052 client   1 keyboard processKeyEvent( true ,  [object KeyboardEvent] ) key= Quote keycode= 222
2021-01-18 10:23:38,052 client   1 keyboard _get_keyboard_layout() keyboard_layout= es
2021-01-18 10:23:38,053 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:23:38,053 do_get_keycode(222, 'dead_acute', True, [], 222, 'dead', 0)=48 (level=0, shift=False, mode=0, keysyms=['dead_acute', 'dead_diaeresis', 'braceleft', 'braceleft'])
2021-01-18 10:23:38,053 process_key_action([b'key-action', 1, b'dead_acute', True, (), 222, b'dead', 222, 0]) server keycode=48, group=0
2021-01-18 10:23:38,054 set_keyboard_layout_group(0) ignored, no layout groups support
2021-01-18 10:23:38,054 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:23:38,055 filtered_modifiers_set([])=set()
2021-01-18 10:23:38,055 filtered_modifiers_set([])=set()
2021-01-18 10:23:38,055 is_modifier(48) not found
2021-01-18 10:23:38,056 handle_key((1, True, 'dead_acute', 222, 48, [], False, True))
2021-01-18 10:23:38,056 handle keycode pressing    48: key 'dead_acute'
2021-01-18 10:23:38,056 fake_key(48, True)
2021-01-18 10:23:38,080 client   1 keyboard last keycode pressed= 222 , keycode= 222 , pressed= false , str= Dead
2021-01-18 10:23:38,080 client   1 keyboard processKeyEvent( false ,  [object KeyboardEvent] ) key= Quote keycode= 222
2021-01-18 10:23:38,081 process_key_action([b'key-action', 1, b'dead_acute', False, (), 222, b'dead', 222, 0]) server keycode=48, group=0
2021-01-18 10:23:38,082 set_keyboard_layout_group(0) ignored, no layout groups support
2021-01-18 10:23:38,082 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:23:38,083 filtered_modifiers_set([])=set()
2021-01-18 10:23:38,083 filtered_modifiers_set([])=set()
2021-01-18 10:23:38,084 is_modifier(48) not found
2021-01-18 10:23:38,084 handle_key((1, False, 'dead_acute', 222, 48, [], False, True))
2021-01-18 10:23:38,084 handle keycode unpressing  48: key 'dead_acute'
2021-01-18 10:23:38,084 fake_key(48, False)
2021-01-18 10:23:39,890 client   1 keyboard last keycode pressed= 0 , keycode= 65 , pressed= true , str= ??
2021-01-18 10:23:39,890 client   1 keyboard processKeyEvent( true ,  [object KeyboardEvent] ) key= KeyA keycode= 65
2021-01-18 10:23:39,891 client   1 keyboard _get_keyboard_layout() keyboard_layout= es
2021-01-18 10:23:39,892 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:23:39,892 do_get_keycode(65, 'aacute', True, [], 65, '?', 0)=-1, 0 (keyname translation)
2021-01-18 10:23:39,892 process_key_action([b'key-action', 1, b'aacute', True, (), 65, b'\xc3\xa1', 65, 0]) server keycode=-1, group=0
2021-01-18 10:23:39,893 client   1 keyboard last keycode pressed= 65 , keycode= 65 , pressed= false , str= a
2021-01-18 10:23:39,893 filtered_modifiers_set([])=set()
2021-01-18 10:23:39,894 client   1 keyboard processKeyEvent( false ,  [object KeyboardEvent] ) key= KeyA keycode= 65
2021-01-18 10:23:39,894 filtered_modifiers_set([])=set()
2021-01-18 10:23:39,895 process_key_action([b'key-action', 1, b'a', False, (), 65, b'a', 65, 0]) server keycode=-1, group=0

This is the output when I type ['][e][a] (á is written)

2021-01-18 10:26:00,471 client   1 keyboard last keycode pressed= 0 , keycode= 222 , pressed= true , str= Dead
2021-01-18 10:26:00,471 client   1 keyboard processKeyEvent( true ,  [object KeyboardEvent] ) key= Quote keycode= 222
2021-01-18 10:26:00,472 client   1 keyboard _get_keyboard_layout() keyboard_layout= es
2021-01-18 10:26:00,481 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:26:00,482 do_get_keycode(222, 'dead_acute', True, [], 222, 'dead', 0)=48 (level=0, shift=False, mode=0, keysyms=['dead_acute', 'dead_diaeresis', 'braceleft', 'braceleft'])
2021-01-18 10:26:00,482 process_key_action([b'key-action', 1, b'dead_acute', True, (), 222, b'dead', 222, 0]) server keycode=48, group=0
2021-01-18 10:26:00,482 set_keyboard_layout_group(0) ignored, no layout groups support
2021-01-18 10:26:00,482 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:26:00,483 filtered_modifiers_set([])=set()
2021-01-18 10:26:00,483 filtered_modifiers_set([])=set()
2021-01-18 10:26:00,484 is_modifier(48) not found
2021-01-18 10:26:00,484 handle_key((1, True, 'dead_acute', 222, 48, [], False, True))
2021-01-18 10:26:00,484 handle keycode pressing    48: key 'dead_acute'
2021-01-18 10:26:00,484 fake_key(48, True)
2021-01-18 10:26:00,541 client   1 keyboard last keycode pressed= 222 , keycode= 222 , pressed= false , str= Dead
2021-01-18 10:26:00,541 client   1 keyboard processKeyEvent( false ,  [object KeyboardEvent] ) key= Quote keycode= 222
2021-01-18 10:26:00,543 process_key_action([b'key-action', 1, b'dead_acute', False, (), 222, b'dead', 222, 0]) server keycode=48, group=0
2021-01-18 10:26:00,543 set_keyboard_layout_group(0) ignored, no layout groups support
2021-01-18 10:26:00,543 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:26:00,544 filtered_modifiers_set([])=set()
2021-01-18 10:26:00,544 filtered_modifiers_set([])=set()
2021-01-18 10:26:00,545 is_modifier(48) not found
2021-01-18 10:26:00,545 handle_key((1, False, 'dead_acute', 222, 48, [], False, True))
2021-01-18 10:26:00,545 handle keycode unpressing  48: key 'dead_acute'
2021-01-18 10:26:00,545 fake_key(48, False)
2021-01-18 10:26:02,319 client   1 keyboard last keycode pressed= 0 , keycode= 69 , pressed= true , str= ??
2021-01-18 10:26:02,320 client   1 keyboard processKeyEvent( true ,  [object KeyboardEvent] ) key= KeyE keycode= 69
2021-01-18 10:26:02,320 client   1 keyboard _get_keyboard_layout() keyboard_layout= es
2021-01-18 10:26:02,321 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:26:02,321 do_get_keycode(69, 'eacute', True, [], 69, '?', 0)=-1, 0 (keyname translation)
2021-01-18 10:26:02,321 process_key_action([b'key-action', 1, b'eacute', True, (), 69, b'\xc3\xa9', 69, 0]) server keycode=-1, group=0
2021-01-18 10:26:02,322 filtered_modifiers_set([])=set()
2021-01-18 10:26:02,322 filtered_modifiers_set([])=set()
2021-01-18 10:26:02,384 client   1 keyboard last keycode pressed= 69 , keycode= 69 , pressed= false , str= e
2021-01-18 10:26:02,384 client   1 keyboard processKeyEvent( false ,  [object KeyboardEvent] ) key= KeyE keycode= 69
2021-01-18 10:26:02,386 process_key_action([b'key-action', 1, b'e', False, (), 69, b'e', 69, 0]) server keycode=-1, group=0
2021-01-18 10:26:02,386 filtered_modifiers_set([])=set()
2021-01-18 10:26:02,387 filtered_modifiers_set([])=set()
2021-01-18 10:26:04,033 client   1 keyboard last keycode pressed= 0 , keycode= 65 , pressed= true , str= a
2021-01-18 10:26:04,035 client   1 keyboard processKeyEvent( true ,  [object KeyboardEvent] ) key= KeyA keycode= 65
2021-01-18 10:26:04,035 client   1 keyboard _get_keyboard_layout() keyboard_layout= es
2021-01-18 10:26:04,036 client   1 keyboard last keycode pressed= 65 , keycode= 65 , pressed= false , str= a
2021-01-18 10:26:04,036 client   1 keyboard processKeyEvent( false ,  [object KeyboardEvent] ) key= KeyA keycode= 65
2021-01-18 10:26:04,036 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:26:04,037 do_get_keycode(65, 'a', True, [], 65, 'a', 0)=38 (level=0, shift=False, mode=0, keysyms=['a', 'A', 'ae', 'AE'])
2021-01-18 10:26:04,037 process_key_action([b'key-action', 1, b'a', True, (), 65, b'a', 65, 0]) server keycode=38, group=0
2021-01-18 10:26:04,037 set_keyboard_layout_group(0) ignored, no layout groups support
2021-01-18 10:26:04,037 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:26:04,038 filtered_modifiers_set([])=set()
2021-01-18 10:26:04,038 filtered_modifiers_set([])=set()
2021-01-18 10:26:04,039 is_modifier(38) not found
2021-01-18 10:26:04,039 handle_key((1, True, 'a', 65, 38, [], False, True))
2021-01-18 10:26:04,039 handle keycode pressing    38: key 'a'
2021-01-18 10:26:04,039 fake_key(38, True)
2021-01-18 10:26:04,040 process_key_action([b'key-action', 1, b'a', False, (), 65, b'a', 65, 0]) server keycode=38, group=0
2021-01-18 10:26:04,040 set_keyboard_layout_group(0) ignored, no layout groups support
2021-01-18 10:26:04,041 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:26:04,041 filtered_modifiers_set([])=set()
2021-01-18 10:26:04,042 filtered_modifiers_set([])=set()
2021-01-18 10:26:04,042 is_modifier(38) not found
2021-01-18 10:26:04,042 handle_key((1, False, 'a', 65, 38, [], False, True))
2021-01-18 10:26:04,043 handle keycode unpressing  38: key 'a'
2021-01-18 10:26:04,043 fake_key(38, False)

This is the output using the desktop client (works fine, writes á):

2021-01-18 10:41:56,326 client   1 @30.809 mask_to_names(<flags 0 of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=[]
2021-01-18 10:41:56,346 client   1 @30.811 parse_key_event(<Gdk.EventKey object at 0x000000005b3d0680 (void at 0x0000000047eb20b0)>, True)=<GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'dead_acute', 'keyval': 65105, 'keycode': 222, 'group': 0, 'string': '', 'pressed': True}>
2021-01-18 10:41:56,347 client   1 @30.811 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'dead_acute', 'keyval': 65105, 'keycode': 222, 'group': 0, 'string': '', 'pressed': True}>) wid=1
2021-01-18 10:41:56,347 client   1 @30.813 key_handled_as_shortcut(ClientWindow(1), 'dead_acute', [], True) shortcuts=None
2021-01-18 10:41:56,348 client   1 @30.814 send_delayed_key() delayed_event=None
2021-01-18 10:41:56,348 client   1 @30.814 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'dead_acute', 'keyval': 65105, 'keycode': 222, 'group': 0, 'string': '', 'pressed': True}>)
2021-01-18 10:41:56,349 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:41:56,349 do_get_keycode(222, 'dead_acute', True, [], 65105, '', 0)=48 (level=0, shift=False, mode=0, keysyms=['dead_acute', 'dead_diaeresis', 'braceleft', 'braceleft'])
2021-01-18 10:41:56,350 process_key_action(['key-action', 1, b'dead_acute', True, (), 65105, b'', 222, 0]) server keycode=48, group=0
2021-01-18 10:41:56,350 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:41:56,351 filtered_modifiers_set([])=set()
2021-01-18 10:41:56,351 filtered_modifiers_set([])=set()
2021-01-18 10:41:56,351 is_modifier(48) not found
2021-01-18 10:41:56,352 handle_key((1, True, 'dead_acute', 65105, 48, [], False, True))
2021-01-18 10:41:56,352 handle keycode pressing    48: key 'dead_acute'
2021-01-18 10:41:56,352 fake_key(48, True)
2021-01-18 10:41:56,353 scheduling key repeat timer with delay 500 for dead_acute / 48
2021-01-18 10:41:56,389 client   1 @30.872 mask_to_names(<flags 0 of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=[]
2021-01-18 10:41:56,390 client   1 @30.873 parse_key_event(<Gdk.EventKey object at 0x000000005b3d0680 (void at 0x0000000047a9df20)>, False)=<GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'dead_acute', 'keyval': 65105, 'keycode': 222, 'group': 0, 'string': '', 'pressed': False}>
2021-01-18 10:41:56,395 client   1 @30.874 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'dead_acute', 'keyval': 65105, 'keycode': 222, 'group': 0, 'string': '', 'pressed': False}>) wid=1
2021-01-18 10:41:56,395 client   1 @30.875 key_handled_as_shortcut(ClientWindow(1), 'dead_acute', [], False) shortcuts=None
2021-01-18 10:41:56,396 client   1 @30.876 send_delayed_key() delayed_event=None
2021-01-18 10:41:56,396 client   1 @30.876 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'dead_acute', 'keyval': 65105, 'keycode': 222, 'group': 0, 'string': '', 'pressed': False}>)
2021-01-18 10:41:56,397 process_key_action(['key-action', 1, b'dead_acute', False, (), 65105, b'', 222, 0]) server keycode=48, group=0
2021-01-18 10:41:56,397 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:41:56,397 filtered_modifiers_set([])=set()
2021-01-18 10:41:56,398 filtered_modifiers_set([])=set()
2021-01-18 10:41:56,398 is_modifier(48) not found
2021-01-18 10:41:56,398 handle_key((1, False, 'dead_acute', 65105, 48, [], False, True))
2021-01-18 10:41:56,399 handle keycode unpressing  48: key 'dead_acute'
2021-01-18 10:41:56,399 fake_key(48, False)
2021-01-18 10:41:56,762 client   1 @31.102 mask_to_names(<flags 0 of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=[]
2021-01-18 10:41:56,764 filtered_modifiers_set([])=set()
2021-01-18 10:41:56,765 filtered_modifiers_set([])=set()
2021-01-18 10:41:57,047 client   1 @31.533 mask_to_names(<flags 0 of type Gdk.ModifierType>) GetKeyState(VK_NUMLOCK)=0, names=[]
2021-01-18 10:41:57,048 client   1 @31.533 parse_key_event(<Gdk.EventKey object at 0x000000005b3d07c0 (void at 0x0000000047a9ddc0)>, True)=<GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'a', 'keyval': 97, 'keycode': 65, 'group': 0, 'string': 'a', 'pressed': True}>
2021-01-18 10:41:57,075 client   1 @31.533 handle_key_action(ClientWindow(1), <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'a', 'keyval': 97, 'keycode': 65, 'group': 0, 'string': 'a', 'pressed': True}>) wid=1
2021-01-18 10:41:57,075 client   1 @31.534 key_handled_as_shortcut(ClientWindow(1), 'a', [], True) shortcuts=None
2021-01-18 10:41:57,076 client   1 @31.534 send_delayed_key() delayed_event=None
2021-01-18 10:41:57,076 client   1 @31.534 send_key_action(1, <GTKKeyEvent object, contents: {'modifiers': [], 'keyname': 'a', 'keyval': 97, 'keycode': 65, 'group': 0, 'string': 'a', 'pressed': True}>)
2021-01-18 10:41:57,077 will try levels: [0, 4, 1, 5, 2, 6, 3, 7]
2021-01-18 10:41:57,077 do_get_keycode(65, 'a', True, [], 97, 'a', 0)=38 (level=0, shift=False, mode=0, keysyms=['a', 'A', 'ae', 'AE'])
2021-01-18 10:41:57,077 process_key_action(['key-action', 1, b'a', True, (), 97, b'a', 65, 0]) server keycode=38, group=0
2021-01-18 10:41:57,077 set_keyboard_layout_group(0) ignored, value unchanged
2021-01-18 10:41:57,078 filtered_modifiers_set([])=set()
2021-01-18 10:41:57,078 filtered_modifiers_set([])=set()
2021-01-18 10:41:57,079 is_modifier(38) not found
2021-01-18 10:41:57,079 handle_key((1, True, 'a', 97, 38, [], False, True))
2021-01-18 10:41:57,079 handle keycode pressing    38: key 'a'
2021-01-18 10:41:57,079 fake_key(38, True)
2021-01-18 10:41:57,080 scheduling key repeat timer with delay 500 for a / 38

The bug is also present with --no-keyboard-sync. I have attached also setxkbmap info for the server.

If there is anything else I can provide, please let me know.

Regards.

@totaam
Copy link
Collaborator Author

totaam commented Jan 18, 2021

2021-01-18 09:51:37: alv982 commented


Sorry, the formatting deleted a key, it should read: The procedure to write for example á is to press ['] and then [a].

@totaam
Copy link
Collaborator Author

totaam commented Jan 18, 2021

I think that the correct way to fix this is to send a not aacute, because the server can't find aacute in the keymap:

process_key_action([b'key-action', 1, b'aacute', True, (), 65, b'\xc3\xa1', 65, 0]) server keycode=-1, group=0

We do know it is an a:

client   1 keyboard last keycode pressed= 65 , keycode= 65 , pressed= false , str= a

So then the server will find the keycode and things should just work.

Should this be done for all instances of aacute or just when preceded by a dead key? Is this going to work the same in all browsers? (from past experience, that's unlikely..)
I don't know yet the answer to these questions.

@totaam
Copy link
Collaborator Author

totaam commented Jan 18, 2021

2021-01-18 17:53:29: alv982 commented


In theory, I think I should be done for all the instances of aacute, as it's impossible to write "á" without pressing "'" (right to "Ñ") before. This key is only used to compose accented characters (like á é í, etc).

There is another "'" key right to the "0" in the keyboard image, that writes an apostrophe, and can't be used to compose accented characters. This key has code 219 instead 222 of the "'" to compose accented characters.

@totaam
Copy link
Collaborator Author

totaam commented Jan 18, 2021

2021-01-18 20:40:04: alv982 commented


Based on your comment, I have tried changing Keycodes.js, from aacute: 225 to aacute: 65, and added HARCODE_TO_NAME[222] = "dead_acute", and it seems to work fine both in Firefox and Chrome under Windows, and Chrome under Ubuntu (doesn't work in Firefox under Ubuntu, neither with the original file).

@totaam totaam transferred this issue from Xpra-org/xpra Jan 22, 2021
@danisla
Copy link
Contributor

danisla commented Nov 8, 2021

@totaam Any update on this? Would be great to see Spanish keyboard support.

@totaam
Copy link
Collaborator Author

totaam commented Nov 9, 2021

Sorry, I don't have time to work on this right now, perhaps #142 would help?

@totaam
Copy link
Collaborator Author

totaam commented May 10, 2022

I assume that your keyboard layout is something similar to this one:
spanish

From your log, the problematic key event is this one:

process_key_action([b'key-action', 1, b'aacute', True, (), 65, b'\xc3\xa1', 65, 0]) server keycode=-1, group=0

Note that this log event uses an outdated version of xpra. The key string is actually:

b'\xc3\xa1'.decode("utf8")
'á'

With chrome and an es client layout, I get:

process_key_action(['key-action', 1, 'apostrophe', True, ('mod2',), 222, 'dead', 222, 0]) server keycode=20, group=0
process_key_action(['key-action', 1, 'a', True, ('mod2',), 65, 'a', 65, 0]) server keycode=38, group=0
process_key_action(['key-action', 1, 'a', False, ('mod2',), 65, 'a', 65, 0]) server keycode=38, group=0

And the apostrophe is never unpressed...
The other accent character is backtick:

process_key_action(['key-action', 1, 'backtick', True, ('mod2',), 219, 'dead', 219, 0]) server keycode=-1, group=0

I don't think I can fix this properly since the native client doesn't work either!
I also get plain as there.

Looking at xev, there is a single KeyPress, without a corresponding KeyRelease that triggers the correct key:

KeyPress event, serial 57, synthetic NO, window 0x5600001,
    root 0x1ea, subw 0x0, time 127974803, (403,545), root:(4283,675),
    state 0x0, keycode 0 (keysym 0xe0, agrave), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 2 bytes: (c3 a0) "à"
    XFilterEvent returns: False

Surrounded by the KeyPress / KeyRelease for a.

totaam added a commit that referenced this issue May 10, 2022
key-press + key-release
totaam added a commit that referenced this issue May 11, 2022
@totaam
Copy link
Collaborator Author

totaam commented May 11, 2022

The commits above work, most of the time...
I get à and á, unless I type really quick then I occasionally get separate characters instead.

We should probably add more dead keys to

DEAD_KEYS = {
"`" : "dead_grave",
"'" : "dead_acute",
};

@danisla does that work for you?

@totaam totaam closed this as completed Aug 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants