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

Tunnel F7 keypresses directly into special handlers in TermControl #4807

Merged
3 commits merged into from
Mar 5, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 35 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,41 @@ namespace winrt::TerminalApp::implementation
}
}

// Method Description:
// - Implements the F7 handler (per GH#638)
// Return value:
// - whether F7 was handled
bool AppLogic::OnF7Pressed()
{
if (_root)
{
// Manually bubble the OnF7Pressed event up through the focus tree.
auto xamlRoot{ _root->XamlRoot() };
auto focusedObject{ Windows::UI::Xaml::Input::FocusManager::GetFocusedElement(xamlRoot) };
do
{
if (auto f7Listener{ focusedObject.try_as<IF7Listener>() })
{
if (f7Listener.OnF7Pressed())
{
return true;
}
// otherwise, keep walking. bubble the event manually.
}

if (auto focusedElement{ focusedObject.try_as<Windows::UI::Xaml::FrameworkElement>() })
{
focusedObject = focusedElement.Parent();
}
else
{
break; // we hit a non-FE object, stop bubbling.
}
} while (focusedObject);
}
return false;
}

// Method Description:
// - Used to tell the app that the 'X' button has been clicked and
// the user wants to close the app. We kick off the close warning
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/AppLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace winrt::TerminalApp::implementation

hstring Title();
void TitlebarClicked();
bool OnF7Pressed();

void WindowCloseButtonClicked();

Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/TerminalApp/AppLogic.idl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import "../TerminalPage.idl";
import "../ShortcutActionDispatch.idl";
import "../IF7Listener.idl";

namespace TerminalApp
{
Expand All @@ -12,7 +13,7 @@ namespace TerminalApp
MaximizedMode,
};

[default_interface] runtimeclass AppLogic {
[default_interface] runtimeclass AppLogic: IF7Listener {
AppLogic();

// For your own sanity, it's better to do setup outside the ctor.
Expand Down
16 changes: 16 additions & 0 deletions src/cascadia/TerminalApp/IF7Listener.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

namespace TerminalApp
{
// C++/winrt makes it difficult to share this idl between two projects,
// Instead, we just pin the uuid and include it in both TermControl and App
// If you update this one, please update the one in TerminalControl\TermControl.idl
// If you change this interface, please update the guid.
// If you press F7 and get a runtime error, go make sure both copies are the same.
[uuid("339e1a87-5315-4da6-96f0-565549b6472b")]
interface IF7Listener
DHowett-MSFT marked this conversation as resolved.
Show resolved Hide resolved
{
Boolean OnF7Pressed();
DHowett-MSFT marked this conversation as resolved.
Show resolved Hide resolved
}
}
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/lib/TerminalAppLib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
<ItemGroup>
<!-- If you add idl files here, make sure to include their implementation's
header in TerminalApp.vcxproj (as well as in this file) -->
<Midl Include="../IF7Listener.idl" />
<Midl Include="../App.idl">
<DependentUpon>../App.xaml</DependentUpon>
</Midl>
Expand Down
32 changes: 32 additions & 0 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,38 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
e.Handled(handled);
}

// Method Description:
// - Manually generate an F7 event into the key bindings or terminal.
// This is required as part of GH#638.
// Return value:
// - Whether F7 was handled.
bool TermControl::OnF7Pressed()
{
bool handled{ false };
auto bindings{ _settings.KeyBindings() };

const auto modifiers{ _GetPressedModifierKeys() };

if (bindings)
{
handled = bindings.TryKeyChord({
modifiers.IsCtrlPressed(),
modifiers.IsAltPressed(),
modifiers.IsShiftPressed(),
VK_F7,
});
}

if (!handled)
{
// _TrySendKeyEvent pretends it didn't handle F7 for some unknown reason.
(void)_TrySendKeyEvent(VK_F7, 0, modifiers);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
handled = true;
}

return handled;
}

void TermControl::_KeyDownHandler(winrt::Windows::Foundation::IInspectable const& /*sender*/,
Input::KeyRoutedEventArgs const& e)
{
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalControl/TermControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation

void CreateSearchBoxControl();

bool OnF7Pressed();

~TermControl();

Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
Expand Down
13 changes: 12 additions & 1 deletion src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ namespace Microsoft.Terminal.TerminalControl
delegate void FontSizeChangedEventArgs(Int32 width, Int32 height, Boolean isInitialChange);
delegate void ScrollPositionChangedEventArgs(Int32 viewTop, Int32 viewHeight, Int32 bufferLength);

// C++/winrt makes it difficult to share this idl between two projects,
// Instead, we just pin the uuid and include it in both TermControl and App
// If you update this one, please update TerminalApp\IF7Listener.idl.
// If you change this interface, please update the guid.
// If you press F7 and get a runtime error, go make sure both copies are the same.
[uuid("339e1a87-5315-4da6-96f0-565549b6472b")]
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
interface IF7Listener
{
Boolean OnF7Pressed();
}

runtimeclass CopyToClipboardEventArgs
{
String Text { get; };
Expand All @@ -19,7 +30,7 @@ namespace Microsoft.Terminal.TerminalControl
void HandleClipboardData(String data);
}

[default_interface] runtimeclass TermControl : Windows.UI.Xaml.Controls.UserControl
[default_interface] runtimeclass TermControl : Windows.UI.Xaml.Controls.UserControl, IF7Listener
{
TermControl();
TermControl(Microsoft.Terminal.Settings.IControlSettings settings, Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
Expand Down
9 changes: 9 additions & 0 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ AppHost::~AppHost()
_app = nullptr;
}

bool AppHost::OnF7Pressed()
{
if (_logic)
{
return _logic.OnF7Pressed();
}
return false;
}

// Method Description:
// - Retrieve any commandline args passed on the commandline, and pass them to
// the app logic for processing.
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/WindowsTerminal/AppHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AppHost
void AppTitleChanged(const winrt::Windows::Foundation::IInspectable& sender, winrt::hstring newTitle);
void LastTabClosed(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::LastTabClosedEventArgs& args);
void Initialize();
bool OnF7Pressed();

private:
bool _useNonClientArea;
Expand Down
22 changes: 22 additions & 0 deletions src/cascadia/WindowsTerminal/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ static void EnsureNativeArchitecture()
}
}

static bool _messageIsF7Keypress(const MSG& message)
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
return (message.message == WM_KEYDOWN || message.message == WM_SYSKEYDOWN) && message.wParam == VK_F7;
}

int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
TraceLoggingRegister(g_hWindowsTerminalProvider);
Expand Down Expand Up @@ -115,6 +120,23 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)

while (GetMessage(&message, nullptr, 0, 0))
{
// GH#638 (Pressing F7 brings up both the history AND a caret browsing message)
// The Xaml input stack doesn't allow an application to suppress the "caret browsing"
// dialog experience triggered when you press F7. Official recommendation from the Xaml
// team is to catch F7 before we hand it off.
// AppLogic contains an ad-hoc implementation of event bubbling for a runtime classes
// implementing a custom IF7Listener interface.
// If the recipient of IF7Listener::OnF7Pressed suggests that the F7 press has, in fact,
// been handled we can discard the message before we even translate it.
if (_messageIsF7Keypress(message))
{
if (host.OnF7Pressed())
{
// The application consumed the F7. Don't let Xaml get it.
continue;
}
}

TranslateMessage(&message);
DispatchMessage(&message);
}
Expand Down