Let's assume the user has bound the dead key ^ to a sendInput command that sends "b". If the user presses the two keys ^a it'll produce "bâ", despite us marking the key event as handled. We can use `ToUnicodeEx` to clear such dead keys from the keyboard state and should make use of that for keybindings. Unfortunately `SetKeyboardState` cannot be used for this purpose as it doesn't clear the dead key state. Validation * Enabled a German keyboard layout * Added the following two keybindings: { "command": { "action": "sendInput", "input": "x" }, "keys": "q" }, { "command": { "action": "sendInput", "input": "b" }, "keys": "^" } * Pressed the following keys → ensured that the given text is printed: * q → x * ´ → nothing * a → á * ^ → b * a → a (previously this would print: â) * ´ → nothing * ^ → b * a → a (unfortunately we cannot specifically clear only ^) Closes #5784
This commit is contained in:
parent
1ad7a25cb2
commit
4099aacacb
|
@ -31,9 +31,11 @@ mbadolato
|
|||
Mehrain
|
||||
mgravell
|
||||
michaelniksa
|
||||
michkap
|
||||
migrie
|
||||
mikegr
|
||||
mikemaccana
|
||||
miloush
|
||||
miniksa
|
||||
niksa
|
||||
oising
|
||||
|
|
|
@ -895,7 +895,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
// keybindings on the keyUp, then we'll still send the keydown to the
|
||||
// connected terminal application, and something like ctrl+shift+T will
|
||||
// emit a ^T to the pipe.
|
||||
if (!modifiers.IsAltGrPressed() && keyDown && _TryHandleKeyBinding(vkey, modifiers))
|
||||
if (!modifiers.IsAltGrPressed() && keyDown && _TryHandleKeyBinding(vkey, scanCode, modifiers))
|
||||
{
|
||||
e.Handled(true);
|
||||
return;
|
||||
|
@ -917,8 +917,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
// - Attempt to handle this key combination as a key binding
|
||||
// Arguments:
|
||||
// - vkey: The vkey of the key pressed.
|
||||
// - scanCode: The scan code of the key pressed.
|
||||
// - modifiers: The ControlKeyStates representing the modifier key states.
|
||||
bool TermControl::_TryHandleKeyBinding(const WORD vkey, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const
|
||||
bool TermControl::_TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const
|
||||
{
|
||||
auto bindings = _settings.KeyBindings();
|
||||
if (!bindings)
|
||||
|
@ -926,12 +927,44 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
return false;
|
||||
}
|
||||
|
||||
return bindings.TryKeyChord({
|
||||
auto success = bindings.TryKeyChord({
|
||||
modifiers.IsCtrlPressed(),
|
||||
modifiers.IsAltPressed(),
|
||||
modifiers.IsShiftPressed(),
|
||||
vkey,
|
||||
});
|
||||
if (!success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let's assume the user has bound the dead key "^" to a sendInput command that sends "b".
|
||||
// If the user presses the two keys "^a" it'll produce "bâ", despite us marking the key event as handled.
|
||||
// The following is used to manually "consume" such dead keys and clear them from the keyboard state.
|
||||
_ClearKeyboardState(vkey, scanCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Discards currently pressed dead keys.
|
||||
// Arguments:
|
||||
// - vkey: The vkey of the key pressed.
|
||||
// - scanCode: The scan code of the key pressed.
|
||||
void TermControl::_ClearKeyboardState(const WORD vkey, const WORD scanCode) const noexcept
|
||||
{
|
||||
std::array<BYTE, 256> keyState;
|
||||
if (!GetKeyboardState(keyState.data()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// As described in "Sometimes you *want* to interfere with the keyboard's state buffer":
|
||||
// http://archives.miloush.net/michkap/archive/2006/09/10/748775.html
|
||||
// > "The key here is to keep trying to pass stuff to ToUnicode until -1 is not returned."
|
||||
std::array<wchar_t, 16> buffer;
|
||||
while (ToUnicodeEx(vkey, scanCode, keyState.data(), buffer.data(), gsl::narrow_cast<int>(buffer.size()), 0b1, nullptr) < 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -941,6 +974,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
// - Makes the cursor briefly visible during typing.
|
||||
// Arguments:
|
||||
// - vkey: The vkey of the key pressed.
|
||||
// - scanCode: The scan code of the key pressed.
|
||||
// - states: The Microsoft::Terminal::Core::ControlKeyStates representing the modifier key states.
|
||||
// - keyDown: If true, the key was pressed, otherwise the key was released.
|
||||
bool TermControl::_TrySendKeyEvent(const WORD vkey,
|
||||
|
|
|
@ -285,7 +285,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
|
||||
void _KeyHandler(Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e, const bool keyDown);
|
||||
::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() const;
|
||||
bool _TryHandleKeyBinding(const WORD vkey, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const;
|
||||
bool _TryHandleKeyBinding(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers) const;
|
||||
void _ClearKeyboardState(const WORD vkey, const WORD scanCode) const noexcept;
|
||||
bool _TrySendKeyEvent(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const bool keyDown);
|
||||
bool _TrySendMouseEvent(Windows::UI::Input::PointerPoint const& point);
|
||||
bool _CanSendVTMouseInput();
|
||||
|
|
Loading…
Reference in a new issue