Skip to content

Commit 5b44476

Browse files
authored
Replace IInputEvent with INPUT_RECORD (#15673)
`IInputEvent` makes adding Unicode support to `InputBuffer` more difficult than necessary as the abstract class makes downcasting as well as copying quite verbose. I found that using `INPUT_RECORD`s directly 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 to match whenever the numpad key was set, which it usually is. ## Validation Steps Performed * Unit and feature tests are ✅
1 parent e9c8391 commit 5b44476

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+786
-2278
lines changed

src/cascadia/TerminalControl/ControlCore.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
511511
// modifier key. We'll wait for a real keystroke to dismiss the
512512
// GH #7395 - don't update selection when taking PrintScreen
513513
// selection.
514-
return HasSelection() && !KeyEvent::IsModifierKey(vkey) && vkey != VK_SNAPSHOT;
514+
return HasSelection() && ::Microsoft::Terminal::Core::Terminal::IsInputKey(vkey);
515515
}
516516

517517
bool ControlCore::TryMarkModeKeybinding(const WORD vkey,

src/cascadia/TerminalCore/Terminal.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ bool Terminal::SendKeyEvent(const WORD vkey,
661661
// modifier key. We'll wait for a real keystroke to snap to the bottom.
662662
// GH#6481 - Additionally, make sure the key was actually pressed. This
663663
// check will make sure we behave the same as before GH#6309
664-
if (!KeyEvent::IsModifierKey(vkey) && keyDown)
664+
if (IsInputKey(vkey) && keyDown)
665665
{
666666
TrySnapOnInput();
667667
}
@@ -714,8 +714,8 @@ bool Terminal::SendKeyEvent(const WORD vkey,
714714
return false;
715715
}
716716

717-
const KeyEvent keyEv{ keyDown, 1, vkey, sc, ch, states.Value() };
718-
return _handleTerminalInputResult(_terminalInput.HandleKey(&keyEv));
717+
const auto keyEv = SynthesizeKeyEvent(keyDown, 1, vkey, sc, ch, states.Value());
718+
return _handleTerminalInputResult(_terminalInput.HandleKey(keyEv));
719719
}
720720

721721
// Method Description:
@@ -791,8 +791,8 @@ bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const Contro
791791
MarkOutputStart();
792792
}
793793

794-
const KeyEvent keyDown{ true, 1, vkey, scanCode, ch, states.Value() };
795-
return _handleTerminalInputResult(_terminalInput.HandleKey(&keyDown));
794+
const auto keyDown = SynthesizeKeyEvent(true, 1, vkey, scanCode, ch, states.Value());
795+
return _handleTerminalInputResult(_terminalInput.HandleKey(keyDown));
796796
}
797797

798798
// Method Description:

src/cascadia/TerminalCore/Terminal.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,22 @@ class Microsoft::Terminal::Core::Terminal final :
6060
using RenderSettings = Microsoft::Console::Render::RenderSettings;
6161

6262
public:
63+
static constexpr bool IsInputKey(WORD vkey)
64+
{
65+
return vkey != VK_CONTROL &&
66+
vkey != VK_LCONTROL &&
67+
vkey != VK_RCONTROL &&
68+
vkey != VK_MENU &&
69+
vkey != VK_LMENU &&
70+
vkey != VK_RMENU &&
71+
vkey != VK_SHIFT &&
72+
vkey != VK_LSHIFT &&
73+
vkey != VK_RSHIFT &&
74+
vkey != VK_LWIN &&
75+
vkey != VK_RWIN &&
76+
vkey != VK_SNAPSHOT;
77+
}
78+
6379
Terminal();
6480

6581
void Create(til::size viewportSize,

src/host/cmdline.h

+2
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,6 @@ void RedrawCommandLine(COOKED_READ_DATA& cookedReadData);
8787
bool IsWordDelim(const wchar_t wch);
8888
bool IsWordDelim(const std::wstring_view charData);
8989

90+
bool IsValidStringBuffer(_In_ bool Unicode, _In_reads_bytes_(Size) PVOID Buffer, _In_ ULONG Size, _In_ ULONG Count, ...);
91+
9092
void SetCurrentCommandLine(COOKED_READ_DATA& cookedReadData, _In_ CommandHistory::Index Index);

src/host/conimeinfo.cpp

+4-9
Original file line numberDiff line numberDiff line change
@@ -462,18 +462,13 @@ void ConsoleImeInfo::_InsertConvertedString(const std::wstring_view text)
462462
}
463463

464464
const auto dwControlKeyState = GetControlKeyState(0);
465-
std::deque<std::unique_ptr<IInputEvent>> inEvents;
466-
KeyEvent keyEvent{ TRUE, // keydown
467-
1, // repeatCount
468-
0, // virtualKeyCode
469-
0, // virtualScanCode
470-
0, // charData
471-
dwControlKeyState }; // activeModifierKeys
465+
InputEventQueue inEvents;
466+
auto keyEvent = SynthesizeKeyEvent(true, 1, 0, 0, 0, dwControlKeyState);
472467

