Skip to content

Commit

Permalink
Switch to the I-beam cursor when hovering over the terminal
Browse files Browse the repository at this point in the history
This commit makes us use the I-beam cursor when the user hovers over the
terminal, *unless* mouse mode is enabled. I've also plumbed up a bunch
of events so that:

* If mouse mode is _toggled_ while hovering, the cursor will switch to
  the arrow if it's on or the I-beam if it's off.
* If you hold down shift to suppress mouse mode, the cursor will switch
  back to the I-beam.

Fixes #1441.
  • Loading branch information
DHowett committed Mar 20, 2020
1 parent 5672636 commit 0f38659
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 2 deletions.
83 changes: 82 additions & 1 deletion src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
_lastMouseClickPos{},
_searchBox{ nullptr },
_focusRaisedClickPos{ std::nullopt },
_clickDrag{ false }
_clickDrag{ false },
_textCursor{ Windows::UI::Core::CoreCursorType::IBeam, 0 },
_pointerCursor{ Windows::UI::Core::CoreCursorType::Arrow, 0 }
{
_EnsureStaticInitialization();
InitializeComponent();
Expand Down Expand Up @@ -589,6 +591,12 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation

auto inputFn = std::bind(&TermControl::_SendInputToConnection, this, std::placeholders::_1);
_terminal->SetWriteInputCallback(inputFn);
_terminal->SetMouseModeChangedCallback([weakThis = get_weak()]() {
if (auto strongThis{ weakThis.get() })
{
strongThis->_TerminalMouseModeChanged();
}
});

_SwapChainRoutine();

Expand Down Expand Up @@ -715,6 +723,11 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
e.OriginalKey() == VirtualKey::RightWindows)

{
if (!_closing && e.OriginalKey() == VirtualKey::Shift)
{
// If the user presses or releases shift, check whether we're in mouse mode and the cursor needs updating
_TerminalMouseModeChanged();
}
e.Handled(true);
return;
}
Expand Down Expand Up @@ -766,6 +779,23 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
e.Handled(handled);
}

void TermControl::_KeyUpHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/,
Input::KeyRoutedEventArgs const& e)
{
// If the current focused element is a child element of searchbox,
// we do not send this event up to terminal
if (_searchBox && _searchBox->ContainsFocus())
{
return;
}

if (!_closing && e.OriginalKey() == VirtualKey::Shift)
{
// If the user presses or releases shift, check whether we're in mouse mode and the cursor needs updating
_TerminalMouseModeChanged();
}
}

// Method Description:
// - Send this particular key event to the terminal.
// See Terminal::SendKeyEvent for more information.
Expand Down Expand Up @@ -889,6 +919,18 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
return _terminal->IsTrackingMouseInput();
}

// Method Description:
// - Handles changes in mouse mode state
winrt::fire_and_forget TermControl::_TerminalMouseModeChanged()
{
co_await Dispatcher();
if (_oldCursor) // if we have an active cursor transition
{
auto coreWindow = Window::Current().CoreWindow();
coreWindow.PointerCursor(_CanSendVTMouseInput() ? _pointerCursor : _textCursor);
}
}

// Method Description:
// - handle a mouse click event. Begin selection process.
// Arguments:
Expand Down Expand Up @@ -1150,6 +1192,45 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
args.Handled(true);
}

// Method Description:
// - Event handler for the PointerEntered event. We use this for cursor manipulation.
// Arguments:
// - sender: the XAML element responding to the pointer input
// - args: event data
void TermControl::_PointerEnteredHandler(Windows::Foundation::IInspectable const& /*sender*/,
Input::PointerRoutedEventArgs const& /*args*/)
{
if (_closing)
{
return;
}

auto coreWindow = Window::Current().CoreWindow();
_oldCursor = coreWindow.PointerCursor();

if (_terminal->IsTrackingMouseInput())
{
return;
}

coreWindow.PointerCursor(_textCursor);
}

// Method Description:
// - Event handler for the PointerExited event. We use this for cursor manipulation.
// Arguments:
// - sender: the XAML element responding to the pointer input
// - args: event data
void TermControl::_PointerExitedHandler(Windows::Foundation::IInspectable const& /*sender*/,
Input::PointerRoutedEventArgs const& /*args*/)
{
if (auto oldCursor{ std::exchange(_oldCursor, std::nullopt) })
{
auto coreWindow = Window::Current().CoreWindow();
coreWindow.PointerCursor(*oldCursor);
}
}

// Method Description:
// - Event handler for the PointerWheelChanged event. This is raised in
// response to mouse wheel changes. Depending upon what modifier keys are
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation

winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;

std::optional<winrt::Windows::UI::Core::CoreCursor> _oldCursor; // when we toggle the cursor, we have to save it here to restore it
winrt::Windows::UI::Core::CoreCursor _textCursor;
winrt::Windows::UI::Core::CoreCursor _pointerCursor;

