@@ -332,6 +332,13 @@ public static int CursorTop
332
332
}
333
333
}
334
334
335
+ /// <summary>
336
+ /// Tracks whether we've ever successfully received a response to a cursor position request (CPR).
337
+ /// If we have, then we can be more aggressive about expecting a response to subsequent requests,
338
+ /// e.g. using a longer timeout.
339
+ /// </summary>
340
+ private static bool s_everReceivedCursorPositionResponse ;
341
+
335
342
/// <summary>Gets the current cursor position. This involves both writing to stdout and reading stdin.</summary>
336
343
private static unsafe void GetCursorPosition ( out int left , out int top )
337
344
{
@@ -358,7 +365,15 @@ private static unsafe void GetCursorPosition(out int left, out int top)
358
365
// one thread's get_CursorLeft/Top from providing input to the other's Console.Read*.
359
366
lock ( StdInReader )
360
367
{
361
- Interop . Sys . InitializeConsoleBeforeRead ( minChars : 0 , decisecondsTimeout : 10 ) ;
368
+ // Because the CPR request/response protocol involves blocking until we get a certain
369
+ // response from the terminal, we want to avoid doing so if we don't know the terminal
370
+ // will definitely response. As such, we start with minChars == 0, which causes the
371
+ // terminal's read timer to start immediately. Once we've received a response for
372
+ // a request such that we know the terminal supports the protocol, we then specify
373
+ // minChars == 1. With that, the timer won't start until the first character is
374
+ // received. This makes the mechanism more reliable when there are high latencies
375
+ // involved in reading/writing, such as when accessing a remote system.
376
+ Interop . Sys . InitializeConsoleBeforeRead ( minChars : ( byte ) ( s_everReceivedCursorPositionResponse ? 1 : 0 ) , decisecondsTimeout : 10 ) ;
362
377
try
363
378
{
364
379
// Write out the cursor position report request.
@@ -425,6 +440,9 @@ private static unsafe void GetCursorPosition(out int left, out int top)
425
440
// else back into the StdInReader.
426
441
ReadRowOrCol ( bracketPos , semiPos , r , readBytes , ref top ) ;
427
442
ReadRowOrCol ( semiPos , rPos , r , readBytes , ref left ) ;
443
+
444
+ // Mark that we've successfully received a CPR response at least once.
445
+ s_everReceivedCursorPositionResponse = true ;
428
446
}
429
447
finally
430
448
{
0 commit comments