473468
for (const auto& ch : text)
474469
{
475-
keyEvent.SetCharData(ch);
476-
inEvents.push_back(std::make_unique<KeyEvent>(keyEvent));
470+
keyEvent.Event.KeyEvent.uChar.UnicodeChar = ch;
471+
inEvents.push_back(keyEvent);
477472
}
478473

479474
gci.pInputBuffer->Write(inEvents);

src/host/directio.cpp

+6-9
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ using Microsoft::Console::Interactivity::ServiceLocator;
101101
// Return Value:
102102
// - HRESULT indicating success or failure
103103
[[nodiscard]] static HRESULT _WriteConsoleInputWImplHelper(InputBuffer& context,
104-
std::deque<std::unique_ptr<IInputEvent>>& events,
104+
const std::span<const INPUT_RECORD>& events,
105105
size_t& written,
106106
const bool append) noexcept
107107
{
@@ -151,7 +151,7 @@ try
151151
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
152152

153153
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
154-
til::small_vector<INPUT_RECORD, 16> events;
154+
InputEventQueue events;
155155

156156
auto it = buffer.begin();
157157
const auto end = buffer.end();
@@ -160,7 +160,7 @@ try
160160
// the next call to WriteConsoleInputAImpl to join it with the now available trailing DBCS.
161161
if (context.IsWritePartialByteSequenceAvailable())
162162
{
163-
auto lead = context.FetchWritePartialByteSequence(false)->ToInputRecord();
163+
auto lead = context.FetchWritePartialByteSequence();
164164
const auto& trail = *it;
165165

166166
if (trail.EventType == KEY_EVENT)
@@ -200,7 +200,7 @@ try
200200
if (it == end)
201201
{
202202
// Missing trailing DBCS -> Store the lead for the next call to WriteConsoleInputAImpl.
203-
context.StoreWritePartialByteSequence(IInputEvent::Create(lead));
203+
context.StoreWritePartialByteSequence(lead);
204204
break;
205205
}
206206

@@ -225,8 +225,7 @@ try
225225
}
226226
}
227227

228-
auto result = IInputEvent::Create(std::span{ events.data(), events.size() });
229-
return _WriteConsoleInputWImplHelper(context, result, written, append);
228+
return _WriteConsoleInputWImplHelper(context, events, written, append);
230229
}
231230
CATCH_RETURN();
232231

@@ -252,9 +251,7 @@ CATCH_RETURN();
252251

253252
try
254253
{
255-
auto events = IInputEvent::Create(buffer);
256-
257-
return _WriteConsoleInputWImplHelper(context, events, written, append);
254+
return _WriteConsoleInputWImplHelper(context, buffer, written, append);
258255
}
259256
CATCH_RETURN();
260257
}

src/host/ft_host/CJK_DbcsTests.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1919,11 +1919,11 @@ void DbcsTests::TestMultibyteInputCoalescing()
19191919

19201920
DWORD count;
19211921
{
1922-
const auto record = KeyEvent{ true, 1, 123, 456, 0x82, 789 }.ToInputRecord();
1922+
const auto record = SynthesizeKeyEvent(true, 1, 123, 456, 0x82, 789);
19231923
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInputA(in, &record, 1, &count));
19241924
}
19251925
{
1926-
const auto record = KeyEvent{ true, 1, 234, 567, 0xA2, 890 }.ToInputRecord();
1926+
const auto record = SynthesizeKeyEvent(true, 1, 234, 567, 0xA2, 890);
19271927
VERIFY_WIN32_BOOL_SUCCEEDED(WriteConsoleInputA(in, &record, 1, &count));
19281928
}
19291929

@@ -1933,7 +1933,7 @@ void DbcsTests::TestMultibyteInputCoalescing()
19331933
VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleInputW(in, &actual[0], 2, &count));
19341934
VERIFY_ARE_EQUAL(1u, count);
19351935

1936-
const auto expected = KeyEvent{ true, 1, 123, 456, L'', 789 }.ToInputRecord();
1936+
const auto expected = SynthesizeKeyEvent(true, 1, 123, 456, L'', 789);
19371937
VERIFY_ARE_EQUAL(expected, actual[0]);
19381938
}
19391939

src/host/ft_host/Message_KeyPressTests.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ class KeyPressTests
8686
expectedRecord.Event.KeyEvent.uChar.UnicodeChar = 0x0;
8787
expectedRecord.Event.KeyEvent.bKeyDown = true;
8888
expectedRecord.Event.KeyEvent.dwControlKeyState = ENHANCED_KEY;
89-
expectedRecord.Event.KeyEvent.dwControlKeyState |= (GetKeyState(VK_NUMLOCK) & KEY_STATE_TOGGLED) ? NUMLOCK_ON : 0;
9089
expectedRecord.Event.KeyEvent.wRepeatCount = SINGLE_KEY_REPEAT;
9190
expectedRecord.Event.KeyEvent.wVirtualKeyCode = VK_APPS;
9291
expectedRecord.Event.KeyEvent.wVirtualScanCode = (WORD)scanCode;

