Skip to content
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

Scrolling not handled correctly #14622

Closed
cnayoung opened this issue Jan 1, 2023 · 5 comments
Closed

Scrolling not handled correctly #14622

cnayoung opened this issue Jan 1, 2023 · 5 comments
Labels
Resolution-Duplicate There's another issue on the tracker that's pretty much the same thing.

Comments

@cnayoung
Copy link

cnayoung commented Jan 1, 2023

When a VT100 ‘r’ code is used to create a scroll region in the console window, as lines scroll off the top of the window, their content is lost and the displayed lines may be repeated and printed in an incorrect order. The same code works as expected in old command console, but the issue occurs in Windows Terminal from both PowerShell and Command Prompts.

To reproduce, I’ve create a basic C# console application. The code ensures that VT100 support is switched on (it is off by default when using the old command console). It sets the buffer height to an appropriate value. It then creates a status line in the last line of the console window and sets the rest of the window area as a scrollable region (ESC[0;28r). Then, having set the cursor to the top left of the window, it prints out 50 lines.

If the code is run under the old command console, all is well. When you scroll up, the lines that have scrolled off the screen are visible. However, the same code (compiled binary) does not work correctly under Windows Terminal. The output is garbled with some lines repeated, and displayed out of order. The behaviour of the code can be improved by adding a delay (100ms sleep) after each line is output. This slows the code down significantly, but the lines are at least output in the correct order. However, when you scroll up, the lines that have scrolled off the screen are empty.

NB., if you build a debug build under Visual Studio, it will probably run a bit better (less garbled) than a release build.

I’m using version 1.15.3466.0 of Windows Terminal on version 21H2 of Windows 11 Pro (22000.1335). I have not upgraded yet to 22H2 due to an unresolved boot issue under that version on my laptop. I have compiled the code under both .NET 6 and .NET 7.

Here is the source code:

using System.Runtime.InteropServices;
using static System.Console;

DoTest();

void DoTest()
{
    // Ensure that VT100 code support is enabled - Windows only.
    WindowsVt.Enable();

    BufferHeight = 60;
    SetCursorPosition(0,WindowHeight - 1);
    Write("This is a status line at the bottom of the console.");
    WriteLine($"\u001b[0;{Console.WindowHeight - 2}r");
    SetCursorPosition(0, 0);

    for (var i = 0; i < 50; i++)
    {
        WriteLine(i.ToString());
        //Thread.Sleep(100);  // Work around for Windows Terminal
    }

    ReadKey();
}

public static class WindowsVt {

    private const int STD_OUTPUT_HANDLE = -11;

    private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;

    private const uint DISABLE_NEWLINE_AUTO_RETURN = 0x0008;

    public static bool Enable() {
        var iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

        if (!GetConsoleMode(iStdOut, out var outConsoleMode)) {
            return false;
        }

        outConsoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;

        return SetConsoleMode(iStdOut, outConsoleMode);
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetConsoleMode(nint hConsoleHandle, out uint lpMode);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetConsoleMode(nint hConsoleHandle, uint dwMode);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern nint GetStdHandle(int nStdHandle);
}

ConsoleScrollingExample.zip

@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Jan 1, 2023
@j4james
Copy link
Collaborator

j4james commented Jan 1, 2023

Thanks for the detailed report. The scroll margin thing is a known problem (see issue #3673). We just don't have a way to propagate that state over the conpty connection at this point in time. In the long term it could be solved by the passthrough mode (#1173).

The output is garbled with some lines repeated, and displayed out of order

This bit I'm not so sure about. But if the BufferHeight = 60; statement is intended to resize the window, that could be the reason. We don't yet support resizing in Windows Terminal (that's tracked in issue #5094), so any console resize operation can leave the conpty buffer in a confused state, which might explain the corruption you're seeing.

@cnayoung
Copy link
Author

cnayoung commented Jan 2, 2023

Thanks. That's clear.

The BufferHeight property in the .NET Console class does not resize the window. It simply sets the buffer height, presumably using SetConsoleScreenBufferInfoEx() and the dwSize field in the CONSOLE_SCREEN_BUFFER_INFO_EX struct (on Windows).

There are separate properties for getting or setting the console window dimensions, and also a SetWindowSize() method for resizing the window, presumably using SetConsoleWindowInfo().

These properties and methods are very sensitive, of course, to the OS platform, and are only fully supported on Windows. Setting the BufferHeight property, for example (as used in the example code) is only supported on Windows, while getting the BufferHeight value is supported on Linux and FreeBSD, but not on iOS or Android.

@cnayoung
Copy link
Author

cnayoung commented Jan 2, 2023

...and just in case it's any use in the future, here are screen shots of the output from the code I attached. In both cases, I ran the code in a smaller window and then maximised it to show all the scrolled content. As you can see, the output in Windows Terminal is seriously corrupted, but improves with the Thread.Sleep() workaround.

Classic Command Console
ClassicCommandConsole

Windows Terminal (Release build without Thread.Sleep() workaround)
WindowsTerminal

Windows Terminal (Release build with Thread.Sleep() workaround)
WindowsTerminalWithWorkAround

With the workaround, the output is not corrupted, but also, you cannot scroll back up to see the empty lines.

@zadjii-msft
Copy link
Member

Thanks for the detailed writeup! I'd agree with the assesment that this seems to be a /dupe of #3673. Let's call it that until proven otherwise. Thanks!

@zadjii-msft zadjii-msft closed this as not planned Won't fix, can't repro, duplicate, stale Jan 3, 2023
@ghost
Copy link

ghost commented Jan 3, 2023

Hi! We've identified this issue as a duplicate of another one that already exists on this Issue Tracker. This specific instance is being closed in favor of tracking the concern over on the referenced thread. Thanks for your report!

@ghost ghost closed this as completed Jan 3, 2023
@ghost ghost added Resolution-Duplicate There's another issue on the tracker that's pretty much the same thing. and removed Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Jan 3, 2023
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution-Duplicate There's another issue on the tracker that's pretty much the same thing.
Projects
None yet
Development

No branches or pull requests

3 participants