Skip to content

Conversation

@eugenesvk
Copy link
Contributor

@eugenesvk eugenesvk commented May 19, 2025

To at least allow separate handling of Ctrl+Alt and AltGr. Though AltGr+Ctrl is still broken and can't be differentiated from AltGr since in the current model without raw key tracking Winit can't get enough info from window messages to detect the artificial Ctrl that Windows sends on AltGr

Another benefit is it allows separating AltGr+X and Alt+X and not fire shortcuts with a key meant to insert symbols is pressed.

  • Windows Tested on all platforms changed
  • Added an entry to the changelog module if knowledge of this change could be valuable to users
  • Updated documentation to reflect any user-facing changes, including notes of platform-specific behavior
  • Created or updated an example program if it would help users understand this functionality

Based on top of #4235 as it needs the side-aware state and the example

Partially addresses #3012

Copy link
Member

@kchibisov kchibisov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AltGr is not a modifier, pretending that it's is not expected by anyone.

It also doesn't even work like a modifier, so putting it there is not a good option. If you want to indicate that compose is going on, other options should be used, such as exposing some kind of keymap for the end user, which I plan to do eventually.

@eugenesvk
Copy link
Contributor Author

eugenesvk commented May 20, 2025

AltGr is not a modifier, pretending that it's is not expected by anyone.

Of course it is, both logically - just like Shift prints Upper case of a key AltGr prints Symbol of a key - and "officially", it's recognized as a separate modifier in eg official specs like Web https://w3c.github.io/uievents/#keys-modifiers and defined as such in various other places

And this symbolic expectation is also what makes it different from a regular right alt modifier, which the normal expectaton for is to e.g. work with menu shortcuts on Windows (not insert symbols), just like LAlt.

It also doesn't even work like a modifier

In what way does it not?

If you want to indicate that compose is going on

It's not compose, it's getting access to 1 for 1 key regardless of previous input (outside of special deadkeys and special unicode composable symbols), just like Shift. Compose is by definition when you ... well, compose a symbol from usually multiple chars. And Compose is a "sticky" state (on older keyboards signalled via an LED light, in some compose apps via a tray icon light or maybe some cursor change UI mechanism like dead keys), which AltGr isn't

A compose key (sometimes called multi key) is a key on a computer keyboard that indicates that the following (usually 2 or more) keystrokes trigger the insertion of an alternate character, typically a precomposed character or a symbol.[1]

https://en.wikipedia.org/wiki/Compose_key

@kchibisov
Copy link
Member

kchibisov commented May 20, 2025

https://w3c.github.io/uievents/tools/key-event-viewer.html

https://w3c.github.io/uievents/tools/key-event-viewer.html

I mean, for me it's not a modifier(firefox) on those tools, it's just a Compose key, I've never seen it as a modifier passed as its own state. Also given how you've implemented it's just right alt from your impl, it's not AltGr, in windows docs it's also just right alt, and I don't see why not just have it as right alt, since any other backend won't be able to ever have this "modifier".

In what way does it not?

tap -> then you type the sequence to input keys, in some impls it could be done differently by holding, but generally it's a tap dance.

@eugenesvk
Copy link
Contributor Author

eugenesvk commented May 20, 2025

s just a Compose key,

Maybe that's because how your system is set up?

Here is an example with a layout that has AltGr
AltGr

I've never seen it as a modifier passed as its own state.

That's not surprising, in general a lot of this keyboard stuff is pretty broken everywhere. I mean, on Windows you have this dumb design where AltGr is LCtrl+RAlt, so you waste the whole set of Ctrl+Alt key combos

That's not a reason not to do it properly.

Also given how you've implemented it's just right alt from your impl

That's not me, I'm using existing detection. If you believe there are cases when this detection is wrong, ok, but that's a separate bug.

Also, even in that case it's not "just right alt" since it will NOT trigger Alt+X shortcuts! That's the important part and the reason to separate these two functionally different modifiers

