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

Switch to the I-beam cursor when hovering over the terminal #5028

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spell-check/whitelist/whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,7 @@ IAction
IApi
IApplication
IBase
IBeam
icacls
iccex
icch
Expand Down
83 changes: 82 additions & 1 deletion src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
_lastMouseClickTimestamp{},
_lastMouseClickPos{},
_selectionNeedsToBeCopied{ false },
_searchBox{ nullptr }
_searchBox{ nullptr },
_textCursor{ Windows::UI::Core::CoreCursorType::IBeam, 0 },
_pointerCursor{ Windows::UI::Core::CoreCursorType::Arrow, 0 }
{
_EnsureStaticInitialization();
InitializeComponent();
Expand Down Expand Up @@ -588,6 +590,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 @@ -714,6 +722,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 @@ -765,6 +778,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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably this bit would go away with #4748?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

{
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 @@ -888,6 +918,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();
DHowett-MSFT marked this conversation as resolved.
Show resolved Hide resolved
if (_oldCursor) // if we have an active cursor transition
{
auto coreWindow = Window::Current().CoreWindow();
coreWindow.PointerCursor(_CanSendVTMouseInput() ? _pointerCursor : _textCursor);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a helper method that's just "set the PointerCursor to the correct cursor for our current mouse input mode"?

}
}

// Method Description:
// - handle a mouse click event. Begin selection process.
// Arguments:
Expand Down Expand Up @@ -1147,6 +1189,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);
DHowett-MSFT marked this conversation as resolved.
Show resolved Hide resolved
}

// 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 @@ -167,6 +167,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;
Comment on lines +171 to +172
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Correct me if I'm wrong) It looks like you only set these in the constructor. Why not just make them constexpr in the namespace?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they're winrt objects. it sucks.


void _ApplyUISettings();
void _InitializeBackgroundBrush();
winrt::fire_and_forget _BackgroundColorChanged(const uint32_t color);
Expand All @@ -175,10 +179,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 @@ -216,6 +223,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
9 changes: 9 additions & 0 deletions src/cascadia/TerminalCore/Terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,3 +791,12 @@ bool Terminal::IsCursorBlinkingAllowed() const noexcept
const auto& cursor = _buffer->GetCursor();
return cursor.IsBlinkingAllowed();
}

// Routine Description:
// - Sets up the callback for mouse input mode changes
// Parameters:
// - mouseModeChangedCallback: the callback
void Terminal::SetMouseModeChangedCallback(std::function<void()> mouseModeChangedCallback) noexcept
{
_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) noexcept;

#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
Expand Down
36 changes: 36 additions & 0 deletions src/terminal/input/mouseInputState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ 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)
{
try
{
_mouseModeChangedCallback();
}
CATCH_LOG();
}
}

// Routine Description:
Expand All @@ -63,6 +72,15 @@ 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)
{
try
{
_mouseModeChangedCallback();
}
CATCH_LOG();
}
}

// Routine Description:
Expand All @@ -79,6 +97,15 @@ 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)
{
try
{
_mouseModeChangedCallback();
}
CATCH_LOG();
}
}

// Routine Description:
Expand Down Expand Up @@ -113,3 +140,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) noexcept
{
_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) noexcept;
#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