Skip to content

Commit

Permalink
Add support for alternate scroll mode in Terminal (#12569)
Browse files Browse the repository at this point in the history
"Alternate scroll mode" is a neat little mode where the app wants mouse wheel events to come through as arrow keypresses instead, when in the alternate buffer. Now that we've got support for the alt buffer in the Terminal, we can support this as well.

* [x] Closes #3321
* [x] I work here
* [ ] Tests would be nice

Tested manually with

```bash
printf "\e[?1007h" ; man ps
```
  • Loading branch information
zadjii-msft authored Apr 12, 2022
1 parent 26d67d9 commit 9905192
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
return _terminal != nullptr && _terminal->IsTrackingMouseInput();
}
bool ControlCore::ShouldSendAlternateScroll(const unsigned int uiButton,
const int32_t delta) const
{
return _terminal != nullptr && _terminal->ShouldSendAlternateScroll(uiButton, delta);
}

Core::Point ControlCore::CursorPosition() const
{
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void CursorOn(const bool isCursorOn);

bool IsVtMouseModeEnabled() const;
bool ShouldSendAlternateScroll(const unsigned int uiButton, const int32_t delta) const;
Core::Point CursorPosition() const;

bool HasSelection() const;
Expand Down
21 changes: 19 additions & 2 deletions src/cascadia/TerminalControl/ControlInteractivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
const til::point terminalPosition = _getTerminalPosition(til::point{ pixelPosition });

// Short-circuit isReadOnly check to avoid warning dialog
if (!_core->IsInReadOnlyMode() && _canSendVTMouseInput(modifiers))
// Short-circuit isReadOnly check to avoid warning dialog.
//
// GH#3321: Alternate scroll mode is a special type of mouse input mode
// where the terminal sends arrow keys when the user mouse wheels, but
// the client app doesn't care for other mouse input. It's tracked
// separately from _canSendVTMouseInput.
if (!_core->IsInReadOnlyMode() &&
(_canSendVTMouseInput(modifiers) || _shouldSendAlternateScroll(modifiers, delta)))
{
// Most mouse event handlers call
// _trySendMouseEvent(point);
Expand Down Expand Up @@ -571,6 +577,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core->IsVtMouseModeEnabled();
}

bool ControlInteractivity::_shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta)
{
// If the user is holding down Shift, suppress mouse events
// TODO GH#4875: disable/customize this functionality
if (modifiers.IsShiftPressed())
{
return false;
}
return _core->ShouldSendAlternateScroll(WM_MOUSEWHEEL, delta);
}

// Method Description:
// - Sets selection's end position to match supplied cursor position, e.g. while mouse dragging.
// Arguments:
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/ControlInteractivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation

void _hyperlinkHandler(const std::wstring_view uri);
bool _canSendVTMouseInput(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
bool _shouldSendAlternateScroll(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers, const int32_t delta);

void _sendPastedTextToConnection(std::wstring_view wstr);
til::point _getTerminalPosition(const til::point pixelPosition);
Expand Down
14 changes: 14 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,20 @@ bool Terminal::IsTrackingMouseInput() const noexcept
return _terminalInput->IsTrackingMouseInput();
}

// Routine Description:
// - Relays if we are in alternate scroll mode, a special type of mouse input
// mode where scrolling sends the arrow keypresses, but the app doesn't
// otherwise want mouse input.
// Parameters:
// - <none>
// Return value:
// - true, if we are tracking mouse input. False, otherwise
bool Terminal::ShouldSendAlternateScroll(const unsigned int uiButton,
const int32_t delta) const noexcept
{
return _terminalInput->ShouldSendAlternateScroll(uiButton, ::base::saturated_cast<short>(delta));
}

// Method Description:
// - Given a coord, get the URI at that location
// Arguments:
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class Microsoft::Terminal::Core::Terminal final :

void TrySnapOnInput() override;
bool IsTrackingMouseInput() const noexcept;
bool ShouldSendAlternateScroll(const unsigned int uiButton, const int32_t delta) const noexcept;

std::wstring GetHyperlinkAtPosition(const COORD position);
uint16_t GetHyperlinkIdAtPosition(const COORD position);
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalCore/TerminalApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,10 @@ void Terminal::UseAlternateScreenBuffer()
// update all the hyperlinks on the screen
_updateUrlDetection();

// GH#3321: Make sure we let the TerminalInput know that we switched
// buffers. This might affect how we interpret certain mouse events.
_terminalInput->UseAlternateScreenBuffer();

// Update scrollbars
_NotifyScrollEvent();

Expand Down Expand Up @@ -674,6 +678,10 @@ void Terminal::UseMainScreenBuffer()
_mainBuffer->ClearPatternRecognizers();
_updateUrlDetection();

// GH#3321: Make sure we let the TerminalInput know that we switched
// buffers. This might affect how we interpret certain mouse events.
_terminalInput->UseMainScreenBuffer();

// Update scrollbars
_NotifyScrollEvent();

Expand Down
13 changes: 7 additions & 6 deletions src/terminal/input/mouseInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ bool TerminalInput::HandleMouse(const COORD position,
// on the wheel, accumulate delta until we hit the amount required to dispatch one
// "line" worth of scroll.
// Mark the event as "handled" if we would have otherwise emitted a scroll event.
return IsTrackingMouseInput() || _ShouldSendAlternateScroll(button, delta);
return IsTrackingMouseInput() || ShouldSendAlternateScroll(button, delta);
}

// We're ready to send this event through, but first we need to clear the accumulated;
Expand All @@ -330,7 +330,7 @@ bool TerminalInput::HandleMouse(const COORD position,
}

bool success = false;
if (_ShouldSendAlternateScroll(button, delta))
if (ShouldSendAlternateScroll(button, delta))
{
success = _SendAlternateScroll(delta);
}
Expand Down Expand Up @@ -539,11 +539,12 @@ std::wstring TerminalInput::_GenerateSGRSequence(const COORD position,
// - delta: The scroll wheel delta of the input event
// Return value:
// True iff the alternate buffer is active and alternate scroll mode is enabled and the event is a mouse wheel event.
bool TerminalInput::_ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept
bool TerminalInput::ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept
{
return _mouseInputState.inAlternateBuffer &&
_inputMode.test(Mode::AlternateScroll) &&
(button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0;
const bool inAltBuffer{ _mouseInputState.inAlternateBuffer };
const bool inAltScroll{ _inputMode.test(Mode::AlternateScroll) };
const bool wasMouseWheel{ (button == WM_MOUSEWHEEL || button == WM_MOUSEHWHEEL) && delta != 0 };
return inAltBuffer && inAltScroll && wasMouseWheel;
}

// Routine Description:
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/input/terminalInput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace Microsoft::Console::VirtualTerminal
const MouseButtonState state);

bool IsTrackingMouseInput() const noexcept;
bool ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
#pragma endregion

#pragma region MouseInputState Management
Expand Down Expand Up @@ -127,7 +128,6 @@ namespace Microsoft::Console::VirtualTerminal
const short modifierKeyState,
const short delta);

bool _ShouldSendAlternateScroll(const unsigned int button, const short delta) const noexcept;
bool _SendAlternateScroll(const short delta) const noexcept;

static constexpr unsigned int s_GetPressedButton(const MouseButtonState state) noexcept;
Expand Down

0 comments on commit 9905192

Please sign in to comment.