void _ApplyUISettings();
void _InitializeBackgroundBrush();
winrt::fire_and_forget _BackgroundColorChanged(const uint32_t color);
Expand All @@ -172,10 +176,13 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
void _SetFontSize(int fontSize);
void _TappedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs const& e);
void _KeyDownHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
void _KeyUpHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e);
void _CharacterHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::CharacterReceivedRoutedEventArgs const& e);
void _PointerPressedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerMovedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerReleasedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerEnteredHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _PointerExitedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _MouseWheelHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
void _ScrollbarChangeHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
void _GotFocusHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
Expand Down Expand Up @@ -213,6 +220,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
bool _TrySendKeyEvent(const WORD vkey, const WORD scanCode, ::Microsoft::Terminal::Core::ControlKeyStates modifiers);
bool _TrySendMouseEvent(Windows::UI::Input::PointerPoint const& point);
bool _CanSendVTMouseInput();
winrt::fire_and_forget _TerminalMouseModeChanged();

const COORD _GetTerminalPosition(winrt::Windows::Foundation::Point cursorPosition);
const unsigned int _NumberOfClicks(winrt::Windows::Foundation::Point clickPos, Timestamp clickTime);
Expand Down
5 changes: 4 additions & 1 deletion src/cascadia/TerminalControl/TermControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
Tapped="_TappedHandler"
PointerWheelChanged="_MouseWheelHandler"
PreviewKeyDown="_KeyDownHandler"
KeyUp="_KeyUpHandler"
CharacterReceived="_CharacterHandler"
GotFocus="_GotFocusHandler"
LostFocus="_LostFocusHandler">
Expand All @@ -43,7 +44,9 @@
CompositionScaleChanged="_SwapChainScaleChanged"
PointerPressed="_PointerPressedHandler"
PointerMoved="_PointerMovedHandler"
PointerReleased="_PointerReleasedHandler" />
PointerReleased="_PointerReleasedHandler"
PointerEntered="_PointerEnteredHandler"
PointerExited="_PointerExitedHandler" />

<!-- Putting this in a grid w/ the SwapChainPanel
ensures that it's always aligned w/ the scrollbar -->
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,3 +788,7 @@ bool Terminal::IsCursorBlinkingAllowed() const noexcept
const auto& cursor = _buffer->GetCursor();
return cursor.IsBlinkingAllowed();
}

void Terminal::SetMouseModeChangedCallback(std::function<void()> mouseModeChangedCallback) {
_terminalInput->SetMouseModeChangedCallback(std::move(mouseModeChangedCallback));
}
1 change: 1 addition & 0 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class Microsoft::Terminal::Core::Terminal final :

void SetCursorOn(const bool isOn) noexcept;
bool IsCursorBlinkingAllowed() const noexcept;
void SetMouseModeChangedCallback(std::function<void()> mouseModeChangedCallback);

#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
Expand Down
24 changes: 24 additions & 0 deletions src/terminal/input/mouseInputState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ void TerminalInput::EnableDefaultTracking(const bool enable) noexcept
_mouseInputState.trackingMode = enable ? TrackingMode::Default : TrackingMode::None;
_mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
_mouseInputState.lastButton = 0;

if (_mouseModeChangedCallback)
{
_mouseModeChangedCallback();
}
}

// Routine Description:
Expand All @@ -63,6 +68,11 @@ void TerminalInput::EnableButtonEventTracking(const bool enable) noexcept
_mouseInputState.trackingMode = enable ? TrackingMode::ButtonEvent : TrackingMode::None;
_mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
_mouseInputState.lastButton = 0;

if (_mouseModeChangedCallback)
{
_mouseModeChangedCallback();
}
}

// Routine Description:
Expand All @@ -79,6 +89,11 @@ void TerminalInput::EnableAnyEventTracking(const bool enable) noexcept
_mouseInputState.trackingMode = enable ? TrackingMode::AnyEvent : TrackingMode::None;
_mouseInputState.lastPos = { -1, -1 }; // Clear out the last saved mouse position & button.
_mouseInputState.lastButton = 0;

if (_mouseModeChangedCallback)
{
_mouseModeChangedCallback();
}
}

// Routine Description:
Expand Down Expand Up @@ -113,3 +128,12 @@ void TerminalInput::UseMainScreenBuffer() noexcept
{
_mouseInputState.inAlternateBuffer = false;
}

// Routine Description:
// - Sets up the callback for mouse input mode changes
// Parameters:
// - mouseModeChangedCallback: the callback
void TerminalInput::SetMouseModeChangedCallback(std::function<void()> mouseModeChangedCallback)
{
_mouseModeChangedCallback = std::move(mouseModeChangedCallback);
}
3 changes: 3 additions & 0 deletions src/terminal/input/terminalInput.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ namespace Microsoft::Console::VirtualTerminal
void EnableAlternateScroll(const bool enable) noexcept;
void UseAlternateScreenBuffer() noexcept;
void UseMainScreenBuffer() noexcept;

void SetMouseModeChangedCallback(std::function<void()> mouseModeChangedCallback);
#pragma endregion

private:
std::function<void(std::deque<std::unique_ptr<IInputEvent>>&)> _pfnWriteEvents;
std::function<void()> _mouseModeChangedCallback;

// storage location for the leading surrogate of a utf-16 surrogate pair
std::optional<wchar_t> _leadingSurrogate;
Expand Down

0 comments on commit 0f38659

Please sign in to comment.