Skip to content

Commit

Permalink
Make screen reader announce successful MovePane and MoveTab actions (#…
Browse files Browse the repository at this point in the history
…15771)

Uses the `RaiseNotificationEvent()` API from UIA automation peers to
announce successful `MovePane` and `MoveTab` actions. The announcements
are localized in the resw file.

Closes #15159
Based on #13575

(cherry picked from commit 2fb4a7f)
Service-Card-Id: 90438494
Service-Version: 1.18
  • Loading branch information
carlos-zamora authored and DHowett committed Sep 22, 2023
1 parent 1eab243 commit eff8cfa
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 5 deletions.
4 changes: 2 additions & 2 deletions src/cascadia/TerminalApp/AppActionHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ namespace winrt::TerminalApp::implementation
}
else if (const auto& realArgs = args.ActionArgs().try_as<MovePaneArgs>())
{
auto moved = _MovePane(realArgs);
const auto moved = _MovePane(realArgs);
args.Handled(moved);
}
}
Expand Down Expand Up @@ -839,7 +839,7 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = actionArgs.ActionArgs().try_as<MoveTabArgs>())
{
auto moved = _MoveTab(_senderOrFocusedTab(sender), realArgs);
const auto moved = _MoveTab(_senderOrFocusedTab(sender), realArgs);
actionArgs.Handled(moved);
}
}
Expand Down
28 changes: 28 additions & 0 deletions src/cascadia/TerminalApp/Resources/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -831,4 +831,32 @@
<value>Run as Administrator</value>
<comment>This text is displayed on context menu for profile entries in add new tab button.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingTab" xml:space="preserve">
<value>Active pane moved to "{0}" tab</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Default" xml:space="preserve">
<value>"{0}" tab moved to "{1}" window</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the name of the window the tab was moved to.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_NewWindow" xml:space="preserve">
<value>"{0}" tab moved to new window</value>
<comment>{Locked="{0}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab.</comment>
</data>
<data name="TerminalPage_TabMovedAnnouncement_Direction" xml:space="preserve">
<value>"{0}" tab moved to position "{1}"</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful tab movement. {0} is the name of the tab. {1} is the new tab index in the tab row.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_ExistingWindow" xml:space="preserve">
<value>Active pane moved to "{0}" tab in "{1}" window</value>
<comment>{Locked="{0}"}{Locked="{1}"}This text is read out by screen readers upon a successful pane movement. {0} is the name of the tab the pane was moved to. {1} is the name of the window the pane was moved to.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewWindow" xml:space="preserve">
<value>Active pane moved to new window</value>
<comment>This text is read out by screen readers upon a successful pane movement to a new window.</comment>
</data>
<data name="TerminalPage_PaneMovedAnnouncement_NewTab" xml:space="preserve">
<value>Active pane moved to new tab</value>
<comment>This text is read out by screen readers upon a successful pane movement to a new tab within the existing window.</comment>
</data>
</root>
9 changes: 9 additions & 0 deletions src/cascadia/TerminalApp/TabManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,15 @@ namespace winrt::TerminalApp::implementation
_tabView.TabItems().RemoveAt(currentTabIndex);
_tabView.TabItems().InsertAt(newTabIndex, tabViewItem);
_tabView.SelectedItem(tabViewItem);

if (auto autoPeer = Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this))
{
const auto tabTitle = tab.Title();
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
fmt::format(std::wstring_view{ RS_(L"TerminalPage_TabMovedAnnouncement_Direction") }, tabTitle, newTabIndex + 1),
L"TerminalPageMoveTabWithDirection" /* unique name for this notification category */);
}
}
}

Expand Down
65 changes: 62 additions & 3 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ namespace winrt::TerminalApp::implementation
ShowSetAsDefaultInfoBar();
}

Windows::UI::Xaml::Automation::Peers::AutomationPeer TerminalPage::OnCreateAutomationPeer()
{
return Automation::Peers::FrameworkElementAutomationPeer(*this);
}