src/host/input.cpp

+16-23
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,18 @@ bool ShouldTakeOverKeyboardShortcuts()
105105

106106
// Routine Description:
107107
// - handles key events without reference to Win32 elements.
108-
void HandleGenericKeyEvent(_In_ KeyEvent keyEvent, const bool generateBreak)
108+
void HandleGenericKeyEvent(INPUT_RECORD event, const bool generateBreak)
109109
{
110+
auto& keyEvent = event.Event.KeyEvent;
110111
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
111112
auto ContinueProcessing = true;
112113

113-
if (keyEvent.IsCtrlPressed() &&
114-
!keyEvent.IsAltPressed() &&
115-
keyEvent.IsKeyDown())
114+
if (WI_IsAnyFlagSet(keyEvent.dwControlKeyState, CTRL_PRESSED) &&
115+
WI_AreAllFlagsClear(keyEvent.dwControlKeyState, ALT_PRESSED) &&
116+
keyEvent.bKeyDown)
116117
{
117118
// check for ctrl-c, if in line input mode.
118-
if (keyEvent.GetVirtualKeyCode() == 'C' && IsInProcessedInputMode())
119+
if (keyEvent.wVirtualKeyCode == 'C' && IsInProcessedInputMode())
119120
{
120121
HandleCtrlEvent(CTRL_C_EVENT);
121122
if (gci.PopupCount == 0)
@@ -130,7 +131,7 @@ void HandleGenericKeyEvent(_In_ KeyEvent keyEvent, const bool generateBreak)
130131
}
131132

132133
// Check for ctrl-break.
133-
else if (keyEvent.GetVirtualKeyCode() == VK_CANCEL)
134+
else if (keyEvent.wVirtualKeyCode == VK_CANCEL)
134135
{
135136
gci.pInputBuffer->Flush();
136137
HandleCtrlEvent(CTRL_BREAK_EVENT);
@@ -146,33 +147,25 @@ void HandleGenericKeyEvent(_In_ KeyEvent keyEvent, const bool generateBreak)
146147
}
147148

148149
// don't write ctrl-esc to the input buffer
149-
else if (keyEvent.GetVirtualKeyCode() == VK_ESCAPE)
150+
else if (keyEvent.wVirtualKeyCode == VK_ESCAPE)
150151
{
151152
ContinueProcessing = false;
152153
}
153154
}
154-
else if (keyEvent.IsAltPressed() &&
155-
keyEvent.IsKeyDown() &&
156-
keyEvent.GetVirtualKeyCode() == VK_ESCAPE)
155+
else if (WI_IsAnyFlagSet(keyEvent.dwControlKeyState, ALT_PRESSED) &&
156+
keyEvent.bKeyDown &&
157+
keyEvent.wVirtualKeyCode == VK_ESCAPE)
157158
{
158159
ContinueProcessing = false;
159160
}
160161

161162
if (ContinueProcessing)
162163
{
163-
size_t EventsWritten = 0;
164-
try
164+
gci.pInputBuffer->Write(event);
165+
if (generateBreak)
165166
{
166-
EventsWritten = gci.pInputBuffer->Write(std::make_unique<KeyEvent>(keyEvent));
167-
if (EventsWritten && generateBreak)
168-
{
169-
keyEvent.SetKeyDown(false);
170-
EventsWritten = gci.pInputBuffer->Write(std::make_unique<KeyEvent>(keyEvent));
171-
}
172-
}
173-
catch (...)
174-
{
175-
LOG_HR(wil::ResultFromCaughtException());
167+
keyEvent.bKeyDown = false;
168+
gci.pInputBuffer->Write(event);
176169
}
177170
}
178171
}
@@ -210,7 +203,7 @@ void HandleMenuEvent(const DWORD wParam)
210203
size_t EventsWritten = 0;
211204
try
212205
{
213-
EventsWritten = gci.pInputBuffer->Write(std::make_unique<MenuEvent>(wParam));
206+
EventsWritten = gci.pInputBuffer->Write(SynthesizeMenuEvent(wParam));
214207
if (EventsWritten != 1)
215208
{
216209
RIPMSG0(RIP_WARNING, "PutInputInBuffer: EventsWritten != 1, 1 expected");

src/host/input.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ bool ShouldTakeOverKeyboardShortcuts();
7878
void HandleMenuEvent(const DWORD wParam);
7979
void HandleFocusEvent(const BOOL fSetFocus);
8080
void HandleCtrlEvent(const DWORD EventType);
81-
void HandleGenericKeyEvent(_In_ KeyEvent keyEvent, const bool generateBreak);
81+
void HandleGenericKeyEvent(INPUT_RECORD event, const bool generateBreak);
8282

8383
void ProcessCtrlEvents();
8484

0 commit comments

Comments
 (0)