in windows docs it's also just right alt

it's not, in Win docs its Ctrl+Alt

Don't use Ctrl+Alt combinations, because Windows interprets this combination in some language versions as an AltGR key, which generates alphanumeric characters.
https://learn.microsoft.com/en-us/windows/win32/uxguide/inter-keyboard

, and I don't see why not just have it as right alt, since any other backend won't be able to ever have this "modifier".

Because then you'll have very common bugs where you can't use Ctrl+Alt key combos just because your AltGr key isn't implemented properly,

In what way does it not?
tap -> then you type the sequence to input keys, in some impls it could be done differently by holding, but generally it's a tap dance.

This is NOT how AltGr works, you must hold it, same as Shift (ignoring sticky keys), what you're describing is Compose key as I've quoted above. I think you're confusing these two because your system is setup in a way where RAlt is bound to Compose

@kchibisov
Copy link
Member

That's not me, I'm using existing detection. If you believe there are cases when this detection is wrong, ok, but that's a separate bug.

I'm just saying that it doesn't look like modifier at all. In this case I guess it'll be fine though.

in windows docs it's also just right alt
it's not, in Win docs its Ctrl+Alt

I meant here the way you detect, and what windows docs say about VK_RMENU (https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).

Also, according to your log in the browser, you have just AltGr, which means that you shouldn't have Alt set at all in such cases, like you would have now?

@eugenesvk
Copy link
Contributor Author

eugenesvk commented May 20, 2025

I meant here the way you detect, and what windows docs say about VK_RMENU (https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes).

But Windows also automatically inserts LCtrl event, so it's not just VK_RMENU, its VK_RMENU+VK_LCONTROL.

Also, according to your log in the browser, you have just AltGr, which means that you shouldn't have Alt set at all in such cases, like you would have now?

I have Alt (see below), but if you mean I can't have them both, then yeah, I can't, but that's just because the web spec has this very common bug - they don't distinguish betwen left and right modifier state, and since AltGr = Alt+Ctrl, you can't have AltGr + Alt. But also you can't have AltGr + Ctrl on the web

But Winit is smarter here - it does distinguish between modifier sides (though not completely)!

AltGr2

