Pass <Alt> to the application (#6461)
For mysterious reasons lost to the sands of time, XAML will _never_ pass us a VK_MENU event. This is something that'll probably get fixed in WinUI 3, but considering we're stuck on system XAML for the time being, the only way to work around this bug is to pass the event through manually. This change generalizes the F7 handler into a "direct key event" handler that uses the same focus and tunneling method to send different key events, and then uses it to send VK_MENU. ## Validation Steps Performed Opened the debug tap, verified that I was seeing alt key ups. Also used some alt keybindings to make sure I didn't break them. Closes #6421
This commit is contained in:
parent
827cc42a45
commit
e8ece1645c
|
@ -12,6 +12,7 @@ IBind
|
|||
IClass
|
||||
IComparable
|
||||
ICustom
|
||||
IDirect
|
||||
IExplorer
|
||||
IMap
|
||||
IObject
|
||||
|
|
|
@ -906,20 +906,21 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
// Method Description:
|
||||
// - Implements the F7 handler (per GH#638)
|
||||
// - Implements the Alt handler (per GH#6421)
|
||||
// Return value:
|
||||
// - whether F7 was handled
|
||||
bool AppLogic::OnF7Pressed()
|
||||
// - whether the key was handled
|
||||
bool AppLogic::OnDirectKeyEvent(const uint32_t vkey, const bool down)
|
||||
{
|
||||
if (_root)
|
||||
{
|
||||
// Manually bubble the OnF7Pressed event up through the focus tree.
|
||||
// Manually bubble the OnDirectKeyEvent 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 (auto keyListener{ focusedObject.try_as<IDirectKeyListener>() })
|
||||
{
|
||||
if (f7Listener.OnF7Pressed())
|
||||
if (keyListener.OnDirectKeyEvent(vkey, down))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
hstring Title();
|
||||
void TitlebarClicked();
|
||||
bool OnF7Pressed();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const bool down);
|
||||
|
||||
void WindowCloseButtonClicked();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import "../TerminalPage.idl";
|
||||
import "../ShortcutActionDispatch.idl";
|
||||
import "../IF7Listener.idl";
|
||||
import "../IDirectKeyListener.idl";
|
||||
|
||||
namespace TerminalApp
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace TerminalApp
|
|||
FullscreenMode,
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass AppLogic : IF7Listener
|
||||
[default_interface] runtimeclass AppLogic : IDirectKeyListener
|
||||
{
|
||||
AppLogic();
|
||||
|
||||
|
|
|
@ -7,10 +7,8 @@ namespace TerminalApp
|
|||
// 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
|
||||
{
|
||||
Boolean OnF7Pressed();
|
||||
// If you press F7 or Alt and get a runtime error, go make sure both copies are the same.
|
||||
[uuid("339e1a87-5315-4da6-96f0-565549b6472b")] interface IDirectKeyListener {
|
||||
Boolean OnDirectKeyEvent(UInt32 vkey, Boolean down);
|
||||
}
|
||||
}
|
|
@ -201,7 +201,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="../IDirectKeyListener.idl" />
|
||||
<Midl Include="../App.idl">
|
||||
<DependentUpon>../App.xaml</DependentUpon>
|
||||
</Midl>
|
||||
|
|
|
@ -683,36 +683,46 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
}
|
||||
|
||||
// Method Description:
|
||||
// - Manually generate an F7 event into the key bindings or terminal.
|
||||
// This is required as part of GH#638.
|
||||
// - Manually handles key events for certain keys that can't be passed to us
|
||||
// normally. Namely, the keys we're concerned with are F7 down and Alt up.
|
||||
// Return value:
|
||||
// - Whether F7 was handled.
|
||||
bool TermControl::OnF7Pressed()
|
||||
// - Whether the key was handled.
|
||||
bool TermControl::OnDirectKeyEvent(const uint32_t vkey, const bool down)
|
||||
{
|
||||
bool handled{ false };
|
||||
auto bindings{ _settings.KeyBindings() };
|
||||
|
||||
const auto modifiers{ _GetPressedModifierKeys() };
|
||||
|
||||
if (bindings)
|
||||
auto handled = false;
|
||||
if (vkey == VK_MENU && !down)
|
||||
{
|
||||
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, true);
|
||||
// GH#6438: Note that we're _not_ sending the key up here - that'll
|
||||
// get passed through XAML to our KeyUp handler normally.
|
||||
// Manually generate an Alt KeyUp event into the key bindings or terminal.
|
||||
// This is required as part of GH#6421.
|
||||
(void)_TrySendKeyEvent(VK_MENU, 0, modifiers, false);
|
||||
handled = true;
|
||||
}
|
||||
else if (vkey == VK_F7 && down)
|
||||
{
|
||||
// Manually generate an F7 event into the key bindings or terminal.
|
||||
// This is required as part of GH#638.
|
||||
auto bindings{ _settings.KeyBindings() };
|
||||
|
||||
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, true);
|
||||
// GH#6438: Note that we're _not_ sending the key up here - that'll
|
||||
// get passed through XAML to our KeyUp handler normally.
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
|
|||
|
||||
void CreateSearchBoxControl();
|
||||
|
||||
bool OnF7Pressed();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const bool down);
|
||||
|
||||
bool OnMouseWheel(const Windows::Foundation::Point location, const int32_t delta);
|
||||
|
||||
|
|
|
@ -11,13 +11,11 @@ namespace Microsoft.Terminal.TerminalControl
|
|||
|
||||
// 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 update this one, please update TerminalApp\IDirectKeyListener.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
|
||||
{
|
||||
Boolean OnF7Pressed();
|
||||
// If you press F7 or Alt and get a runtime error, go make sure both copies are the same.
|
||||
[uuid("339e1a87-5315-4da6-96f0-565549b6472b")] interface IDirectKeyListener {
|
||||
Boolean OnDirectKeyEvent(UInt32 vkey, Boolean down);
|
||||
}
|
||||
|
||||
runtimeclass CopyToClipboardEventArgs
|
||||
|
@ -32,7 +30,7 @@ namespace Microsoft.Terminal.TerminalControl
|
|||
void HandleClipboardData(String data);
|
||||
}
|
||||
|
||||
[default_interface] runtimeclass TermControl : Windows.UI.Xaml.Controls.UserControl, IF7Listener, IMouseWheelListener
|
||||
[default_interface] runtimeclass TermControl : Windows.UI.Xaml.Controls.UserControl, IDirectKeyListener, IMouseWheelListener
|
||||
{
|
||||
TermControl();
|
||||
TermControl(Microsoft.Terminal.Settings.IControlSettings settings, Microsoft.Terminal.TerminalConnection.ITerminalConnection connection);
|
||||
|
|
|
@ -63,11 +63,11 @@ AppHost::~AppHost()
|
|||
_app = nullptr;
|
||||
}
|
||||
|
||||
bool AppHost::OnF7Pressed()
|
||||
bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const bool down)
|
||||
{
|
||||
if (_logic)
|
||||
{
|
||||
return _logic.OnF7Pressed();
|
||||
return _logic.OnDirectKeyEvent(vkey, down);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
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();
|
||||
bool OnDirectKeyEvent(const uint32_t vkey, const bool down);
|
||||
|
||||
private:
|
||||
bool _useNonClientArea;
|
||||
|
|
|
@ -77,6 +77,10 @@ static bool _messageIsF7Keypress(const MSG& message)
|
|||
{
|
||||
return (message.message == WM_KEYDOWN || message.message == WM_SYSKEYDOWN) && message.wParam == VK_F7;
|
||||
}
|
||||
static bool _messageIsAltKeyup(const MSG& message)
|
||||
{
|
||||
return (message.message == WM_KEYUP || message.message == WM_SYSKEYUP) && message.wParam == VK_MENU;
|
||||
}
|
||||
|
||||
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
|
@ -137,13 +141,26 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
|
|||
// been handled we can discard the message before we even translate it.
|
||||
if (_messageIsF7Keypress(message))
|
||||
{
|
||||
if (host.OnF7Pressed())
|
||||
if (host.OnDirectKeyEvent(VK_F7, true))
|
||||
{
|
||||
// The application consumed the F7. Don't let Xaml get it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// GH#6421 - System XAML will never send an Alt KeyUp event. So, similar
|
||||
// to how we'll steal the F7 KeyDown above, we'll steal the Alt KeyUp
|
||||
// here, and plumb it through.
|
||||
if (_messageIsAltKeyup(message))
|
||||
{
|
||||
// Let's pass <Alt> to the application
|
||||
if (host.OnDirectKeyEvent(VK_MENU, false))
|
||||
{
|
||||
// The application consumed the Alt. Don't let Xaml get it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
TranslateMessage(&message);
|
||||
DispatchMessage(&message);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue