mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Rewrite the MSAA/UIA integration into conhost
This commit is contained in:
parent
814f78ed2c
commit
3230cb18b6
@ -13,7 +13,6 @@
|
|||||||
// - ulSize - The height of the cursor within this buffer
|
// - ulSize - The height of the cursor within this buffer
|
||||||
Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
|
Cursor::Cursor(const ULONG ulSize, TextBuffer& parentBuffer) noexcept :
|
||||||
_parentBuffer{ parentBuffer },
|
_parentBuffer{ parentBuffer },
|
||||||
_fHasMoved(false),
|
|
||||||
_fIsVisible(true),
|
_fIsVisible(true),
|
||||||
_fIsOn(true),
|
_fIsOn(true),
|
||||||
_fIsDouble(false),
|
_fIsDouble(false),
|
||||||
@ -35,11 +34,6 @@ til::point Cursor::GetPosition() const noexcept
|
|||||||
return _cPosition;
|
return _cPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cursor::HasMoved() const noexcept
|
|
||||||
{
|
|
||||||
return _fHasMoved;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Cursor::IsVisible() const noexcept
|
bool Cursor::IsVisible() const noexcept
|
||||||
{
|
{
|
||||||
return _fIsVisible;
|
return _fIsVisible;
|
||||||
@ -75,11 +69,6 @@ ULONG Cursor::GetSize() const noexcept
|
|||||||
return _ulSize;
|
return _ulSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cursor::SetHasMoved(const bool fHasMoved) noexcept
|
|
||||||
{
|
|
||||||
_fHasMoved = fHasMoved;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cursor::SetIsVisible(const bool fIsVisible) noexcept
|
void Cursor::SetIsVisible(const bool fIsVisible) noexcept
|
||||||
{
|
{
|
||||||
_fIsVisible = fIsVisible;
|
_fIsVisible = fIsVisible;
|
||||||
@ -249,7 +238,6 @@ void Cursor::CopyProperties(const Cursor& OtherCursor) noexcept
|
|||||||
// We shouldn't copy the position as it will be already rearranged by the resize operation.
|
// We shouldn't copy the position as it will be already rearranged by the resize operation.
|
||||||
//_cPosition = pOtherCursor->_cPosition;
|
//_cPosition = pOtherCursor->_cPosition;
|
||||||
|
|
||||||
_fHasMoved = OtherCursor._fHasMoved;
|
|
||||||
_fIsVisible = OtherCursor._fIsVisible;
|
_fIsVisible = OtherCursor._fIsVisible;
|
||||||
_fIsOn = OtherCursor._fIsOn;
|
_fIsOn = OtherCursor._fIsOn;
|
||||||
_fIsDouble = OtherCursor._fIsDouble;
|
_fIsDouble = OtherCursor._fIsDouble;
|
||||||
|
|||||||
@ -38,7 +38,6 @@ public:
|
|||||||
Cursor(Cursor&&) = default;
|
Cursor(Cursor&&) = default;
|
||||||
Cursor& operator=(Cursor&&) & = delete;
|
Cursor& operator=(Cursor&&) & = delete;
|
||||||
|
|
||||||
bool HasMoved() const noexcept;
|
|
||||||
bool IsVisible() const noexcept;
|
bool IsVisible() const noexcept;
|
||||||
bool IsOn() const noexcept;
|
bool IsOn() const noexcept;
|
||||||
bool IsBlinkingAllowed() const noexcept;
|
bool IsBlinkingAllowed() const noexcept;
|
||||||
@ -54,7 +53,6 @@ public:
|
|||||||
bool IsDeferDrawing() noexcept;
|
bool IsDeferDrawing() noexcept;
|
||||||
void EndDeferDrawing() noexcept;
|
void EndDeferDrawing() noexcept;
|
||||||
|
|
||||||
void SetHasMoved(const bool fHasMoved) noexcept;
|
|
||||||
void SetIsVisible(const bool fIsVisible) noexcept;
|
void SetIsVisible(const bool fIsVisible) noexcept;
|
||||||
void SetIsOn(const bool fIsOn) noexcept;
|
void SetIsOn(const bool fIsOn) noexcept;
|
||||||
void SetBlinkingAllowed(const bool fIsOn) noexcept;
|
void SetBlinkingAllowed(const bool fIsOn) noexcept;
|
||||||
@ -90,7 +88,6 @@ private:
|
|||||||
|
|
||||||
til::point _cPosition; // current position on screen (in screen buffer coords).
|
til::point _cPosition; // current position on screen (in screen buffer coords).
|
||||||
|
|
||||||
bool _fHasMoved;
|
|
||||||
bool _fIsVisible; // whether cursor is visible (set only through the API)
|
bool _fIsVisible; // whether cursor is visible (set only through the API)
|
||||||
bool _fIsOn; // whether blinking cursor is on or not
|
bool _fIsOn; // whether blinking cursor is on or not
|
||||||
bool _fIsDouble; // whether the cursor size should be doubled
|
bool _fIsDouble; // whether the cursor size should be doubled
|
||||||
|
|||||||
@ -154,7 +154,6 @@ public:
|
|||||||
void UseMainScreenBuffer() override;
|
void UseMainScreenBuffer() override;
|
||||||
|
|
||||||
bool IsVtInputEnabled() const noexcept override;
|
bool IsVtInputEnabled() const noexcept override;
|
||||||
void NotifyAccessibilityChange(const til::rect& changedRect) noexcept override;
|
|
||||||
void NotifyBufferRotation(const int delta) override;
|
void NotifyBufferRotation(const int delta) override;
|
||||||
void NotifyShellIntegrationMark() override;
|
void NotifyShellIntegrationMark() override;
|
||||||
|
|
||||||
|
|||||||
@ -347,11 +347,6 @@ bool Terminal::IsVtInputEnabled() const noexcept
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::NotifyAccessibilityChange(const til::rect& /*changedRect*/) noexcept
|
|
||||||
{
|
|
||||||
// This is only needed in conhost. Terminal handles accessibility in another way.
|
|
||||||
}
|
|
||||||
|
|
||||||
void Terminal::InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength)
|
void Terminal::InvokeCompletions(std::wstring_view menuJson, unsigned int replaceLength)
|
||||||
{
|
{
|
||||||
if (_pfnCompletionsChanged)
|
if (_pfnCompletionsChanged)
|
||||||
|
|||||||
511
src/host/AccessibilityNotifier.cpp
Normal file
511
src/host/AccessibilityNotifier.cpp
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
#include "AccessibilityNotifier.h"
|
||||||
|
|
||||||
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
|
|
||||||
|
using namespace Microsoft::Console;
|
||||||
|
using namespace Microsoft::Console::Interactivity;
|
||||||
|
|
||||||
|
template<typename U, typename T>
|
||||||
|
constexpr U satcast(T v) noexcept
|
||||||
|
{
|
||||||
|
static_assert(sizeof(U) <= sizeof(T), "use this for narrowing");
|
||||||
|
constexpr T min = std::numeric_limits<U>::min();
|
||||||
|
constexpr T max = std::numeric_limits<U>::max();
|
||||||
|
return gsl::narrow_cast<U>(v < min ? min : (v > max ? max : v));
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibilityNotifier::AccessibilityNotifier()
|
||||||
|
{
|
||||||
|
// Mirrors _timerEmitMSAA / _timerEmitUIA
|
||||||
|
memset(&_state, 0, sizeof(_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessibilityNotifier::~AccessibilityNotifier()
|
||||||
|
{
|
||||||
|
SetUIAProvider(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::Initialize(HWND hwnd, DWORD msaaDelay, DWORD uiaDelay) noexcept
|
||||||
|
{
|
||||||
|
_hwnd = hwnd;
|
||||||
|
|
||||||
|
// delay=INFINITE is intended to disable events completely, but realistically,
|
||||||
|
// even a delay of 1s makes little sense. So, the cut-off was set to 10s.
|
||||||
|
if (msaaDelay < 10000 && hwnd)
|
||||||
|
{
|
||||||
|
_msaaEnabled = true;
|
||||||
|
|
||||||
|
// msaaDelay=0 makes all events synchronous. That's how
|
||||||
|
// it used to work and has a huge performance impact.
|
||||||
|
if (msaaDelay != 0)
|
||||||
|
{
|
||||||
|
// Convert from milliseconds to 100-nanosecond intervals.
|
||||||
|
// Negative values indicate relative time.
|
||||||
|
_msaaDelay = static_cast<int64_t>(msaaDelay) * -10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiaDelay < 10000)
|
||||||
|
{
|
||||||
|
_uiaEnabled = true;
|
||||||
|
|
||||||
|
if (uiaDelay != 0)
|
||||||
|
{
|
||||||
|
_uiaDelay = static_cast<int64_t>(uiaDelay) * -10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_msaaDelay || _uiaDelay)
|
||||||
|
{
|
||||||
|
_timer.reset(_createTimer(&_timerEmitMSAA));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triggers the computation of _delay and _delayWindow.
|
||||||
|
SetUIAProvider(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::SetUIAProvider(IRawElementProviderSimple* provider) noexcept
|
||||||
|
{
|
||||||
|
// NOTE: The assumption is that you're holding the console lock when calling any of the member functions.
|
||||||
|
// This is why we can safely update these members (no worker thread is running nor can be scheduled).
|
||||||
|
assert(ServiceLocator::LocateGlobals().getConsoleInformation().IsConsoleLocked());
|
||||||
|
|
||||||
|
// If UIA events are disabled, don't set _uiaProvider either.
|
||||||
|
// It would trigger unnecessary work.
|
||||||
|
if (!_uiaEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Of course we must ensure our precious provider object doesn't go away.
|
||||||
|
if (provider)
|
||||||
|
{
|
||||||
|
provider->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto old = _uiaProvider.exchange(provider, std::memory_order_relaxed);
|
||||||
|
|
||||||
|
// Before we can release the old object, we must ensure it's not in use by a worker thread.
|
||||||
|
WaitForThreadpoolTimerCallbacks(_timer.get(), TRUE);
|
||||||
|
|
||||||
|
if (old)
|
||||||
|
{
|
||||||
|
old->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the delay. If UIA is enabled now, use the UIA delay.
|
||||||
|
// Note that a delay of 0 means "no delay" and we signal that as _delay=nullptr.
|
||||||
|
//
|
||||||
|
// NOTE: We don't set a second timer just for UIA, because some applications like NVDA
|
||||||
|
// listen to both MSAA and UIA events. If they don't arrive approximately together,
|
||||||
|
// they'll be announced as seperate events, which breaks announcements.
|
||||||
|
if (const auto delay = provider ? &_uiaDelay : &_msaaDelay; *delay == 0)
|
||||||
|
{
|
||||||
|
_delay = nullptr;
|
||||||
|
_delayWindow = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(sizeof(FILETIME) == sizeof(_uiaDelay));
|
||||||
|
_delay = reinterpret_cast<FILETIME*>(delay);
|
||||||
|
// Set the delay window to 1/5th of the delay, but in milliseconds.
|
||||||
|
_delayWindow = gsl::narrow_cast<DWORD>(std::max<int64_t>(0, *delay / (5 * -10000)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we canceled the timer, reschedule it.
|
||||||
|
if (_state.timerScheduled)
|
||||||
|
{
|
||||||
|
_state.timerScheduled = false;
|
||||||
|
|
||||||
|
// Of course there's no point to schedule it if there isn't a provider.
|
||||||
|
if (provider)
|
||||||
|
{
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits EVENT_CONSOLE_CARET, indicating the new cursor position.
|
||||||
|
// `rectangle` is the cursor rectangle in buffer coordinates (rows/columns)
|
||||||
|
// `flags` can be either CONSOLE_CARET_SELECTION _or_ CONSOLE_CARET_VISIBLE (not a bitfield)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// It then also Calls ConsoleControl() with ConsoleSetCaretInfo, which goes through the kernel sets
|
||||||
|
// cciConsole on the HWND and then raises EVENT_OBJECT_LOCATIONCHANGE with OBJID_CARET, INDEXID_CONTAINER.
|
||||||
|
// The cciConsole information is then used by GetGUIThreadInfo() to populate hwndCaret and rcCaret.
|
||||||
|
// Unfortunately there's no way to know whether anyone even needs this information so we always raise this.
|
||||||
|
void AccessibilityNotifier::CursorChanged(til::point position, bool activeSelection) noexcept
|
||||||
|
{
|
||||||
|
// Can't check for IsWinEventHookInstalled(EVENT_CONSOLE_CARET),
|
||||||
|
// because we need to emit a ConsoleControl() call regardless.
|
||||||
|
if (_msaaEnabled)
|
||||||
|
{
|
||||||
|
const auto guard = _lock.lock_exclusive();
|
||||||
|
|
||||||
|
_state.eventConsoleCaretPositionX = position.x;
|
||||||
|
_state.eventConsoleCaretPositionY = position.y;
|
||||||
|
_state.eventConsoleCaretSelecting = activeSelection;
|
||||||
|
_state.eventConsoleCaretPrimed = true;
|
||||||
|
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::SelectionChanged() noexcept
|
||||||
|
{
|
||||||
|
if (_uiaProvider.load(std::memory_order_relaxed))
|
||||||
|
{
|
||||||
|
const auto guard = _lock.lock_exclusive();
|
||||||
|
|
||||||
|
_state.textSelectionChanged = true;
|
||||||
|
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits EVENT_CONSOLE_UPDATE_REGION, the region of the console that changed.
|
||||||
|
void AccessibilityNotifier::RegionChanged(til::point begin, til::point end) noexcept
|
||||||
|
{
|
||||||
|
if (begin >= end)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto msaa = _msaaEnabled && IsWinEventHookInstalled(EVENT_CONSOLE_UPDATE_REGION);
|
||||||
|
const auto uia = _uiaProvider.load(std::memory_order_relaxed) != nullptr;
|
||||||
|
|
||||||
|
if (!msaa && !uia)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto guard = _lock.lock_exclusive();
|
||||||
|
|
||||||
|
if (msaa)
|
||||||
|
{
|
||||||
|
const til::HugeCoordType begX = begin.x;
|
||||||
|
const til::HugeCoordType begY = begin.y;
|
||||||
|
const til::HugeCoordType endX = end.x;
|
||||||
|
const til::HugeCoordType endY = end.y;
|
||||||
|
|
||||||
|
const auto primed = _state.eventConsoleUpdateRegionPrimed;
|
||||||
|
|
||||||
|
// Initialize the region (if !primed) or extend the region to the union of old and new.
|
||||||
|
if (!primed || begY < _state.eventConsoleUpdateRegionBeginY || (begY == _state.eventConsoleUpdateRegionBeginY && begX < _state.eventConsoleUpdateRegionBeginX))
|
||||||
|
{
|
||||||
|
_state.eventConsoleUpdateRegionBeginX = begX;
|
||||||
|
_state.eventConsoleUpdateRegionBeginY = begY;
|
||||||
|
_state.eventConsoleUpdateRegionPrimed = true;
|
||||||
|
}
|
||||||
|
if (!primed || endY > _state.eventConsoleUpdateRegionEndY || (endY == _state.eventConsoleUpdateRegionEndY && endX > _state.eventConsoleUpdateRegionEndX))
|
||||||
|
{
|
||||||
|
_state.eventConsoleUpdateRegionEndX = endX;
|
||||||
|
_state.eventConsoleUpdateRegionEndY = endY;
|
||||||
|
_state.eventConsoleUpdateRegionPrimed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uia)
|
||||||
|
{
|
||||||
|
_state.textChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits EVENT_CONSOLE_UPDATE_SCROLL. Specific to buffer scrolls and
|
||||||
|
// allows us to adjust previously cached buffer coordinates accordingly.
|
||||||
|
void AccessibilityNotifier::ScrollBuffer(til::CoordType delta) noexcept
|
||||||
|
{
|
||||||
|
if (_msaaEnabled && IsWinEventHookInstalled(EVENT_CONSOLE_UPDATE_SCROLL))
|
||||||
|
{
|
||||||
|
const auto guard = _lock.lock_exclusive();
|
||||||
|
|
||||||
|
// They say accessibility is hard, but then they design EVENT_CONSOLE_UPDATE_SCROLL
|
||||||
|
// to count _both_ viewport scrolls _and_ buffer scrolls as the same thing,
|
||||||
|
// making the information carried by the event completely useless. Don't ask me.
|
||||||
|
//
|
||||||
|
// Fun fact: conhost "v2" (Windows 10+) would raise EVENT_CONSOLE_UPDATE_SCROLL events every
|
||||||
|
// time ScrollConsoleScreenBuffer is called. People ask me why I'm balding. They don't know.
|
||||||
|
_state.eventConsoleUpdateScrollDeltaY += delta;
|
||||||
|
_state.eventConsoleUpdateScrollPrimed = true;
|
||||||
|
|
||||||
|
if (_state.eventConsoleCaretPrimed)
|
||||||
|
{
|
||||||
|
_state.eventConsoleCaretPositionY += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state.eventConsoleUpdateRegionPrimed)
|
||||||
|
{
|
||||||
|
_state.eventConsoleUpdateRegionBeginY += delta;
|
||||||
|
_state.eventConsoleUpdateRegionEndY += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits EVENT_CONSOLE_UPDATE_SCROLL. Specific to viewport scrolls.
|
||||||
|
void AccessibilityNotifier::ScrollViewport(til::point delta) noexcept
|
||||||
|
{
|
||||||
|
if (_msaaEnabled && IsWinEventHookInstalled(EVENT_CONSOLE_UPDATE_SCROLL))
|
||||||
|
{
|
||||||
|
const auto guard = _lock.lock_exclusive();
|
||||||
|
|
||||||
|
_state.eventConsoleUpdateScrollDeltaX += delta.x;
|
||||||
|
_state.eventConsoleUpdateScrollDeltaY += delta.y;
|
||||||
|
_state.eventConsoleUpdateScrollPrimed = true;
|
||||||
|
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emits EVENT_CONSOLE_LAYOUT. Documentation just states "The console layout has changed."
|
||||||
|
// but it's absolutely unclear what that even means. Try to emit it when the scrollbar
|
||||||
|
// position or window size has changed... I guess.
|
||||||
|
void AccessibilityNotifier::Layout() noexcept
|
||||||
|
{
|
||||||
|
if (_msaaEnabled && IsWinEventHookInstalled(EVENT_CONSOLE_LAYOUT))
|
||||||
|
{
|
||||||
|
const auto guard = _lock.lock_exclusive();
|
||||||
|
|
||||||
|
_state.eventConsoleLayoutPrimed = true;
|
||||||
|
|
||||||
|
_timerSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::ApplicationStart(DWORD pid) const noexcept
|
||||||
|
{
|
||||||
|
if (_msaaEnabled)
|
||||||
|
{
|
||||||
|
const auto cc = ServiceLocator::LocateConsoleControl<IConsoleControl>();
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_START_APPLICATION, _hwnd, pid, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::ApplicationEnd(DWORD pid) const noexcept
|
||||||
|
{
|
||||||
|
if (_msaaEnabled)
|
||||||
|
{
|
||||||
|
const auto cc = ServiceLocator::LocateConsoleControl<IConsoleControl>();
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_END_APPLICATION, _hwnd, pid, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PTP_TIMER AccessibilityNotifier::_createTimer(PTP_TIMER_CALLBACK callback) noexcept
|
||||||
|
{
|
||||||
|
return THROW_LAST_ERROR_IF_NULL(CreateThreadpoolTimer(callback, this, nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::_timerSet() noexcept
|
||||||
|
{
|
||||||
|
if (!_delay)
|
||||||
|
{
|
||||||
|
_emitMSAA(_state);
|
||||||
|
}
|
||||||
|
else if (!_state.timerScheduled)
|
||||||
|
{
|
||||||
|
_state.timerScheduled = true;
|
||||||
|
SetThreadpoolTimerEx(_timer.get(), _delay, 0, _delayWindow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::_timerEmitMSAA(PTP_CALLBACK_INSTANCE, PVOID context, PTP_TIMER) noexcept
|
||||||
|
{
|
||||||
|
const auto self = static_cast<AccessibilityNotifier*>(context);
|
||||||
|
State state;
|
||||||
|
|
||||||
|
// Make a copy of _state, because UIA and MSAA are very slow (up to 1ms per call).
|
||||||
|
// Holding a lock while _emitEventsCallback would mean that the IO thread can't proceed.
|
||||||
|
//
|
||||||
|
// The only concern I have is whether calling SetThreadpoolTimerEx() again on
|
||||||
|
// _timer while we're still executing will properly schedule another run.
|
||||||
|
// The docs say to read the "Remarks" and the remarks just don't clarify it. Great.
|
||||||
|
// FWIW we can't just create two timer objects since that may (theoretically)
|
||||||
|
// just end up with two callbacks running at the same time = same problem.
|
||||||
|
{
|
||||||
|
const auto guard = self->_lock.lock_exclusive();
|
||||||
|
|
||||||
|
// What we want to do is
|
||||||
|
// state = self->_state;
|
||||||
|
// self->_state = {};
|
||||||
|
// MSVC optimizes the first line with SIMD, but fails to do so for the second line.
|
||||||
|
// This forces us to use memset. memcpy is used for consistency.
|
||||||
|
static_assert(std::is_trivially_copyable_v<State>);
|
||||||
|
memcpy(&state, &self->_state, sizeof(State));
|
||||||
|
memset(&self->_state, 0, sizeof(State));
|
||||||
|
}
|
||||||
|
|
||||||
|
self->_emitMSAA(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::_emitMSAA(State& state) const noexcept
|
||||||
|
{
|
||||||
|
const auto cc = ServiceLocator::LocateConsoleControl<IConsoleControl>();
|
||||||
|
const auto provider = _uiaProvider.load(std::memory_order_relaxed);
|
||||||
|
|
||||||
|
if (state.eventConsoleCaretPrimed)
|
||||||
|
{
|
||||||
|
const auto x = satcast<SHORT>(state.eventConsoleCaretPositionX);
|
||||||
|
const auto y = satcast<SHORT>(state.eventConsoleCaretPositionY);
|
||||||
|
// Technically, CONSOLE_CARET_SELECTION and CONSOLE_CARET_VISIBLE are bitflags,
|
||||||
|
// however Microsoft's _own_ example code for these assumes that they're an
|
||||||
|
// enumation and also assumes that a value of 0 (= invisible cursor) is invalid.
|
||||||
|
// So, we just pretend as if the cursor is always visible.
|
||||||
|
const auto flags = state.eventConsoleCaretSelecting ? CONSOLE_CARET_SELECTION : CONSOLE_CARET_VISIBLE;
|
||||||
|
|
||||||
|
// There's no need to check for IsWinEventHookInstalled,
|
||||||
|
// because NotifyWinEvent is very fast if no event is installed.
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_CARET, _hwnd, flags, MAKELONG(x, y));
|
||||||
|
|
||||||
|
{
|
||||||
|
std::optional<CONSOLE_CARET_INFO> caretInfo;
|
||||||
|
|
||||||
|
// Convert the buffer position to the equivalent screen coordinates
|
||||||
|
// required by CONSOLE_CARET_INFO, taking line rendition into account.
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
gci.LockConsole();
|
||||||
|
if (gci.HasActiveOutputBuffer())
|
||||||
|
{
|
||||||
|
auto& screenInfo = gci.GetActiveOutputBuffer();
|
||||||
|
auto& buffer = screenInfo.GetTextBuffer();
|
||||||
|
const auto position = buffer.BufferToScreenPosition({ x, y });
|
||||||
|
const auto viewport = screenInfo.GetViewport();
|
||||||
|
const auto fontSize = screenInfo.GetScreenFontSize();
|
||||||
|
const auto left = (position.x - viewport.Left()) * fontSize.width;
|
||||||
|
const auto top = (position.y - viewport.Top()) * fontSize.height;
|
||||||
|
caretInfo.emplace(CONSOLE_CARET_INFO{
|
||||||
|
.hwnd = _hwnd,
|
||||||
|
.rc = RECT{
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
left + fontSize.width,
|
||||||
|
top + fontSize.height,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
gci.UnlockConsole();
|
||||||
|
|
||||||
|
if (caretInfo)
|
||||||
|
{
|
||||||
|
cc->Control(ControlType::ConsoleSetCaretInfo, &*caretInfo, sizeof(*caretInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.eventConsoleCaretPositionX = 0;
|
||||||
|
state.eventConsoleCaretPositionY = 0;
|
||||||
|
state.eventConsoleCaretSelecting = false;
|
||||||
|
state.eventConsoleCaretPrimed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.eventConsoleUpdateRegionPrimed)
|
||||||
|
{
|
||||||
|
const auto begX = satcast<SHORT>(state.eventConsoleUpdateRegionBeginX);
|
||||||
|
const auto begY = satcast<SHORT>(state.eventConsoleUpdateRegionBeginY);
|
||||||
|
const auto endX = satcast<SHORT>(state.eventConsoleUpdateRegionEndX);
|
||||||
|
const auto endY = satcast<SHORT>(state.eventConsoleUpdateRegionEndY);
|
||||||
|
const auto beg = MAKELONG(begX, begY);
|
||||||
|
const auto end = MAKELONG(endX, endY);
|
||||||
|
|
||||||
|
// Previously, we'd also emit a EVENT_CONSOLE_UPDATE_SIMPLE event for single-char updates,
|
||||||
|
// but in the 30 years since, the way fast software is written has changed:
|
||||||
|
// We now have plenty CPU power but the speed of light is still the same.
|
||||||
|
// It's much more important to batch events to avoid NotifyWinEvent's latency problems.
|
||||||
|
// EVENT_CONSOLE_UPDATE_SIMPLE is not trivially batchable and so it got removed.
|
||||||
|
//
|
||||||
|
// That said, NVDA is currently a very popular screen reader for Windows.
|
||||||
|
// IF you set its "Windows Console support" to "Legacy" AND disable
|
||||||
|
// "Use enhanced typed character support in legacy Windows Console when available"
|
||||||
|
// then it will purely rely on these WinEvents for accessibility.
|
||||||
|
//
|
||||||
|
// In this case it assumes that EVENT_CONSOLE_UPDATE_REGION is regular output
|
||||||
|
// and that EVENT_CONSOLE_UPDATE_SIMPLE is keyboard input (FYI: don't do this).
|
||||||
|
// The problem now is that it doesn't announce any EVENT_CONSOLE_UPDATE_REGION
|
||||||
|
// events where beg == end (i.e. a single character change).
|
||||||
|
//
|
||||||
|
// The good news is that if you set these two options in NVDA, it crashes whenever
|
||||||
|
// any conhost instance exits, so... maybe we don't need to work around this? :D
|
||||||
|
//
|
||||||
|
// I'll leave this code here, in case we ever need to shim EVENT_CONSOLE_UPDATE_SIMPLE.
|
||||||
|
#if 0
|
||||||
|
LONG charAndAttr = 0;
|
||||||
|
|
||||||
|
if (beg == end)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
gci.LockConsole();
|
||||||
|
|
||||||
|
if (gci.HasActiveOutputBuffer())
|
||||||
|
{
|
||||||
|
auto& tb = gci.GetActiveOutputBuffer().GetTextBuffer();
|
||||||
|
const auto& row = tb.GetRowByOffset(begY);
|
||||||
|
const auto glyph = row.GlyphAt(begX);
|
||||||
|
const auto attr = row.GetAttrByColumn(begX);
|
||||||
|
charAndAttr = MAKELONG(Utf16ToUcs2(glyph), attr.GetLegacyAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
gci.UnlockConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charAndAttr)
|
||||||
|
{
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_UPDATE_SIMPLE, _hwnd, beg, charAndAttr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_UPDATE_REGION, _hwnd, beg, end);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_UPDATE_REGION, _hwnd, beg, end);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
state.eventConsoleUpdateRegionBeginX = 0;
|
||||||
|
state.eventConsoleUpdateRegionBeginY = 0;
|
||||||
|
state.eventConsoleUpdateRegionEndX = 0;
|
||||||
|
state.eventConsoleUpdateRegionEndY = 0;
|
||||||
|
state.eventConsoleUpdateRegionPrimed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.eventConsoleUpdateScrollPrimed)
|
||||||
|
{
|
||||||
|
const auto dx = satcast<LONG>(state.eventConsoleUpdateScrollDeltaX);
|
||||||
|
const auto dy = satcast<LONG>(state.eventConsoleUpdateScrollDeltaY);
|
||||||
|
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_UPDATE_SCROLL, _hwnd, dx, dy);
|
||||||
|
|
||||||
|
state.eventConsoleUpdateScrollDeltaX = 0;
|
||||||
|
state.eventConsoleUpdateScrollDeltaY = 0;
|
||||||
|
state.eventConsoleUpdateScrollPrimed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.eventConsoleLayoutPrimed)
|
||||||
|
{
|
||||||
|
cc->NotifyWinEvent(EVENT_CONSOLE_LAYOUT, _hwnd, 0, 0);
|
||||||
|
state.eventConsoleLayoutPrimed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.textSelectionChanged)
|
||||||
|
{
|
||||||
|
_emitUIAEvent(provider, UIA_Text_TextSelectionChangedEventId);
|
||||||
|
state.textSelectionChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.textChanged)
|
||||||
|
{
|
||||||
|
_emitUIAEvent(provider, UIA_Text_TextChangedEventId);
|
||||||
|
state.textChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccessibilityNotifier::_emitUIAEvent(IRawElementProviderSimple* provider, EVENTID id) noexcept
|
||||||
|
{
|
||||||
|
if (provider)
|
||||||
|
{
|
||||||
|
LOG_IF_FAILED(UiaRaiseAutomationEvent(provider, id));
|
||||||
|
}
|
||||||
|
}
|
||||||
99
src/host/AccessibilityNotifier.h
Normal file
99
src/host/AccessibilityNotifier.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct IRawElementProviderSimple;
|
||||||
|
typedef int EVENTID;
|
||||||
|
|
||||||
|
namespace Microsoft::Console
|
||||||
|
{
|
||||||
|
// UIA and MSAA calls are both extraordinarily slow, so we got this
|
||||||
|
// handy class to batch then up and emit them on a background thread.
|
||||||
|
struct AccessibilityNotifier
|
||||||
|
{
|
||||||
|
AccessibilityNotifier();
|
||||||
|
~AccessibilityNotifier();
|
||||||
|
|
||||||
|
AccessibilityNotifier(const AccessibilityNotifier&) = delete;
|
||||||
|
AccessibilityNotifier& operator=(const AccessibilityNotifier&) = delete;
|
||||||
|
|
||||||
|
// NOTE: It is assumed that you're holding the console lock when calling any of the member functions.
|
||||||
|
// This class uses mutexes, but those are only for synchronizing with the worker threads.
|
||||||
|
|
||||||
|
void Initialize(HWND hwnd, DWORD msaaDelay, DWORD uiaDelay) noexcept;
|
||||||
|
void SetUIAProvider(IRawElementProviderSimple* provider) noexcept;
|
||||||
|
|
||||||
|
void CursorChanged(til::point position, bool activeSelection) noexcept;
|
||||||
|
void SelectionChanged() noexcept;
|
||||||
|
void RegionChanged(til::point begin, til::point end) noexcept;
|
||||||
|
void ScrollBuffer(til::CoordType delta) noexcept;
|
||||||
|
void ScrollViewport(til::point delta) noexcept;
|
||||||
|
void Layout() noexcept;
|
||||||
|
void ApplicationStart(DWORD pid) const noexcept;
|
||||||
|
void ApplicationEnd(DWORD pid) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// !!! NOTE !!!
|
||||||
|
// * _emitEventsCallback assumes that this struct can be quickly initialized with memset(0).
|
||||||
|
// * Members are intentionally left undefined so that we can create instances on the stack without initialization.
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
// EVENT_CONSOLE_CARET / ConsoleControl(ConsoleSetCaretInfo)
|
||||||
|
til::HugeCoordType eventConsoleCaretPositionX;
|
||||||
|
til::HugeCoordType eventConsoleCaretPositionY;
|
||||||
|
bool eventConsoleCaretSelecting;
|
||||||
|
bool eventConsoleCaretPrimed;
|
||||||
|
|
||||||
|
// EVENT_CONSOLE_UPDATE_REGION
|
||||||
|
til::HugeCoordType eventConsoleUpdateRegionBeginX;
|
||||||
|
til::HugeCoordType eventConsoleUpdateRegionBeginY;
|
||||||
|
til::HugeCoordType eventConsoleUpdateRegionEndX;
|
||||||
|
til::HugeCoordType eventConsoleUpdateRegionEndY;
|
||||||
|
bool eventConsoleUpdateRegionPrimed;
|
||||||
|
|
||||||
|
// EVENT_CONSOLE_UPDATE_SCROLL
|
||||||
|
til::HugeCoordType eventConsoleUpdateScrollDeltaX;
|
||||||
|
til::HugeCoordType eventConsoleUpdateScrollDeltaY;
|
||||||
|
bool eventConsoleUpdateScrollPrimed;
|
||||||
|
|
||||||
|
// EVENT_CONSOLE_LAYOUT
|
||||||
|
bool eventConsoleLayoutPrimed;
|
||||||
|
|
||||||
|
// UIA
|
||||||
|
bool textSelectionChanged; // UIA_Text_TextSelectionChangedEventId
|
||||||
|
bool textChanged; // UIA_Text_TextChangedEventId
|
||||||
|
|
||||||
|
bool timerScheduled;
|
||||||
|
};
|
||||||
|
|
||||||
|
PTP_TIMER _createTimer(PTP_TIMER_CALLBACK callback) noexcept;
|
||||||
|
void _timerSet() noexcept;
|
||||||
|
static void _timerEmitMSAA(PTP_CALLBACK_INSTANCE instance, PVOID context, PTP_TIMER timer) noexcept;
|
||||||
|
void _emitMSAA(State& msaa) const noexcept;
|
||||||
|
static void _emitUIAEvent(IRawElementProviderSimple* provider, EVENTID id) noexcept;
|
||||||
|
|
||||||
|
// The main window, used for NotifyWinEvent / ConsoleControl(ConsoleSetCaretInfo) calls.
|
||||||
|
HWND _hwnd = nullptr;
|
||||||
|
// The current UIA provider, if any.
|
||||||
|
std::atomic<IRawElementProviderSimple*> _uiaProvider{ nullptr };
|
||||||
|
// The timer object used to schedule debounced a11y events.
|
||||||
|
// It's null if the delay is set to 0.
|
||||||
|
wil::unique_threadpool_timer _timer;
|
||||||
|
// The delay to use for MSAA/UIA events, in filetime units (100ns units).
|
||||||
|
// The value will be negative because that's what SetThreadpoolTimerEx needs.
|
||||||
|
int64_t _msaaDelay = 0;
|
||||||
|
int64_t _uiaDelay = 0;
|
||||||
|
// Depending on whether we have a UIA provider or not, this points to either _msaaDelay or _uiaDelay.
|
||||||
|
FILETIME* _delay = nullptr;
|
||||||
|
// The delay window to use for SetThreadpoolTimerEx, in milliseconds.
|
||||||
|
DWORD _delayWindow = 0;
|
||||||
|
// Whether MSAA and UIA are enabled.
|
||||||
|
bool _msaaEnabled = false;
|
||||||
|
bool _uiaEnabled = false;
|
||||||
|
|
||||||
|
// _lock protects access to _state.
|
||||||
|
wil::srwlock _lock;
|
||||||
|
State _state;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -81,50 +81,12 @@ void CursorBlinker::TimerRoutine(SCREEN_INFORMATION& ScreenInfo) const noexcept
|
|||||||
auto& buffer = ScreenInfo.GetTextBuffer();
|
auto& buffer = ScreenInfo.GetTextBuffer();
|
||||||
auto& cursor = buffer.GetCursor();
|
auto& cursor = buffer.GetCursor();
|
||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
auto* const pAccessibilityNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
|
||||||
|
|
||||||
if (!WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS))
|
if (!WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS))
|
||||||
{
|
{
|
||||||
goto DoScroll;
|
goto DoScroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the cursor pos in USER so accessibility will work.
|
|
||||||
// Don't do all this work or send events if we don't have a notifier target.
|
|
||||||
if (pAccessibilityNotifier && cursor.HasMoved())
|
|
||||||
{
|
|
||||||
// Convert the buffer position to the equivalent screen coordinates
|
|
||||||
// required by the notifier, taking line rendition into account.
|
|
||||||
const auto position = buffer.BufferToScreenPosition(cursor.GetPosition());
|
|
||||||
const auto viewport = ScreenInfo.GetViewport();
|
|
||||||
const auto fontSize = ScreenInfo.GetScreenFontSize();
|
|
||||||
cursor.SetHasMoved(false);
|
|
||||||
|
|
||||||
til::rect rc;
|
|
||||||
rc.left = (position.x - viewport.Left()) * fontSize.width;
|
|
||||||
rc.top = (position.y - viewport.Top()) * fontSize.height;
|
|
||||||
rc.right = rc.left + fontSize.width;
|
|
||||||
rc.bottom = rc.top + fontSize.height;
|
|
||||||
|
|
||||||
pAccessibilityNotifier->NotifyConsoleCaretEvent(rc);
|
|
||||||
|
|
||||||
// Send accessibility information
|
|
||||||
{
|
|
||||||
auto flags = IAccessibilityNotifier::ConsoleCaretEventFlags::CaretInvisible;
|
|
||||||
|
|
||||||
// Flags is expected to be 2, 1, or 0. 2 in selecting (whether or not visible), 1 if just visible, 0 if invisible/noselect.
|
|
||||||
if (WI_IsFlagSet(gci.Flags, CONSOLE_SELECTING))
|
|
||||||
{
|
|
||||||
flags = IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection;
|
|
||||||
}
|
|
||||||
else if (cursor.IsVisible())
|
|
||||||
{
|
|
||||||
flags = IAccessibilityNotifier::ConsoleCaretEventFlags::CaretVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
pAccessibilityNotifier->NotifyConsoleCaretEvent(flags, MAKELONG(position.x, position.y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the DelayCursor flag has been set, wait one more tick before toggle.
|
// If the DelayCursor flag has been set, wait one more tick before toggle.
|
||||||
// This is used to guarantee the cursor is on for a finite period of time
|
// This is used to guarantee the cursor is on for a finite period of time
|
||||||
// after a move and off for a finite period of time after a WriteString.
|
// after a move and off for a finite period of time after a WriteString.
|
||||||
|
|||||||
@ -253,12 +253,13 @@ static FillConsoleResult FillConsoleImpl(SCREEN_INFORMATION& screenInfo, FillCon
|
|||||||
ImageSlice::EraseCells(screenInfo.GetTextBuffer(), startingCoordinate, result.cellsModified);
|
ImageSlice::EraseCells(screenInfo.GetTextBuffer(), startingCoordinate, result.cellsModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (screenBuffer.HasAccessibilityEventing())
|
|
||||||
{
|
{
|
||||||
// Notify accessibility
|
// Notify accessibility
|
||||||
auto endingCoordinate = startingCoordinate;
|
auto endingCoordinate = startingCoordinate;
|
||||||
bufferSize.WalkInBounds(endingCoordinate, result.cellsModified);
|
bufferSize.WalkInBounds(endingCoordinate, result.cellsModified);
|
||||||
screenBuffer.NotifyAccessibilityEventing(startingCoordinate.x, startingCoordinate.y, endingCoordinate.x, endingCoordinate.y);
|
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.RegionChanged(startingCoordinate, endingCoordinate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -31,6 +31,39 @@ constexpr bool controlCharPredicate(wchar_t wch)
|
|||||||
return wch < L' ' || wch == 0x007F;
|
return wch < L' ' || wch == 0x007F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static auto raiseAccessibilityEventsOnExit(SCREEN_INFORMATION& screenInfo)
|
||||||
|
{
|
||||||
|
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
const auto& bufferBefore = gci.GetActiveOutputBuffer();
|
||||||
|
const auto cursorBefore = bufferBefore.GetTextBuffer().GetCursor().GetPosition();
|
||||||
|
|
||||||
|
auto raise = wil::scope_exit([&bufferBefore, cursorBefore] {
|
||||||
|
// !!! NOTE !!! `bufferBefore` may now be a stale pointer, because VT
|
||||||
|
// sequences can switch between the main and alternative screen buffer.
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
const auto& bufferAfter = gci.GetActiveOutputBuffer();
|
||||||
|
const auto cursorAfter = bufferAfter.GetTextBuffer().GetCursor().GetPosition();
|
||||||
|
|
||||||
|
if (&bufferBefore == &bufferAfter)
|
||||||
|
{
|
||||||
|
an.RegionChanged(cursorBefore, cursorAfter);
|
||||||
|
}
|
||||||
|
if (cursorBefore != cursorAfter)
|
||||||
|
{
|
||||||
|
an.CursorChanged(cursorAfter, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Don't raise any events for inactive buffers.
|
||||||
|
if (&bufferBefore != &screenInfo)
|
||||||
|
{
|
||||||
|
raise.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return raise;
|
||||||
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - This routine updates the cursor position. Its input is the non-special
|
// - This routine updates the cursor position. Its input is the non-special
|
||||||
// cased new location of the cursor. For example, if the cursor were being
|
// cased new location of the cursor. For example, if the cursor were being
|
||||||
@ -76,12 +109,13 @@ static void AdjustCursorPosition(SCREEN_INFORMATION& screenInfo, _In_ til::point
|
|||||||
auto& buffer = screenInfo.GetTextBuffer();
|
auto& buffer = screenInfo.GetTextBuffer();
|
||||||
buffer.IncrementCircularBuffer(buffer.GetCurrentAttributes());
|
buffer.IncrementCircularBuffer(buffer.GetCurrentAttributes());
|
||||||
|
|
||||||
|
// TODO: This is very bad for performance.
|
||||||
|
// Track the total scroll offset as a int64 in buffer --> No need to track it here anymore.
|
||||||
if (buffer.IsActiveBuffer())
|
if (buffer.IsActiveBuffer())
|
||||||
{
|
{
|
||||||
if (const auto notifier = ServiceLocator::LocateAccessibilityNotifier())
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
{
|
an.ScrollBuffer(-1);
|
||||||
notifier->NotifyConsoleUpdateScrollEvent(0, -1);
|
|
||||||
}
|
|
||||||
if (const auto renderer = ServiceLocator::LocateGlobals().pRender)
|
if (const auto renderer = ServiceLocator::LocateGlobals().pRender)
|
||||||
{
|
{
|
||||||
static constexpr til::point delta{ 0, -1 };
|
static constexpr til::point delta{ 0, -1 };
|
||||||
@ -104,7 +138,6 @@ static void AdjustCursorPosition(SCREEN_INFORMATION& screenInfo, _In_ til::point
|
|||||||
static bool _writeCharsLegacyUnprocessed(SCREEN_INFORMATION& screenInfo, const std::wstring_view& text, til::CoordType* psScrollY)
|
static bool _writeCharsLegacyUnprocessed(SCREEN_INFORMATION& screenInfo, const std::wstring_view& text, til::CoordType* psScrollY)
|
||||||
{
|
{
|
||||||
const auto wrapAtEOL = WI_IsFlagSet(screenInfo.OutputMode, ENABLE_WRAP_AT_EOL_OUTPUT);
|
const auto wrapAtEOL = WI_IsFlagSet(screenInfo.OutputMode, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||||
const auto hasAccessibilityEventing = screenInfo.HasAccessibilityEventing();
|
|
||||||
auto& textBuffer = screenInfo.GetTextBuffer();
|
auto& textBuffer = screenInfo.GetTextBuffer();
|
||||||
bool wrapped = false;
|
bool wrapped = false;
|
||||||
|
|
||||||
@ -127,11 +160,6 @@ static bool _writeCharsLegacyUnprocessed(SCREEN_INFORMATION& screenInfo, const s
|
|||||||
textBuffer.SetWrapForced(cursorPosition.y, true);
|
textBuffer.SetWrapForced(cursorPosition.y, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasAccessibilityEventing && state.columnEnd > state.columnBegin)
|
|
||||||
{
|
|
||||||
screenInfo.NotifyAccessibilityEventing(state.columnBegin, cursorPosition.y, state.columnEnd - 1, cursorPosition.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
AdjustCursorPosition(screenInfo, cursorPosition, psScrollY);
|
AdjustCursorPosition(screenInfo, cursorPosition, psScrollY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +176,7 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
|
|||||||
auto& textBuffer = screenInfo.GetTextBuffer();
|
auto& textBuffer = screenInfo.GetTextBuffer();
|
||||||
const auto width = textBuffer.GetSize().Width();
|
const auto width = textBuffer.GetSize().Width();
|
||||||
auto& cursor = textBuffer.GetCursor();
|
auto& cursor = textBuffer.GetCursor();
|
||||||
|
const auto cursorPosBefore = cursor.GetPosition();
|
||||||
const auto wrapAtEOL = WI_IsFlagSet(screenInfo.OutputMode, ENABLE_WRAP_AT_EOL_OUTPUT);
|
const auto wrapAtEOL = WI_IsFlagSet(screenInfo.OutputMode, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||||
const auto beg = text.begin();
|
const auto beg = text.begin();
|
||||||
const auto end = text.end();
|
const auto end = text.end();
|
||||||
@ -156,6 +185,7 @@ void WriteCharsLegacy(SCREEN_INFORMATION& screenInfo, const std::wstring_view& t
|
|||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
auto writer = gci.GetVtWriterForBuffer(&screenInfo);
|
auto writer = gci.GetVtWriterForBuffer(&screenInfo);
|
||||||
|
|
||||||
|
const auto a11y = raiseAccessibilityEventsOnExit(screenInfo);
|
||||||
const auto snap = screenInfo.SnapOnOutput();
|
const auto snap = screenInfo.SnapOnOutput();
|
||||||
|
|
||||||
// If we enter this if condition, then someone wrote text in VT mode and now switched to non-VT mode.
|
// If we enter this if condition, then someone wrote text in VT mode and now switched to non-VT mode.
|
||||||
@ -343,6 +373,7 @@ void WriteCharsVT(SCREEN_INFORMATION& screenInfo, const std::wstring_view& str)
|
|||||||
// may change, so get the VtIo reference now, just in case.
|
// may change, so get the VtIo reference now, just in case.
|
||||||
auto writer = gci.GetVtWriterForBuffer(&screenInfo);
|
auto writer = gci.GetVtWriterForBuffer(&screenInfo);
|
||||||
|
|
||||||
|
const auto a11y = raiseAccessibilityEventsOnExit(screenInfo);
|
||||||
const auto snap = screenInfo.SnapOnOutput();
|
const auto snap = screenInfo.SnapOnOutput();
|
||||||
|
|
||||||
stateMachine.ProcessString(str);
|
stateMachine.ProcessString(str);
|
||||||
|
|||||||
@ -188,7 +188,7 @@ namespace Conhost.UIA.Tests
|
|||||||
Log.Comment("---Status Request Commands---");
|
Log.Comment("---Status Request Commands---");
|
||||||
Globals.WaitForTimeout();
|
Globals.WaitForTimeout();
|
||||||
app.UIRoot.SendKeys("c");
|
app.UIRoot.SendKeys("c");
|
||||||
string expectedTitle = string.Format("Response Received: {0}", "\x1b[?1;0c");
|
string expectedTitle = string.Format("Response Received: {0}", "\x1b[?61;4;6;7;14;21;22;23;24;28;32;42;52c");
|
||||||
|
|
||||||
Globals.WaitForTimeout();
|
Globals.WaitForTimeout();
|
||||||
string title = app.GetWindowTitle();
|
string title = app.GetWindowTitle();
|
||||||
|
|||||||
@ -796,6 +796,8 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
|
|||||||
// how the cmd shell's CLS command resets the buffer.
|
// how the cmd shell's CLS command resets the buffer.
|
||||||
buffer.UpdateBottom();
|
buffer.UpdateBottom();
|
||||||
|
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.CursorChanged(buffer.GetTextBuffer().GetCursor().GetPosition(), false);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
|
|||||||
@ -17,19 +17,18 @@ Revision History:
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "AccessibilityNotifier.h"
|
||||||
|
#include "ApiRoutines.h"
|
||||||
|
#include "ConsoleArguments.hpp"
|
||||||
#include "selection.hpp"
|
#include "selection.hpp"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "ConsoleArguments.hpp"
|
|
||||||
#include "ApiRoutines.h"
|
|
||||||
|
|
||||||
#include "../propslib/DelegationConfig.hpp"
|
#include "../propslib/DelegationConfig.hpp"
|
||||||
#include "../renderer/base/Renderer.hpp"
|
#include "../renderer/base/Renderer.hpp"
|
||||||
#include "../server/DeviceComm.h"
|
#include "../server/DeviceComm.h"
|
||||||
#include "../tsf/Handle.h"
|
#include "../tsf/Handle.h"
|
||||||
#include "../server/ConDrvDeviceComm.h"
|
|
||||||
|
|
||||||
#include <TraceLoggingProvider.h>
|
#include <TraceLoggingProvider.h>
|
||||||
#include <winmeta.h>
|
|
||||||
TRACELOGGING_DECLARE_PROVIDER(g_hConhostV2EventTraceProvider);
|
TRACELOGGING_DECLARE_PROVIDER(g_hConhostV2EventTraceProvider);
|
||||||
|
|
||||||
class Globals
|
class Globals
|
||||||
@ -63,6 +62,7 @@ public:
|
|||||||
std::vector<wchar_t> WordDelimiters;
|
std::vector<wchar_t> WordDelimiters;
|
||||||
Microsoft::Console::Render::Renderer* pRender;
|
Microsoft::Console::Render::Renderer* pRender;
|
||||||
Microsoft::Console::TSF::Handle tsf;
|
Microsoft::Console::TSF::Handle tsf;
|
||||||
|
Microsoft::Console::AccessibilityNotifier accessibilityNotifier;
|
||||||
Microsoft::Console::Render::IFontDefaultList* pFontDefaultList;
|
Microsoft::Console::Render::IFontDefaultList* pFontDefaultList;
|
||||||
|
|
||||||
bool IsHeadless() const;
|
bool IsHeadless() const;
|
||||||
|
|||||||
@ -47,6 +47,7 @@
|
|||||||
<ClCompile Include="..\writeData.cpp" />
|
<ClCompile Include="..\writeData.cpp" />
|
||||||
<ClCompile Include="..\_output.cpp" />
|
<ClCompile Include="..\_output.cpp" />
|
||||||
<ClCompile Include="..\_stream.cpp" />
|
<ClCompile Include="..\_stream.cpp" />
|
||||||
|
<ClCompile Include="..\AccessibilityNotifier.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\IIoProvider.hpp" />
|
<ClInclude Include="..\IIoProvider.hpp" />
|
||||||
@ -95,6 +96,7 @@
|
|||||||
<ClInclude Include="..\writeData.hpp" />
|
<ClInclude Include="..\writeData.hpp" />
|
||||||
<ClInclude Include="..\_output.h" />
|
<ClInclude Include="..\_output.h" />
|
||||||
<ClInclude Include="..\_stream.h" />
|
<ClInclude Include="..\_stream.h" />
|
||||||
|
<ClInclude Include="..\AccessibilityNotifier.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\audio\midi\lib\midi.vcxproj">
|
<ProjectReference Include="..\..\audio\midi\lib\midi.vcxproj">
|
||||||
|
|||||||
@ -355,6 +355,6 @@ void ProcessCtrlEvents()
|
|||||||
// The bad news is that EndTask() returns STATUS_UNSUCCESSFUL no matter whether
|
// The bad news is that EndTask() returns STATUS_UNSUCCESSFUL no matter whether
|
||||||
// the process was already dead, or if the request actually failed for some reason.
|
// the process was already dead, or if the request actually failed for some reason.
|
||||||
// Hopefully there aren't any regressions, but we can't know without trying.
|
// Hopefully there aren't any regressions, but we can't know without trying.
|
||||||
LOG_IF_NTSTATUS_FAILED(ctrl->EndTask(r.dwProcessID, EventType, CtrlFlags));
|
ctrl->EndTask(r.dwProcessID, EventType, CtrlFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,6 +147,9 @@
|
|||||||
<ClCompile Include="..\CursorBlinker.cpp">
|
<ClCompile Include="..\CursorBlinker.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\AccessibilityNotifier.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\precomp.h">
|
<ClInclude Include="..\precomp.h">
|
||||||
@ -287,6 +290,9 @@
|
|||||||
<ClInclude Include="..\IIoProvider.hpp">
|
<ClInclude Include="..\IIoProvider.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\AccessibilityNotifier.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||||
|
|||||||
@ -5,10 +5,6 @@
|
|||||||
|
|
||||||
#include "_output.h"
|
#include "_output.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "handle.h"
|
|
||||||
|
|
||||||
#include "getset.h"
|
|
||||||
#include "misc.h"
|
|
||||||
|
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
#include "../types/inc/Viewport.hpp"
|
#include "../types/inc/Viewport.hpp"
|
||||||
@ -283,17 +279,8 @@ void ScreenBufferSizeChange(const til::size coordNewSize)
|
|||||||
// - source - The viewport describing the region where data was copied from
|
// - source - The viewport describing the region where data was copied from
|
||||||
// - fill - The viewport describing the area that was filled in with the fill character (uncovered area)
|
// - fill - The viewport describing the area that was filled in with the fill character (uncovered area)
|
||||||
// - target - The viewport describing the region where data was copied to
|
// - target - The viewport describing the region where data was copied to
|
||||||
static void _ScrollScreen(SCREEN_INFORMATION& screenInfo, const Viewport& source, const Viewport& fill, const Viewport& target)
|
static void _ScrollScreen(SCREEN_INFORMATION& screenInfo, const Viewport& fill, const Viewport& target)
|
||||||
{
|
{
|
||||||
if (screenInfo.IsActiveScreenBuffer())
|
|
||||||
{
|
|
||||||
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
|
||||||
if (pNotifier != nullptr)
|
|
||||||
{
|
|
||||||
pNotifier->NotifyConsoleUpdateScrollEvent(target.Origin().x - source.Left(), target.Origin().y - source.RightInclusive());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the text buffer and send it commands.
|
// Get the text buffer and send it commands.
|
||||||
// It will figure out whether or not we're active and where the messages need to go.
|
// It will figure out whether or not we're active and where the messages need to go.
|
||||||
auto& textBuffer = screenInfo.GetTextBuffer();
|
auto& textBuffer = screenInfo.GetTextBuffer();
|
||||||
@ -413,7 +400,7 @@ void ScrollRegion(SCREEN_INFORMATION& screenInfo,
|
|||||||
_CopyRectangle(screenInfo, source, target.Origin());
|
_CopyRectangle(screenInfo, source, target.Origin());
|
||||||
|
|
||||||
// Notify the renderer and accessibility as to what moved and where.
|
// Notify the renderer and accessibility as to what moved and where.
|
||||||
_ScrollScreen(screenInfo, source, fill, target);
|
_ScrollScreen(screenInfo, fill, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ 6. FILL ------
|
// ------ 6. FILL ------
|
||||||
|
|||||||
@ -408,42 +408,14 @@ bool ConhostInternalGetSet::IsVtInputEnabled() const
|
|||||||
return _io.GetActiveInputBuffer()->IsInVirtualTerminalInputMode();
|
return _io.GetActiveInputBuffer()->IsInVirtualTerminalInputMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
|
||||||
// - Lets accessibility apps know when an area of the screen has changed.
|
|
||||||
// Arguments:
|
|
||||||
// - changedRect - the area that has changed.
|
|
||||||
// Return value:
|
|
||||||
// - <none>
|
|
||||||
void ConhostInternalGetSet::NotifyAccessibilityChange(const til::rect& changedRect)
|
|
||||||
{
|
|
||||||
auto& screenInfo = _io.GetActiveOutputBuffer();
|
|
||||||
if (screenInfo.HasAccessibilityEventing() && changedRect)
|
|
||||||
{
|
|
||||||
screenInfo.NotifyAccessibilityEventing(
|
|
||||||
changedRect.left,
|
|
||||||
changedRect.top,
|
|
||||||
changedRect.right - 1,
|
|
||||||
changedRect.bottom - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - Implements conhost-specific behavior when the buffer is rotated.
|
// - Implements conhost-specific behavior when the buffer is rotated.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - delta - the number of cycles that the buffer has rotated.
|
// - delta - the number of cycles that the buffer has rotated.
|
||||||
// Return value:
|
// Return value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void ConhostInternalGetSet::NotifyBufferRotation(const int delta)
|
void ConhostInternalGetSet::NotifyBufferRotation(const int)
|
||||||
{
|
{
|
||||||
auto& screenInfo = _io.GetActiveOutputBuffer();
|
|
||||||
if (screenInfo.IsActiveScreenBuffer())
|
|
||||||
{
|
|
||||||
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
|
||||||
if (pNotifier)
|
|
||||||
{
|
|
||||||
pNotifier->NotifyConsoleUpdateScrollEvent(0, -delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConhostInternalGetSet::NotifyShellIntegrationMark()
|
void ConhostInternalGetSet::NotifyShellIntegrationMark()
|
||||||
|
|||||||
@ -65,7 +65,6 @@ public:
|
|||||||
|
|
||||||
bool IsVtInputEnabled() const override;
|
bool IsVtInputEnabled() const override;
|
||||||
|
|
||||||
void NotifyAccessibilityChange(const til::rect& changedRect) override;
|
|
||||||
void NotifyBufferRotation(const int delta) override;
|
void NotifyBufferRotation(const int delta) override;
|
||||||
void NotifyShellIntegrationMark() override;
|
void NotifyShellIntegrationMark() override;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,8 @@
|
|||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
#include "../types/inc/CodepointWidthDetector.hpp"
|
#include "../types/inc/CodepointWidthDetector.hpp"
|
||||||
#include "../types/inc/convert.hpp"
|
#include "../terminal/adapter/adaptDispatch.hpp"
|
||||||
|
#include "../terminal/parser/OutputStateMachineEngine.hpp"
|
||||||
|
|
||||||
using namespace Microsoft::Console;
|
using namespace Microsoft::Console;
|
||||||
using namespace Microsoft::Console::Types;
|
using namespace Microsoft::Console::Types;
|
||||||
@ -19,7 +20,6 @@ using namespace Microsoft::Console::VirtualTerminal;
|
|||||||
|
|
||||||
SCREEN_INFORMATION::SCREEN_INFORMATION(
|
SCREEN_INFORMATION::SCREEN_INFORMATION(
|
||||||
_In_ IWindowMetrics* pMetrics,
|
_In_ IWindowMetrics* pMetrics,
|
||||||
_In_ IAccessibilityNotifier* pNotifier,
|
|
||||||
const TextAttribute popupAttributes,
|
const TextAttribute popupAttributes,
|
||||||
const FontInfo fontInfo) :
|
const FontInfo fontInfo) :
|
||||||
OutputMode{ ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT },
|
OutputMode{ ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT },
|
||||||
@ -31,7 +31,6 @@ SCREEN_INFORMATION::SCREEN_INFORMATION(
|
|||||||
FillOutDbcsLeadChar{ 0 },
|
FillOutDbcsLeadChar{ 0 },
|
||||||
ScrollScale{ 1ul },
|
ScrollScale{ 1ul },
|
||||||
_pConsoleWindowMetrics{ pMetrics },
|
_pConsoleWindowMetrics{ pMetrics },
|
||||||
_pAccessibilityNotifier{ pNotifier },
|
|
||||||
_api{ *this },
|
_api{ *this },
|
||||||
_stateMachine{ nullptr },
|
_stateMachine{ nullptr },
|
||||||
_viewport(Viewport::Empty()),
|
_viewport(Viewport::Empty()),
|
||||||
@ -89,11 +88,10 @@ SCREEN_INFORMATION::~SCREEN_INFORMATION()
|
|||||||
auto pMetrics = ServiceLocator::LocateWindowMetrics();
|
auto pMetrics = ServiceLocator::LocateWindowMetrics();
|
||||||
THROW_HR_IF_NULL(E_FAIL, pMetrics);
|
THROW_HR_IF_NULL(E_FAIL, pMetrics);
|
||||||
|
|
||||||
const auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
|
||||||
// It is possible for pNotifier to be null and that's OK.
|
// It is possible for pNotifier to be null and that's OK.
|
||||||
// For instance, the PTY doesn't need to send events. Just pass it along
|
// For instance, the PTY doesn't need to send events. Just pass it along
|
||||||
// and be sure that `SCREEN_INFORMATION` bypasses all event work if it's not there.
|
// and be sure that `SCREEN_INFORMATION` bypasses all event work if it's not there.
|
||||||
const auto pScreen = new SCREEN_INFORMATION(pMetrics, pNotifier, popupAttributes, fontInfo);
|
const auto pScreen = new SCREEN_INFORMATION(pMetrics, popupAttributes, fontInfo);
|
||||||
|
|
||||||
// Set up viewport
|
// Set up viewport
|
||||||
pScreen->_viewport = Viewport::FromDimensions({ 0, 0 },
|
pScreen->_viewport = Viewport::FromDimensions({ 0, 0 },
|
||||||
@ -572,70 +570,6 @@ void SCREEN_INFORMATION::UpdateFont(const FontInfo* const pfiNewFont)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
|
||||||
// - Informs clients whether we have accessibility eventing so they can
|
|
||||||
// save themselves the work of performing math or lookups before calling
|
|
||||||
// `NotifyAccessibilityEventing`.
|
|
||||||
// Arguments:
|
|
||||||
// - <none>
|
|
||||||
// Return Value:
|
|
||||||
// - True if we have an accessibility listener. False otherwise.
|
|
||||||
bool SCREEN_INFORMATION::HasAccessibilityEventing() const noexcept
|
|
||||||
{
|
|
||||||
return _pAccessibilityNotifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: This method was historically used to notify accessibility apps AND
|
|
||||||
// to aggregate drawing metadata to determine whether or not to use PolyTextOut.
|
|
||||||
// After the Nov 2015 graphics refactor, the metadata drawing flag calculation is no longer necessary.
|
|
||||||
// This now only notifies accessibility apps of a change.
|
|
||||||
void SCREEN_INFORMATION::NotifyAccessibilityEventing(const til::CoordType sStartX,
|
|
||||||
const til::CoordType sStartY,
|
|
||||||
const til::CoordType sEndX,
|
|
||||||
const til::CoordType sEndY)
|
|
||||||
{
|
|
||||||
if (!_pAccessibilityNotifier)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire off a winevent to let accessibility apps know what changed.
|
|
||||||
if (IsActiveScreenBuffer())
|
|
||||||
{
|
|
||||||
const auto coordScreenBufferSize = GetBufferSize().Dimensions();
|
|
||||||
FAIL_FAST_IF(!(sEndX < coordScreenBufferSize.width));
|
|
||||||
|
|
||||||
if (sStartX == sEndX && sStartY == sEndY)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const auto cellData = GetCellDataAt({ sStartX, sStartY });
|
|
||||||
const auto charAndAttr = MAKELONG(Utf16ToUcs2(cellData->Chars()),
|
|
||||||
cellData->TextAttr().GetLegacyAttributes());
|
|
||||||
_pAccessibilityNotifier->NotifyConsoleUpdateSimpleEvent(MAKELONG(sStartX, sStartY),
|
|
||||||
charAndAttr);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
LOG_HR(wil::ResultFromCaughtException());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pAccessibilityNotifier->NotifyConsoleUpdateRegionEvent(MAKELONG(sStartX, sStartY),
|
|
||||||
MAKELONG(sEndX, sEndY));
|
|
||||||
}
|
|
||||||
auto pConsoleWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pConsoleWindow)
|
|
||||||
{
|
|
||||||
LOG_IF_FAILED(pConsoleWindow->SignalUia(UIA_Text_TextChangedEventId));
|
|
||||||
// TODO MSFT 7960168 do we really need this event to not signal?
|
|
||||||
//pConsoleWindow->SignalUia(UIA_LayoutInvalidatedEventId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region UI_Refresh
|
#pragma region UI_Refresh
|
||||||
@ -663,10 +597,7 @@ SCREEN_INFORMATION::ScrollBarState SCREEN_INFORMATION::FetchScrollBarState()
|
|||||||
WI_ClearFlag(gci.Flags, CONSOLE_UPDATING_SCROLL_BARS);
|
WI_ClearFlag(gci.Flags, CONSOLE_UPDATING_SCROLL_BARS);
|
||||||
|
|
||||||
// Fire off an event to let accessibility apps know the layout has changed.
|
// Fire off an event to let accessibility apps know the layout has changed.
|
||||||
if (_pAccessibilityNotifier)
|
ServiceLocator::LocateGlobals().accessibilityNotifier.Layout();
|
||||||
{
|
|
||||||
_pAccessibilityNotifier->NotifyConsoleLayoutEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto buffer = GetBufferSize();
|
const auto buffer = GetBufferSize();
|
||||||
const auto isAltBuffer = _IsAltBuffer();
|
const auto isAltBuffer = _IsAltBuffer();
|
||||||
@ -1481,15 +1412,12 @@ NT_CATCH_RETURN()
|
|||||||
|
|
||||||
if (SUCCEEDED_NTSTATUS(status))
|
if (SUCCEEDED_NTSTATUS(status))
|
||||||
{
|
{
|
||||||
if (HasAccessibilityEventing())
|
|
||||||
{
|
|
||||||
NotifyAccessibilityEventing(0, 0, coordNewScreenSize.width - 1, coordNewScreenSize.height - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire off an event to let accessibility apps know the layout has changed.
|
// Fire off an event to let accessibility apps know the layout has changed.
|
||||||
if (_pAccessibilityNotifier && IsActiveScreenBuffer())
|
if (IsActiveScreenBuffer())
|
||||||
{
|
{
|
||||||
_pAccessibilityNotifier->NotifyConsoleLayoutEvent();
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.RegionChanged({}, { coordNewScreenSize.width - 1, coordNewScreenSize.height - 1 });
|
||||||
|
an.Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fDoScrollBarUpdate)
|
if (fDoScrollBarUpdate)
|
||||||
@ -1665,7 +1593,6 @@ void SCREEN_INFORMATION::SetCursorDBMode(const bool DoubleCursor)
|
|||||||
{
|
{
|
||||||
cursor.SetDelay(true);
|
cursor.SetDelay(true);
|
||||||
}
|
}
|
||||||
cursor.SetHasMoved(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|||||||
@ -19,8 +19,6 @@ Revision History:
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "conapi.h"
|
|
||||||
#include "settings.hpp"
|
|
||||||
#include "outputStream.hpp"
|
#include "outputStream.hpp"
|
||||||
|
|
||||||
#include "../buffer/out/OutputCellRect.hpp"
|
#include "../buffer/out/OutputCellRect.hpp"
|
||||||
@ -30,15 +28,10 @@ Revision History:
|
|||||||
#include "../buffer/out/textBufferTextIterator.hpp"
|
#include "../buffer/out/textBufferTextIterator.hpp"
|
||||||
|
|
||||||
#include "IIoProvider.hpp"
|
#include "IIoProvider.hpp"
|
||||||
#include "outputStream.hpp"
|
|
||||||
#include "../terminal/adapter/adaptDispatch.hpp"
|
|
||||||
#include "../terminal/parser/stateMachine.hpp"
|
#include "../terminal/parser/stateMachine.hpp"
|
||||||
#include "../terminal/parser/OutputStateMachineEngine.hpp"
|
|
||||||
|
|
||||||
#include "../server/ObjectHeader.h"
|
#include "../server/ObjectHeader.h"
|
||||||
|
|
||||||
#include "../interactivity/inc/IAccessibilityNotifier.hpp"
|
|
||||||
#include "../interactivity/inc/IConsoleWindow.hpp"
|
|
||||||
#include "../interactivity/inc/IWindowMetrics.hpp"
|
#include "../interactivity/inc/IWindowMetrics.hpp"
|
||||||
|
|
||||||
#include "../renderer/inc/FontInfo.hpp"
|
#include "../renderer/inc/FontInfo.hpp"
|
||||||
@ -110,9 +103,6 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] NTSTATUS ResizeScreenBuffer(const til::size coordNewScreenSize, const bool fDoScrollBarUpdate);
|
[[nodiscard]] NTSTATUS ResizeScreenBuffer(const til::size coordNewScreenSize, const bool fDoScrollBarUpdate);
|
||||||
|
|
||||||
bool HasAccessibilityEventing() const noexcept;
|
|
||||||
void NotifyAccessibilityEventing(const til::CoordType sStartX, const til::CoordType sStartY, const til::CoordType sEndX, const til::CoordType sEndY);
|
|
||||||
|
|
||||||
struct ScrollBarState
|
struct ScrollBarState
|
||||||
{
|
{
|
||||||
til::size maxSize;
|
til::size maxSize;
|
||||||
@ -236,12 +226,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
SCREEN_INFORMATION(_In_ Microsoft::Console::Interactivity::IWindowMetrics* pMetrics,
|
SCREEN_INFORMATION(_In_ Microsoft::Console::Interactivity::IWindowMetrics* pMetrics,
|
||||||
_In_ Microsoft::Console::Interactivity::IAccessibilityNotifier* pNotifier,
|
|
||||||
const TextAttribute popupAttributes,
|
const TextAttribute popupAttributes,
|
||||||
const FontInfo fontInfo);
|
const FontInfo fontInfo);
|
||||||
|
|
||||||
Microsoft::Console::Interactivity::IWindowMetrics* _pConsoleWindowMetrics;
|
Microsoft::Console::Interactivity::IWindowMetrics* _pConsoleWindowMetrics;
|
||||||
Microsoft::Console::Interactivity::IAccessibilityNotifier* _pAccessibilityNotifier;
|
|
||||||
|
|
||||||
[[nodiscard]] HRESULT _AdjustScreenBufferHelper(const til::rect* const prcClientNew,
|
[[nodiscard]] HRESULT _AdjustScreenBufferHelper(const til::rect* const prcClientNew,
|
||||||
const til::size coordBufferOld,
|
const til::size coordBufferOld,
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
#include "_output.h"
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "scrolling.hpp"
|
#include "scrolling.hpp"
|
||||||
|
|
||||||
@ -121,10 +120,9 @@ void Selection::_SetSelectionVisibility(const bool fMakeVisible)
|
|||||||
|
|
||||||
_PaintSelection();
|
_PaintSelection();
|
||||||
}
|
}
|
||||||
if (const auto window = ServiceLocator::LocateConsoleWindow())
|
|
||||||
{
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
LOG_IF_FAILED(window->SignalUia(UIA_Text_TextSelectionChangedEventId));
|
an.SelectionChanged();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -179,15 +177,14 @@ void Selection::InitializeMouseSelection(const til::point coordBufferPos)
|
|||||||
if (pWindow != nullptr)
|
if (pWindow != nullptr)
|
||||||
{
|
{
|
||||||
pWindow->UpdateWindowText();
|
pWindow->UpdateWindowText();
|
||||||
LOG_IF_FAILED(pWindow->SignalUia(UIA_Text_TextSelectionChangedEventId));
|
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.SelectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire off an event to let accessibility apps know the selection has changed.
|
// Fire off an event to let accessibility apps know the selection has changed.
|
||||||
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
if (pNotifier)
|
an.CursorChanged(coordBufferPos, true);
|
||||||
{
|
|
||||||
pNotifier->NotifyConsoleCaretEvent(IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection, PACKCOORD(coordBufferPos));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -303,14 +300,9 @@ void Selection::_ExtendSelection(Selection::SelectionData* d, _In_ til::point co
|
|||||||
_PaintSelection();
|
_PaintSelection();
|
||||||
|
|
||||||
// Fire off an event to let accessibility apps know the selection has changed.
|
// Fire off an event to let accessibility apps know the selection has changed.
|
||||||
if (const auto pNotifier = ServiceLocator::LocateAccessibilityNotifier())
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
{
|
an.CursorChanged(coordBufferPos, true);
|
||||||
pNotifier->NotifyConsoleCaretEvent(IAccessibilityNotifier::ConsoleCaretEventFlags::CaretSelection, PACKCOORD(coordBufferPos));
|
an.SelectionChanged();
|
||||||
}
|
|
||||||
if (const auto window = ServiceLocator::LocateConsoleWindow())
|
|
||||||
{
|
|
||||||
LOG_IF_FAILED(window->SignalUia(UIA_Text_TextSelectionChangedEventId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -338,7 +330,9 @@ void Selection::_CancelMouseSelection()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark the cursor position as changed so we'll fire off a win event.
|
// Mark the cursor position as changed so we'll fire off a win event.
|
||||||
ScreenInfo.GetTextBuffer().GetCursor().SetHasMoved(true);
|
// NOTE(lhecker): Why is this the only cancel function that would raise a WinEvent? Makes no sense to me.
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.CursorChanged(ScreenInfo.GetTextBuffer().GetCursor().GetPosition(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -402,10 +396,9 @@ void Selection::ClearSelection(const bool fStartingNewSelection)
|
|||||||
{
|
{
|
||||||
_CancelMarkSelection();
|
_CancelMarkSelection();
|
||||||
}
|
}
|
||||||
if (const auto window = ServiceLocator::LocateConsoleWindow())
|
|
||||||
{
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
LOG_IF_FAILED(window->SignalUia(UIA_Text_TextSelectionChangedEventId));
|
an.SelectionChanged();
|
||||||
}
|
|
||||||
|
|
||||||
auto d{ _d.write() };
|
auto d{ _d.write() };
|
||||||
wil::hide_name _d;
|
wil::hide_name _d;
|
||||||
@ -523,7 +516,9 @@ void Selection::InitializeMarkSelection()
|
|||||||
if (pWindow != nullptr)
|
if (pWindow != nullptr)
|
||||||
{
|
{
|
||||||
pWindow->UpdateWindowText();
|
pWindow->UpdateWindowText();
|
||||||
LOG_IF_FAILED(pWindow->SignalUia(UIA_Text_TextSelectionChangedEventId));
|
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.SelectionChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ Revision History:
|
|||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
#include "../interactivity/inc/IAccessibilityNotifier.hpp"
|
|
||||||
#include "../interactivity/inc/IConsoleWindow.hpp"
|
#include "../interactivity/inc/IConsoleWindow.hpp"
|
||||||
#include "til/generational.h"
|
#include "til/generational.h"
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,7 @@
|
|||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
#include "../buffer/out/search.h"
|
#include "../buffer/out/search.h"
|
||||||
|
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
#include "../types/inc/convert.hpp"
|
|
||||||
|
|
||||||
using namespace Microsoft::Console::Types;
|
using namespace Microsoft::Console::Types;
|
||||||
using Microsoft::Console::Interactivity::ServiceLocator;
|
using Microsoft::Console::Interactivity::ServiceLocator;
|
||||||
@ -903,11 +901,13 @@ bool Selection::_HandleMarkModeSelectionNav(const INPUT_KEY_INFO* const pInputKe
|
|||||||
d->fUseAlternateSelection = false;
|
d->fUseAlternateSelection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor.SetHasMoved(true);
|
|
||||||
d->coordSelectionAnchor = textBuffer.GetCursor().GetPosition();
|
d->coordSelectionAnchor = textBuffer.GetCursor().GetPosition();
|
||||||
ScreenInfo.MakeCursorVisible(d->coordSelectionAnchor);
|
ScreenInfo.MakeCursorVisible(d->coordSelectionAnchor);
|
||||||
d->srSelectionRect.left = d->srSelectionRect.right = d->coordSelectionAnchor.x;
|
d->srSelectionRect.left = d->srSelectionRect.right = d->coordSelectionAnchor.x;
|
||||||
d->srSelectionRect.top = d->srSelectionRect.bottom = d->coordSelectionAnchor.y;
|
d->srSelectionRect.top = d->srSelectionRect.bottom = d->coordSelectionAnchor.y;
|
||||||
|
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.CursorChanged(d->coordSelectionAnchor, true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
|
|
||||||
#include "../types/inc/viewport.hpp"
|
#include "../types/inc/viewport.hpp"
|
||||||
|
|
||||||
using namespace Microsoft::Console::Types;
|
using namespace Microsoft::Console::Types;
|
||||||
|
|||||||
@ -777,6 +777,16 @@ std::wstring_view Settings::GetAnswerbackMessage() const noexcept
|
|||||||
return _answerbackMessage;
|
return _answerbackMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD Settings::GetMSAADelay() const noexcept
|
||||||
|
{
|
||||||
|
return _msaaDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD Settings::GetUIADelay() const noexcept
|
||||||
|
{
|
||||||
|
return _uiaDelay;
|
||||||
|
}
|
||||||
|
|
||||||
// Determines whether our primary renderer should be DirectX or GDI.
|
// Determines whether our primary renderer should be DirectX or GDI.
|
||||||
// This is based on user preference and velocity hold back state.
|
// This is based on user preference and velocity hold back state.
|
||||||
bool Settings::GetUseDx() const noexcept
|
bool Settings::GetUseDx() const noexcept
|
||||||
|
|||||||
@ -179,6 +179,8 @@ public:
|
|||||||
|
|
||||||
std::wstring_view GetAnswerbackMessage() const noexcept;
|
std::wstring_view GetAnswerbackMessage() const noexcept;
|
||||||
|
|
||||||
|
DWORD GetMSAADelay() const noexcept;
|
||||||
|
DWORD GetUIADelay() const noexcept;
|
||||||
bool GetUseDx() const noexcept;
|
bool GetUseDx() const noexcept;
|
||||||
bool GetCopyColor() const noexcept;
|
bool GetCopyColor() const noexcept;
|
||||||
SettingsTextMeasurementMode GetTextMeasurementMode() const noexcept;
|
SettingsTextMeasurementMode GetTextMeasurementMode() const noexcept;
|
||||||
@ -225,6 +227,8 @@ private:
|
|||||||
std::wstring _LaunchFaceName;
|
std::wstring _LaunchFaceName;
|
||||||
bool _fAllowAltF4Close;
|
bool _fAllowAltF4Close;
|
||||||
DWORD _dwVirtTermLevel;
|
DWORD _dwVirtTermLevel;
|
||||||
|
DWORD _msaaDelay = 100;
|
||||||
|
DWORD _uiaDelay = 25;
|
||||||
SettingsTextMeasurementMode _textMeasurement = SettingsTextMeasurementMode::Graphemes;
|
SettingsTextMeasurementMode _textMeasurement = SettingsTextMeasurementMode::Graphemes;
|
||||||
bool _fUseDx;
|
bool _fUseDx;
|
||||||
bool _fCopyColor;
|
bool _fCopyColor;
|
||||||
@ -238,7 +242,7 @@ private:
|
|||||||
|
|
||||||
bool _fInterceptCopyPaste;
|
bool _fInterceptCopyPaste;
|
||||||
|
|
||||||
bool _TerminalScrolling;
|
bool _TerminalScrolling = true;
|
||||||
WCHAR _answerbackMessage[32] = {};
|
WCHAR _answerbackMessage[32] = {};
|
||||||
friend class RegistrySerialization;
|
friend class RegistrySerialization;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "../interactivity/base/ApiDetector.hpp"
|
#include "../interactivity/base/ApiDetector.hpp"
|
||||||
#include "../interactivity/base/RemoteConsoleControl.hpp"
|
#include "../interactivity/base/RemoteConsoleControl.hpp"
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
|
#include "../server/ConDrvDeviceComm.h"
|
||||||
#include "../server/DeviceHandle.h"
|
#include "../server/DeviceHandle.h"
|
||||||
#include "../server/IoSorter.h"
|
#include "../server/IoSorter.h"
|
||||||
#include "../types/inc/CodepointWidthDetector.hpp"
|
#include "../types/inc/CodepointWidthDetector.hpp"
|
||||||
@ -73,17 +74,6 @@ try
|
|||||||
Globals.defaultTerminalMarkerCheckRequired = true;
|
Globals.defaultTerminalMarkerCheckRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the accessibility notifier early in the startup process.
|
|
||||||
// Only create if we're not in PTY mode.
|
|
||||||
// The notifiers use expensive legacy MSAA events and the PTY isn't even responsible
|
|
||||||
// for the terminal user interface, so we should set ourselves up to skip all
|
|
||||||
// those notifications and the mathematical calculations required to send those events
|
|
||||||
// for performance reasons.
|
|
||||||
if (!args->InConptyMode())
|
|
||||||
{
|
|
||||||
RETURN_IF_FAILED(ServiceLocator::CreateAccessibilityNotifier());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed allocation of scroll buffer here.
|
// Removed allocation of scroll buffer here.
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,17 +3,11 @@
|
|||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
#include "_stream.h"
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "readDataRaw.hpp"
|
#include "readDataRaw.hpp"
|
||||||
|
|
||||||
#include "ApiRoutines.h"
|
|
||||||
|
|
||||||
#include "../types/inc/GlyphWidth.hpp"
|
|
||||||
|
|
||||||
#include "../interactivity/inc/ServiceLocator.hpp"
|
#include "../interactivity/inc/ServiceLocator.hpp"
|
||||||
|
|
||||||
using Microsoft::Console::Interactivity::ServiceLocator;
|
using Microsoft::Console::Interactivity::ServiceLocator;
|
||||||
|
|||||||
@ -363,9 +363,6 @@ void TextBufferTests::TestCopyProperties()
|
|||||||
VERIFY_IS_NOT_NULL(testTextBuffer.get());
|
VERIFY_IS_NOT_NULL(testTextBuffer.get());
|
||||||
|
|
||||||
// set initial mapping values
|
// set initial mapping values
|
||||||
testTextBuffer->GetCursor().SetHasMoved(false);
|
|
||||||
otherTbi.GetCursor().SetHasMoved(true);
|
|
||||||
|
|
||||||
testTextBuffer->GetCursor().SetIsVisible(false);
|
testTextBuffer->GetCursor().SetIsVisible(false);
|
||||||
otherTbi.GetCursor().SetIsVisible(true);
|
otherTbi.GetCursor().SetIsVisible(true);
|
||||||
|
|
||||||
@ -382,7 +379,6 @@ void TextBufferTests::TestCopyProperties()
|
|||||||
testTextBuffer->CopyProperties(otherTbi);
|
testTextBuffer->CopyProperties(otherTbi);
|
||||||
|
|
||||||
// test that new now contains values from other
|
// test that new now contains values from other
|
||||||
VERIFY_IS_TRUE(testTextBuffer->GetCursor().HasMoved());
|
|
||||||
VERIFY_IS_TRUE(testTextBuffer->GetCursor().IsVisible());
|
VERIFY_IS_TRUE(testTextBuffer->GetCursor().IsVisible());
|
||||||
VERIFY_IS_TRUE(testTextBuffer->GetCursor().IsOn());
|
VERIFY_IS_TRUE(testTextBuffer->GetCursor().IsOn());
|
||||||
VERIFY_IS_TRUE(testTextBuffer->GetCursor().IsDouble());
|
VERIFY_IS_TRUE(testTextBuffer->GetCursor().IsDouble());
|
||||||
|
|||||||
@ -9,6 +9,10 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|||||||
inline constexpr CoordType CoordTypeMin = INT32_MIN;
|
inline constexpr CoordType CoordTypeMin = INT32_MIN;
|
||||||
inline constexpr CoordType CoordTypeMax = INT32_MAX;
|
inline constexpr CoordType CoordTypeMax = INT32_MAX;
|
||||||
|
|
||||||
|
using HugeCoordType = int64_t;
|
||||||
|
inline constexpr HugeCoordType HugeCoordTypeMin = INT64_MIN;
|
||||||
|
inline constexpr HugeCoordType HugeCoordTypeMax = INT64_MAX;
|
||||||
|
|
||||||
namespace details
|
namespace details
|
||||||
{
|
{
|
||||||
template<typename T, typename U = T>
|
template<typename T, typename U = T>
|
||||||
@ -249,6 +253,15 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr COORD unwrap_coord_clamped(const point pt) noexcept
|
||||||
|
{
|
||||||
|
constexpr short min = -32768;
|
||||||
|
constexpr short max = 32767;
|
||||||
|
const auto x = pt.x < min ? min : (pt.x > max ? max : gsl::narrow_cast<short>(pt.x));
|
||||||
|
const auto y = pt.y < min ? min : (pt.y > max ? max : gsl::narrow_cast<short>(pt.y));
|
||||||
|
return { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
constexpr HRESULT unwrap_coord_hr(const point pt, COORD& out) noexcept
|
constexpr HRESULT unwrap_coord_hr(const point pt, COORD& out) noexcept
|
||||||
{
|
{
|
||||||
short x = 0;
|
short x = 0;
|
||||||
|
|||||||
@ -86,10 +86,8 @@ T HostSignalInputThread::_ReceiveTypedPacket()
|
|||||||
{
|
{
|
||||||
case HostSignals::NotifyApp:
|
case HostSignals::NotifyApp:
|
||||||
{
|
{
|
||||||
auto msg = _ReceiveTypedPacket<HostSignalNotifyAppData>();
|
const auto msg = _ReceiveTypedPacket<HostSignalNotifyAppData>();
|
||||||
|
ServiceLocator::LocateConsoleControl()->NotifyConsoleApplication(msg.processId);
|
||||||
LOG_IF_NTSTATUS_FAILED(ServiceLocator::LocateConsoleControl()->NotifyConsoleApplication(msg.processId));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HostSignals::SetForeground:
|
case HostSignals::SetForeground:
|
||||||
@ -104,10 +102,8 @@ T HostSignalInputThread::_ReceiveTypedPacket()
|
|||||||
}
|
}
|
||||||
case HostSignals::EndTask:
|
case HostSignals::EndTask:
|
||||||
{
|
{
|
||||||
auto msg = _ReceiveTypedPacket<HostSignalEndTaskData>();
|
const auto msg = _ReceiveTypedPacket<HostSignalEndTaskData>();
|
||||||
|
ServiceLocator::LocateConsoleControl()->EndTask(msg.processId, msg.eventType, msg.ctrlFlags);
|
||||||
LOG_IF_NTSTATUS_FAILED(ServiceLocator::LocateConsoleControl()->EndTask(msg.processId, msg.eventType, msg.ctrlFlags));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
#include "..\onecore\WindowMetrics.hpp"
|
#include "..\onecore\WindowMetrics.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../win32/AccessibilityNotifier.hpp"
|
|
||||||
#include "../win32/ConsoleControl.hpp"
|
#include "../win32/ConsoleControl.hpp"
|
||||||
#include "../win32/ConsoleInputThread.hpp"
|
#include "../win32/ConsoleInputThread.hpp"
|
||||||
#include "../win32/WindowDpiApi.hpp"
|
#include "../win32/WindowDpiApi.hpp"
|
||||||
@ -199,48 +198,6 @@ using namespace Microsoft::Console::Interactivity;
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS InteractivityFactory::CreateAccessibilityNotifier(_Inout_ std::unique_ptr<IAccessibilityNotifier>& notifier)
|
|
||||||
{
|
|
||||||
auto status = STATUS_SUCCESS;
|
|
||||||
|
|
||||||
ApiLevel level;
|
|
||||||
status = ApiDetector::DetectNtUserWindow(&level);
|
|
||||||
|
|
||||||
if (SUCCEEDED_NTSTATUS(status))
|
|
||||||
{
|
|
||||||
std::unique_ptr<IAccessibilityNotifier> newNotifier;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
switch (level)
|
|
||||||
{
|
|
||||||
case ApiLevel::Win32:
|
|
||||||
newNotifier = std::make_unique<Microsoft::Console::Interactivity::Win32::AccessibilityNotifier>();
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef BUILD_ONECORE_INTERACTIVITY
|
|
||||||
case ApiLevel::OneCore:
|
|
||||||
newNotifier = std::make_unique<Microsoft::Console::Interactivity::OneCore::AccessibilityNotifier>();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
status = STATUS_INVALID_LEVEL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
status = NTSTATUS_FROM_HRESULT(wil::ResultFromCaughtException());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SUCCEEDED_NTSTATUS(status))
|
|
||||||
{
|
|
||||||
notifier.swap(newNotifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS InteractivityFactory::CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider)
|
[[nodiscard]] NTSTATUS InteractivityFactory::CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider)
|
||||||
{
|
{
|
||||||
auto status = STATUS_SUCCESS;
|
auto status = STATUS_SUCCESS;
|
||||||
|
|||||||
@ -24,7 +24,6 @@ namespace Microsoft::Console::Interactivity
|
|||||||
|
|
||||||
[[nodiscard]] NTSTATUS CreateHighDpiApi(_Inout_ std::unique_ptr<IHighDpiApi>& api);
|
[[nodiscard]] NTSTATUS CreateHighDpiApi(_Inout_ std::unique_ptr<IHighDpiApi>& api);
|
||||||
[[nodiscard]] NTSTATUS CreateWindowMetrics(_Inout_ std::unique_ptr<IWindowMetrics>& metrics);
|
[[nodiscard]] NTSTATUS CreateWindowMetrics(_Inout_ std::unique_ptr<IWindowMetrics>& metrics);
|
||||||
[[nodiscard]] NTSTATUS CreateAccessibilityNotifier(_Inout_ std::unique_ptr<IAccessibilityNotifier>& notifier);
|
|
||||||
[[nodiscard]] NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider);
|
[[nodiscard]] NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider);
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd);
|
[[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd);
|
||||||
|
|||||||
@ -14,10 +14,20 @@ RemoteConsoleControl::RemoteConsoleControl(HANDLE signalPipe) :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteConsoleControl::Control(ControlType, PVOID, DWORD) noexcept
|
||||||
|
{
|
||||||
|
WI_ASSERT_FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoteConsoleControl::NotifyWinEvent(DWORD, HWND, LONG, LONG) noexcept
|
||||||
|
{
|
||||||
|
WI_ASSERT_FAIL();
|
||||||
|
}
|
||||||
|
|
||||||
#pragma region IConsoleControl Members
|
#pragma region IConsoleControl Members
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] NTSTATUS _SendTypedPacket(HANDLE pipe, ::Microsoft::Console::HostSignals signalCode, T& payload)
|
void _SendTypedPacket(HANDLE pipe, ::Microsoft::Console::HostSignals signalCode, T& payload) noexcept
|
||||||
{
|
{
|
||||||
// To ensure it's a happy wire format, pack it tight at 1.
|
// To ensure it's a happy wire format, pack it tight at 1.
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@ -33,21 +43,10 @@ template<typename T>
|
|||||||
packet.data = payload;
|
packet.data = payload;
|
||||||
|
|
||||||
DWORD bytesWritten = 0;
|
DWORD bytesWritten = 0;
|
||||||
if (!WriteFile(pipe, &packet, sizeof(packet), &bytesWritten, nullptr))
|
LOG_IF_WIN32_BOOL_FALSE(WriteFile(pipe, &packet, sizeof(packet), &bytesWritten, nullptr));
|
||||||
{
|
|
||||||
const auto gle = ::GetLastError();
|
|
||||||
NT_RETURN_NTSTATUS(static_cast<NTSTATUS>(NTSTATUS_FROM_WIN32(gle)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytesWritten != sizeof(packet))
|
|
||||||
{
|
|
||||||
NT_RETURN_NTSTATUS(static_cast<NTSTATUS>(NTSTATUS_FROM_WIN32(E_UNEXPECTED)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS RemoteConsoleControl::NotifyConsoleApplication(_In_ DWORD dwProcessId)
|
void RemoteConsoleControl::NotifyConsoleApplication(_In_ DWORD dwProcessId) noexcept
|
||||||
{
|
{
|
||||||
HostSignalNotifyAppData data{};
|
HostSignalNotifyAppData data{};
|
||||||
data.sizeInBytes = sizeof(data);
|
data.sizeInBytes = sizeof(data);
|
||||||
@ -56,15 +55,15 @@ template<typename T>
|
|||||||
return _SendTypedPacket(_pipe.get(), HostSignals::NotifyApp, data);
|
return _SendTypedPacket(_pipe.get(), HostSignals::NotifyApp, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS RemoteConsoleControl::SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground)
|
void RemoteConsoleControl::SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) noexcept
|
||||||
{
|
{
|
||||||
// GH#13211 - Apparently this API doesn't need to be forwarded to conhost at
|
// GH#13211 - Apparently this API doesn't need to be forwarded to conhost at
|
||||||
// all. Instead, just perform the ConsoleControl operation here, in proc.
|
// all. Instead, just perform the ConsoleControl operation here, in proc.
|
||||||
// This lets us avoid all sorts of strange handle duplicating weirdness.
|
// This lets us avoid all sorts of strange handle duplicating weirdness.
|
||||||
return _control.SetForeground(hProcess, fForeground);
|
_control.SetForeground(hProcess, fForeground);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS RemoteConsoleControl::EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags)
|
void RemoteConsoleControl::EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) noexcept
|
||||||
{
|
{
|
||||||
HostSignalEndTaskData data{};
|
HostSignalEndTaskData data{};
|
||||||
data.sizeInBytes = sizeof(data);
|
data.sizeInBytes = sizeof(data);
|
||||||
@ -75,11 +74,11 @@ template<typename T>
|
|||||||
return _SendTypedPacket(_pipe.get(), HostSignals::EndTask, data);
|
return _SendTypedPacket(_pipe.get(), HostSignals::EndTask, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS RemoteConsoleControl::SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId)
|
void RemoteConsoleControl::SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept
|
||||||
{
|
{
|
||||||
// This call doesn't need to get forwarded to the root conhost. Just handle
|
// This call doesn't need to get forwarded to the root conhost. Just handle
|
||||||
// it in-proc, to set the owner of OpenConsole
|
// it in-proc, to set the owner of OpenConsole
|
||||||
return _control.SetWindowOwner(hwnd, processId, threadId);
|
_control.SetWindowOwner(hwnd, processId, threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|||||||
@ -24,10 +24,12 @@ namespace Microsoft::Console::Interactivity
|
|||||||
RemoteConsoleControl(HANDLE signalPipe);
|
RemoteConsoleControl(HANDLE signalPipe);
|
||||||
|
|
||||||
// IConsoleControl Members
|
// IConsoleControl Members
|
||||||
[[nodiscard]] NTSTATUS NotifyConsoleApplication(_In_ DWORD dwProcessId);
|
void Control(ControlType command, PVOID ptr, DWORD len) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground);
|
void NotifyWinEvent(DWORD event, HWND hwnd, LONG idObject, LONG idChild) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags);
|
void NotifyConsoleApplication(_In_ DWORD dwProcessId) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId);
|
void SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) noexcept override;
|
||||||
|
void EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) noexcept override;
|
||||||
|
void SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wil::unique_handle _pipe;
|
wil::unique_handle _pipe;
|
||||||
|
|||||||
@ -23,7 +23,6 @@ std::unique_ptr<IConsoleControl> ServiceLocator::s_consoleControl;
|
|||||||
std::unique_ptr<IConsoleInputThread> ServiceLocator::s_consoleInputThread;
|
std::unique_ptr<IConsoleInputThread> ServiceLocator::s_consoleInputThread;
|
||||||
std::unique_ptr<IConsoleWindow> ServiceLocator::s_consoleWindow;
|
std::unique_ptr<IConsoleWindow> ServiceLocator::s_consoleWindow;
|
||||||
std::unique_ptr<IWindowMetrics> ServiceLocator::s_windowMetrics;
|
std::unique_ptr<IWindowMetrics> ServiceLocator::s_windowMetrics;
|
||||||
std::unique_ptr<IAccessibilityNotifier> ServiceLocator::s_accessibilityNotifier;
|
|
||||||
std::unique_ptr<IHighDpiApi> ServiceLocator::s_highDpiApi;
|
std::unique_ptr<IHighDpiApi> ServiceLocator::s_highDpiApi;
|
||||||
std::unique_ptr<ISystemConfigurationProvider> ServiceLocator::s_systemConfigurationProvider;
|
std::unique_ptr<ISystemConfigurationProvider> ServiceLocator::s_systemConfigurationProvider;
|
||||||
void (*ServiceLocator::s_oneCoreTeardownFunction)() = nullptr;
|
void (*ServiceLocator::s_oneCoreTeardownFunction)() = nullptr;
|
||||||
@ -137,24 +136,6 @@ void ServiceLocator::RundownAndExit(const HRESULT hr)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ServiceLocator::CreateAccessibilityNotifier()
|
|
||||||
{
|
|
||||||
// Can't create if we've already created.
|
|
||||||
if (s_accessibilityNotifier)
|
|
||||||
{
|
|
||||||
return E_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s_interactivityFactory)
|
|
||||||
{
|
|
||||||
RETURN_IF_NTSTATUS_FAILED(ServiceLocator::LoadInteractivityFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_IF_NTSTATUS_FAILED(s_interactivityFactory->CreateAccessibilityNotifier(s_accessibilityNotifier));
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Set Methods
|
#pragma region Set Methods
|
||||||
@ -277,11 +258,6 @@ IWindowMetrics* ServiceLocator::LocateWindowMetrics()
|
|||||||
return s_windowMetrics.get();
|
return s_windowMetrics.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
IAccessibilityNotifier* ServiceLocator::LocateAccessibilityNotifier()
|
|
||||||
{
|
|
||||||
return s_accessibilityNotifier.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
ISystemConfigurationProvider* ServiceLocator::LocateSystemConfigurationProvider()
|
ISystemConfigurationProvider* ServiceLocator::LocateSystemConfigurationProvider()
|
||||||
{
|
{
|
||||||
auto status = STATUS_SUCCESS;
|
auto status = STATUS_SUCCESS;
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
<ClCompile Include="..\VtApiRedirection.cpp" />
|
<ClCompile Include="..\VtApiRedirection.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\inc\IAccessibilityNotifier.hpp" />
|
|
||||||
<ClInclude Include="..\..\inc\IConsoleControl.hpp" />
|
<ClInclude Include="..\..\inc\IConsoleControl.hpp" />
|
||||||
<ClInclude Include="..\..\inc\IConsoleInputThread.hpp" />
|
<ClInclude Include="..\..\inc\IConsoleInputThread.hpp" />
|
||||||
<ClInclude Include="..\..\inc\IConsoleWindow.hpp" />
|
<ClInclude Include="..\..\inc\IConsoleWindow.hpp" />
|
||||||
|
|||||||
@ -53,9 +53,6 @@
|
|||||||
<ClInclude Include="..\..\inc\ServiceLocator.hpp">
|
<ClInclude Include="..\..\inc\ServiceLocator.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\inc\IAccessibilityNotifier.hpp">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\inc\IConsoleControl.hpp">
|
<ClInclude Include="..\..\inc\IConsoleControl.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -101,5 +98,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||||
|
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -1,41 +0,0 @@
|
|||||||
/*++
|
|
||||||
Copyright (c) Microsoft Corporation
|
|
||||||
Licensed under the MIT license.
|
|
||||||
|
|
||||||
Module Name:
|
|
||||||
- IAccessibilityNotifier.hpp
|
|
||||||
|
|
||||||
Abstract:
|
|
||||||
- Defines accessibility notification methods used by accessibility systems to
|
|
||||||
provide accessible access to the console.
|
|
||||||
|
|
||||||
Author(s):
|
|
||||||
- Hernan Gatta (HeGatta) 29-Mar-2017
|
|
||||||
--*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace Microsoft::Console::Interactivity
|
|
||||||
{
|
|
||||||
class IAccessibilityNotifier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class ConsoleCaretEventFlags
|
|
||||||
{
|
|
||||||
CaretInvisible,
|
|
||||||
CaretSelection,
|
|
||||||
CaretVisible
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~IAccessibilityNotifier() = default;
|
|
||||||
|
|
||||||
virtual void NotifyConsoleCaretEvent(_In_ const til::rect& rectangle) = 0;
|
|
||||||
virtual void NotifyConsoleCaretEvent(_In_ ConsoleCaretEventFlags flags, _In_ LONG position) = 0;
|
|
||||||
virtual void NotifyConsoleUpdateScrollEvent(_In_ LONG x, _In_ LONG y) = 0;
|
|
||||||
virtual void NotifyConsoleUpdateSimpleEvent(_In_ LONG start, _In_ LONG charAndAttribute) = 0;
|
|
||||||
virtual void NotifyConsoleUpdateRegionEvent(_In_ LONG startXY, _In_ LONG endXY) = 0;
|
|
||||||
virtual void NotifyConsoleLayoutEvent() = 0;
|
|
||||||
virtual void NotifyConsoleStartApplicationEvent(_In_ DWORD processId) = 0;
|
|
||||||
virtual void NotifyConsoleEndApplicationEvent(_In_ DWORD processId) = 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -17,13 +17,27 @@ Author(s):
|
|||||||
|
|
||||||
namespace Microsoft::Console::Interactivity
|
namespace Microsoft::Console::Interactivity
|
||||||
{
|
{
|
||||||
|
enum class ControlType
|
||||||
|
{
|
||||||
|
ConsoleSetVDMCursorBounds,
|
||||||
|
ConsoleNotifyConsoleApplication,
|
||||||
|
ConsoleFullscreenSwitch,
|
||||||
|
ConsoleSetCaretInfo,
|
||||||
|
ConsoleSetReserveKeys,
|
||||||
|
ConsoleSetForeground,
|
||||||
|
ConsoleSetWindowOwner,
|
||||||
|
ConsoleEndTask,
|
||||||
|
};
|
||||||
|
|
||||||
class IConsoleControl
|
class IConsoleControl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IConsoleControl() = default;
|
virtual ~IConsoleControl() = default;
|
||||||
[[nodiscard]] virtual NTSTATUS NotifyConsoleApplication(DWORD dwProcessId) = 0;
|
virtual void Control(ControlType command, PVOID ptr, DWORD len) noexcept = 0;
|
||||||
[[nodiscard]] virtual NTSTATUS SetForeground(HANDLE hProcess, BOOL fForeground) = 0;
|
virtual void NotifyWinEvent(DWORD event, HWND hwnd, LONG idObject, LONG idChild) noexcept = 0;
|
||||||
[[nodiscard]] virtual NTSTATUS EndTask(DWORD dwProcessId, DWORD dwEventType, ULONG ulCtrlFlags) = 0;
|
virtual void NotifyConsoleApplication(DWORD dwProcessId) noexcept = 0;
|
||||||
[[nodiscard]] virtual NTSTATUS SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) = 0;
|
virtual void SetForeground(HANDLE hProcess, BOOL fForeground) noexcept = 0;
|
||||||
|
virtual void EndTask(DWORD dwProcessId, DWORD dwEventType, ULONG ulCtrlFlags) noexcept = 0;
|
||||||
|
virtual void SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,6 @@ namespace Microsoft::Console::Types
|
|||||||
virtual void VerticalScroll(const WORD wScrollCommand,
|
virtual void VerticalScroll(const WORD wScrollCommand,
|
||||||
const WORD wAbsoluteChange) = 0;
|
const WORD wAbsoluteChange) = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual HRESULT SignalUia(_In_ EVENTID id) = 0;
|
|
||||||
[[nodiscard]] virtual HRESULT UiaSetTextAreaFocus() = 0;
|
[[nodiscard]] virtual HRESULT UiaSetTextAreaFocus() = 0;
|
||||||
virtual til::rect GetWindowRect() const noexcept = 0;
|
virtual til::rect GetWindowRect() const noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -21,7 +21,6 @@ Author(s):
|
|||||||
|
|
||||||
#include "IHighDpiApi.hpp"
|
#include "IHighDpiApi.hpp"
|
||||||
#include "IWindowMetrics.hpp"
|
#include "IWindowMetrics.hpp"
|
||||||
#include "IAccessibilityNotifier.hpp"
|
|
||||||
#include "ISystemConfigurationProvider.hpp"
|
#include "ISystemConfigurationProvider.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -37,7 +36,6 @@ namespace Microsoft::Console::Interactivity
|
|||||||
|
|
||||||
[[nodiscard]] virtual NTSTATUS CreateHighDpiApi(_Inout_ std::unique_ptr<IHighDpiApi>& api) = 0;
|
[[nodiscard]] virtual NTSTATUS CreateHighDpiApi(_Inout_ std::unique_ptr<IHighDpiApi>& api) = 0;
|
||||||
[[nodiscard]] virtual NTSTATUS CreateWindowMetrics(_Inout_ std::unique_ptr<IWindowMetrics>& metrics) = 0;
|
[[nodiscard]] virtual NTSTATUS CreateWindowMetrics(_Inout_ std::unique_ptr<IWindowMetrics>& metrics) = 0;
|
||||||
[[nodiscard]] virtual NTSTATUS CreateAccessibilityNotifier(_Inout_ std::unique_ptr<IAccessibilityNotifier>& notifier) = 0;
|
|
||||||
[[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider) = 0;
|
[[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider) = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0;
|
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0;
|
||||||
|
|||||||
@ -39,9 +39,6 @@ namespace Microsoft::Console::Interactivity
|
|||||||
// In case the on-demand creation fails, the return value
|
// In case the on-demand creation fails, the return value
|
||||||
// is nullptr and a message is logged.
|
// is nullptr and a message is logged.
|
||||||
|
|
||||||
[[nodiscard]] static HRESULT CreateAccessibilityNotifier();
|
|
||||||
static IAccessibilityNotifier* LocateAccessibilityNotifier();
|
|
||||||
|
|
||||||
[[nodiscard]] static NTSTATUS SetConsoleControlInstance(_In_ std::unique_ptr<IConsoleControl>&& control);
|
[[nodiscard]] static NTSTATUS SetConsoleControlInstance(_In_ std::unique_ptr<IConsoleControl>&& control);
|
||||||
static IConsoleControl* LocateConsoleControl();
|
static IConsoleControl* LocateConsoleControl();
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -96,7 +93,6 @@ namespace Microsoft::Console::Interactivity
|
|||||||
|
|
||||||
static std::unique_ptr<IInteractivityFactory> s_interactivityFactory;
|
static std::unique_ptr<IInteractivityFactory> s_interactivityFactory;
|
||||||
|
|
||||||
static std::unique_ptr<IAccessibilityNotifier> s_accessibilityNotifier;
|
|
||||||
static std::unique_ptr<IConsoleControl> s_consoleControl;
|
static std::unique_ptr<IConsoleControl> s_consoleControl;
|
||||||
static std::unique_ptr<IConsoleInputThread> s_consoleInputThread;
|
static std::unique_ptr<IConsoleInputThread> s_consoleInputThread;
|
||||||
// TODO: MSFT 15344939 - some implementations of IConsoleWindow are currently singleton
|
// TODO: MSFT 15344939 - some implementations of IConsoleWindow are currently singleton
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
#include "precomp.h"
|
|
||||||
|
|
||||||
#include "AccessibilityNotifier.hpp"
|
|
||||||
|
|
||||||
using namespace Microsoft::Console::Interactivity::OneCore;
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleCaretEvent(_In_ const til::rect& /*rectangle*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleCaretEvent(_In_ ConsoleCaretEventFlags /*flags*/, _In_ LONG /*position*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleUpdateScrollEvent(_In_ LONG /*x*/, _In_ LONG /*y*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleUpdateSimpleEvent(_In_ LONG /*start*/, _In_ LONG /*charAndAttribute*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleUpdateRegionEvent(_In_ LONG /*startXY*/, _In_ LONG /*endXY*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleLayoutEvent() noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleStartApplicationEvent(_In_ DWORD /*processId*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleEndApplicationEvent(_In_ DWORD /*processId*/) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
/*++
|
|
||||||
Copyright (c) Microsoft Corporation
|
|
||||||
Licensed under the MIT license.
|
|
||||||
|
|
||||||
Module Name:
|
|
||||||
- IAccessibilityNotifier.hpp
|
|
||||||
|
|
||||||
Abstract:
|
|
||||||
- OneCore implementation of the IAccessibilityNotifier interface.
|
|
||||||
|
|
||||||
Author(s):
|
|
||||||
- Hernan Gatta (HeGatta) 29-Mar-2017
|
|
||||||
--*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../inc/IAccessibilityNotifier.hpp"
|
|
||||||
|
|
||||||
#pragma hdrstop
|
|
||||||
|
|
||||||
namespace Microsoft::Console::Interactivity::OneCore
|
|
||||||
{
|
|
||||||
class AccessibilityNotifier : public IAccessibilityNotifier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void NotifyConsoleCaretEvent(_In_ const til::rect& rectangle) noexcept override;
|
|
||||||
void NotifyConsoleCaretEvent(_In_ ConsoleCaretEventFlags flags, _In_ LONG position) noexcept override;
|
|
||||||
void NotifyConsoleUpdateScrollEvent(_In_ LONG x, _In_ LONG y) noexcept override;
|
|
||||||
void NotifyConsoleUpdateSimpleEvent(_In_ LONG start, _In_ LONG charAndAttribute) noexcept override;
|
|
||||||
void NotifyConsoleUpdateRegionEvent(_In_ LONG startXY, _In_ LONG endXY) noexcept override;
|
|
||||||
void NotifyConsoleLayoutEvent() noexcept override;
|
|
||||||
void NotifyConsoleStartApplicationEvent(_In_ DWORD processId) noexcept override;
|
|
||||||
void NotifyConsoleEndApplicationEvent(_In_ DWORD processId) noexcept override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -12,6 +12,10 @@ using namespace Microsoft::Console::Interactivity::OneCore;
|
|||||||
|
|
||||||
#pragma region IConsoleControl Members
|
#pragma region IConsoleControl Members
|
||||||
|
|
||||||
|
void ConsoleControl::NotifyWinEvent(DWORD event, HWND hwnd, LONG idObject, LONG idChild) noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS ConsoleControl::NotifyConsoleApplication(_In_ DWORD /*dwProcessId*/) noexcept
|
[[nodiscard]] NTSTATUS ConsoleControl::NotifyConsoleApplication(_In_ DWORD /*dwProcessId*/) noexcept
|
||||||
{
|
{
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|||||||
@ -24,6 +24,7 @@ namespace Microsoft::Console::Interactivity::OneCore
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// IConsoleControl Members
|
// IConsoleControl Members
|
||||||
|
void NotifyWinEvent(DWORD event, HWND hwnd, LONG idObject, LONG idChild) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS NotifyConsoleApplication(_In_ DWORD dwProcessId) noexcept override;
|
[[nodiscard]] NTSTATUS NotifyConsoleApplication(_In_ DWORD dwProcessId) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) noexcept override;
|
[[nodiscard]] NTSTATUS SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) override;
|
[[nodiscard]] NTSTATUS EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) override;
|
||||||
|
|||||||
@ -111,11 +111,6 @@ void ConsoleWindow::VerticalScroll(const WORD /*wScrollCommand*/, const WORD /*w
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ConsoleWindow::SignalUia(_In_ EVENTID /*id*/) noexcept
|
|
||||||
{
|
|
||||||
return E_NOTIMPL;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ConsoleWindow::UiaSetTextAreaFocus() noexcept
|
[[nodiscard]] HRESULT ConsoleWindow::UiaSetTextAreaFocus() noexcept
|
||||||
{
|
{
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
|
|||||||
@ -51,7 +51,6 @@ namespace Microsoft::Console::Interactivity::OneCore
|
|||||||
void HorizontalScroll(const WORD wScrollCommand, const WORD wAbsoluteChange) noexcept override;
|
void HorizontalScroll(const WORD wScrollCommand, const WORD wAbsoluteChange) noexcept override;
|
||||||
void VerticalScroll(const WORD wScrollCommand, const WORD wAbsoluteChange) noexcept override;
|
void VerticalScroll(const WORD wScrollCommand, const WORD wAbsoluteChange) noexcept override;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT SignalUia(_In_ EVENTID id) noexcept override;
|
|
||||||
[[nodiscard]] HRESULT UiaSetTextAreaFocus() noexcept override;
|
[[nodiscard]] HRESULT UiaSetTextAreaFocus() noexcept override;
|
||||||
til::rect GetWindowRect() const noexcept override;
|
til::rect GetWindowRect() const noexcept override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,135 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Corporation.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
#include "precomp.h"
|
|
||||||
|
|
||||||
#include "AccessibilityNotifier.hpp"
|
|
||||||
|
|
||||||
#include "../inc/ServiceLocator.hpp"
|
|
||||||
#include "ConsoleControl.hpp"
|
|
||||||
|
|
||||||
using namespace Microsoft::Console::Types;
|
|
||||||
using namespace Microsoft::Console::Interactivity::Win32;
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleCaretEvent(_In_ const til::rect& rectangle)
|
|
||||||
{
|
|
||||||
const auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow != nullptr)
|
|
||||||
{
|
|
||||||
CONSOLE_CARET_INFO caretInfo;
|
|
||||||
caretInfo.hwnd = pWindow->GetWindowHandle();
|
|
||||||
caretInfo.rc = rectangle.to_win32_rect();
|
|
||||||
|
|
||||||
LOG_IF_FAILED(ServiceLocator::LocateConsoleControl<ConsoleControl>()->Control(ConsoleControl::ControlType::ConsoleSetCaretInfo,
|
|
||||||
&caretInfo,
|
|
||||||
sizeof(caretInfo)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleCaretEvent(_In_ ConsoleCaretEventFlags flags, _In_ LONG position)
|
|
||||||
{
|
|
||||||
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
|
||||||
DWORD dwFlags = 0;
|
|
||||||
|
|
||||||
if (flags == ConsoleCaretEventFlags::CaretSelection)
|
|
||||||
{
|
|
||||||
dwFlags = CONSOLE_CARET_SELECTION;
|
|
||||||
}
|
|
||||||
else if (flags == ConsoleCaretEventFlags::CaretVisible)
|
|
||||||
{
|
|
||||||
dwFlags = CONSOLE_CARET_VISIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UIA event notification
|
|
||||||
static til::point previousCursorLocation;
|
|
||||||
const auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
|
|
||||||
if (pWindow != nullptr)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_CARET,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
dwFlags,
|
|
||||||
position);
|
|
||||||
|
|
||||||
const auto& screenInfo = gci.GetActiveOutputBuffer();
|
|
||||||
const auto& cursor = screenInfo.GetTextBuffer().GetCursor();
|
|
||||||
const auto currentCursorPosition = cursor.GetPosition();
|
|
||||||
if (currentCursorPosition != previousCursorLocation)
|
|
||||||
{
|
|
||||||
LOG_IF_FAILED(pWindow->SignalUia(UIA_Text_TextSelectionChangedEventId));
|
|
||||||
}
|
|
||||||
previousCursorLocation = currentCursorPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleUpdateScrollEvent(_In_ LONG x, _In_ LONG y)
|
|
||||||
{
|
|
||||||
auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_UPDATE_SCROLL,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
x,
|
|
||||||
y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleUpdateSimpleEvent(_In_ LONG start, _In_ LONG charAndAttribute)
|
|
||||||
{
|
|
||||||
auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_UPDATE_SIMPLE,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
start,
|
|
||||||
charAndAttribute);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleUpdateRegionEvent(_In_ LONG startXY, _In_ LONG endXY)
|
|
||||||
{
|
|
||||||
auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_UPDATE_REGION,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
startXY,
|
|
||||||
endXY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleLayoutEvent()
|
|
||||||
{
|
|
||||||
auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_LAYOUT,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleStartApplicationEvent(_In_ DWORD processId)
|
|
||||||
{
|
|
||||||
auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_START_APPLICATION,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
processId,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessibilityNotifier::NotifyConsoleEndApplicationEvent(_In_ DWORD processId)
|
|
||||||
{
|
|
||||||
auto pWindow = ServiceLocator::LocateConsoleWindow();
|
|
||||||
if (pWindow)
|
|
||||||
{
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_END_APPLICATION,
|
|
||||||
pWindow->GetWindowHandle(),
|
|
||||||
processId,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/*++
|
|
||||||
Copyright (c) Microsoft Corporation
|
|
||||||
Licensed under the MIT license.
|
|
||||||
|
|
||||||
Module Name:
|
|
||||||
- IAccessibilityNotifier.hpp
|
|
||||||
|
|
||||||
Abstract:
|
|
||||||
- Win32 implementation of the IAccessibilityNotifier interface.
|
|
||||||
|
|
||||||
Author(s):
|
|
||||||
- Hernan Gatta (HeGatta) 29-Mar-2017
|
|
||||||
--*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "precomp.h"
|
|
||||||
|
|
||||||
#include "../inc/IAccessibilityNotifier.hpp"
|
|
||||||
|
|
||||||
#pragma hdrstop
|
|
||||||
|
|
||||||
namespace Microsoft::Console::Interactivity::Win32
|
|
||||||
{
|
|
||||||
class AccessibilityNotifier final : public IAccessibilityNotifier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~AccessibilityNotifier() = default;
|
|
||||||
|
|
||||||
void NotifyConsoleCaretEvent(_In_ const til::rect& rectangle);
|
|
||||||
void NotifyConsoleCaretEvent(_In_ ConsoleCaretEventFlags flags, _In_ LONG position);
|
|
||||||
void NotifyConsoleUpdateScrollEvent(_In_ LONG x, _In_ LONG y);
|
|
||||||
void NotifyConsoleUpdateSimpleEvent(_In_ LONG start, _In_ LONG charAndAttribute);
|
|
||||||
void NotifyConsoleUpdateRegionEvent(_In_ LONG startXY, _In_ LONG endXY);
|
|
||||||
void NotifyConsoleLayoutEvent();
|
|
||||||
void NotifyConsoleStartApplicationEvent(_In_ DWORD processId);
|
|
||||||
void NotifyConsoleEndApplicationEvent(_In_ DWORD processId);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -13,31 +13,51 @@
|
|||||||
|
|
||||||
using namespace Microsoft::Console::Interactivity::Win32;
|
using namespace Microsoft::Console::Interactivity::Win32;
|
||||||
|
|
||||||
#pragma region IConsoleControl Members
|
#ifdef CON_USERPRIVAPI_INDIRECT
|
||||||
|
ConsoleControl::ConsoleControl()
|
||||||
|
{
|
||||||
|
// NOTE: GetModuleHandleW is rather expensive, but GetProcAddress is quite cheap.
|
||||||
|
const auto user32 = GetModuleHandleW(L"user32.dll");
|
||||||
|
_consoleControl = reinterpret_cast<PfnConsoleControl>(GetProcAddress(user32, "ConsoleControl"));
|
||||||
|
_enterReaderModeHelper = reinterpret_cast<PfnEnterReaderModeHelper>(GetProcAddress(user32, "EnterReaderModeHelper"));
|
||||||
|
_translateMessageEx = reinterpret_cast<PfnTranslateMessageEx>(GetProcAddress(user32, "TranslateMessageEx"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS ConsoleControl::NotifyConsoleApplication(_In_ DWORD dwProcessId)
|
void ConsoleControl::Control(ControlType command, PVOID ptr, DWORD len) noexcept
|
||||||
|
{
|
||||||
|
#ifdef CON_USERPRIVAPI_INDIRECT
|
||||||
|
if (_consoleControl)
|
||||||
|
{
|
||||||
|
LOG_IF_FAILED(_consoleControl(command, ptr, len));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
LOG_IF_FAILED(::ConsoleControl(command, ptr, len));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleControl::NotifyWinEvent(DWORD event, HWND hwnd, LONG idObject, LONG idChild) noexcept
|
||||||
|
{
|
||||||
|
::NotifyWinEvent(event, hwnd, idObject, idChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsoleControl::NotifyConsoleApplication(_In_ DWORD dwProcessId) noexcept
|
||||||
{
|
{
|
||||||
CONSOLE_PROCESS_INFO cpi;
|
CONSOLE_PROCESS_INFO cpi;
|
||||||
cpi.dwProcessID = dwProcessId;
|
cpi.dwProcessID = dwProcessId;
|
||||||
cpi.dwFlags = CPI_NEWPROCESSWINDOW;
|
cpi.dwFlags = CPI_NEWPROCESSWINDOW;
|
||||||
|
Control(ControlType::ConsoleNotifyConsoleApplication, &cpi, sizeof(CONSOLE_PROCESS_INFO));
|
||||||
return Control(ControlType::ConsoleNotifyConsoleApplication,
|
|
||||||
&cpi,
|
|
||||||
sizeof(CONSOLE_PROCESS_INFO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS ConsoleControl::SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground)
|
void ConsoleControl::SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) noexcept
|
||||||
{
|
{
|
||||||
CONSOLESETFOREGROUND Flags;
|
CONSOLESETFOREGROUND Flags;
|
||||||
Flags.hProcess = hProcess;
|
Flags.hProcess = hProcess;
|
||||||
Flags.bForeground = fForeground;
|
Flags.bForeground = fForeground;
|
||||||
|
Control(ControlType::ConsoleSetForeground, &Flags, sizeof(Flags));
|
||||||
return Control(ControlType::ConsoleSetForeground,
|
|
||||||
&Flags,
|
|
||||||
sizeof(Flags));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS ConsoleControl::EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags)
|
void ConsoleControl::EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) noexcept
|
||||||
{
|
{
|
||||||
auto pConsoleWindow = ServiceLocator::LocateConsoleWindow();
|
auto pConsoleWindow = ServiceLocator::LocateConsoleWindow();
|
||||||
|
|
||||||
@ -46,108 +66,32 @@ using namespace Microsoft::Console::Interactivity::Win32;
|
|||||||
ConsoleEndTaskParams.ConsoleEventCode = dwEventType;
|
ConsoleEndTaskParams.ConsoleEventCode = dwEventType;
|
||||||
ConsoleEndTaskParams.ConsoleFlags = ulCtrlFlags;
|
ConsoleEndTaskParams.ConsoleFlags = ulCtrlFlags;
|
||||||
ConsoleEndTaskParams.hwnd = pConsoleWindow == nullptr ? nullptr : pConsoleWindow->GetWindowHandle();
|
ConsoleEndTaskParams.hwnd = pConsoleWindow == nullptr ? nullptr : pConsoleWindow->GetWindowHandle();
|
||||||
|
Control(ControlType::ConsoleEndTask, &ConsoleEndTaskParams, sizeof(ConsoleEndTaskParams));
|
||||||
return Control(ControlType::ConsoleEndTask,
|
|
||||||
&ConsoleEndTaskParams,
|
|
||||||
sizeof(ConsoleEndTaskParams));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS ConsoleControl::SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept
|
void ConsoleControl::SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept
|
||||||
{
|
{
|
||||||
CONSOLEWINDOWOWNER ConsoleOwner;
|
CONSOLEWINDOWOWNER ConsoleOwner;
|
||||||
ConsoleOwner.hwnd = hwnd;
|
ConsoleOwner.hwnd = hwnd;
|
||||||
ConsoleOwner.ProcessId = processId;
|
ConsoleOwner.ProcessId = processId;
|
||||||
ConsoleOwner.ThreadId = threadId;
|
ConsoleOwner.ThreadId = threadId;
|
||||||
|
Control(ControlType::ConsoleSetWindowOwner, &ConsoleOwner, sizeof(ConsoleOwner));
|
||||||
return Control(ConsoleControl::ControlType::ConsoleSetWindowOwner,
|
|
||||||
&ConsoleOwner,
|
|
||||||
sizeof(ConsoleOwner));
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
#pragma region Public Methods
|
|
||||||
|
|
||||||
[[nodiscard]] NTSTATUS ConsoleControl::Control(_In_ ControlType ConsoleCommand,
|
|
||||||
_In_reads_bytes_(ConsoleInformationLength) PVOID ConsoleInformation,
|
|
||||||
_In_ DWORD ConsoleInformationLength)
|
|
||||||
{
|
|
||||||
#ifdef CON_USERPRIVAPI_INDIRECT
|
|
||||||
if (_hUser32 != nullptr)
|
|
||||||
{
|
|
||||||
typedef NTSTATUS(WINAPI * PfnConsoleControl)(ControlType Command, PVOID Information, DWORD Length);
|
|
||||||
|
|
||||||
static auto pfn = (PfnConsoleControl)GetProcAddress(_hUser32, "ConsoleControl");
|
|
||||||
|
|
||||||
if (pfn != nullptr)
|
|
||||||
{
|
|
||||||
return pfn(ConsoleCommand, ConsoleInformation, ConsoleInformationLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
#else
|
|
||||||
return ConsoleControl(ConsoleCommand, ConsoleInformation, ConsoleInformationLength);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ConsoleControl::EnterReaderModeHelper(_In_ HWND hwnd)
|
BOOL ConsoleControl::EnterReaderModeHelper(_In_ HWND hwnd)
|
||||||
{
|
{
|
||||||
#ifdef CON_USERPRIVAPI_INDIRECT
|
#ifdef CON_USERPRIVAPI_INDIRECT
|
||||||
if (_hUser32 != nullptr)
|
return _enterReaderModeHelper ? _enterReaderModeHelper(hwnd) : FALSE;
|
||||||
{
|
|
||||||
typedef BOOL(WINAPI * PfnEnterReaderModeHelper)(HWND hwnd);
|
|
||||||
|
|
||||||
static auto pfn = (PfnEnterReaderModeHelper)GetProcAddress(_hUser32, "EnterReaderModeHelper");
|
|
||||||
|
|
||||||
if (pfn != nullptr)
|
|
||||||
{
|
|
||||||
return pfn(hwnd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
#else
|
#else
|
||||||
return EnterReaderModeHelper(hwnd);
|
return ::EnterReaderModeHelper(hwnd);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL ConsoleControl::TranslateMessageEx(const MSG* pmsg,
|
BOOL ConsoleControl::TranslateMessageEx(const MSG* pmsg, _In_ UINT flags)
|
||||||
_In_ UINT flags)
|
|
||||||
{
|
{
|
||||||
#ifdef CON_USERPRIVAPI_INDIRECT
|
#ifdef CON_USERPRIVAPI_INDIRECT
|
||||||
if (_hUser32 != nullptr)
|
return _translateMessageEx ? _translateMessageEx(pmsg, flags) : FALSE;
|
||||||
{
|
|
||||||
typedef BOOL(WINAPI * PfnTranslateMessageEx)(const MSG* pmsg, UINT flags);
|
|
||||||
|
|
||||||
static auto pfn = (PfnTranslateMessageEx)GetProcAddress(_hUser32, "TranslateMessageEx");
|
|
||||||
|
|
||||||
if (pfn != nullptr)
|
|
||||||
{
|
|
||||||
return pfn(pmsg, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
#else
|
#else
|
||||||
return TranslateMessageEx(pmsg, flags);
|
return ::TranslateMessageEx(pmsg, flags);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
#ifdef CON_USERPRIVAPI_INDIRECT
|
|
||||||
ConsoleControl::ConsoleControl()
|
|
||||||
{
|
|
||||||
_hUser32 = LoadLibraryW(L"user32.dll");
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleControl::~ConsoleControl()
|
|
||||||
{
|
|
||||||
if (_hUser32 != nullptr)
|
|
||||||
{
|
|
||||||
FreeLibrary(_hUser32);
|
|
||||||
_hUser32 = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -32,28 +32,13 @@ namespace Microsoft::Console::Interactivity::Win32
|
|||||||
class ConsoleControl final : public IConsoleControl
|
class ConsoleControl final : public IConsoleControl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum ControlType
|
|
||||||
{
|
|
||||||
ConsoleSetVDMCursorBounds,
|
|
||||||
ConsoleNotifyConsoleApplication,
|
|
||||||
ConsoleFullscreenSwitch,
|
|
||||||
ConsoleSetCaretInfo,
|
|
||||||
ConsoleSetReserveKeys,
|
|
||||||
ConsoleSetForeground,
|
|
||||||
ConsoleSetWindowOwner,
|
|
||||||
ConsoleEndTask,
|
|
||||||
};
|
|
||||||
|
|
||||||
// IConsoleControl Members
|
// IConsoleControl Members
|
||||||
[[nodiscard]] NTSTATUS NotifyConsoleApplication(_In_ DWORD dwProcessId) override;
|
void Control(ControlType command, PVOID ptr, DWORD len) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) override;
|
void NotifyWinEvent(DWORD event, HWND hwnd, LONG idObject, LONG idChild) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) override;
|
void NotifyConsoleApplication(_In_ DWORD dwProcessId) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept override;
|
void SetForeground(_In_ HANDLE hProcess, _In_ BOOL fForeground) noexcept override;
|
||||||
|
void EndTask(_In_ DWORD dwProcessId, _In_ DWORD dwEventType, _In_ ULONG ulCtrlFlags) noexcept override;
|
||||||
// Public Members
|
void SetWindowOwner(HWND hwnd, DWORD processId, DWORD threadId) noexcept override;
|
||||||
[[nodiscard]] NTSTATUS Control(_In_ ConsoleControl::ControlType ConsoleCommand,
|
|
||||||
_In_reads_bytes_(ConsoleInformationLength) PVOID ConsoleInformation,
|
|
||||||
_In_ DWORD ConsoleInformationLength);
|
|
||||||
|
|
||||||
BOOL EnterReaderModeHelper(_In_ HWND hwnd);
|
BOOL EnterReaderModeHelper(_In_ HWND hwnd);
|
||||||
|
|
||||||
@ -62,10 +47,14 @@ namespace Microsoft::Console::Interactivity::Win32
|
|||||||
|
|
||||||
#ifdef CON_USERPRIVAPI_INDIRECT
|
#ifdef CON_USERPRIVAPI_INDIRECT
|
||||||
ConsoleControl();
|
ConsoleControl();
|
||||||
~ConsoleControl();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HMODULE _hUser32;
|
using PfnConsoleControl = NTSTATUS(WINAPI*)(ControlType, PVOID, DWORD);
|
||||||
|
using PfnEnterReaderModeHelper = BOOL(WINAPI*)(HWND);
|
||||||
|
using PfnTranslateMessageEx = BOOL(WINAPI*)(const MSG*, UINT);
|
||||||
|
PfnConsoleControl _consoleControl = nullptr;
|
||||||
|
PfnEnterReaderModeHelper _enterReaderModeHelper = nullptr;
|
||||||
|
PfnTranslateMessageEx _translateMessageEx = nullptr;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\AccessibilityNotifier.cpp" />
|
|
||||||
<ClCompile Include="..\Clipboard.cpp" />
|
<ClCompile Include="..\Clipboard.cpp" />
|
||||||
<ClCompile Include="..\ConsoleControl.cpp" />
|
<ClCompile Include="..\ConsoleControl.cpp" />
|
||||||
<ClCompile Include="..\ConsoleInputThread.cpp" />
|
<ClCompile Include="..\ConsoleInputThread.cpp" />
|
||||||
@ -38,7 +37,6 @@
|
|||||||
<ClCompile Include="..\windowUiaProvider.cpp" />
|
<ClCompile Include="..\windowUiaProvider.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\AccessibilityNotifier.hpp" />
|
|
||||||
<ClInclude Include="..\Clipboard.hpp" />
|
<ClInclude Include="..\Clipboard.hpp" />
|
||||||
<ClInclude Include="..\ConsoleControl.hpp" />
|
<ClInclude Include="..\ConsoleControl.hpp" />
|
||||||
<ClInclude Include="..\ConsoleInputThread.hpp" />
|
<ClInclude Include="..\ConsoleInputThread.hpp" />
|
||||||
@ -70,4 +68,4 @@
|
|||||||
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
<!-- Careful reordering these. Some default props (contained in these files) are order sensitive. -->
|
||||||
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
<Import Project="$(SolutionDir)src\common.build.post.props" />
|
||||||
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
<Import Project="$(SolutionDir)src\common.nugetversions.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@ -15,9 +15,6 @@
|
|||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\AccessibilityNotifier.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\Clipboard.cpp">
|
<ClCompile Include="..\Clipboard.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -71,9 +68,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\AccessibilityNotifier.hpp">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\Clipboard.hpp">
|
<ClInclude Include="..\Clipboard.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -128,5 +122,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
|
||||||
|
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -428,12 +428,8 @@ void Window::ChangeViewport(const til::inclusive_rect& NewWindow)
|
|||||||
pSelection->HideSelection();
|
pSelection->HideSelection();
|
||||||
|
|
||||||
// Fire off an event to let accessibility apps know we've scrolled.
|
// Fire off an event to let accessibility apps know we've scrolled.
|
||||||
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
if (pNotifier != nullptr)
|
an.ScrollViewport({ ScreenInfo.GetViewport().Left() - NewWindow.left, ScreenInfo.GetViewport().Top() - NewWindow.top });
|
||||||
{
|
|
||||||
pNotifier->NotifyConsoleUpdateScrollEvent(ScreenInfo.GetViewport().Left() - NewWindow.left,
|
|
||||||
ScreenInfo.GetViewport().Top() - NewWindow.top);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The new window is OK. Store it in screeninfo and refresh screen.
|
// The new window is OK. Store it in screeninfo and refresh screen.
|
||||||
ScreenInfo.SetViewport(Viewport::FromInclusive(NewWindow), false);
|
ScreenInfo.SetViewport(Viewport::FromInclusive(NewWindow), false);
|
||||||
@ -1356,20 +1352,13 @@ IRawElementProviderSimple* Window::_GetUiaProvider()
|
|||||||
if (nullptr == _pUiaProvider)
|
if (nullptr == _pUiaProvider)
|
||||||
{
|
{
|
||||||
LOG_IF_FAILED(WRL::MakeAndInitialize<WindowUiaProvider>(&_pUiaProvider, this));
|
LOG_IF_FAILED(WRL::MakeAndInitialize<WindowUiaProvider>(&_pUiaProvider, this));
|
||||||
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.SetUIAProvider(_pUiaProvider->GetScreenInfoProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
return _pUiaProvider.Get();
|
return _pUiaProvider.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Window::SignalUia(_In_ EVENTID id)
|
|
||||||
{
|
|
||||||
if (_pUiaProvider != nullptr)
|
|
||||||
{
|
|
||||||
return _pUiaProvider->Signal(id);
|
|
||||||
}
|
|
||||||
return S_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Window::UiaSetTextAreaFocus()
|
[[nodiscard]] HRESULT Window::UiaSetTextAreaFocus()
|
||||||
{
|
{
|
||||||
if (_pUiaProvider != nullptr)
|
if (_pUiaProvider != nullptr)
|
||||||
|
|||||||
@ -82,8 +82,6 @@ namespace Microsoft::Console::Interactivity::Win32
|
|||||||
BOOL PostUpdateWindowSize() const;
|
BOOL PostUpdateWindowSize() const;
|
||||||
BOOL PostUpdateExtendedEditKeys() const;
|
BOOL PostUpdateExtendedEditKeys() const;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT SignalUia(_In_ EVENTID id);
|
|
||||||
|
|
||||||
void SetOwner();
|
void SetOwner();
|
||||||
BOOL GetCursorPosition(_Out_ til::point* lpPoint);
|
BOOL GetCursorPosition(_Out_ til::point* lpPoint);
|
||||||
BOOL GetClientRectangle(_Out_ til::rect* lpRect);
|
BOOL GetClientRectangle(_Out_ til::rect* lpRect);
|
||||||
|
|||||||
@ -31,51 +31,14 @@ try
|
|||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
|
|
||||||
[[nodiscard]] HRESULT WindowUiaProvider::Signal(_In_ EVENTID id)
|
ScreenInfoUiaProvider* WindowUiaProvider::GetScreenInfoProvider() const noexcept
|
||||||
{
|
{
|
||||||
auto hr = S_OK;
|
return _pScreenInfoProvider.Get();
|
||||||
|
|
||||||
// ScreenInfoUiaProvider is responsible for signaling selection
|
|
||||||
// changed events and text changed events
|
|
||||||
if (id == UIA_Text_TextSelectionChangedEventId ||
|
|
||||||
id == UIA_Text_TextChangedEventId)
|
|
||||||
{
|
|
||||||
if (_pScreenInfoProvider)
|
|
||||||
{
|
|
||||||
hr = _pScreenInfoProvider->Signal(id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hr = E_POINTER;
|
|
||||||
}
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_signalEventFiring.find(id) != _signalEventFiring.end() &&
|
|
||||||
_signalEventFiring[id] == true)
|
|
||||||
{
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_signalEventFiring[id] = true;
|
|
||||||
}
|
|
||||||
CATCH_RETURN();
|
|
||||||
|
|
||||||
hr = UiaRaiseAutomationEvent(this, id);
|
|
||||||
_signalEventFiring[id] = false;
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] HRESULT WindowUiaProvider::SetTextAreaFocus()
|
[[nodiscard]] HRESULT WindowUiaProvider::SetTextAreaFocus()
|
||||||
{
|
{
|
||||||
try
|
return UiaRaiseAutomationEvent(_pScreenInfoProvider.Get(), UIA_AutomationFocusChangedEventId);
|
||||||
{
|
|
||||||
return _pScreenInfoProvider->Signal(UIA_AutomationFocusChangedEventId);
|
|
||||||
}
|
|
||||||
CATCH_RETURN();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma region IRawElementProviderSimple
|
#pragma region IRawElementProviderSimple
|
||||||
@ -188,9 +151,6 @@ IFACEMETHODIMP WindowUiaProvider::Navigate(_In_ NavigateDirection direction, _CO
|
|||||||
if (direction == NavigateDirection_FirstChild || direction == NavigateDirection_LastChild)
|
if (direction == NavigateDirection_FirstChild || direction == NavigateDirection_LastChild)
|
||||||
{
|
{
|
||||||
RETURN_IF_FAILED(_pScreenInfoProvider.CopyTo(ppProvider));
|
RETURN_IF_FAILED(_pScreenInfoProvider.CopyTo(ppProvider));
|
||||||
|
|
||||||
// signal that the focus changed
|
|
||||||
LOG_IF_FAILED(_pScreenInfoProvider->Signal(UIA_AutomationFocusChangedEventId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the other directions (parent, next, previous) the default of nullptr is correct
|
// For the other directions (parent, next, previous) the default of nullptr is correct
|
||||||
@ -240,8 +200,7 @@ IFACEMETHODIMP WindowUiaProvider::GetEmbeddedFragmentRoots(_Outptr_result_mayben
|
|||||||
|
|
||||||
IFACEMETHODIMP WindowUiaProvider::SetFocus()
|
IFACEMETHODIMP WindowUiaProvider::SetFocus()
|
||||||
{
|
{
|
||||||
RETURN_IF_FAILED(_EnsureValidHwnd());
|
return S_OK;
|
||||||
return Signal(UIA_AutomationFocusChangedEventId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IFACEMETHODIMP WindowUiaProvider::get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider)
|
IFACEMETHODIMP WindowUiaProvider::get_FragmentRoot(_COM_Outptr_result_maybenull_ IRawElementProviderFragmentRoot** ppProvider)
|
||||||
|
|||||||
@ -47,7 +47,7 @@ namespace Microsoft::Console::Interactivity::Win32
|
|||||||
WindowUiaProvider& operator=(WindowUiaProvider&&) = delete;
|
WindowUiaProvider& operator=(WindowUiaProvider&&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] virtual HRESULT Signal(_In_ EVENTID id);
|
ScreenInfoUiaProvider* GetScreenInfoProvider() const noexcept;
|
||||||
[[nodiscard]] virtual HRESULT SetTextAreaFocus();
|
[[nodiscard]] virtual HRESULT SetTextAreaFocus();
|
||||||
|
|
||||||
// IRawElementProviderSimple methods
|
// IRawElementProviderSimple methods
|
||||||
@ -78,19 +78,6 @@ namespace Microsoft::Console::Interactivity::Win32
|
|||||||
void ChangeViewport(const til::inclusive_rect& NewWindow);
|
void ChangeViewport(const til::inclusive_rect& NewWindow);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// this is used to prevent the object from
|
|
||||||
// signaling an event while it is already in the
|
|
||||||
// process of signalling another event.
|
|
||||||
// This fixes a problem with JAWS where it would
|
|
||||||
// call a public method that calls
|
|
||||||
// UiaRaiseAutomationEvent to signal something
|
|
||||||
// happened, which JAWS then detects the signal
|
|
||||||
// and calls the same method in response,
|
|
||||||
// eventually overflowing the stack.
|
|
||||||
// We aren't using this as a cheap locking
|
|
||||||
// mechanism for multi-threaded code.
|
|
||||||
std::unordered_map<EVENTID, bool> _signalEventFiring;
|
|
||||||
|
|
||||||
[[nodiscard]] HRESULT _EnsureValidHwnd() const;
|
[[nodiscard]] HRESULT _EnsureValidHwnd() const;
|
||||||
|
|
||||||
const OLECHAR* AutomationIdPropertyName = L"Console Window";
|
const OLECHAR* AutomationIdPropertyName = L"Console Window";
|
||||||
|
|||||||
@ -89,7 +89,7 @@ VOID SetConsoleWindowOwner(const HWND hwnd, _Inout_opt_ ConsoleProcessHandle* pP
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comment out this line to enable UIA tree to be visible until UIAutomationCore.dll can support our scenario.
|
// Comment out this line to enable UIA tree to be visible until UIAutomationCore.dll can support our scenario.
|
||||||
LOG_IF_NTSTATUS_FAILED(ServiceLocator::LocateConsoleControl()->SetWindowOwner(hwnd, dwProcessId, dwThreadId));
|
ServiceLocator::LocateConsoleControl()->SetWindowOwner(hwnd, dwProcessId, dwThreadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------
|
// ----------------------------
|
||||||
@ -892,11 +892,14 @@ NTSTATUS InitWindowsSubsystem(_Out_ HHOOK* phhook)
|
|||||||
// was special cased (for CSRSS) to always succeed. Thus, we ignore failure for app compat (as not having the hook isn't fatal).
|
// was special cased (for CSRSS) to always succeed. Thus, we ignore failure for app compat (as not having the hook isn't fatal).
|
||||||
*phhook = SetWindowsHookExW(WH_MSGFILTER, DialogHookProc, nullptr, GetCurrentThreadId());
|
*phhook = SetWindowsHookExW(WH_MSGFILTER, DialogHookProc, nullptr, GetCurrentThreadId());
|
||||||
|
|
||||||
SetConsoleWindowOwner(ServiceLocator::LocateConsoleWindow()->GetWindowHandle(), ProcessData);
|
const auto hwnd = ServiceLocator::LocateConsoleWindow()->GetWindowHandle();
|
||||||
|
SetConsoleWindowOwner(hwnd, ProcessData);
|
||||||
|
|
||||||
LOG_IF_FAILED(ServiceLocator::LocateConsoleWindow<Window>()->ActivateAndShow(gci.GetShowWindow()));
|
LOG_IF_FAILED(ServiceLocator::LocateConsoleWindow<Window>()->ActivateAndShow(gci.GetShowWindow()));
|
||||||
|
|
||||||
NotifyWinEvent(EVENT_CONSOLE_START_APPLICATION, ServiceLocator::LocateConsoleWindow()->GetWindowHandle(), ProcessData->dwProcessId, 0);
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
|
an.Initialize(hwnd, gci.GetMSAADelay(), gci.GetUIADelay());
|
||||||
|
an.ApplicationStart(ProcessData->dwProcessId);
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -782,18 +782,6 @@ static constexpr TsfDataProvider s_tsfDataProvider;
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EVENT_CONSOLE_CARET:
|
|
||||||
case EVENT_CONSOLE_UPDATE_REGION:
|
|
||||||
case EVENT_CONSOLE_UPDATE_SIMPLE:
|
|
||||||
case EVENT_CONSOLE_UPDATE_SCROLL:
|
|
||||||
case EVENT_CONSOLE_LAYOUT:
|
|
||||||
case EVENT_CONSOLE_START_APPLICATION:
|
|
||||||
case EVENT_CONSOLE_END_APPLICATION:
|
|
||||||
{
|
|
||||||
NotifyWinEvent(Message, hWnd, (LONG)wParam, (LONG)lParam);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
CallDefWin:
|
CallDefWin:
|
||||||
{
|
{
|
||||||
|
|||||||
@ -64,6 +64,8 @@ const RegistrySerialization::_RegPropertyMap RegistrySerialization::s_PropertyMa
|
|||||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_USEDX, SET_FIELD_AND_SIZE(_fUseDx) },
|
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_USEDX, SET_FIELD_AND_SIZE(_fUseDx) },
|
||||||
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_COPYCOLOR, SET_FIELD_AND_SIZE(_fCopyColor) },
|
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_COPYCOLOR, SET_FIELD_AND_SIZE(_fCopyColor) },
|
||||||
{ _RegPropertyType::Dword, L"TextMeasurement", SET_FIELD_AND_SIZE(_textMeasurement) },
|
{ _RegPropertyType::Dword, L"TextMeasurement", SET_FIELD_AND_SIZE(_textMeasurement) },
|
||||||
|
{ _RegPropertyType::Dword, L"MSAADelay", SET_FIELD_AND_SIZE(_msaaDelay) },
|
||||||
|
{ _RegPropertyType::Dword, L"UIADelay", SET_FIELD_AND_SIZE(_uiaDelay) },
|
||||||
#if TIL_FEATURE_CONHOSTATLASENGINE_ENABLED
|
#if TIL_FEATURE_CONHOSTATLASENGINE_ENABLED
|
||||||
{ _RegPropertyType::Boolean, L"EnableBuiltinGlyphs", SET_FIELD_AND_SIZE(_fEnableBuiltinGlyphs) },
|
{ _RegPropertyType::Boolean, L"EnableBuiltinGlyphs", SET_FIELD_AND_SIZE(_fEnableBuiltinGlyphs) },
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -456,14 +456,11 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API
|
|||||||
// ConsoleApp will be false in the AttachConsole case.
|
// ConsoleApp will be false in the AttachConsole case.
|
||||||
if (Cac.ConsoleApp)
|
if (Cac.ConsoleApp)
|
||||||
{
|
{
|
||||||
LOG_IF_FAILED(ServiceLocator::LocateConsoleControl()->NotifyConsoleApplication(dwProcessId));
|
ServiceLocator::LocateConsoleControl()->NotifyConsoleApplication(dwProcessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
if (pNotifier)
|
an.ApplicationStart(dwProcessId);
|
||||||
{
|
|
||||||
pNotifier->NotifyConsoleStartApplicationEvent(dwProcessId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WI_IsFlagClear(gci.Flags, CONSOLE_INITIALIZED))
|
if (WI_IsFlagClear(gci.Flags, CONSOLE_INITIALIZED))
|
||||||
{
|
{
|
||||||
@ -556,11 +553,8 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleClientDisconnectRoutine(_In_ PCONSOLE_API
|
|||||||
{
|
{
|
||||||
const auto pProcessData = pMessage->GetProcessHandle();
|
const auto pProcessData = pMessage->GetProcessHandle();
|
||||||
|
|
||||||
auto pNotifier = ServiceLocator::LocateAccessibilityNotifier();
|
auto& an = ServiceLocator::LocateGlobals().accessibilityNotifier;
|
||||||
if (pNotifier)
|
an.ApplicationEnd(pProcessData->dwProcessId);
|
||||||
{
|
|
||||||
pNotifier->NotifyConsoleEndApplicationEvent(pProcessData->dwProcessId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tracing::s_TraceConsoleAttachDetach(pProcessData, false);
|
Tracing::s_TraceConsoleAttachDetach(pProcessData, false);
|
||||||
|
|
||||||
|
|||||||
@ -298,5 +298,5 @@ bool ConsoleProcessList::IsEmpty() const
|
|||||||
// - <none>
|
// - <none>
|
||||||
void ConsoleProcessList::_ModifyProcessForegroundRights(const HANDLE hProcess, const bool fForeground) const
|
void ConsoleProcessList::_ModifyProcessForegroundRights(const HANDLE hProcess, const bool fForeground) const
|
||||||
{
|
{
|
||||||
LOG_IF_NTSTATUS_FAILED(ServiceLocator::LocateConsoleControl()->SetForeground(hProcess, fForeground));
|
ServiceLocator::LocateConsoleControl()->SetForeground(hProcess, fForeground);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
|
|
||||||
virtual bool ResizeWindow(const til::CoordType width, const til::CoordType height) = 0;
|
virtual bool ResizeWindow(const til::CoordType width, const til::CoordType height) = 0;
|
||||||
|
|
||||||
virtual void NotifyAccessibilityChange(const til::rect& changedRect) = 0;
|
|
||||||
virtual void NotifyBufferRotation(const int delta) = 0;
|
virtual void NotifyBufferRotation(const int delta) = 0;
|
||||||
virtual void NotifyShellIntegrationMark() = 0;
|
virtual void NotifyShellIntegrationMark() = 0;
|
||||||
|
|
||||||
|
|||||||
@ -160,12 +160,6 @@ void AdaptDispatch::_WriteToBuffer(const std::wstring_view string)
|
|||||||
}
|
}
|
||||||
const auto textPositionAfter = state.text.data();
|
const auto textPositionAfter = state.text.data();
|
||||||
|
|
||||||
if (state.columnBeginDirty != state.columnEndDirty)
|
|
||||||
{
|
|
||||||
const til::rect changedRect{ state.columnBeginDirty, cursorPosition.y, state.columnEndDirty, cursorPosition.y + 1 };
|
|
||||||
_api.NotifyAccessibilityChange(changedRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're past the end of the line, we need to clamp the cursor
|
// If we're past the end of the line, we need to clamp the cursor
|
||||||
// back into range, and if wrapping is enabled, set the delayed wrap
|
// back into range, and if wrapping is enabled, set the delayed wrap
|
||||||
// flag. The wrapping only occurs once another character is output.
|
// flag. The wrapping only occurs once another character is output.
|
||||||
@ -413,8 +407,7 @@ void AdaptDispatch::_CursorMovePosition(const Offset rowOffset, const Offset col
|
|||||||
// - Helper method which applies a bunch of flags that are typically set whenever
|
// - Helper method which applies a bunch of flags that are typically set whenever
|
||||||
// the cursor is moved. The IsOn flag is set to true, and the Delay flag to false,
|
// the cursor is moved. The IsOn flag is set to true, and the Delay flag to false,
|
||||||
// to force a blinking cursor to be visible, so the user can immediately see the
|
// to force a blinking cursor to be visible, so the user can immediately see the
|
||||||
// new position. The HasMoved flag is set to let the accessibility notifier know
|
// new position.
|
||||||
// that there was movement that needs to be reported.
|
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - cursor - The cursor instance to be updated
|
// - cursor - The cursor instance to be updated
|
||||||
// Return Value:
|
// Return Value:
|
||||||
@ -423,7 +416,6 @@ void AdaptDispatch::_ApplyCursorMovementFlags(Cursor& cursor) noexcept
|
|||||||
{
|
{
|
||||||
cursor.SetDelay(false);
|
cursor.SetDelay(false);
|
||||||
cursor.SetIsOn(true);
|
cursor.SetIsOn(true);
|
||||||
cursor.SetHasMoved(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -726,7 +718,6 @@ void AdaptDispatch::DeleteCharacter(const VTInt count)
|
|||||||
void AdaptDispatch::_FillRect(const Page& page, const til::rect& fillRect, const std::wstring_view& fillChar, const TextAttribute& fillAttrs) const
|
void AdaptDispatch::_FillRect(const Page& page, const til::rect& fillRect, const std::wstring_view& fillChar, const TextAttribute& fillAttrs) const
|
||||||
{
|
{
|
||||||
page.Buffer().FillRect(fillRect, fillChar, fillAttrs);
|
page.Buffer().FillRect(fillRect, fillChar, fillAttrs);
|
||||||
_api.NotifyAccessibilityChange(fillRect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -870,7 +861,6 @@ void AdaptDispatch::_SelectiveEraseRect(const Page& page, const til::rect& erase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_api.NotifyAccessibilityChange(eraseRect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -980,7 +970,6 @@ void AdaptDispatch::_ChangeRectAttributes(const Page& page, const til::rect& cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
page.Buffer().TriggerRedraw(Viewport::FromExclusive(changeRect));
|
page.Buffer().TriggerRedraw(Viewport::FromExclusive(changeRect));
|
||||||
_api.NotifyAccessibilityChange(changeRect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1212,7 +1201,6 @@ void AdaptDispatch::CopyRectangularArea(const VTInt top, const VTInt left, const
|
|||||||
} while (dstView.WalkInBounds(dstPos, walkDirection));
|
} while (dstView.WalkInBounds(dstPos, walkDirection));
|
||||||
// Copy any image content in the affected area.
|
// Copy any image content in the affected area.
|
||||||
ImageSlice::CopyBlock(src.Buffer(), srcView.ToExclusive(), dst.Buffer(), dstView.ToExclusive());
|
ImageSlice::CopyBlock(src.Buffer(), srcView.ToExclusive(), dst.Buffer(), dstView.ToExclusive());
|
||||||
_api.NotifyAccessibilityChange(dstRect);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3142,7 +3130,6 @@ void AdaptDispatch::_EraseScrollback()
|
|||||||
_api.SetViewportPosition({ page.XPanOffset(), 0 });
|
_api.SetViewportPosition({ page.XPanOffset(), 0 });
|
||||||
// Move the cursor to the same relative location.
|
// Move the cursor to the same relative location.
|
||||||
cursor.SetYPosition(row - page.Top());
|
cursor.SetYPosition(row - page.Top());
|
||||||
cursor.SetHasMoved(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Routine Description:
|
//Routine Description:
|
||||||
@ -3194,7 +3181,6 @@ void AdaptDispatch::_EraseAll()
|
|||||||
}
|
}
|
||||||
// Restore the relative cursor position
|
// Restore the relative cursor position
|
||||||
cursor.SetYPosition(row + newPageTop);
|
cursor.SetYPosition(row + newPageTop);
|
||||||
cursor.SetHasMoved(true);
|
|
||||||
|
|
||||||
// Erase all the rows in the current page.
|
// Erase all the rows in the current page.
|
||||||
const auto eraseAttributes = _GetEraseAttributes(page);
|
const auto eraseAttributes = _GetEraseAttributes(page);
|
||||||
|
|||||||
@ -202,11 +202,6 @@ public:
|
|||||||
Log::Comment(L"PlayMidiNote MOCK called...");
|
Log::Comment(L"PlayMidiNote MOCK called...");
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyAccessibilityChange(const til::rect& /*changedRect*/) override
|
|
||||||
{
|
|
||||||
Log::Comment(L"NotifyAccessibilityChange MOCK called...");
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyBufferRotation(const int /*delta*/) override
|
void NotifyBufferRotation(const int /*delta*/) override
|
||||||
{
|
{
|
||||||
Log::Comment(L"NotifyBufferRotation MOCK called...");
|
Log::Comment(L"NotifyBufferRotation MOCK called...");
|
||||||
|
|||||||
@ -43,29 +43,6 @@ try
|
|||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
|
|
||||||
[[nodiscard]] HRESULT ScreenInfoUiaProviderBase::Signal(_In_ EVENTID eventId)
|
|
||||||
{
|
|
||||||
auto hr = S_OK;
|
|
||||||
// check to see if we're already firing this particular event
|
|
||||||
if (_signalFiringMapping.find(eventId) != _signalFiringMapping.end() &&
|
|
||||||
_signalFiringMapping[eventId] == true)
|
|
||||||
{
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_signalFiringMapping[eventId] = true;
|
|
||||||
}
|
|
||||||
CATCH_RETURN();
|
|
||||||
|
|
||||||
IRawElementProviderSimple* pProvider = this;
|
|
||||||
hr = UiaRaiseAutomationEvent(pProvider, eventId);
|
|
||||||
_signalFiringMapping[eventId] = false;
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma region IRawElementProviderSimple
|
#pragma region IRawElementProviderSimple
|
||||||
|
|
||||||
// Implementation of IRawElementProviderSimple::get_ProviderOptions.
|
// Implementation of IRawElementProviderSimple::get_ProviderOptions.
|
||||||
@ -211,7 +188,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetEmbeddedFragmentRoots(_Outptr_resul
|
|||||||
IFACEMETHODIMP ScreenInfoUiaProviderBase::SetFocus()
|
IFACEMETHODIMP ScreenInfoUiaProviderBase::SetFocus()
|
||||||
{
|
{
|
||||||
UiaTracing::TextProvider::SetFocus(*this);
|
UiaTracing::TextProvider::SetFocus(*this);
|
||||||
return Signal(UIA_AutomationFocusChangedEventId);
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|||||||
@ -47,7 +47,6 @@ namespace Microsoft::Console::Types
|
|||||||
ScreenInfoUiaProviderBase& operator=(ScreenInfoUiaProviderBase&&) = delete;
|
ScreenInfoUiaProviderBase& operator=(ScreenInfoUiaProviderBase&&) = delete;
|
||||||
~ScreenInfoUiaProviderBase() = default;
|
~ScreenInfoUiaProviderBase() = default;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT Signal(_In_ EVENTID id);
|
|
||||||
virtual void ChangeViewport(const til::inclusive_rect& NewWindow) = 0;
|
virtual void ChangeViewport(const til::inclusive_rect& NewWindow) = 0;
|
||||||
|
|
||||||
// IRawElementProviderSimple methods
|
// IRawElementProviderSimple methods
|
||||||
@ -109,19 +108,6 @@ namespace Microsoft::Console::Types
|
|||||||
std::wstring _wordDelimiters{};
|
std::wstring _wordDelimiters{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// this is used to prevent the object from
|
|
||||||
// signaling an event while it is already in the
|
|
||||||
// process of signalling another event.
|
|
||||||
// This fixes a problem with JAWS where it would
|
|
||||||
// call a public method that calls
|
|
||||||
// UiaRaiseAutomationEvent to signal something
|
|
||||||
// happened, which JAWS then detects the signal
|
|
||||||
// and calls the same method in response,
|
|
||||||
// eventually overflowing the stack.
|
|
||||||
// We aren't using this as a cheap locking
|
|
||||||
// mechanism for multi-threaded code.
|
|
||||||
std::unordered_map<EVENTID, bool> _signalFiringMapping{};
|
|
||||||
|
|
||||||
til::size _getScreenBufferCoords() const noexcept;
|
til::size _getScreenBufferCoords() const noexcept;
|
||||||
const TextBuffer& _getTextBuffer() const noexcept;
|
const TextBuffer& _getTextBuffer() const noexcept;
|
||||||
Viewport _getViewport() const noexcept;
|
Viewport _getViewport() const noexcept;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user