terminal/src/cascadia/TerminalApp/TabHeaderControl.cpp
Mike Griese 24f80bd9ba
Don't yeet focus to the control when the tab renamer is opened (#10114)
This is a hotfix to #10048. When the tab renamer is opened, we need to make sure to not immediately steal focus from it.

* [x] closes #10112
* [x] I work here
* [x] tested manually
2021-05-18 18:48:57 +00:00

139 lines
5.6 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "TabHeaderControl.h"
#include "TabHeaderControl.g.cpp"
using namespace winrt;
using namespace winrt::Microsoft::UI::Xaml;
namespace winrt::TerminalApp::implementation
{
TabHeaderControl::TabHeaderControl()
{
InitializeComponent();
// We'll only process the KeyUp event if we received an initial KeyDown event first.
// Avoids issue immediately closing the tab rename when we see the enter KeyUp event that was
// sent to the command palette to trigger the openTabRenamer action in the first place.
HeaderRenamerTextBox().KeyDown([&](auto&&, auto&& e) {
_receivedKeyDown = true;
// GH#9632 - mark navigation buttons as handled.
// This should prevent the tab view to use this key for navigation between tabs
if (e.OriginalKey() == Windows::System::VirtualKey::Down ||
e.OriginalKey() == Windows::System::VirtualKey::Up ||
e.OriginalKey() == Windows::System::VirtualKey::Left ||
e.OriginalKey() == Windows::System::VirtualKey::Right)
{
e.Handled(true);
}
});
// NOTE: (Preview)KeyDown does not work here. If you use that, we'll
// remove the TextBox from the UI tree, then the following KeyUp
// will bubble to the NewTabButton, which we don't want to have
// happen.
HeaderRenamerTextBox().KeyUp([&](auto&&, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e) {
if (_receivedKeyDown)
{
if (e.OriginalKey() == Windows::System::VirtualKey::Enter)
{
// User is done making changes, close the rename box
_CloseRenameBox();
}
else if (e.OriginalKey() == Windows::System::VirtualKey::Escape)
{
// User wants to discard the changes they made,
// set _renameCancelled to true and close the rename box
_renameCancelled = true;
_CloseRenameBox();
}
}
});
}
// Method Description:
// - Returns true if we're in the middle of a tab rename. This is used to
// mitigate GH#10112.
// Arguments:
// - <none>
// Return Value:
// - true if the renamer is open.
bool TabHeaderControl::InRename()
{
return Windows::UI::Xaml::Visibility::Visible == HeaderRenamerTextBox().Visibility();
}
// Method Description:
// - Show the tab rename box for the user to rename the tab title
// - We automatically use the previous title as the initial text of the box
void TabHeaderControl::BeginRename()
{
_receivedKeyDown = false;
_renameCancelled = false;
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Visible);
HeaderRenamerTextBox().Text(Title());
HeaderRenamerTextBox().SelectAll();
HeaderRenamerTextBox().Focus(Windows::UI::Xaml::FocusState::Programmatic);
TraceLoggingWrite(
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
"TabRenamerOpened",
TraceLoggingDescription("Event emitted when the tab renamer is opened"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
// Method Description:
// - Event handler for when the rename box loses focus
// - When the rename box loses focus, we send a request for the title change depending
// on whether the rename was cancelled
void TabHeaderControl::RenameBoxLostFocusHandler(Windows::Foundation::IInspectable const& /*sender*/,
Windows::UI::Xaml::RoutedEventArgs const& /*e*/)
{
// If the context menu associated with the renamer text box is open we know it gained the focus.
// In this case we ignore this event (we will regain the focus once the menu will be closed).
const auto flyout = HeaderRenamerTextBox().ContextFlyout();
if (flyout && flyout.IsOpen())
{
return;
}
// Log the data here, rather than in _CloseRenameBox. If we do it there,
// it'll get fired twice, once when the key is pressed to commit/cancel,
// and then again when the focus is lost
TraceLoggingWrite(
g_hTerminalAppProvider, // handle to TerminalApp tracelogging provider
"TabRenamerClosed",
TraceLoggingDescription("Event emitted when the tab renamer is closed"),
TraceLoggingBoolean(_renameCancelled, "CancelledRename", "True if the user cancelled the rename, false if they committed."),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
_CloseRenameBox();
if (!_renameCancelled)
{
_TitleChangeRequestedHandlers(HeaderRenamerTextBox().Text());
}
}
// Method Description:
// - Hides the rename box and displays the title text block
void TabHeaderControl::_CloseRenameBox()
{
if (HeaderRenamerTextBox().Visibility() == Windows::UI::Xaml::Visibility::Visible)
{
HeaderRenamerTextBox().Visibility(Windows::UI::Xaml::Visibility::Collapsed);
HeaderTextBlock().Visibility(Windows::UI::Xaml::Visibility::Visible);
_RenameEndedHandlers(*this, nullptr);
}
}
}