Skip to content

Commit 6e9b537

Browse files
lheckerDHowett
authored andcommitted
Fixed Ctrl+Alt shortcuts conflicting with AltGr (#2235)
This moves the detection of AltGr keypresses in front of the shortcut handling. This allows one to have Ctrl+Alt shortcuts, while simultaneously being able to use the AltGr key for special characters. (cherry picked from commit 4529e46)
1 parent 2096fa5 commit 6e9b537

File tree

3 files changed

+64
-29
lines changed

3 files changed

+64
-29
lines changed

src/cascadia/TerminalControl/TermControl.cpp

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -619,35 +619,41 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
619619
}
620620

621621
const auto modifiers = _GetPressedModifierKeys();
622-
const auto vkey = static_cast<WORD>(e.OriginalKey());
623622

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());
624641
bool handled = false;
642+
625643
auto bindings = _settings.KeyBindings();
626644
if (bindings)
627645
{
628-
KeyChord chord(
646+
handled = bindings.TryKeyChord({
629647
modifiers.IsCtrlPressed(),
630648
modifiers.IsAltPressed(),
631649
modifiers.IsShiftPressed(),
632-
vkey);
633-
handled = bindings.TryKeyChord(chord);
650+
vkey,
651+
});
634652
}
635653

636654
if (!handled)
637655
{
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);
651657
}
652658

653659
// Manually prevent keyboard navigation with tab. We want to send tab to
@@ -661,6 +667,45 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
661667
e.Handled(handled);
662668
}
663669

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+
664709
// Method Description:
665710
// - handle a mouse click event. Begin selection process.
666711
// Arguments:

src/cascadia/TerminalControl/TermControl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
164164
static Windows::UI::Xaml::Thickness _ParseThicknessFromPadding(const hstring padding);
165165

166166
::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() const;
167+
void _HandleVoidKeyEvent();
168+
bool _TrySendKeyEvent(WORD vkey, ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
167169

168170
const COORD _GetTerminalPosition(winrt::Windows::Foundation::Point cursorPosition);
169171
const unsigned int _NumberOfClicks(winrt::Windows::Foundation::Point clickPos, Timestamp clickTime);

src/cascadia/TerminalCore/Terminal.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,6 @@ bool Terminal::SendKeyEvent(const WORD vkey, const ControlKeyStates states)
210210
_NotifyScrollEvent();
211211
}
212212

213-
// AltGr key combinations don't always contain any meaningful,
214-
// pretranslated unicode character during WM_KEYDOWN.
215-
// E.g. on a German keyboard AltGr+Q should result in a "@" character,
216-
// but actually results in "Q" with Alt and Ctrl modifier states.
217-
// By returning false though, we can abort handling this WM_KEYDOWN
218-
// event and let the WM_CHAR handler kick in, which will be
219-
// provided with an appropriate unicode character.
220-
if (states.IsAltGrPressed())
221-
{
222-
return false;
223-
}
224-
225213
// Alt key sequences _require_ the char to be in the keyevent. If alt is
226214
// pressed, manually get the character that's being typed, and put it in the
227215
// KeyEvent.

0 commit comments

Comments
 (0)