-
Notifications
You must be signed in to change notification settings - Fork 8.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace IInputEvent with INPUT_RECORD #15673
Replace IInputEvent with INPUT_RECORD #15673
Conversation
@@ -86,7 +86,6 @@ class KeyPressTests | |||
expectedRecord.Event.KeyEvent.uChar.UnicodeChar = 0x0; | |||
expectedRecord.Event.KeyEvent.bKeyDown = true; | |||
expectedRecord.Event.KeyEvent.dwControlKeyState = ENHANCED_KEY; | |||
expectedRecord.Event.KeyEvent.dwControlKeyState |= (GetKeyState(VK_NUMLOCK) & KEY_STATE_TOGGLED) ? NUMLOCK_ON : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was quite puzzling. On line 78 above we call TurnOffModifierKeys(hwnd)
and then assume that conhost still thinks that the numlock is set? This test should've always failed on every keyboard where numlock was on.
if (LOBYTE(zeroKey) == Event.Event.KeyEvent.wVirtualKeyCode && | ||
WI_IsAnyFlagSet(Event.Event.KeyEvent.dwControlKeyState, ALT_PRESSED) == WI_IsFlagSet(zeroKey, 0x400) && | ||
WI_IsAnyFlagSet(Event.Event.KeyEvent.dwControlKeyState, CTRL_PRESSED) == WI_IsFlagSet(zeroKey, 0x200) && | ||
WI_IsAnyFlagSet(Event.Event.KeyEvent.dwControlKeyState, SHIFT_PRESSED) == WI_IsFlagSet(zeroKey, 0x100)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what replaces the std::unordered_set
code. I've decided against using clever bitmasking or against converting dwControlKeyState
into a Win32 compatible bitset first, because I felt like writing it this way is easier to understand (and review). The constants at the end are kind of magic, but it should be easy to see how they correspond to the ALT_PRESSED, CTRL_PRESSED, SHIFT_PRESSED constants.
[[nodiscard]] friend constexpr small_vector_iterator operator+(const difference_type off, small_vector_iterator next) noexcept | ||
{ | ||
next += off; | ||
return next; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was missing. It's required for til::small_vector
to fulfill the Range
concept and be implicitly convertible to a std::span
.
@@ -166,64 +120,35 @@ std::deque<std::unique_ptr<KeyEvent>> Microsoft::Console::Interactivity::Synthes | |||
// alt + numpad | |||
// Note: | |||
// - will throw exception on error | |||
std::deque<std::unique_ptr<KeyEvent>> Microsoft::Console::Interactivity::SynthesizeNumpadEvents(const wchar_t wch, const unsigned int codepage) | |||
void Microsoft::Console::Interactivity::SynthesizeNumpadEvents(const wchar_t wch, const unsigned int codepage, InputEventQueue& keyEvents) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An out-parameter allows us to directly append to an existing buffer instead of returning a buffer and then appending that buffer to another buffer. This function is only called from a single place too (the clipboard handler).
80fcebc
to
42ac9b7
Compare
1caa29f
to
12038ca
Compare
@@ -45,9 +45,27 @@ | |||
</Expand> | |||
</Type> | |||
|
|||
<Type Name="KeyEvent"> | |||
<DisplayString Condition="_keyDown">{{↓ wch:{_charData} mod:{_activeModifierKeys} repeat:{_repeatCount} vk:{_virtualKeyCode} vsc:{_virtualScanCode}}</DisplayString> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i did think the arrows were clever... :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll restore the arrows before this merges. 🙂
12038ca
to
fcbbe08
Compare
@DHowett @zadjii-msft The PR is now ready. Despite the size, I feel like it's actually a surprisingly light read. 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
24/54, checkpoint
@@ -4,6 +4,7 @@ | |||
#include "precomp.h" | |||
#include "terminalInput.hpp" | |||
|
|||
#include "../types/inc/IInputEvent.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IInputEvent lives?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort of... It now contains helper functions to generate INPUT_RECORD
s. They all start with "Synthesize".
{ | ||
return MakeUnhandled(); | ||
} | ||
|
||
auto keyEvent = *static_cast<const KeyEvent* const>(pInEvent); | ||
auto keyEvent = event.Event.KeyEvent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm would we benefit from an auto&
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We modify the keyEvent
unfortunately to decoalesce the repeated key events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, I think I'm cool with this. I don't think any of my comments are blocking
src/terminal/input/terminalInput.cpp
Outdated
const bool ansiMode, | ||
const bool cursorApplicationMode, | ||
const bool keypadApplicationMode) noexcept | ||
{ | ||
if (ansiMode) | ||
{ | ||
if (keyEvent.IsCursorKey()) | ||
if (keyEvent.wVirtualKeyCode >= VK_END && keyEvent.wVirtualKeyCode <= VK_DOWN) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could probably use a comment - IsCursorKey
was definitely more informative
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I felt like it was fine given that the code inside the if condition mentions s_cursorKeysApplicationMapping
and s_cursorKeysNormalMapping
. I've got an idea how to improve it though! 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW I thought a little bit about how to construct the function "optimally" and I came up with this:
static std::span<const TermKeyMap> _getKeyMapping(const KEY_EVENT_RECORD& keyEvent, const bool ansiMode, const bool cursorApplicationMode, const bool keypadApplicationMode) noexcept
static constexpr uint8_t stage1[2][2][2][2]{
// ansiMode | cursorApplicationMode | keypadApplicationMode
0, 1, // f | f | f
0, 1, // f | f | true
0, 1, // f | true | f
0, 1, // f | true | true
2, 4, // true | f | f
3, 4, // true | f | true
2, 5, // true | true | f
3, 5, // true | true | true
};
static constexpr std::span<const TermKeyMap> stage2[]{
s_keypadVt52Mapping,
s_cursorKeysVt52Mapping,
s_keypadNumericMapping,
s_keypadApplicationMapping,
s_cursorKeysNormalMapping,
s_cursorKeysApplicationMapping,
};
// Cursor keys: VK_END, VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN
const auto isCursorKey = keyEvent.wVirtualKeyCode >= VK_END && keyEvent.wVirtualKeyCode <= VK_DOWN;
const auto idx = stage1[ansiMode][cursorApplicationMode][keypadApplicationMode][isCursorKey];
return stage2[idx];
}
Would that be too much / too confusing? I personally do like seeing that 2-3, 2-3 and 4-4, 5-5 symmetry, but that's a pretty strong matter of taste. 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I TOTALLY MISSED THIS
I LOVE IT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do this. I'm so excited to not be making individual 8-byte allocations ALL OVER THE PLACE and PASSING POINTERS AROUND.
Thank you for this necessary cleanup :D
@@ -63,9 +63,6 @@ | |||
<ClCompile Include="VtRendererTests.cpp"> | |||
<Filter>Source Files</Filter> | |||
</ClCompile> | |||
<Clcompile Include="..\..\types\IInputEventStreams.cpp"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
YIKES including a cpp file right out of another project lol
} | ||
|
||
return CodepointWidth::Narrow; | ||
return (0x1100 <= wch && wch <= 0x115f) || // From Unicode 9.0, Hangul Choseong is wide |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cute, this reformatting is much better
@@ -16,35 +12,29 @@ static constexpr WORD leftShiftScanCode = 0x2A; | |||
// Routine Description: | |||
// - naively determines the width of a UCS2 encoded wchar (with caveats noted above) | |||
#pragma warning(suppress : 4505) // this function will be deleted if numpad events are disabled | |||
static CodepointWidth GetQuickCharWidthLegacyForNumpadEventSynthesis(const wchar_t wch) noexcept | |||
static bool GetQuickCharWidthLegacyForNumpadEventSynthesis(const wchar_t wch) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i might recommend renaming this since it doesn't get a width any longer
const auto shiftSet = WI_IsFlagSet(modifierState, 1); | ||
const auto ctrlSet = WI_IsFlagSet(modifierState, 2); | ||
const auto altSet = WI_IsFlagSet(modifierState, 4); | ||
const auto altGrSet = WI_AreAllFlagsSet(modifierState, 4 | 2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
huh this doesn't care about left ctrl or right alt specifically. good to know!
|
||
// add modifier key up event | ||
// handle yucky alt-gr keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ha
IInputEvent
makes adding Unicode support toInputBuffer
moredifficult than necessary as the abstract class makes downcasting
as well as copying quite verbose. I found that using
INPUT_RECORD
sdirectly leads to a significantly simplified implementation.
In addition, this commit fixes at least one bug: The previous approach
to detect the null key via
DoActiveModifierKeysMatch
didn't work.As it compared the modifier keys as a bitset with
==
it failed tomatch whenever the numpad key was set, which it usually is.
Validation Steps Performed