// Method Description:
// - This is a bit of trickiness: If we're running unelevated, and the user
// passed in only --elevate actions, the we don't _actually_ want to
Expand Down Expand Up @@ -1993,10 +1998,31 @@ namespace winrt::TerminalApp::implementation
{
if (const auto pane{ terminalTab->GetActivePane() })
{
// Get the tab title _before_ moving things around in case the tabIdx doesn't point to the right one after the move
const auto tabTitle = _tabs.GetAt(tabIdx).Title();

auto startupActions = pane->BuildStartupActions(0, 1, true, true);
_DetachPaneFromWindow(pane);
_MoveContent(std::move(startupActions.args), args.Window(), args.TabIndex());
_MoveContent(std::move(startupActions.args), windowId, tabIdx);
focusedTab->DetachPane();

if (auto autoPeer = Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this))
{
if (windowId == L"new")
{
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
RS_(L"TerminalPage_PaneMovedAnnouncement_NewWindow"),
L"TerminalPageMovePaneToNewWindow" /* unique name for this notification category */);
}
else
{
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
fmt::format(std::wstring_view{ RS_(L"TerminalPage_PaneMovedAnnouncement_ExistingWindow") }, tabTitle, windowId),
L"TerminalPageMovePaneToExistingWindow" /* unique name for this notification category */);
}
}
return true;
}
}
Expand All @@ -2022,11 +2048,27 @@ namespace winrt::TerminalApp::implementation
auto pane = focusedTab->DetachPane();
targetTab->AttachPane(pane);
_SetFocusedTab(*targetTab);

if (auto autoPeer = Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this))
{
const auto tabTitle = targetTab->Title();
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
fmt::format(std::wstring_view{ RS_(L"TerminalPage_PaneMovedAnnouncement_ExistingTab") }, tabTitle),
L"TerminalPageMovePaneToExistingTab" /* unique name for this notification category */);
}
}
else
{
auto pane = focusedTab->DetachPane();
_CreateNewTabFromPane(pane);
if (auto autoPeer = Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this))
{
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
RS_(L"TerminalPage_PaneMovedAnnouncement_NewTab"),
L"TerminalPageMovePaneToNewTab" /* unique name for this notification category */);
}
}

return true;
Expand Down Expand Up @@ -2103,8 +2145,26 @@ namespace winrt::TerminalApp::implementation
{
auto startupActions = tab->BuildStartupActions(true);
_DetachTabFromWindow(tab);
_MoveContent(std::move(startupActions), args.Window(), 0);
_MoveContent(std::move(startupActions), windowId, 0);
_RemoveTab(*tab);
if (auto autoPeer = Automation::Peers::FrameworkElementAutomationPeer::FromElement(*this))
{
const auto tabTitle = tab->Title();
if (windowId == L"new")
{
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
fmt::format(std::wstring_view{ RS_(L"TerminalPage_TabMovedAnnouncement_NewWindow") }, tabTitle),
L"TerminalPageMoveTabToNewWindow" /* unique name for this notification category */);
}
else
{
autoPeer.RaiseNotificationEvent(Automation::Peers::AutomationNotificationKind::ActionCompleted,
Automation::Peers::AutomationNotificationProcessing::ImportantMostRecent,
fmt::format(std::wstring_view{ RS_(L"TerminalPage_TabMovedAnnouncement_Default") }, tabTitle, windowId),
L"TerminalPageMoveTabToExistingWindow" /* unique name for this notification category */);
}
}
return true;
}
}
Expand Down Expand Up @@ -4882,5 +4942,4 @@ namespace winrt::TerminalApp::implementation

return profileMenuItemFlyout;
}

}
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ namespace winrt::TerminalApp::implementation
void SetSettings(Microsoft::Terminal::Settings::Model::CascadiaSettings settings, bool needRefreshUI);

void Create();
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();

bool ShouldImmediatelyHandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings) const;
void HandoffToElevated(const Microsoft::Terminal::Settings::Model::CascadiaSettings& settings);
Expand Down

0 comments on commit eff8cfa

Please sign in to comment.