Fix click-drag selection on an unfocused Terminal (#4506)

## Summary of the Pull Request
This PR tries to address some of the weird interactions with pointer pressed events when the Terminal isn't in focus. Here's the four things that have changed as part of this PR;

1. This PR will allow the user to be able to make a selection with a click-drag without having to first perform a single click on a tab/pane to bring it to focus. 
2. Another weird bug that's fixed in this PR is where trying to make a selection on an unfocused tab when it already has a selection active will simply extend the existing selection instead of making a new one.
3. Not related to the issue that his PR closes: a right click will now focus the tab/pane.

I've made sure that we still have the existing functionality where a single click on an unfocused tab/pane does not make a single-cell selection and just focuses the tab/pane.

## PR Checklist
* [x] Closes #4282
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed

## Validation Steps Performed
Played around with all sorts of selection when in-focus and out of focus with multiple panes and tabs.
Unit tests still pass as well.
This commit is contained in:
Leon Liang 2020-02-12 16:32:50 -08:00 committed by GitHub
parent c05ad5dfb5
commit 7836da07dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 9 deletions

View file

@ -886,17 +886,20 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
const auto ptr = args.Pointer();
const auto point = args.GetCurrentPoint(_root);
if (!_focused)
{
Focus(FocusState::Pointer);
// Save the click position here when the terminal does not have focus
// because they might be performing a click-drag selection. Since we
// only want to start the selection when the user moves the pointer with
// the left mouse button held down, the PointerMovedHandler will use
// this saved position to set the SelectionAnchor.
_clickDragStartPos = point.Position();
}
if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Mouse || ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Pen)
{
// Ignore mouse events while the terminal does not have focus.
// This prevents the user from selecting and copying text if they
// click inside the current tab to refocus the terminal window.
if (!_focused)
{
args.Handled(true);
return;
}
const auto modifiers = static_cast<uint32_t>(args.KeyModifiers());
// static_cast to a uint32_t because we can't use the WI_IsFlagSet
// macro directly with a VirtualKeyModifiers
@ -905,6 +908,16 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
if (point.Properties().IsLeftButtonPressed())
{
// _clickDragStartPos having a value signifies to us that
// the user clicked on an unfocused terminal. We don't want
// a single left click from out of focus to start a selection,
// so we return fast here.
if (_clickDragStartPos)
{
args.Handled(true);
return;
}
const auto cursorPosition = point.Position();
const auto terminalPosition = _GetTerminalPosition(cursorPosition);
@ -981,6 +994,15 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
{
if (point.Properties().IsLeftButtonPressed())
{
// If this does not have a value, it means that PointerPressedHandler already
// set the SelectionAnchor. If it does have a value, that means the user is
// performing a click-drag selection on an unfocused terminal, so
// a SelectionAnchor isn't set yet. We'll have to set it here.
if (_clickDragStartPos)
{
_terminal->SetSelectionAnchor(_GetTerminalPosition(*_clickDragStartPos));
}
const auto cursorPosition = point.Position();
_SetEndSelectionPointAtCursor(cursorPosition);
@ -1053,6 +1075,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
const auto ptr = args.Pointer();
_clickDragStartPos = std::nullopt;
if (ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Mouse || ptr.PointerDeviceType() == Windows::Devices::Input::PointerDeviceType::Pen)
{
const auto modifiers = static_cast<uint32_t>(args.KeyModifiers());

View file

@ -162,6 +162,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
Timestamp _lastMouseClick;
unsigned int _multiClickCounter;
std::optional<winrt::Windows::Foundation::Point> _lastMouseClickPos;
std::optional<winrt::Windows::Foundation::Point> _clickDragStartPos{ std::nullopt };
// Event revokers -- we need to deregister ourselves before we die,
// lest we get callbacks afterwards.