Skip to content

ScrollConsoleScreenBuffer API shouldn't be affected by DECSTBM margins #2659

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

Closed
j4james opened this issue Sep 4, 2019 · 0 comments
Closed
Labels
Area-VT Virtual Terminal sequence support Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Tag-Fix Doesn't match tag requirements Product-Conhost For issues in the Console codebase

Comments

@j4james
Copy link
Collaborator

j4james commented Sep 4, 2019

Environment

Windows build number: Version 10.0.18362.239

Steps to reproduce

Compile and run the following C++ code:

#include <windows.h>
#include <conio.h>
#include <stdio.h>

int main()
{
  HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

  // Enable support for VT esape sequences
  DWORD mode;
  GetConsoleMode(handle, &mode);
  mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
  SetConsoleMode(handle, mode);

  // Set the viewport and buffer size to 40 x 15
  SHORT width = 40;
  SHORT height = 15;
  SMALL_RECT viewRect = { 0, 0, width - 1, height - 1 };
  SetConsoleWindowInfo(handle, true, &viewRect);
  SetConsoleScreenBufferSize(handle, { width, height });
  SetConsoleWindowInfo(handle, true, &viewRect);

  // Write some content into the viewport
  for (SHORT y = 0; y < height; y++) {
    SetConsoleCursorPosition(handle, { 0, y });
    for (SHORT x = 0; x < width; x++)
      printf("%c", y+65);
  }

  // Set the DECSTBM margins to lines 6 to 10
  printf("\033[6;10r");

  // Set the scroll rectangle to the maximum size
  SMALL_RECT scrollRect = { 0, 0, 32767, 32767 };

  // Set the destination position 4 lines down
  COORD destPos{0, 4};

  // Set the clip rectangle to an area in the center
  SMALL_RECT clipRect = { 2, 2, 37, 12 };

  // Set the fill attributes
  CHAR_INFO fill;
  fill.Char.UnicodeChar = L' ';
  fill.Attributes = 0x4F;

  // Move the specified content down by 4 lines
  ScrollConsoleScreenBuffer(handle, &scrollRect, &clipRect, destPos, &fill);

  // Reset the DECSTBM margins
  printf("\033[r");

  // Wait for a keypress
  _getch();

  return 0;
}

Expected behavior

I'd expect the ScrollConsoleScreenBuffer to behave exactly as specified in the documentation. So the viewport content should be moved down by 4 lines, but only altering the area within the clipRect. I wouldn't expect the DECSTBM margins to have any affect on this operation.

Essentially the output should look like this:

image

Actual behavior

The vertical extent of the affected area seems to be determined by the DECSTBM margins rather than the clipRect, and the viewport content is actually moved up by 1 line instead of down by 4.

image

I could possibly imagine it was intentional for the DECSTBM margins to have an affect if it wasn't for the fact that the scroll direction was backwards. So I'm almost certain that this is not the intended behaviour.

As I mentioned in issue #2543, I think this is another argument in favor of removing the DECSTBM margin checking from the ScrollRegion function.

@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 Sep 4, 2019
@bitcrazed bitcrazed assigned bitcrazed and unassigned bitcrazed Sep 9, 2019
@bitcrazed bitcrazed added Area-VT Virtual Terminal sequence support Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal. Product-Conhost For issues in the Console codebase and removed Needs-Tag-Fix Doesn't match tag requirements Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Product-Terminal The new Windows Terminal. labels Sep 9, 2019
@bitcrazed bitcrazed added this to the Console Backlog milestone Sep 9, 2019
@ghost ghost added the Needs-Tag-Fix Doesn't match tag requirements label Sep 23, 2019
DHowett-MSFT pushed a commit that referenced this issue Sep 26, 2019
The `DECSTBM` margins are meant to define the range of lines within which
certain vertical scrolling operations take place. However, we were applying
these margin restrictions in the `ScrollRegion` function, which is also used in
a number of places that shouldn't be affected by `DECSTBM`.

This includes the `ICH` and `DCH` escape sequences (which are only affected by
the horizontal margins, which we don't yet support), the
`ScrollConsoleScreenBuffer` API (which is public Console API, not meant to be
affected by the VT terminal emulation), and the `CSI 3 J` erase scrollback
extension (which isn't really scrolling as such, but uses the `ScrollRegion`
function to manipulate the scrollback buffer).

This commit moves the margin clipping out of the `ScrollRegion` function, so it
can be applied exclusively in the places that need it.

With the margin clipping removed from the `ScrollRegion` function, it now had
to be applied manually in the places it was actually required. This included:

* The `DoSrvPrivateReverseLineFeed` function (for the `RI` control): This was
* just a matter of updating the bottom of the scroll rect to the bottom margin
* (at least when the margins were actually set), since the top of the scroll
* rect would always be the top of the viewport.  The
* `DoSrvPrivateModifyLinesImpl` function (for the `IL` and `DL` commands):
* Again this was just a matter of updating the bottom of the scroll rect, since
* the cursor position would always determine the top of the scroll rect.  The
* `AdaptDispatch::_ScrollMovement` method (for the `SU` and `SD` commands):
* This required updating both the top and bottom coordinates of the scroll
* rect, and also a simpler destination Y coordinate (the way the `ScrollRegion`
* function worked before, the caller was expected to take the margins into
* account when determining the destination).

On the plus side, there was now no longer a need to override the margins when
calling `ScrollRegion` in the `AdjustCursorPosition` function. In the first
case, the margins had needed to be cleared (_stream.cpp 143-145), but that is
now the default behaviour. In the second case, there had been a more
complicated adjustment of the margins (_stream.cpp 196-209), but that code was
never actually used so could be removed completely (to get to that point either
_fScrollUp_ was true, so _scrollDownAtTop_ couldn't also be true, or
_fScrollDown_ was true, but in that case there is a check to make sure
_scrollDownAtTop_ is false).

While testing, I also noticed that one of the `ScrollRegion` calls in the
`AdjustCursorPosition` function was not setting the horizontal range correctly
- the scrolling should always affect the full buffer width rather than just the
  viewport width - so I've fixed that now as well.

## Validation Steps Performed

For commands like `RI`, `IL`, `DL`, etc. where we've changed the implementation
but not the behaviour, there were already unit tests that could confirm that
the new implementation was still producing the correct results.

Where there has been a change in behaviour - namely for the `ICH` and `DCH`
commands, and the `ScrollConsoleScreenBuffer` API - I've extended the existing
unit tests to check that they still function correctly even when the `DECSTBM`
margins are set (which would previously have caused them to fail).

I've also tested manually with the test cases in issues #2543 and #2659, and
confirmed that they now work as expected.

Closes #2543
Closes #2659

(cherry picked from commit 0c8a4df)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-VT Virtual Terminal sequence support Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Tag-Fix Doesn't match tag requirements Product-Conhost For issues in the Console codebase
Projects
None yet
Development

No branches or pull requests

2 participants