terminal/src/host/directio.h
Dustin L. Howett cb037f3953
Switch all DSR responses to appending instead of prepending (#7583)
This fixes an issue where two CPRs could end up corrupted in the input
buffer. An application that sent two CPRs back-to-back could
end up reading the first few characters of the first prepended CPR
before handing us another CPR. We would dutifully prepend it to the
buffer, causing them to overlap.

```
^[^[2;2R[1;1R
^^      ^^^^^ First CPR
  ^^^^^^ Second CPR
```

The end result of this corruption is that a requesting application
would receive an unbidden `R` on stdin; for vim, this would trigger
replace mode immediately on startup.

Response prepending was implemented in !997738 without much comment.
There's very little in the way of audit trail as to why we switched.
Michael believes that we wanted to make sure that applications got DSR
responses immediately. It had the unfortunate side effect of causing
subsequence CPRs across cursor moves to come out in the wrong order.

I discussed our options with him, and he suggested that we could
implement a priority queue in InputBuffer and make sure that "response"
input was dispatched to a client application before any application- or
user-generated input. This was deemed to be too much work.

We decided that DSR responses getting top billing was likely to be a
stronger guarantee than most terminals are capable of giving, and that
we should be fine if we just switch it back to append.

Thanks to @k-takata, @tekki and @brammool for the investigation on the
vim side.

Fixes #1637.
2020-09-09 23:55:22 +00:00

36 lines
1.3 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- directio.h
Abstract:
- This file implements the NT console direct I/O API (read/write STDIO streams)
Author:
- KazuM Apr.19.1996
Revision History:
--*/
#pragma once
#include "conapi.h"
#include "inputBuffer.hpp"
class SCREEN_INFORMATION;
[[nodiscard]] HRESULT DoSrvPrivateWriteConsoleInputW(_Inout_ InputBuffer* const pInputBuffer,
_Inout_ std::deque<std::unique_ptr<IInputEvent>>& events,
_Out_ size_t& eventsWritten,
const bool append) noexcept;
[[nodiscard]] NTSTATUS ConsoleCreateScreenBuffer(std::unique_ptr<ConsoleHandleData>& handle,
_In_ PCONSOLE_API_MSG Message,
_In_ PCD_CREATE_OBJECT_INFORMATION Information,
_In_ PCONSOLE_CREATESCREENBUFFER_MSG a);
[[nodiscard]] NTSTATUS DoSrvPrivateWriteConsoleControlInput(_Inout_ InputBuffer* const pInputBuffer,
_In_ KeyEvent key);