Bug 5226 - detect AltGr on Windows
Summary: detect AltGr on Windows
Status: CLOSED FIXED
Alias: None
Product: ThinLinc
Classification: Unclassified
Component: VNC (show other bugs)
Version: trunk
Hardware: PC Windows
: P2 Normal
Target Milestone: 4.10.0
Assignee: Pierre Ossman
URL:
Keywords: hean01_tester, ossman_tester, relnotes, upstream
Depends on: 7158
Blocks: keyboard 965 7429
  Show dependency treegraph
 
Reported: 2014-08-21 13:23 CEST by Pierre Ossman
Modified: 2019-10-31 12:43 CET (History)
1 user (show)

See Also:
Acceptance Criteria:
* Pressing AltGr should send _only_ ISO_Level3_Shift to the server * Pressing right Alt (e.g. us layout) should send Alt_R * Pressing Ctrl+AltGr should send Ctrl_* and ISO_Level3_Shift * Release note should be written * Switching client layout should directly change Alt/AltGr behaviour


Attachments

Description Pierre Ossman cendio 2014-08-21 13:23:15 CEST
Windows has this idiotic behaviour of sending a VK_LCONTROL/VK_RMENU combination when you press AltGr. This wreaks havoc with VNC as we cannot tell an actual press of the left control key from that fake one, and we don't know if we should be sending XK_ISO_Level3_Shift of XK_Alt_R.

We have as of yet not figured out a good way to work around this. The window messages are identical for fake and real presses, as well are the responses from GetKeyState() and GetAsyncKeyState(). There are currently three known methods of detecting this scenario:

 1. Check if a VK_LCONTROL is immediately followed by a VK_RMENU on the message queue. This is however race-y, and Windows doesn't send the fake VK_LCONTROL if that key is already down anyway.

 2. Keyboard hook. Entirely undocumented, the scan code will have an extra 0x200 or:ed in for the fake control events. Spice relies on this somehow. The problem is that keyboard hooks are a pain in the ass as they run globally, asynchronously relative our main message queue, and we don't even know if this key press will be for us.

 3. Raw input. The fake control events are not seen at this level, so we can detect the AltGr scenario by seeing if we get a window message for a key that we did not get a raw input event for. Unfortunately Windows, for brain dead reasons (and this is also completely undocumented), disables keyboard hooks in your process if you enable raw input. And since we need keyboard hooks to grab things like Alt+Tab and the Windows keys, it means we cannot use raw input.
Comment 2 Pierre Ossman cendio 2018-02-05 15:55:36 CET
Chromium/Chrome has implemented some detection for this:

https://bugs.chromium.org/p/chromium/issues/detail?id=25503
Comment 3 Pierre Ossman cendio 2018-03-07 17:01:36 CET
(In reply to comment #0)
> 
>  2. Keyboard hook. Entirely undocumented, the scan code will have an extra
> 0x200 or:ed in for the fake control events. Spice relies on this somehow. The
> problem is that keyboard hooks are a pain in the ass as they run globally,
> asynchronously relative our main message queue, and we don't even know if this
> key press will be for us.
> 

gtk-vnc copied this approach:

https://git.gnome.org/browse/gtk-vnc/commit/?id=590c344ad3340dfabb9985c98f418ce2fcae7b44

It also demonstrates how they hook it up with the main window:

 - They use SendMessage() to bounce the keyboard events to the main window

 - They have a global variable that is updated on focus changes to determine if messages should be bounced or not
Comment 4 Pierre Ossman cendio 2018-03-08 17:34:28 CET
https://github.com/TigerVNC/tigervnc/pull/608
Comment 5 Pierre Ossman cendio 2018-09-19 13:29:11 CEST
The method implemented upstream is the method used by Chrome. This is a variant of method 1. with the addition that the system keymap is also examined to see if it contains the AltGr key or not. This addition avoid the risk of false detections when they layout doesn't have AltGr, and it makes it reliable to detect AltGr even when Ctrl is already pressed.

(The method Chrome, and now TigerVNC, uses is that it checks if Ctrl+Alt+<key> gives a symbol for any value for <key>. If so the layout is assumed to use AltGr.)
Comment 6 Henrik Andersson cendio 2018-09-20 08:10:03 CEST
> * Pressing AltGr should send _only_ ISO_Level3_Shift to the server
>

Works as expected

> * Pressing right Alt (e.g. us layout) should send Alt_R
>

Selecting english layout on client will send Alt_L instead of
expected Alt_R

> * Pressing Ctrl+AltGr should send Ctrl_* and ISO_Level3_Shift
>

Work as expected
Comment 7 Pierre Ossman cendio 2018-09-24 10:04:24 CEST
(In reply to comment #6)
> > * Pressing right Alt (e.g. us layout) should send Alt_R
> >
> 
> Selecting english layout on client will send Alt_L instead of
> expected Alt_R
> 

We got this because the server had a layout configured that didn't include Alt_R (Swedish). Instead of mapping a new key the server then picks an equivalent one, Alt_L in this case. Selecting e.g. us layout gets a Alt_R here.
Comment 9 Pierre Ossman cendio 2018-09-28 10:35:12 CEST
> * Release note should be written

Done.

> * Switching client layout should directly change Alt/AltGr behaviour

It does.
Comment 10 Pierre Ossman cendio 2018-11-05 17:46:15 CET
Does not work properly with the virtual, touch keyboard on Windows 10:

https://github.com/TigerVNC/tigervnc/issues/760

Doesn't work properly for Chrome or Firefox either, but maybe we can do better?
Comment 12 Pierre Ossman cendio 2018-11-06 17:22:49 CET
The above commit was for the touch keyboard in its advanced mode. Unfortunately it is also broken in other was in its standard mode. Added bug 7276 for that.
Comment 14 Pierre Ossman cendio 2018-11-07 11:03:33 CET
Retested the various AltGr and Alt_R combinations using both a physical keyboard, and the touch keyboard. Works well now.

Also tested multimedia keys as they also come without a scancode (lack of scancode is part of the detection for the touch keyboard's AltGr).

Note You need to log in before you can comment on or make changes to this bug.