Skip to content
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
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