Skip to content
Draft
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
2 changes: 2 additions & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,8 @@ msft
MSGCMDLINEF
MSGF
MSGFILTER
MSGFINDNORESULT
MSGFINDRESULT
MSGFLG
MSGMARKMODE
MSGSCROLLMODE
Expand Down
66 changes: 66 additions & 0 deletions src/host/AccessibilityNotifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "precomp.h"
#include "AccessibilityNotifier.h"

#include "resource.h"
#include "utils.hpp"

#include "../types/inc/convert.hpp"
#include "../interactivity/inc/ServiceLocator.hpp"

Expand Down Expand Up @@ -183,6 +186,69 @@ void AccessibilityNotifier::SelectionChanged() noexcept
}
}

// Announces the state of the Find dialog's search results to screen readers.
// `index` is the 0-based index of the current match and `count` is the total number of matches.
//
// Unlike the other members of this class, this is emitted synchronously and isn't batched.
void AccessibilityNotifier::AnnounceSearchResults(ptrdiff_t index, size_t count) noexcept
try
{
const auto provider = _uiaProvider.load(std::memory_order_relaxed);
if (!provider)
{
return;
}

std::wstring format;
std::wstring announcement;

if (count == 0)
{
// No results found
_LoadString(ID_CONSOLE_MSGFINDNORESULT, announcement);
}
else
{
// Results found, announce as 1-based index of total ("2 of 5")
_LoadString(ID_CONSOLE_MSGFINDRESULT, format);

const auto position = std::clamp<size_t>(gsl::narrow_cast<size_t>(std::max<ptrdiff_t>(index, 0)) + 1, 1, count);

// The resource uses positional inserts (%1, %2) so that translations can reorder them
const DWORD_PTR args[]{
gsl::narrow_cast<DWORD_PTR>(position),
gsl::narrow_cast<DWORD_PTR>(count),
};
wil::unique_hlocal_string formatted;
const auto length = FormatMessageW(
FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
format.c_str(),
0,
0,
reinterpret_cast<LPWSTR>(formatted.addressof()),
0,
reinterpret_cast<va_list*>(const_cast<DWORD_PTR*>(&args[0])));
if (length == 0)
{
LOG_LAST_ERROR();
return;
}
announcement.assign(formatted.get(), length);
}

if (announcement.empty())
{
return;
}

if (const auto bstrAnnouncement = wil::make_bstr_nothrow(announcement.c_str()))
{
static const auto bstrActivityId = wil::make_bstr_nothrow(L"ConhostSearchResultAnnouncement");
LOG_IF_FAILED(UiaRaiseNotificationEvent(provider, NotificationKind_ActionCompleted, NotificationProcessing_ImportantMostRecent, bstrAnnouncement.get(), bstrActivityId.get()));
}
}
CATCH_LOG()

bool AccessibilityNotifier::WantsRegionChangedEvents() const noexcept
{
// See RegionChanged().
Expand Down
1 change: 1 addition & 0 deletions src/host/AccessibilityNotifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace Microsoft::Console

void CursorChanged(til::point position, bool activeSelection) noexcept;
void SelectionChanged() noexcept;
void AnnounceSearchResults(ptrdiff_t index, size_t count) noexcept;
bool WantsRegionChangedEvents() const noexcept;
void RegionChanged(til::point begin, til::point end) noexcept;
void ScrollBuffer(til::CoordType delta) noexcept;
Expand Down
5 changes: 5 additions & 0 deletions src/host/res.rc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ BEGIN

ID_CONSOLE_FMT_WINDOWTITLE, "%s%s"

/* Find dialog screen reader announcements. %1 is the 1-based index of the current
match, %2 is the total number of matches. */
ID_CONSOLE_MSGFINDRESULT, "%1!d! of %2!d!"
ID_CONSOLE_MSGFINDNORESULT, "No results"

/* Menu items that replace the standard ones. These don't have the accelerators */
SC_CLOSE, "&Close"

Expand Down
2 changes: 2 additions & 0 deletions src/host/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Author(s):
#define ID_CONSOLE_MSGMARKMODE 0x100C
#define ID_CONSOLE_MSGSCROLLMODE 0x100D
#define ID_CONSOLE_FMT_WINDOWTITLE 0x100E
#define ID_CONSOLE_MSGFINDRESULT 0x100F
#define ID_CONSOLE_MSGFINDNORESULT 0x1010

// Menu Item strings
#define ID_CONSOLE_COPY 0xFFF0
Expand Down
2 changes: 2 additions & 0 deletions src/interactivity/win32/find.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ INT_PTR CALLBACK FindDialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM l
searcher.FindNext(reverse);
}

ServiceLocator::LocateGlobals().accessibilityNotifier.AnnounceSearchResults(searcher.CurrentMatch(), searcher.Results().size());

if (searcher.SelectCurrent())
{
return TRUE;
Expand Down
2 changes: 2 additions & 0 deletions src/interactivity/win32/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Author(s):
#define ID_CONSOLE_MSGMARKMODE 0x100C
#define ID_CONSOLE_MSGSCROLLMODE 0x100D
#define ID_CONSOLE_FMT_WINDOWTITLE 0x100E
#define ID_CONSOLE_MSGFINDRESULT 0x100F
#define ID_CONSOLE_MSGFINDNORESULT 0x1010

// Menu Item strings
#define ID_CONSOLE_COPY 0xFFF0
Expand Down
Loading