first round of actions

This commit is contained in:
Pankaj Bhojwani 2025-08-12 11:09:45 -07:00
parent a285f8ac28
commit d264f2b7f1
5 changed files with 169 additions and 71 deletions

View File

@ -42,6 +42,17 @@ namespace winrt::TerminalApp::implementation
}
return _GetActiveControl();
}
TermControl TerminalPage::_senderOrFocusedElementIfControl(const IInspectable& sender)
{
if (sender)
{
if (auto arg{ sender.try_as<TermControl>() })
{
return arg;
}
}
return _GetFocusedElementIfControl();
}
winrt::com_ptr<TerminalTab> TerminalPage::_senderOrFocusedTab(const IInspectable& sender)
{
if (sender)
@ -134,10 +145,13 @@ namespace winrt::TerminalApp::implementation
const ActionEventArgs& args)
{
const auto& realArgs = args.ActionArgs().try_as<ScrollUpArgs>();
if (realArgs)
if (const auto termControl = _GetFocusedElementIfControl())
{
_Scroll(ScrollUp, realArgs.RowsToScroll());
args.Handled(true);
if (realArgs)
{
_Scroll(ScrollUp, realArgs.RowsToScroll(), termControl);
args.Handled(true);
}
}
}
@ -145,10 +159,13 @@ namespace winrt::TerminalApp::implementation
const ActionEventArgs& args)
{
const auto& realArgs = args.ActionArgs().try_as<ScrollDownArgs>();
if (realArgs)
if (const auto termControl = _GetFocusedElementIfControl())
{
_Scroll(ScrollDown, realArgs.RowsToScroll());
args.Handled(true);
if (realArgs)
{
_Scroll(ScrollDown, realArgs.RowsToScroll(), termControl);
args.Handled(true);
}
}
}
@ -174,7 +191,7 @@ namespace winrt::TerminalApp::implementation
}
}
void TerminalPage::_HandleSendInput(const IInspectable& sender,
void TerminalPage::_HandleSendInput(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (args == nullptr)
@ -183,7 +200,7 @@ namespace winrt::TerminalApp::implementation
}
else if (const auto& realArgs = args.ActionArgs().try_as<SendInputArgs>())
{
if (const auto termControl{ _senderOrActiveControl(sender) })
if (const auto termControl = _GetFocusedElementIfControl())
{
termControl.SendInput(realArgs.Input());
args.Handled(true);
@ -353,29 +370,41 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleScrollUpPage(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_ScrollPage(ScrollUp);
args.Handled(true);
if (const auto termControl = _GetFocusedElementIfControl())
{
_ScrollPage(ScrollUp, termControl);
args.Handled(true);
}
}
void TerminalPage::_HandleScrollDownPage(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_ScrollPage(ScrollDown);
args.Handled(true);
if (const auto termControl = _GetFocusedElementIfControl())
{
_ScrollPage(ScrollDown, termControl);
args.Handled(true);
}
}
void TerminalPage::_HandleScrollToTop(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_ScrollToBufferEdge(ScrollUp);
args.Handled(true);
if (const auto termControl = _GetFocusedElementIfControl())
{
_ScrollToBufferEdge(ScrollUp, termControl);
args.Handled(true);
}
}
void TerminalPage::_HandleScrollToBottom(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_ScrollToBufferEdge(ScrollDown);
args.Handled(true);
if (const auto termControl = _GetFocusedElementIfControl())
{
_ScrollToBufferEdge(ScrollDown, termControl);
args.Handled(true);
}
}
void TerminalPage::_HandleScrollToMark(const IInspectable& /*sender*/,
@ -430,11 +459,11 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleFindMatch(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& realArgs = args.ActionArgs().try_as<FindMatchArgs>())
if (const auto termControl = _GetFocusedElementIfControl())
{
if (const auto& control{ _GetActiveControl() })
if (const auto& realArgs = args.ActionArgs().try_as<FindMatchArgs>())
{
control.SearchMatch(realArgs.Direction() == FindMatchDirection::Next);
termControl.SearchMatch(realArgs.Direction() == FindMatchDirection::Next);
args.Handled(true);
}
}
@ -452,8 +481,11 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandlePasteText(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_PasteText();
args.Handled(true);
if (_GetFocusedElementIfControl())
{
_PasteText();
args.Handled(true);
}
}
void TerminalPage::_HandleNewTab(const IInspectable& /*sender*/,
@ -547,10 +579,13 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleCopyText(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& realArgs = args.ActionArgs().try_as<CopyTextArgs>())
if (const auto termControl = _GetFocusedElementIfControl())
{
const auto handled = _CopyText(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), realArgs.CopyFormatting());
args.Handled(handled);
if (const auto& realArgs = args.ActionArgs().try_as<CopyTextArgs>())
{
const auto handled = termControl.CopySelectionToClipboard(realArgs.DismissSelection(), realArgs.SingleLine(), realArgs.WithControlSequences(), realArgs.CopyFormatting());
args.Handled(handled);
}
}
}
@ -1112,7 +1147,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleSearchForText(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto termControl{ _GetActiveControl() })
if (const auto termControl = _GetFocusedElementIfControl())
{
if (termControl.HasSelection())
{
@ -1152,7 +1187,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleOpenCWD(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto control = _GetFocusedElementIfControl())
{
control.OpenCWD();
args.Handled(true);
@ -1286,7 +1321,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleSelectAll(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _senderOrActiveControl(sender) })
if (const auto control = _senderOrFocusedElementIfControl(sender))
{
control.SelectAll();
args.Handled(true);
@ -1308,7 +1343,7 @@ namespace winrt::TerminalApp::implementation
auto commandLine = realArgs.Commandline();
if (commandLine.empty())
{
if (const auto termControl{ _GetActiveControl() })
if (const auto termControl = _GetFocusedElementIfControl())
{
if (termControl.HasSelection())
{
@ -1432,7 +1467,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleMarkMode(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _senderOrActiveControl(sender) })
if (const auto control = _senderOrFocusedElementIfControl(sender))
{
control.ToggleMarkMode();
args.Handled(true);
@ -1442,7 +1477,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleToggleBlockSelection(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _senderOrActiveControl(sender) })
if (const auto control = _senderOrFocusedElementIfControl(sender))
{
const auto handled = control.ToggleBlockSelection();
args.Handled(handled);
@ -1452,7 +1487,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleSwitchSelectionEndpoint(const IInspectable& sender,
const ActionEventArgs& args)
{
if (const auto& control{ _senderOrActiveControl(sender) })
if (const auto control = _senderOrFocusedElementIfControl(sender))
{
const auto handled = control.SwitchSelectionEndpoint();
args.Handled(handled);
@ -1486,7 +1521,7 @@ namespace winrt::TerminalApp::implementation
// then get that here.
const bool shouldGetContext = realArgs.UseCommandline() ||
WI_IsAnyFlagSet(source, SuggestionsSource::CommandHistory | SuggestionsSource::QuickFixes);
if (const auto& control{ _GetActiveControl() })
if (const auto control = _GetFocusedElementIfControl())
{
currentWorkingDirectory = control.CurrentWorkingDirectory();
@ -1543,7 +1578,7 @@ namespace winrt::TerminalApp::implementation
co_await wil::resume_foreground(Dispatcher());
// Open the palette with all these commands in it.
_OpenSuggestions(_GetActiveControl(),
_OpenSuggestions(_GetFocusedElementIfControl(),
winrt::single_threaded_vector<Command>(std::move(commandsCollection)),
SuggestionsMode::Palette,
currentCommandline);
@ -1567,7 +1602,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleExpandSelectionToWord(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto control = _GetFocusedElementIfControl())
{
const auto handled = control.ExpandSelectionToWord();
args.Handled(handled);
@ -1601,7 +1636,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleShowContextMenu(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
if (const auto& control{ _GetActiveControl() })
if (const auto control = _GetFocusedElementIfControl())
{
control.ShowContextMenu();
}

View File

@ -1722,6 +1722,72 @@ namespace winrt::TerminalApp::implementation
e.Handled(true);
}
void TerminalPage::_PreviewKeyDown(const Windows::Foundation::IInspectable& /*sender*/, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e)
{
const auto keyStatus = e.KeyStatus();
const auto vkey = gsl::narrow_cast<WORD>(e.OriginalKey());
const auto scanCode = gsl::narrow_cast<WORD>(keyStatus.ScanCode);
const auto modifiers = _GetPressedModifierKeys();
// GH#11076:
// For some weird reason we sometimes receive a WM_KEYDOWN
// message without vkey or scanCode if a user drags a tab.
// The KeyChord constructor has a debug assertion ensuring that all KeyChord
// either have a valid vkey/scanCode. This is important, because this prevents
// accidental insertion of invalid KeyChords into classes like ActionMap.
if (!vkey && !scanCode)
{
return;
}
// Alt-Numpad# input will send us a character once the user releases
// Alt, so we should be ignoring the individual keydowns. The character
// will be sent through the TSFInputControl. See GH#1401 for more
// details
if (modifiers.IsAltPressed() && (vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9))
{
return;
}
// GH#2235: Terminal::Settings hasn't been modified to differentiate
// between AltGr and Ctrl+Alt yet.
// -> Don't check for key bindings if this is an AltGr key combination.
if (modifiers.IsAltGrPressed())
{
return;
}
const auto actionMap = _settings.ActionMap();
if (!actionMap)
{
return;
}
const auto cmd = actionMap.GetActionByKeyChord({
modifiers.IsCtrlPressed(),
modifiers.IsAltPressed(),
modifiers.IsShiftPressed(),
modifiers.IsWinPressed(),
vkey,
scanCode,
});
if (!cmd)
{
return;
}
if (!_actionDispatch->DoAction(cmd.ActionAndArgs()))
{
return;
}
// Let's assume the user has bound the dead key "^" to a sendInput command that sends "b".
// If the user presses the two keys "^a" it'll produce "bâ", despite us marking the key event as handled.
// The following is used to manually "consume" such dead keys and clear them from the keyboard state.
_ClearKeyboardState(vkey, scanCode);
e.Handled(true);
}
bool TerminalPage::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down)
{
const auto modifiers = _GetPressedModifierKeys();
@ -2053,6 +2119,16 @@ namespace winrt::TerminalApp::implementation
return nullptr;
}
TermControl TerminalPage::_GetFocusedElementIfControl()
{
const auto focusedElement = Windows::UI::Xaml::Input::FocusManager::GetFocusedElement(this->XamlRoot());
if (const auto termControl = focusedElement.try_as<TermControl>())
{
return termControl;
}
return nullptr;
}
CommandPalette TerminalPage::LoadCommandPalette()
{
if (const auto p = CommandPaletteElement())
@ -2248,16 +2324,16 @@ namespace winrt::TerminalApp::implementation
// Arguments:
// - scrollDirection: ScrollUp will move the viewport up, ScrollDown will move the viewport down
// - rowsToScroll: a number of lines to move the viewport. If not provided we will use a system default.
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll)
void TerminalPage::_Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll, winrt::Microsoft::Terminal::Control::TermControl focusedControl)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (focusedControl)
{
uint32_t realRowsToScroll;
if (rowsToScroll == nullptr)
{
// The magic value of WHEEL_PAGESCROLL indicates that we need to scroll the entire page
realRowsToScroll = _systemRowsToScroll == WHEEL_PAGESCROLL ?
terminalTab->GetActiveTerminalControl().ViewHeight() :
focusedControl.ViewHeight() :
_systemRowsToScroll;
}
else
@ -2266,7 +2342,8 @@ namespace winrt::TerminalApp::implementation
realRowsToScroll = rowsToScroll.Value();
}
auto scrollDelta = _ComputeScrollDelta(scrollDirection, realRowsToScroll);
terminalTab->Scroll(scrollDelta);
const auto currentOffset = focusedControl.ScrollOffset();
focusedControl.ScrollViewport(::base::ClampAdd(currentOffset, scrollDelta));
}
}
@ -2692,26 +2769,25 @@ namespace winrt::TerminalApp::implementation
// down a page. The page length will be dependent on the terminal view height.
// Arguments:
// - scrollDirection: ScrollUp will move the viewport up, ScrollDown will move the viewport down
void TerminalPage::_ScrollPage(ScrollDirection scrollDirection)
void TerminalPage::_ScrollPage(ScrollDirection scrollDirection, winrt::Microsoft::Terminal::Control::TermControl focusedControl)
{
// Do nothing if for some reason, there's no terminal tab in focus. We don't want to crash.
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (focusedControl)
{
if (const auto& control{ _GetActiveControl() })
{
const auto termHeight = control.ViewHeight();
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
terminalTab->Scroll(scrollDelta);
}
const auto termHeight = focusedControl.ViewHeight();
auto scrollDelta = _ComputeScrollDelta(scrollDirection, termHeight);
const auto currentOffset = focusedControl.ScrollOffset();
focusedControl.ScrollViewport(::base::ClampAdd(currentOffset, scrollDelta));
}
}
void TerminalPage::_ScrollToBufferEdge(ScrollDirection scrollDirection)
void TerminalPage::_ScrollToBufferEdge(ScrollDirection scrollDirection, winrt::Microsoft::Terminal::Control::TermControl focusedControl)
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
if (focusedControl)
{
auto scrollDelta = _ComputeScrollDelta(scrollDirection, INT_MAX);
terminalTab->Scroll(scrollDelta);
const auto currentOffset = focusedControl.ScrollOffset();
focusedControl.ScrollViewport(::base::ClampAdd(currentOffset, scrollDelta));
}
}

View File

@ -326,6 +326,7 @@ namespace winrt::TerminalApp::implementation
void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _KeyDownHandler(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
void _PreviewKeyDown(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::KeyRoutedEventArgs& e);
static ::Microsoft::Terminal::Core::ControlKeyStates _GetPressedModifierKeys() noexcept;
static void _ClearKeyboardState(const WORD vkey, const WORD scanCode) noexcept;
void _HookupKeyBindings(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap) noexcept;
@ -383,6 +384,7 @@ namespace winrt::TerminalApp::implementation
}
winrt::Microsoft::Terminal::Control::TermControl _GetActiveControl();
winrt::Microsoft::Terminal::Control::TermControl _GetFocusedElementIfControl();
std::optional<uint32_t> _GetFocusedTabIndex() const noexcept;
std::optional<uint32_t> _GetTabIndex(const TerminalApp::TabBase& tab) const noexcept;
TerminalApp::TabBase _GetFocusedTab() const noexcept;
@ -396,7 +398,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::Foundation::IAsyncOperation<bool> _PaneConfirmCloseReadOnly(std::shared_ptr<Pane> pane);
void _AddPreviouslyClosedPaneOrTab(std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>&& args);
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll);
void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference<uint32_t>& rowsToScroll, winrt::Microsoft::Terminal::Control::TermControl focusedControl);
void _SplitPane(const winrt::com_ptr<TerminalTab>& tab,
const Microsoft::Terminal::Settings::Model::SplitDirection splitType,
@ -405,8 +407,8 @@ namespace winrt::TerminalApp::implementation
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ToggleSplitOrientation();
void _ScrollPage(ScrollDirection scrollDirection);
void _ScrollToBufferEdge(ScrollDirection scrollDirection);
void _ScrollPage(ScrollDirection scrollDirection, winrt::Microsoft::Terminal::Control::TermControl focusedControl);
void _ScrollToBufferEdge(ScrollDirection scrollDirection, winrt::Microsoft::Terminal::Control::TermControl focusedControl);
void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::Control::KeyChord& keyChord);
safe_void_coroutine _PasteFromClipboardHandler(const IInspectable sender,
@ -553,6 +555,7 @@ namespace winrt::TerminalApp::implementation
winrt::Windows::UI::Xaml::Controls::MenuFlyout _CreateRunAsAdminFlyout(int profileIndex);
winrt::Microsoft::Terminal::Control::TermControl _senderOrActiveControl(const winrt::Windows::Foundation::IInspectable& sender);
winrt::Microsoft::Terminal::Control::TermControl _senderOrFocusedElementIfControl(const winrt::Windows::Foundation::IInspectable& sender);
winrt::com_ptr<TerminalTab> _senderOrFocusedTab(const IInspectable& sender);
void _loadQueryExtension();

View File

@ -14,7 +14,8 @@
mc:Ignorable="d">
<Grid x:Name="Root"
Background="Transparent">
Background="Transparent"
PreviewKeyDown="_PreviewKeyDown">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
@ -170,7 +171,6 @@
<ContentPresenter x:Name="ExtensionPresenter"
Grid.Row="2"
VerticalAlignment="Stretch"
PreviewKeyDown="_KeyDownHandler"
Visibility="Collapsed" />
<local:SuggestionsControl x:Name="SuggestionsElement"

View File

@ -1798,22 +1798,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_altNumpadState = {};
}
// GH#2235: Terminal::Settings hasn't been modified to differentiate
// between AltGr and Ctrl+Alt yet.
// -> Don't check for key bindings if this is an AltGr key combination.
//
// GH#4999: Only process keybindings on the keydown. If we don't check
// this at all, we'll process the keybinding twice. If we only process
// keybindings on the keyUp, then we'll still send the keydown to the
// connected terminal application, and something like ctrl+shift+T will
// emit a ^T to the pipe.
if (!modifiers.IsAltGrPressed() &&
keyDown &&
_TryHandleKeyBinding(vkey, scanCode, modifiers))
{
return true;
}
if (_TrySendKeyEvent(vkey, scanCode, modifiers, keyDown))
{
return true;