Xpra: Ticket #2154: Keyboard mapping issues in HTML5 client

I know that there is a long guide how to report keyboard layout mapping problems, but I think here the issue is clearly in the HTML5 JS code.

Most of the users to whom I tried to provide remote access through a browser report that input is not working even with the en_US layout. It is only possible to input numbers into xterm. Other keys cause beeps and either spaces or numbers are typed instead of, e.g., letters.

For me, en_US layout is working at the beginning. Switching to Russian layout breaks everything and switching back to en_US does not help. Here are logs from the JS console (Browser version: Firefox 65.0 (64-bit). OS: Ubuntu 18.04, LANG=en_US.UTF-8. Xpra 2.4.2 is running inside a CentOS 7 Docker container).

debug enabled for:
Array []
1:438:5
connection_progress( Initializing ,   ,  20 ) 1:399:6
connection_progress( Connecting to server ,  localhost:8888/display/1/ ,  40 ) 1:399:6
we have webworker support Client.js:320:3
we can use websocket in webworker Client.js:329:5
connection_progress( Opening WebSocket connection ,  ws://localhost:8888/display/1/ ,  60 ) Client.js:228:2
connection_progress( WebSocket connection established ,   ,  80 ) Client.js:228:2
sending hello Client.js:942:3
return all encodings:
Array(6) [ "jpeg", "png", "rgb", "rgb32", "h264", "mpeg1" ]
Client.js:865:3
return all encodings:
Array(6) [ "jpeg", "png", "rgb", "rgb32", "h264", "mpeg1" ]
Client.js:865:3
getFirstBrowserLanguage()= en-US Utilities.js:135:3
getKeyboardLayout()= us Utilities.js:150:3
hello capabilities: [object Object] Client.js:956:2
got hello: server version 2.4.2 accepted our connection Client.js:228:2
server screen sizes:
Array(1571) [ (2) […], (2) […], (2) […], (2) […], (2) […], (2) […], (2) […], (2) […], (2) […], (2) […], … ]
Client.js:1648:5
connection_progress( Session started ,   ,  100 ) Client.js:228:2
startup complete Client.js:228:2
connection-established Client.js:228:2
server connection is OK Client.js:890:4

Now, if I type something into xterm having en_US layout active, everything works fine. If I try to switch the layout to Russian, I get the following in the JS console

input language changed from null to ru Client.js:595:3

I don't see symbols in xterm, only spaces, but I think this is fonts-related issue.

Then, if I switch back to en_US layout and try to type something, I see nothing in the JS console about input language change. And typing causes beeps.



Mon, 18 Feb 2019 13:33:30 GMT - Antoine Martin: owner changed

Most of the users to whom I tried to provide remote access through a browser report that input is not working even with the en_US layout

How do they en_US?

Switching to Russian layout breaks everything and switching back to en_US does not help

How do you switch?

Then, if I switch back to en_US layout and try to type something, I see nothing in the JS console about input language change. And typing causes beeps.

How to you switch back?

It would help to have the server log, with or without -d keyboard.


Mon, 18 Feb 2019 14:09:45 GMT - berserker: attachment set


Mon, 18 Feb 2019 14:29:05 GMT - berserker: attachment set


Mon, 18 Feb 2019 14:34:25 GMT - berserker:

Replying to Antoine Martin:

Most of the users to whom I tried to provide remote access through a browser report that input is not working even with the en_US layout

How do they en_US?

Lets forget about other users for now.

Switching to Russian layout breaks everything and switching back to en_US does not help

How do you switch?

Using CapsLock while having browser tab with HTML5 client active.

Then, if I switch back to en_US layout and try to type something, I see nothing in the JS console about input language change. And typing causes beeps.

How to you switch back?

The same way.

It would help to have the server log, with or without -d keyboard.

I've attached the log xpra-noasciivt.log with keyboard debugging ON. Plz ignore and delete the other attachment. At first, I typed ls into xterm and hit Enter. Then I switched the layout using CapsLock, typed фыва and pushed Enter again. Then I switched back to en_US and tried to type ls. Even though there are l and s keys logged, what I got in xterm was ~4


Fri, 08 Mar 2019 23:29:50 GMT - berserker: attachment set


Fri, 08 Mar 2019 23:39:24 GMT - berserker: owner, priority, milestone changed

Hi. I've attached a log with xev running instead of xterm to see what X11 applications receive when I type. As can be seen, after switching layout to ru and back to en, xev starting to get F10 when I press l and 4 when s.

Do you have any ideas? Need other logs?


Thu, 14 Mar 2019 13:01:25 GMT - Antoine Martin: owner, priority, status, milestone changed

Do you have any ideas? Need other logs?

I don't really know how to re-create this setup, having more information as per wiki/Keyboard would help.

Too late for 2.5, re-scheduling.


Sat, 08 Jun 2019 16:07:24 GMT - berserker: priority, version changed

Replying to Antoine Martin:

Do you have any ideas? Need other logs?

I don't really know how to re-create this setup, having more information as per wiki/Keyboard would help.

It could be easily seen that the JS logics is flawed, without me going through that giant list of tasks you require to report bugs.

Let's take a look at Client.js:XpraClient.prototype._keyb_process

	var key_language = null;
// ...
	//next try mapping the actual character
	else if (str in CHAR_TO_NAME) {
		keyname = CHAR_TO_NAME[str];
		if (keyname.includes("_")) {
			//ie: Thai_dochada
			var lang = keyname.split("_")[0];
			key_language = KEYSYM_TO_LAYOUT[lang];
		}
	}
// ...
	this._check_browser_language(key_language);

where Client.js:XpraClient.prototype._check_browser_language(key_layout) contains

	var new_layout = null;
	if (key_layout && this.key_layout!=key_layout) {
		this.clog("input language changed from", this.key_layout, "to", key_layout);
		new_layout = key_layout;
		this.key_layout = key_layout;
	}
// ...
	if (new_layout!=null) {
		this.send(["layout-changed", new_layout, ""]);

When I press д, keyname = CHAR_TO_NAME[str] (== Cyrillic_de) includes "_", key_language (through KEYSYM_TO_LAYOUT) is mapped to ru, _check_browser_language, being invoked with key_layout == "ru", sends a notification about layout change to the server, the server changes layout from us (initial layout, because browser language is en_US) to ru. When I press l, keyname = CHAR_TO_NAME[str] (== l) does not include "_" and key_language remains null, which is passed to _check_browser_language which does almost nothing in this case, i.e. it does not notify the server about layout change!!! And if it was previously switched to ru and now receives en keys, one gets wrong key mapping.


Sat, 08 Jun 2019 16:35:06 GMT - Antoine Martin: attachment set

change back to the default layout


Sat, 08 Jun 2019 16:36:04 GMT - Antoine Martin: owner, status changed

How about this patch? Does it help? attachment/ticket/2154/html-layout-change-back.patch

Without steps, I don't know how to configure my keyboard, so I can't reproduce or test.


Sat, 08 Jun 2019 18:37:31 GMT - berserker: owner, priority changed

Replying to Antoine Martin:

How about this patch? Does it help? attachment/ticket/2154/html-layout-change-back.patch

No. When I repeatedly type д (Cyrillic_de), the HTML5 client switches layout every 2 seconds to ru and then back to en then back to ru... (starting from ru):

2019-06-08 18:16:13,243 setting keyboard layout to 'ru'
2019-06-08 18:16:15,293 setting keyboard layout to 'us'
2019-06-08 18:16:17,295 setting keyboard layout to 'ru'
2019-06-08 18:16:19,316 setting keyboard layout to 'us'
2019-06-08 18:16:21,367 setting keyboard layout to 'ru'
2019-06-08 18:16:30,962 setting keyboard layout to 'us'

I think it is clear why. Here key_layout is always "ru". At the first time, the if branch is taken, because key_layout && this.key_layout!=key_layout is true. On the next invocation of _check_browser_language with key_layout == "ru" the else if branch is taken, because this.key_layout!=null holds. And in that block of code, default_layout = this._get_keyboard_layout() is "us" and it is not equal to this.key_layout == "ru". In this case you set new_layout to default_layout == "us", even though the symbol being typed is not from "us" layout.


Sun, 09 Jun 2019 03:15:08 GMT - Antoine Martin: attachment set

updated patch


Sun, 09 Jun 2019 03:15:54 GMT - Antoine Martin: owner changed

Please try the updated patch.


Sun, 09 Jun 2019 09:02:39 GMT - berserker:

Replying to Antoine Martin:

Please try the updated patch.

It seem to solve the issue for me if I don't switch the layout too often. I think embargo time has to be set to 100ms in all cases. Also, I didn't test how this behaves in non-en browser locales.


Sun, 09 Jun 2019 09:42:05 GMT - berserker:

Replying to Antoine Martin:

Please try the updated patch.

_check_browser_language is called from Client.js:do_window_mouse_move with no argument (key_layout is undefined). In this case, the else if branch is selected, new_layout is set to "en" (or "us"?) and if this.key_layout == "ru", "layout-changed" message is sent to the server. Not an optimal behavior, IMO.


Sun, 09 Jun 2019 11:19:01 GMT - Antoine Martin: attachment set

updated patch - don't change from motion events


Sun, 09 Jun 2019 11:19:38 GMT - Antoine Martin:

This call to _check_browser_language was added in r15510. (for #1484)

How about the updated patch?


Sun, 09 Jun 2019 18:56:49 GMT - berserker:

Replying to Antoine Martin:

This call to _check_browser_language was added in r15510. (for #1484)

I'm surprised that it worked for someone with Ru layout...

How about the updated patch?

Latin symbols are incorrectly handled in Chromium in Russian locale (started as LANGUAGE=ru chromium-browser ...). The server (looking at the user-agent?) sets the layout to ru on connection:

2019-06-09 18:33:04,726 Handshake complete; enabling connection
2019-06-09 18:33:04,777  automatic picture encoding enabled, also available:
2019-06-09 18:33:04,777   jpeg, png, rgb32, webp, h264, mpeg1
2019-06-09 18:33:04,779 HTML5 Linux Chrome client version 3.0
2019-06-09 18:33:04,907 setting keyboard layout to 'ru'

and when I type a latin character, _check_browser_language is called with the null argument when this.key_layout is also null:

2019-06-09 18:33:08,801 client keyboard processKeyEvent( true ,  [object KeyboardEvent] ) key= KeyL keycode= 76
2019-06-09 18:33:08,802 client keyboard Client.js:628: _check_browser_language( null )
2019-06-09 18:33:08,803 client keyboard Client.js:656 new_layout = null  this.key_layout = null
2019-06-09 18:33:08,807 client keyboard key-action,1,l,true,mod2,76,l,76,0

(I've added some "keyboard" debug info to _check_browser_language). So, neither if (key_layout) nor else if (this.key_layout!=null) branches are taken. new_layout!=null && this.key_layout!=new_layout is also false. This l keypress is mapped to F10 keypress on the server side because of the incorrect "ru" locale.


Mon, 10 Jun 2019 18:40:30 GMT - berserker: attachment set


Mon, 10 Jun 2019 18:47:30 GMT - berserker: owner changed

See the attached patch. It works for me.

Basic idea is that if _check_browser_language is called with null (~Latin characters) and the current layout is the same as the browser language, switch to the "us" layout. It also works in case the browser language is "us" and the locales being used are "us" and a non-Latin one.

It probably won't work for non-English Latin language/locale, so this is not a complete solution.


Mon, 10 Jun 2019 18:59:29 GMT - berserker:

Replying to Antoine Martin:

Without steps, I don't know how to configure my keyboard, so I can't reproduce or test.

I think you don't even need to start Xpra or a browser to work on this. There are: the current layout, the browser language and the argument to _check_browser_language. The problem is: how to implement the _check_browser_language function which guarantees proper change of the current layout for the most common combinations:


Tue, 11 Jun 2019 04:52:50 GMT - Antoine Martin: attachment set

updated patch


Tue, 11 Jun 2019 04:53:28 GMT - Antoine Martin: owner changed

I think you don't even need to start Xpra or a browser to work on this.

I do, on macos, on windows, on Linux, with Firefox, with Safari, with chrome, etc. Removing layout detection is not a solution.

AFAICT, the 'ru' keyboard layout does have support for all the latin characters, so there should be no need to switch to another layout.

From my limited testing using setxkbmap ru on Linux, the latest patch works fine.

Unless you can provide the information required, I will have to close this as 'invalid' or 'wontfix'.


Tue, 11 Jun 2019 15:41:28 GMT - berserker: status changed; resolution set

Replying to Antoine Martin:

I think you don't even need to start Xpra or a browser to work on this.

I do, on macos, on windows, on Linux, with Firefox, with Safari, with chrome, etc.

As I see now, the problem is in the _check_browser_language function, which does not depend on the keyboard layout.

AFAICT, the 'ru' keyboard layout does have support for all the latin characters

Experience shows that it does not. Maybe I do not clearly understand what "layout" is. Or the system on the server side is misconfigured.

From my limited testing using setxkbmap ru on Linux, the latest patch works fine.

There is no immediate problem with the ru layout. Try to test with this._get_keyboard_layout() returning "ru" (mocking a browser with the first language == Russian) and "us" layout. There is no difference between your third and fourth patches in this context.

Unless you can provide the information required, I will have to close this as 'invalid' or 'wontfix'.

I've tested my patch in Linux with Firefox (us) ("us" is the browser language, not layout) and chromium (us + ru), Windows with Firefox (ru), MacOS with chromium (ru). Both "us" and "ru" layouts work as expected when I switch between them in any order. Your last two patches do not work for latin characters input when the browser language is "ru". As I wrote above, I don't see how _check_browser_language depends on the information you would like me to provide, so I'm closing this. Maybe I'll reopen it later if there is any problem. Thank you for your time and effort.


Sat, 23 Jan 2021 05:43:38 GMT - migration script:

this ticket has been moved to: https://github.com/Xpra-org/xpra/issues/2154