Skip to content

Commit

Permalink
Horizontal snapping à la vim
Browse files Browse the repository at this point in the history
  • Loading branch information
lhecker committed Aug 5, 2024
1 parent 5174c96 commit 1ade14e
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/host/_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
writer.Submit();
}

screenInfo.SnapOnOutput();
return;
}

Expand Down Expand Up @@ -328,6 +329,8 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
{
writer.Submit();
}

screenInfo.SnapOnOutput();
}

// This is the main entrypoint for conhost to write VT to the buffer.
Expand Down Expand Up @@ -375,6 +378,8 @@ void WriteCharsVT(SCREEN_INFORMATION& screenInfo, const std::wstring_view& str)
write(offset, std::wstring_view::npos);
writer.Submit();
}

screenInfo.SnapOnOutput();
}

// Erases all contents of the given screenInfo, including the current screen and scrollback.
Expand Down
7 changes: 6 additions & 1 deletion src/host/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ bool ShouldTakeOverKeyboardShortcuts()
void HandleGenericKeyEvent(INPUT_RECORD event, const bool generateBreak)
{
auto& keyEvent = event.Event.KeyEvent;
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto ContinueProcessing = true;

if (WI_IsAnyFlagSet(keyEvent.dwControlKeyState, CTRL_PRESSED) &&
Expand Down Expand Up @@ -167,6 +167,11 @@ void HandleGenericKeyEvent(INPUT_RECORD event, const bool generateBreak)
keyEvent.bKeyDown = false;
gci.pInputBuffer->Write(event);
}

if (gci.HasActiveOutputBuffer())
{
gci.GetActiveOutputBuffer().SnapOnInput(keyEvent.wVirtualKeyCode);
}
}
}

Expand Down
86 changes: 66 additions & 20 deletions src/host/screenInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,39 +1669,85 @@ void SCREEN_INFORMATION::SetCursorDBMode(const bool DoubleCursor)
return STATUS_SUCCESS;
}

void SCREEN_INFORMATION::MakeCursorVisible(const til::point CursorPosition)
static constexpr bool IsInputKey(WORD vkey)
{
til::point WindowOrigin;
return vkey != VK_CONTROL &&
vkey != VK_LCONTROL &&
vkey != VK_RCONTROL &&
vkey != VK_MENU &&
vkey != VK_LMENU &&
vkey != VK_RMENU &&
vkey != VK_SHIFT &&
vkey != VK_LSHIFT &&
vkey != VK_RSHIFT &&
vkey != VK_LWIN &&
vkey != VK_RWIN &&
vkey != VK_SNAPSHOT;
}

if (CursorPosition.x > _viewport.RightInclusive())
{
WindowOrigin.x = CursorPosition.x - _viewport.RightInclusive();
}
else if (CursorPosition.x < _viewport.Left())
{
WindowOrigin.x = CursorPosition.x - _viewport.Left();
}
else
void SCREEN_INFORMATION::MakeCursorVisible(til::point position)
{
_makeLocationVisible(position, ViewportMovementMask::Vertical | ViewportMovementMask::Horizontal);
}

void SCREEN_INFORMATION::SnapOnInput(const WORD vkey)
{
if (IsInputKey(vkey))
{
WindowOrigin.x = 0;
_makeLocationVisible(_textBuffer->GetCursor().GetPosition(), ViewportMovementMask::Vertical);
}
}

if (CursorPosition.y > _viewport.BottomInclusive())
void SCREEN_INFORMATION::SnapOnOutput()
{
_makeLocationVisible(_textBuffer->GetCursor().GetPosition(), ViewportMovementMask::HorizontalCenter);
}

