@@ -619,35 +619,41 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
619
619
}
620
620
621
621
const auto modifiers = _GetPressedModifierKeys ();
622
- const auto vkey = static_cast <WORD>(e.OriginalKey ());
623
622
623
+ // AltGr key combinations don't always contain any meaningful,
624
+ // pretranslated unicode character during WM_KEYDOWN.
625
+ // E.g. on a German keyboard AltGr+Q should result in a "@" character,
626
+ // but actually results in "Q" with Alt and Ctrl modifier states.
627
+ // By returning false though, we can abort handling this WM_KEYDOWN
628
+ // event and let the WM_CHAR handler kick in, which will be
629
+ // provided with an appropriate unicode character.
630
+ //
631
+ // GH#2235: Make sure to handle AltGr before trying keybindings,
632
+ // so Ctrl+Alt keybindings won't eat an AltGr keypress.
633
+ if (modifiers.IsAltGrPressed ())
634
+ {
635
+ _HandleVoidKeyEvent ();
636
+ e.Handled (false );
637
+ return ;
638
+ }
639
+
640
+ const auto vkey = static_cast <WORD>(e.OriginalKey ());
624
641
bool handled = false ;
642
+
625
643
auto bindings = _settings.KeyBindings ();
626
644
if (bindings)
627
645
{
628
- KeyChord chord (
646
+ handled = bindings. TryKeyChord ({
629
647
modifiers.IsCtrlPressed (),
630
648
modifiers.IsAltPressed (),
631
649
modifiers.IsShiftPressed (),
632
- vkey);
633
- handled = bindings. TryKeyChord (chord );
650
+ vkey,
651
+ } );
634
652
}
635
653
636
654
if (!handled)
637
655
{
638
- _terminal->ClearSelection ();
639
- // If the terminal translated the key, mark the event as handled.
640
- // This will prevent the system from trying to get the character out
641
- // of it and sending us a CharacterRecieved event.
642
- handled = _terminal->SendKeyEvent (vkey, modifiers);
643
-
644
- if (_cursorTimer.has_value ())
645
- {
646
- // Manually show the cursor when a key is pressed. Restarting
647
- // the timer prevents flickering.
648
- _terminal->SetCursorVisible (true );
649
- _cursorTimer.value ().Start ();
650
- }
656
+ handled = _TrySendKeyEvent (vkey, modifiers);
651
657
}
652
658
653
659
// Manually prevent keyboard navigation with tab. We want to send tab to
@@ -661,6 +667,45 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
661
667
e.Handled (handled);
662
668
}
663
669
670
+ // Method Description:
671
+ // - Some key events cannot be handled (e.g. AltGr combinations) and are
672
+ // delegated to the character handler. Just like with _TrySendKeyEvent(),
673
+ // the character handler counts on us though to:
674
+ // - Clears the current selection.
675
+ // - Makes the cursor briefly visible during typing.
676
+ void TermControl::_HandleVoidKeyEvent ()
677
+ {
678
+ _TrySendKeyEvent (0 , {});
679
+ }
680
+
681
+ // Method Description:
682
+ // - Send this particular key event to the terminal.
683
+ // See Terminal::SendKeyEvent for more information.
684
+ // - Clears the current selection.
685
+ // - Makes the cursor briefly visible during typing.
686
+ // Arguments:
687
+ // - vkey: The vkey of the key pressed.
688
+ // - states: The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
689
+ bool TermControl::_TrySendKeyEvent (WORD vkey, const ControlKeyStates modifiers)
690
+ {
691
+ _terminal->ClearSelection ();
692
+
693
+ // If the terminal translated the key, mark the event as handled.
694
+ // This will prevent the system from trying to get the character out
695
+ // of it and sending us a CharacterRecieved event.
696
+ const auto handled = vkey ? _terminal->SendKeyEvent (vkey, modifiers) : true ;
697
+
698
+ if (_cursorTimer.has_value ())
699
+ {
700
+ // Manually show the cursor when a key is pressed. Restarting
701
+ // the timer prevents flickering.
702
+ _terminal->SetCursorVisible (true );
703
+ _cursorTimer.value ().Start ();
704
+ }
705
+
706
+ return handled;
707
+ }
708
+
664
709
// Method Description:
665
710
// - handle a mouse click event. Begin selection process.
666
711
// Arguments:
0 commit comments