Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/System.Console/src/System/ConsolePal.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,13 @@ public static int CursorTop
}
}

/// <summary>
/// Tracks whether we've ever successfully received a response to a cursor position request (CPR).
/// If we have, then we can be more aggressive about expecting a response to subsequent requests,
/// e.g. using a longer timeout.
/// </summary>
private static bool s_everReceivedCursorPositionResponse;

/// <summary>Gets the current cursor position. This involves both writing to stdout and reading stdin.</summary>
private static unsafe void GetCursorPosition(out int left, out int top)
{
Expand All @@ -358,7 +365,15 @@ private static unsafe void GetCursorPosition(out int left, out int top)
// one thread's get_CursorLeft/Top from providing input to the other's Console.Read*.
lock (StdInReader)
{
Interop.Sys.InitializeConsoleBeforeRead(minChars: 0, decisecondsTimeout: 10);
// Because the CPR request/response protocol involves blocking until we get a certain
// response from the terminal, we want to avoid doing so if we don't know the terminal
// will definitely response. As such, we start with minChars == 0, which causes the
// terminal's read timer to start immediately. Once we've received a response for
// a request such that we know the terminal supports the protocol, we then specify
// minChars == 1. With that, the timer won't start until the first character is
// received. This makes the mechanism more reliable when there are high latencies
// involved in reading/writing, such as when accessing a remote system.
Interop.Sys.InitializeConsoleBeforeRead(minChars: (byte)(s_everReceivedCursorPositionResponse ? 1 : 0), decisecondsTimeout: 10);
try
{
// Write out the cursor position report request.
Expand Down Expand Up @@ -425,6 +440,9 @@ private static unsafe void GetCursorPosition(out int left, out int top)
// else back into the StdInReader.
ReadRowOrCol(bracketPos, semiPos, r, readBytes, ref top);
ReadRowOrCol(semiPos, rPos, r, readBytes, ref left);

// Mark that we've successfully received a CPR response at least once.
s_everReceivedCursorPositionResponse = true;
}
finally
{
Expand Down