Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 2 additions & 1 deletion doc/release-check-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ Net effect: UT shrinks the manual matrix to "did the wiring and UI connect", not
- [ ] `C263` `[new]` `[UT✓]` `[E2E]` **Keyboard selection keeps focused completed turns visible:** Tab and Up/Down navigation scrolls the chat only as needed to keep the focused completed turn visible, without overriding later manual scrolling. _(UT: `render_chat_keeps_keyboard_selected_completed_turn_visible`; E2E: `Feature.CompletedTurnSelection`.)_
- [ ] `C264` `[new]` `[UT✓]` `[E2E]` **Completed turns toggle and select from rendered prompt targets:** A left-button Down/Up anywhere on the same visible prompt row, including its triangle, prefix, text, explicit blank row, or unused row-end space, collapses or expands only that turn and reuses the keyboard selection, highlight, navigation, Esc, and Enter behavior. Hover uses only a hand cursor: action metadata must not add hyperlink underline or tooltip text. Details, separators, drags, overlays, tab changes, scrolling, and stale/offscreen rows do not toggle; clicking the live input dialog clears the history selection and restores draft input. Multiline, wrapped, wide-cell, and double/triple-click paths preserve their expected geometry and text-selection behavior. _(UT: `clicking_multiline_completed_turn_prompt_selects_and_reuses_enter_toggle`, `completed_turn_user_input_hit_spans_full_row_with_wide_cells`, `completed_turn_prompt_rows_expose_state_aware_action_links`, `overlay_preserves_full_rows_and_cell_styles`, `CompletedTurnActionHyperlinksSuppressUnderlines`, `clicking_input_dialog_restores_input_navigation_after_mouse_turn_selection`, `completed_turn_user_input_multi_click_preserves_turn_state_and_text_selection`, `completed_turn_mouse_selection_continues_with_keyboard_navigation`, `completed_turn_triangle_click_ignores_text_drag_and_hidden_chat`, `completed_turn_triangle_hits_follow_visible_scrolled_turns`, `completed_turn_prompt_hits_survive_a_clipped_header_row`; E2E: `Feature.AgentMouse` `CompletedTurnMouse` / `CompletedTurnPromptMouse`; hand cursor and absence of action underline manually verified on the exact deployed Dev build.)_
- [ ] `C242` `[new]` `[UT✓]` `[E2E]` **Mouse wheel scrolls chat without changing the draft:** Wheel input scrolls the chat viewport while Up/Down remain prompt-history controls and the unsent draft stays intact. _(UT: `mouse_wheel_scrolls_chat_without_changing_input_history`; #506; E2E: `Feature.AgentMouse`.)_
- [ ] `C295` `[new]` `[UT✓]` `[E2E]` **Ctrl+wheel zooms the agent pane while plain wheel scrolls chat:** Physical Ctrl+wheel changes the agent pane font size before VT mouse tracking can consume the event, while physical plain wheel still scrolls chat and both paths preserve the unsent draft. _(UT: `AgentPaneCtrlWheelZoomsBeforeVtMouse`; #790; E2E: `Feature.AgentMouse`.)_
- [ ] `C243` `[new]` `[UT✓]` `[E2E]` **Mouse selection copies text and clears after copy:** Double-click selection survives release, `Ctrl+C` copies the exact selected text with confirmation instead of canceling/closing the pane, and the selection is then cleared. _(UT: `mouse_release_does_not_return_text_for_automatic_copy`, `clearing_selection_resets_multi_click_sequence`; #506; E2E: `Feature.AgentMouse`.)_
- [ ] `C287` `[new]` `[UT✓]` `[E2E]` **Ctrl+A selects and copies the current agent frame:** Plain `Ctrl+A` selects the current rendered WTA frame through the existing text-selection path; `Ctrl+C` copies it with the existing confirmation and clears selection so a later `Ctrl+C` cannot replay stale text. _(UT: `select_all_extracts_and_highlights_the_current_frame`, `select_all_tracks_the_latest_frame_snapshot`, `ctrl_a_selects_current_rendered_frame_without_altering_input`; E2E: `Feature.AgentSelectAll`.)_
- [ ] `C265` `[new]` `[UT✓]` `[E2E]` **Right-click copies the agent text selection:** A physical right-click copies the exact WTA-owned selection through the OS clipboard, clears it, shows the existing copied confirmation, and never also pastes; the next right-click follows the no-selection Default Paste path without replaying selected text. _(UT: `right_click_copy_event_is_forwarded`, `right_click_copies_and_clears_text_selection`; E2E: `Feature.AgentMouse` `RightClickCopy`.)_
Expand Down Expand Up @@ -465,4 +466,4 @@ Net effect: UT shrinks the manual matrix to "did the wiring and UI connect", not
- Slash commands: `tools\wta\src\commands.rs`.
- Session state model: `tools\wta\src\agent_sessions.rs`, `tools\wta\AGENTS.md`.
- Multi-window agent pane architecture: `doc\specs\Multi-window-agent-pane.md`.
- Autofix flow, logging, and runtime layout: `AGENTS.md`.
- Autofix flow, logging, and runtime layout: `AGENTS.md`.
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/AgentPaneContent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ namespace winrt::TerminalApp::implementation
{
impl->UpdateSettings(settings);
}
GetTermControl().EnableAgentMouseWheelZoom(true);

const winrt::Microsoft::Terminal::Control::KeyChord ctrlV{ Windows::System::VirtualKeyModifiers::Control, 'V', 0 };
if (const auto actionMap = settings.ActionMap())
Expand Down
24 changes: 21 additions & 3 deletions src/cascadia/TerminalControl/ControlInteractivity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,29 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const Core::Point delta,
const Core::Point pixelPosition,
const Control::MouseButtonState buttonState)
{
return MouseWheel(modifiers, delta, pixelPosition, buttonState, false);
}

bool ControlInteractivity::MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const Core::Point delta,
const Core::Point pixelPosition,
const Control::MouseButtonState buttonState,
const bool prioritizeZoom)
{
const auto terminalPosition = _getTerminalPosition(til::point{ pixelPosition }, false);
const auto ctrlPressed = modifiers.IsCtrlPressed();
const auto shiftPressed = modifiers.IsShiftPressed();

if (prioritizeZoom &&
ctrlPressed &&
!shiftPressed &&
delta.Y != 0 &&
_core->Settings().ScrollToZoom())
{
_mouseZoomHandler(delta.Y);
return false;
}

// Short-circuit isReadOnly check to avoid warning dialog.
//
Expand All @@ -552,9 +573,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
buttonState);
}

const auto ctrlPressed = modifiers.IsCtrlPressed();
const auto shiftPressed = modifiers.IsShiftPressed();

if (ctrlPressed && shiftPressed && _core->Settings().ScrollToChangeOpacity())
{
_mouseTransparencyHandler(delta.Y);
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalControl/ControlInteractivity.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const Core::Point delta,
const Core::Point pixelPosition,
const Control::MouseButtonState state);
bool MouseWheel(const ::Microsoft::Terminal::Core::ControlKeyStates modifiers,
const Core::Point delta,
const Core::Point pixelPosition,
const Control::MouseButtonState state,
bool prioritizeZoom);

void UpdateScrollbar(const float newValue);

Expand Down
19 changes: 12 additions & 7 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2171,12 +2171,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation

const auto point = args.GetCurrentPoint(*this);
auto delta = point.Properties().MouseWheelDelta();
auto result = _interactivity.MouseWheel(ControlKeyStates{ args.KeyModifiers() },
point.Properties().IsHorizontalMouseWheel() ?
Core::Point{ delta, 0 } :
Core::Point{ 0, delta },
_toTerminalOrigin(point.Position()),
TermControl::GetPressedMouseButtons(point));
const auto modifiers = ControlKeyStates{ args.KeyModifiers() };
const auto wheelDelta = point.Properties().IsHorizontalMouseWheel() ?
Core::Point{ delta, 0 } :
Core::Point{ 0, delta };
const auto interactivity = winrt::get_self<implementation::ControlInteractivity>(_interactivity);
const auto result = interactivity->MouseWheel(modifiers,
wheelDelta,
_toTerminalOrigin(point.Position()),
TermControl::GetPressedMouseButtons(point),
_agentMouseWheelZoomEnabled);
if (result)
{
args.Handled(true);
Expand Down Expand Up @@ -2206,7 +2210,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
WI_SetFlagIf(state, Control::MouseButtonState::IsMiddleButtonDown, midButtonDown);
WI_SetFlagIf(state, Control::MouseButtonState::IsRightButtonDown, rightButtonDown);

return _interactivity.MouseWheel(modifiers, delta, _toTerminalOrigin(location), state);
const auto interactivity = winrt::get_self<implementation::ControlInteractivity>(_interactivity);
return interactivity->MouseWheel(modifiers, delta, _toTerminalOrigin(location), state, _agentMouseWheelZoomEnabled);
}

// Method Description:
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 @@ -64,6 +64,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool CopySelectionToClipboard(bool dismissSelection, bool singleLine, bool withControlSequences, const CopyFormat formats);
void PasteTextFromClipboard();
void EnableAgentPasteShortcutFallback(bool enabled) noexcept { _agentPasteShortcutFallbackEnabled = enabled; }
void EnableAgentMouseWheelZoom(bool enabled) noexcept { _agentMouseWheelZoomEnabled = enabled; }
void SelectAll();
bool ToggleBlockSelection();
void ToggleMarkMode();
Expand Down Expand Up @@ -257,6 +258,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::ControlInteractivity _interactivity{ nullptr };
Control::ControlCore _core{ nullptr };
Control::IKeyBindings _keyBindings{ nullptr };
bool _agentMouseWheelZoomEnabled{ false };
TsfDataProvider _tsfDataProvider{ this };
winrt::com_ptr<SearchBoxControl> _searchBox;

Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalControl/TermControl.idl
Original file line number Diff line number Diff line change
Expand Up @@ -170,5 +170,6 @@ namespace Microsoft.Terminal.Control
void ClearQuickFix();

void Detach();
void EnableAgentMouseWheelZoom(Boolean enabled);
}
}
53 changes: 53 additions & 0 deletions src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ namespace ControlUnitTests
TEST_METHOD(IncrementCircularBufferWithSelection);

TEST_METHOD(GetMouseEventsInTest);
TEST_METHOD(AgentPaneCtrlWheelZoomsBeforeVtMouse);
TEST_METHOD(AltBufferClampMouse);
TEST_METHOD(ParseCompletedTurnActionHyperlinks);
TEST_METHOD(CompletedTurnActionHyperlinksSuppressUnderlines);
Expand Down Expand Up @@ -1009,6 +1010,58 @@ namespace ControlUnitTests
cursorPosition0.to_core_point());
}

void ControlInteractivityTests::AgentPaneCtrlWheelZoomsBeforeVtMouse()
{
WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};

auto [settings, conn] = _createSettingsAndConnection();
settings->ScrollToZoom(true);
auto [core, interactivity] = _createCoreAndInteractivity(*settings, *conn);
_standardInit(core, interactivity);

std::deque<std::wstring> expectedOutput{};
auto validateDrained = _addInputCallback(conn, expectedOutput);

auto& term{ *core->_terminal };
term.Write(L"\x1b[?1000h\x1b[?1006h");

const auto modifiers = ControlKeyStates{ CTRL_PRESSED };
interactivity->MouseWheel(modifiers,
Core::Point{ 0, WHEEL_DELTA },
Core::Point{ 0, 0 },
{},
true);

VERIFY_ARE_EQUAL(1.0f, core->_accumulatedFontSizeDelta);
VERIFY_ARE_EQUAL(0u, expectedOutput.size());

expectedOutput.push_back(L"\x1b[<64;1;1M");
interactivity->MouseWheel({},
Core::Point{ 0, WHEEL_DELTA },
Core::Point{ 0, 0 },
{},
true);
VERIFY_ARE_EQUAL(0u, expectedOutput.size());
VERIFY_ARE_EQUAL(1.0f, core->_accumulatedFontSizeDelta);

expectedOutput.push_back(L"\x1b[<83;1;1M");
interactivity->MouseWheel(modifiers,
Core::Point{ WHEEL_DELTA, 0 },
Core::Point{ 0, 0 },
{},
true);
VERIFY_ARE_EQUAL(0u, expectedOutput.size());
VERIFY_ARE_EQUAL(1.0f, core->_accumulatedFontSizeDelta);

expectedOutput.push_back(L"\x1b[<80;1;1M");
interactivity->MouseWheel(modifiers,
Core::Point{ 0, WHEEL_DELTA },
Core::Point{ 0, 0 },
{});
VERIFY_ARE_EQUAL(0u, expectedOutput.size());
VERIFY_ARE_EQUAL(1.0f, core->_accumulatedFontSizeDelta);
}

void ControlInteractivityTests::AltBufferClampMouse()
{
// This is a test for
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/ItE2E/ItE2E.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ $publicFns = @(
# Ui
'Get-UiTree', 'Find-UiElement', 'Get-UiElement', 'Test-UiElementEnabled', 'Invoke-UiElement', 'Invoke-UiClick', 'Get-UiTextBounds', 'Invoke-UiMouseDrag', 'Set-UiValue', 'Get-UiValue',
'Wait-UiElement', 'Test-UiElementExists', 'Save-UiScreenshot', 'Get-WtWindowHwnds', 'Test-WinAppAvailable',
'Send-WtWindowKey', 'Set-WtWindowForeground', 'Test-WtWindowKeyFocusable', 'Open-WtSettings', 'Test-CommandPaletteOpen', 'Invoke-SettingsNav',
'Send-WtWindowKey', 'Invoke-WtWindowWheel', 'Set-WtWindowForeground', 'Test-WtWindowKeyFocusable', 'Open-WtSettings', 'Test-CommandPaletteOpen', 'Invoke-SettingsNav',
# Observe
'Get-ItLogDir', 'Initialize-LogOffsets', 'Get-ItLogText', 'Start-WtEventListener', 'Get-WtEvents',
'Wait-WtEvent', 'Stop-WtEventListener', 'Get-ContextBundle', 'ConvertTo-ContextText',
Expand Down
Loading
Loading