(rebased on top of updates in #4235)

@madsmtm madsmtm added S - enhancement Wouldn't this be the coolest? DS - win32 Affects the Win32/Windows backend S - api Design and usability labels May 20, 2025
Copy link
Member

@madsmtm madsmtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't comment much on the PR itself, because I really don't know. But having this as a separate modifier sounds reasonable.

@kchibisov
Copy link
Member

I won't comment much on the PR itself, because I really don't know. But having this as a separate modifier sounds reasonable.

Maybe we can use keyboard types at this point for modifiers as well?

@madsmtm
Copy link
Member

madsmtm commented May 21, 2025

Maybe we can use keyboard types at this point for modifiers as well?

We cannot with the current design on keyboard-types' modifiers, see #2394 (comment).

@dhardy
Copy link
Contributor

dhardy commented Nov 3, 2025

AltGr is not a modifier, pretending that it's is not expected by anyone.

I use AltGr as a modifier (custom layout) on Linux.
xev reports this as ISO_Level3_Shift.
Winit reports ModifiersChanged even though ModifiersState is currently unaffected by the key.
Basically all applications completely ignore AltGr as a key/modifier (though it still affects text input correctly).

I don't know what should happen here. I wouldn't expect to use AltGr in shortcuts (KDE doesn't appear to support this, and I haven't noticed anything else that does).

If anything, it's Shift that is weird: it adjusts input of other letters and is used as a modifier. Shortcut-matchers also have special handling, for example reporting that Ctrl+Z (not z) triggers "Undo" and Ctrl+Shift+Z triggers "Redo". If I wanted to map Ctrl+AltGr+F to "reformat selection", the (KDE) shortcut matcher instead shows Ctrl+}. This is technically solvable (with keyboard layout awareness), but I don't think anyone cares to solve it.


Another benefit is it allows separating AltGr+X and Alt+X and not fire shortcuts with a key meant to insert symbols is pressed.

This sounds like a separate bug to me: AltGr should not set the Alt modifier.

@eugenesvk
Copy link
Contributor Author

eugenesvk commented Nov 3, 2025

Basically all applications completely ignore AltGr as a key/modifier (though it still affects text input correctly).

Not on Windows, you can map Ctrl+Alt. Though it's advised not to set default keybinds to those due to AltGr conflicts

I wouldn't expect to use AltGr in shortcuts (KDE doesn't appear to support this

Why not? What if you don't use all the symbol keys with AltGr, why wouldn't you want to have the option to map them to something more useful? After all, it has the most convenient modifier position - your right thumb finger!
Also some smarter apps allow separate keybinds for when you input text vs do something else (that's how you can have single key keybinds), so in that case you wouldn't even lose anything as you'd still input symbols with AltGr as usual

This sounds like a separate bug to me: AltGr should not set the Alt modifier

Yes it should, that's how AltGr is defined, it's literally the same as Ctrl+Alt on Windows, there is no extra VK_SHIFT_LEVEL3 separate modifier

@dhardy
Copy link
Contributor

dhardy commented Nov 3, 2025

@eugenesvk are you referring to this?

It sounds to me like applications should not trigger a shortcut for e.g. Alt+F4 if Ctrl is also pressed (which is exactly the behaviour I would expect). A new state is not needed in ModifiersState for this since it can already represent Ctrl+Alt.

On Linux, Ctrl+Alt is not equivalent to AltGr. Ctrl+Alt shortcuts are possible while AltGr is also enabled (e.g. in my editor Ctrl+Alt+O is a shortcut while AltGr+O inserts %). (Although it is possible to configure Ctrl+Alt to enable third layer graphics, e.g. setxkbmap -option grp:lctrl_lalt_toggle; this is not the case by default.)

So it sounds to me like AltGr (without other keys) should map to ModifiersState::CTRL | ModifiersState::Alt on Windows and to ModifiersState::empty() on other platforms.

@eugenesvk
Copy link
Contributor Author

eugenesvk commented Nov 3, 2025

Yes, the link describes the equivalence on Windows. Though I'm confused by your example, why would Alt+F4 trigger if Ctrl is pressed with these changes?

On Linux, Ctrl+Alt is not equivalent to AltGr

Ok, but this is a PR for Windows!

A new state is not needed in ModifiersState for this since it can already represent Ctrl+Alt.

And you've now lost the ability to differentiate between a single key press AltGr = RAlt + LCtrl and two key presses LAlt+LCtrl. For what benefit?
It is semantically a different modifier state, just for some reason represented in a wasteful manner using an extra modifier (on Windows), but still we can limit the fallout to a single physical key instead of two.

to ModifiersState::empty() on other platforms

This is even worse, why? Why don't you map Shift to empty on all platforms if it's the same as AltGr only with a different set of symbols?
How will you differentiate Level 4 shift (AltGr+Shift) from Level 2 shift (Shift alone) if your set is empty for AltGr?

@dhardy
Copy link
Contributor

dhardy commented Nov 3, 2025

And you've now lost the ability to differentiate between a single key press AltGr = RAlt + LCtrl and two key presses LAlt+LCtrl.

On Windows... but as you said at the top of this PR, this is still broken.

This is even worse, why?

It's only worse if you care about supporting AltGr+Key shortcuts. Aside from Windows (which it is recommended not to do as noted in the link above), I haven't seen this supported elsewhere.

You are right that this is justification for adding AltGr as a modifier, except that you appear to be arguing about hypothetical cases.

Personally I just like the clear divide we usually have: shortcuts apply only to F-keys (and media keys ...) or when at least one of Ctrl/Alt/Meta is pressed. Everything else is just text input.

Why don't you map Shift to empty

Shift gets used for other things, like Shift+click may be used for mouse selection, so its state must be known.

How will you differentiate Level 4 shift (AltGr+Shift) from Level 2 shift (Shift alone) if your set is empty for AltGr?

Usually you don't need to. In fact, I think the only times you'd even care about this stuff is (a) if you're writing a layout editor or (b) if you want a "display label" for a shortcut/action key. For the most part applications don't care about keyboard layouts or shift levels, they just receive mapped text input.

@eugenesvk
Copy link
Contributor Author

On Windows... but as you said at the top of this PR, this is still broken.

So? With this PR it can become unbroken

It's only worse if you care about supporting AltGr+Key shortcuts.

Yes, if you don't care about shortcuts, shortcut improvements will not help. But you forgot to explain why you want to block the improvements. What about the apps that do care about such shorcuts?

except that you appear to be arguing about hypothetical cases.

It's mostly you mistake uncommon for non-existent, otherwise there are people already using various external keybind remapping apps to overcome various app/platform limitations. For example, I'm using separate keybinding categories of LAlt+X vs LCtrl+LAlt+X vs RAlt+X

Personally I just like the clear divide we usually have

And since AltGr is Ctrl+Alt, your clarity is preserved. But also, we don't have this divide: games exist and are very popular. So do more niche cases like modal editors and other Shift,Shift IDEs, so do some web/file browsers and other apps that know that you're not typing text all the time

Aside from Windows (which it is recommended not to do as noted in the link above)

No, it's not recommended to change the defaults, it has no relevance to user-defined keybinds, if someone doesn't care about đ, he can bind Ctrl+Alt to his heart's content already today.

Also, it's not recommended because of the conflict, but this PR partially resolves the conflict, so that recommendation is not fully applicable even for defaults.

Aside from Windows ... I haven't seen this supported elsewhere.

Ok, but how is this relevant to Windows?

Usually you don't need to

There is also (c) keyboard shortcuts that are not tied to typed symbols, but to physical keys. But also, why ignore layout editors, OSDs and other 'unusual' apps?

@dhardy
Copy link
Contributor

dhardy commented Nov 3, 2025

And since AltGr is Ctrl+Alt

No, AltGr is not Ctrl+Alt. You've made this clear yourself: you want to add ModifiersState::ALT_GRAPH, and you consider LCtrl+LAlt different from LCtrl+RAlt. I have also said that Ctrl+Alt is not equivalent to AltGr on Linux. So stop repeating this; it is false.

But you forgot to explain why you want to block the improvements. What about the apps that do care about such shorcuts?

As I said, I have not seen AltGr used in shortcuts before, anywhere. Either as standard shortcuts or even proper support for AltGr shortcuts (aside from it being compatible with Ctrl+Alt shortcuts on Windows).

I'm using separate keybinding categories of LAlt+X vs LCtrl+LAlt+X vs RAlt+X

Aha, so we're talking about differentiating LAlt and RAlt. In that case, why not also LCtrl and RCtrl, and the same for Shift and Meta keys?

I believe ArmA3 (game) differentiates left modifiers from right modifiers.

Winit does actually support this; you just have to track the modifier state yourself. physical_key reports AltLeft, ControlLeft, ShiftLeft, SuperLeft (and Right variants of each).

But should a typical application care about left-vs-right here? In my opinion, no.


One more point: are we talking about ISO_Level3_Shift (which may be activated through multiple methods, at least on Linux), or Right Alt? Semantically these are not the same. ALT_GRAPH implies that we're talking about the level-3 shift to me, though admittedly this is ambiguous.

@eugenesvk
Copy link
Contributor Author

you consider LCtrl+LAlt different from LCtrl+RAlt.

And for your "clear divide" of "one of Ctrl/Alt/Meta is pressed" the sides dont'n matter, so yes, AltGr meats your criterion of a modifier for shortcuts.

have not seen ... aside from it being compatible with Ctrl+Alt shortcuts on Windows).

So you have actually seen it. People can and do use Ctrl+Alt shortcuts.

Aha, so we're talking about differentiating LAlt and RAlt.

That's a different issue, though ultimately they about the same broader issue -differentiating different modifiers. It's just that AltGr is a physical RightAlt key.

In that case, why not also LCtrl and RCtrl, and the same for Shift and Meta keys?

What do you mean, "why not" when I do precisely that! This PR is based on #4235 that closes #3611 about side-aware modifiers!
That side-aware foundation is what enables AltGr disambiguation down the line.

I believe ArmA3 (game) differentiates left modifiers from right modifiers.

What's more important is that all games differentiate between single keys as text and single keys as shortcuts=commands, that's how you get WASDF to move instead of typing, and that's what breaks your clarity or mandatory Ctrl/Alt/Win keys in shortcuts

Winit does actually support this; you just have to track the modifier state yourself. physical_key reports AltLeft, ControlLeft, ShiftLeft, SuperLeft (and Right variants of each).

Don't think it's entirely accurate, see various issues linked above and #4233 etc. Though I don't know/remember all the issues (think there was also one with focus changes and modifier state changes which require tracking modifier state change and convert it into a physical key state?)

But should a typical application care about left-vs-right here? In my opinion, no.

Why does it matter what you think about "usual" and "typical" when winit is not that limited? Are you saying it should not be used in "unusual" apps?

And the correct answer - yes, of course apps should care about user comfort! You lose the most ergonomic modifier position without side awareness. And even if the app dev is ergonomically ignorant it should at least not be blocked at the foundational level so that even if all the default keybinds are bad, users should be able to customize to the better ones!

One more point: are we talking about ISO_Level3_Shift (which may be activated through multiple methods, at least on Linux), or Right Alt?

Well, there is no ISO_Level3_Shift on Windows! I can't disambiguate the inherently ambiguous situation when you keep bringing another platform up where it's defined differently. On linux AltGr would reflect L3 Shift, on Windows it reflects physical Right Alt when AltGr is enabled, so Right Alt also sends Left Control

@eugenesvk
Copy link
Contributor Author

eugenesvk commented Nov 3, 2025

hm, by the way, is it possible to detect whether physical RightAlt acts as AltGr so that you would only treat LCtrl+RAlt as a logical AltGr modifier conditionally, i.e., when the current layout supports it?
Otherwise AltGr should not be set on LCtrl+RAlt press

Does Winit store info about the currently active layout somewhere to query what physical RAlt generates and use that as a conditional check?

@dhardy
Copy link
Contributor

dhardy commented Nov 3, 2025

You talk about benefits and capability, but gloss over the implication: using separate states makes all shortcut matching default to differentiate between left and right modifier keys.

I asked "why not also LCtrl and RCtrl", and here is a reason: common shortcuts like Ctrl+Z would instead have to be mapped to both LCtrl+Z and RCtrl+Z.

Well, there is no ISO_Level3_Shift on Windows!

Let me re-phrase: are we talking about a semantic third layer ("alternate graphics") or about differentiating Left Alt from Right Alt for use in shortcuts?

There aren't many common shortcuts using Alt, but there are a few, e.g. Alt+F4 (close), Alt+Left (back), Alt+Down (page down). Should these function with RAlt? Should a user-defined key-bind like Alt+G function also with RAlt?

is it possible to detect whether physical RightAlt acts as AltGr

Good question; I don't know. And this is why I ask about ISO_Level3_Shift: it can be activated multiple different ways. Normally applications are not supposed to care about this or how key-presses are translated to text-input, though they might care about which modifier keys were used.

@eugenesvk
Copy link
Contributor Author

but gloss over the implication: using separate states makes all shortcut matching default to differentiate between left and right modifier keys.

No? You can have APIs that match either sides without losing the capability to differentiate. I do not remove side-agnostic modifiers, only add side-aware ones.

But you should direct this API design conversation to the more appropriate place since this PR is about AltGr, not overall side awareness

I asked "why not also LCtrl and RCtrl", and here is a reason: common shortcuts like Ctrl+Z would instead have to be mapped to both LCtrl+Z and RCtrl+Z.

Nope, they can continue to use the same side-agnostic APIs to set a single Ctrl+Z

Let me re-phrase: are we talking about a semantic third layer ("alternate graphics") or about differentiating Left Alt from Right Alt for use in shortcuts?

Well, both, there are separate PRs that enable separate capabilities, so the answer depends on a specific issue. This PR depends on left vs right, but it's not about LAlt vs RAlt, it's about differentiating LCtrl+RAlt vs RCtrl+RAlt vs LCtrl+LAlt since AltGr is defined as the former.

There aren't many common shortcuts using Alt, but there are a few, e.g. Alt+F4 (close), Alt+Left (back), Alt+Down (page down). Should these function with RAlt?

Nothing in the defaults change depending on this or the other PR! So it would continue to function as is unless the dev/user change it

Should a user-defined key-bind like Alt+G function also with RAlt?

Again, none of the defaults are forced to change! So however you like. In a text config you usually have separate Alt/LAlt/RAlt. In a GUI config you can have a checkmark that differentiates sides but otherwise Alt is bound as both L/R

Good question; I don't know. And this is why I ask about ISO_Level3_Shift: it can be activated multiple different ways.

It's the opposite, the question is about cases when there are 0 ways to activate AltGr because the layout doesn't support it (again, not Level3Shift, it doesn't exist on Windows, stop purposefully confusing the conversation).

Normally applications are not supposed to care about this or how key-presses are translated to text-input , though they might care about which modifier keys were used.

So nothing will change? Who will force apps to care whether AltGr is set incorrectly (from Lctrl+RAlt even on layouts that don't support AltGr)??? They'll just continue to ignore it. Some users might suffer, but not more than today.

But also, for the 3rd time: so what do you suggest apps that do care about which modifiers keys were used do?

@dhardy
Copy link
Contributor

dhardy commented Nov 3, 2025

I do not remove side-agnostic modifiers, only add side-aware ones.

Naively, applications will match shortcut modifiers using the whole of ModifiersState. If ALT_GRAPH is only set when the keyboard layout supports a third layer I think this is fine.

(Though it will only work correctly if applications use key_without_modifiers, not logical_key.)

But also, for the 3rd time: so what do you suggest apps that do care about which modifiers keys were used do?

For the second time: track key events and use the physical_key to update a local state tracker for which modifier keys are pressed, specifically KeyCode::LeftAlt and KeyCode::RightAlt.

@eugenesvk
Copy link
Contributor Author

Naively, applications will match shortcut modifiers using the whole of ModifiersState

So what do you expect to happen when you add caps/numlock modifier etc. state which winit currently lacks? #1426
The naive match to degrade the set or for a better API that can match only "core" modifiers (so, Shift, but not CapsLock?)

For the second time: track key events and use the physical_key to update a local state tracker for which modifier keys are pressed, specifically KeyCode::LeftAlt and KeyCode::RightAlt

For the second time: it doesn't work, winit doesn't properly track it for the app to have the full picture! But also, what's the point of a framework that has modifier state if apps have to do all the work to recreate it manually?

@eugenesvk
Copy link
Contributor Author

Some reference on how to detect layout altgr capability https://stackoverflow.com/questions/54588823/detect-if-the-keyboard-layout-has-altgr-on-it-under-windows

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DS - win32 Affects the Win32/Windows backend S - api Design and usability S - enhancement Wouldn't this be the coolest?

Development

Successfully merging this pull request may close these issues.

4 participants