From 4de3264d602683e5bed2b3277283465ffb72e3a7 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 4 Jul 2017 14:26:48 +0100 Subject: [PATCH] Remove Track: improvement for screen readers. After a focused track is removed by pressing shift+c, the new focus is often not correctly read by screen readers, especially nvda. The fixes: 1. In AudacityProject::RemoveTrack, set the new focus after the track has been deleted, rather than before. (If it is set before, then the childId can be wrong after the track is deleted. 2. In TrackPanelAx::SetFocus, send an object focus event if there are no tracks. This is so the focus is correctly set when there are no tracks after a track has been deleted. 3. In TrackPanelAx::GetFocus, given the change in 2. , only call SetFocus if the focus has changed, to avoid sending unnecessary focus events. (Screen readers are normally tolerant of this, but Window Eyes became a bit too talkative.) --- src/Project.cpp | 22 ++++++++++++---------- src/TrackPanelAx.cpp | 18 ++++++++++++++++-- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index 071a505e2..2d27e8b66 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -5447,14 +5447,16 @@ void AudacityProject::SetTrackPan(WaveTrack * wt, LWSlider * slider) /// Removes the specified track. Called from HandleClosing. void AudacityProject::RemoveTrack(Track * toRemove) { - // If it was focused, reassign focus to the next or, if - // unavailable, the previous track. - if (mTrackPanel->GetFocusedTrack() == toRemove) { - Track *t = mTracks->GetNext(toRemove, true); - if (t == NULL) { - t = mTracks->GetPrev(toRemove, true); + // If it was focused, then new focus is the next or, if + // unavailable, the previous track. (The new focus is set + // after the track has been removed.) + bool toRemoveWasFocused = mTrackPanel->GetFocusedTrack() == toRemove; + Track* newFocus{}; + if (toRemoveWasFocused) { + newFocus = mTracks->GetNext(toRemove, true); + if (!newFocus) { + newFocus = mTracks->GetPrev(toRemove, true); } - mTrackPanel->SetFocusedTrack(t); // It's okay if this is NULL } wxString name = toRemove->GetName(); @@ -5473,9 +5475,9 @@ void AudacityProject::RemoveTrack(Track * toRemove) if (partner) { mTracks->Remove(partner); } - - if (mTracks->IsEmpty()) { - mTrackPanel->SetFocusedTrack(NULL); + + if (toRemoveWasFocused) { + mTrackPanel->SetFocusedTrack(newFocus); } PushState( diff --git a/src/TrackPanelAx.cpp b/src/TrackPanelAx.cpp index 354a08c2d..7e9127aa0 100644 --- a/src/TrackPanelAx.cpp +++ b/src/TrackPanelAx.cpp @@ -49,8 +49,14 @@ TrackPanelAx::~TrackPanelAx() std::shared_ptr TrackPanelAx::GetFocus() { auto focusedTrack = mFocusedTrack.lock(); - if( !focusedTrack ) - focusedTrack = SetFocus(); + if( !focusedTrack ) { + TrackListIterator iter( mTrackPanel->GetTracks() ); + focusedTrack = Track::Pointer( iter.First() ); + // only call SetFocus if the focus has changed to avoid + // unnecessary focus events + if (focusedTrack) + focusedTrack = SetFocus(); + } if( !TrackNum( focusedTrack ) ) { @@ -104,6 +110,14 @@ std::shared_ptr TrackPanelAx::SetFocus( std::shared_ptr track ) num ); } } + else + { + NotifyEvent(wxACC_EVENT_OBJECT_FOCUS, + mTrackPanel, + wxOBJID_CLIENT, + wxACC_SELF); + } + #endif return track;