void SCREEN_INFORMATION::_makeLocationVisible(til::point position, ViewportMovementMask movements)
{
const auto viewportOrigin = _viewport.Origin();
const auto viewportSize = _viewport.Dimensions();
const auto bufferSize = _textBuffer->GetSize().Dimensions();
auto origin = viewportOrigin;

// Ensure the given position is in bounds.
position.x = std::clamp(position.x, 0, bufferSize.width - 1);
position.y = std::clamp(position.y, 0, bufferSize.height - 1);

if (WI_IsAnyFlagSet(movements, ViewportMovementMask::Vertical))
{
WindowOrigin.y = CursorPosition.y - _viewport.BottomInclusive();
origin.y = std::min(origin.y, position.y); // shift up if above
origin.y = std::max(origin.y, position.y - (viewportSize.height - 1)); // shift down if below
}
else if (CursorPosition.y < _viewport.Top())

if (WI_IsAnyFlagSet(movements, ViewportMovementMask::Horizontal))
{
WindowOrigin.y = CursorPosition.y - _viewport.Top();
origin.x = std::min(origin.x, position.x); // shift left if left
origin.x = std::max(origin.x, position.x - (viewportSize.width - 1)); // shift right if right
}
else

if (WI_IsAnyFlagSet(movements, ViewportMovementMask::HorizontalCenter))
{
WindowOrigin.y = 0;
// If the position is horizontally outside the viewport, snap the
// viewport to the nearest multiple of half the viewport width.
if (position.x < origin.x || position.x >= (origin.x + viewportSize.width))
{
const auto div = viewportSize.width / 2;
// We want our viewport to be centered around the position (= "half-width" offset).
// Since the origin is the left edge, we must subtract a half-width from the position.
origin.x = position.x - div;
// Round down to the nearest multiple of the viewport width.
// This also works if origin.x is negative, because the "modulo operator"
// is not a modulo operator, it's a remainder operator. The remainder of a
// negative number is negative and so origin.x cannot end up being less than 0.
origin.x -= origin.x % div;
origin.x = std::min(origin.x, bufferSize.width - viewportSize.width);
}
}

if (WindowOrigin.x != 0 || WindowOrigin.y != 0)
if (origin != viewportOrigin)
{
LOG_IF_FAILED(SetViewportOrigin(false, WindowOrigin, false));
std::ignore = SetViewportOrigin(true, origin, false);
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/host/screenInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ Revision History:
#include "../types/inc/Viewport.hpp"
class ConversionAreaInfo; // forward decl window. circular reference

enum class ViewportMovementMask
{
Vertical = 0x1,
Horizontal = 0x2,
HorizontalCenter = 0x4,
};
DEFINE_ENUM_FLAG_OPERATORS(ViewportMovementMask);

class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console::IIoProvider
{
public:
Expand All @@ -71,6 +79,9 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
void GetRequiredConsoleSizeInPixels(_Out_ til::size* const pRequiredSize) const;

void MakeCurrentCursorVisible();
void MakeCursorVisible(til::point position);
void SnapOnInput(WORD vkey);
void SnapOnOutput();

void ClipToScreenBuffer(_Inout_ til::inclusive_rect* const psrClip) const;

Expand Down Expand Up @@ -184,8 +195,6 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
void SetCursorDBMode(const bool DoubleCursor);
[[nodiscard]] NTSTATUS SetCursorPosition(const til::point Position, const bool TurnOn);

void MakeCursorVisible(const til::point CursorPosition);

[[nodiscard]] NTSTATUS UseAlternateScreenBuffer(const TextAttribute& initAttributes);
void UseMainScreenBuffer();

Expand Down Expand Up @@ -235,6 +244,7 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
void _CalculateViewportSize(const til::rect* const prcClientArea, _Out_ til::size* const pcoordSize);
void _AdjustViewportSize(const til::rect* const prcClientNew, const til::rect* const prcClientOld, const til::size* const pcoordSize);
void _InternalSetViewportSize(const til::size* pcoordSize, const bool fResizeFromTop, const bool fResizeFromLeft);
void _makeLocationVisible(til::point position, ViewportMovementMask movements);

static void s_CalculateScrollbarVisibility(const til::rect* const prcClientArea,
const til::size* const pcoordBufferSize,
Expand Down
5 changes: 5 additions & 0 deletions src/interactivity/win32/Clipboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ void Clipboard::StringPaste(_In_reads_(cchData) const wchar_t* const pData,
const auto bracketedPasteMode = gci.GetBracketedPasteMode();
auto inEvents = TextToKeyEvents(pData, cchData, vtInputMode && bracketedPasteMode);
gci.pInputBuffer->Write(inEvents);

if (gci.HasActiveOutputBuffer())
{
gci.GetActiveOutputBuffer().SnapOnInput(0);
}
}
catch (...)
{
Expand Down

0 comments on commit 1ade14e

Please sign in to comment.