diff --git a/src/engraving/accessibility/accessibleitem.cpp b/src/engraving/accessibility/accessibleitem.cpp index d304772378..ca664c0572 100644 --- a/src/engraving/accessibility/accessibleitem.cpp +++ b/src/engraving/accessibility/accessibleitem.cpp @@ -25,14 +25,27 @@ #include "../libmscore/score.h" #include "../libmscore/measure.h" +#include "translation.h" #include "log.h" +using namespace mu; using namespace mu::engraving; using namespace mu::accessibility; using namespace mu::engraving; bool AccessibleItem::enabled = true; +static QString readable(QString s) +{ + // Remove undesired pauses in screen reader speech output + s.remove(u':'); + + // Handle desired pauses + s.replace(u';', u','); // NVDA doesn't pause for semicolon + + return s; +} + AccessibleItem::AccessibleItem(EngravingItem* e, Role role) : m_element(e), m_role(role) { @@ -169,9 +182,15 @@ QString AccessibleItem::accessibleName() const QString staffInfo = root ? root->staffInfo() : ""; QString barsAndBeats = m_element->formatBarsAndBeats(); - return QString("%1%2%3").arg(!staffInfo.isEmpty() ? (staffInfo + "; ") : "") - .arg(m_element->accessibleInfo().toQString()) - .arg(!barsAndBeats.isEmpty() ? ("; " + barsAndBeats) : ""); + barsAndBeats.remove(u';'); // Too many pauses in speech + + QString name = QString("%1%2%3%4") + .arg(!staffInfo.isEmpty() ? (staffInfo + "; ") : "") + .arg(m_element->screenReaderInfo().toQString()) + .arg(m_element->visible() ? "" : " " + qtrc("engraving", "invisible")) + .arg(!barsAndBeats.isEmpty() ? ("; " + barsAndBeats) : ""); + + return readable(name); } QString AccessibleItem::accessibleDescription() const @@ -185,7 +204,7 @@ QString AccessibleItem::accessibleDescription() const result = accessibleName() + " "; #endif - result += m_element->accessibleExtraInfo(); + result += readable(m_element->accessibleExtraInfo()); return result; } diff --git a/src/engraving/libmscore/chordrest.cpp b/src/engraving/libmscore/chordrest.cpp index 4cd9d04efd..396bdd473d 100644 --- a/src/engraving/libmscore/chordrest.cpp +++ b/src/engraving/libmscore/chordrest.cpp @@ -683,7 +683,8 @@ String ChordRest::durationUserName() const tupletType = mtrc("engraving", "Nonuplet"); break; default: - tupletType = mtrc("engraving", "Custom tuplet"); + //: %1 is tuplet ratio numerator (i.e. the number of notes in the tuplet) + tupletType = mtrc("engraving", "%1 note tuplet").arg(tuplet()->ratio().numerator()); } } String dotString; diff --git a/src/engraving/libmscore/note.cpp b/src/engraving/libmscore/note.cpp index 3319b6f7fb..72329f7f0f 100644 --- a/src/engraving/libmscore/note.cpp +++ b/src/engraving/libmscore/note.cpp @@ -3332,7 +3332,15 @@ String Note::screenReaderInfo() const pitchName = mtrc("engraving", "%1; String: %2; Fret: %3") .arg(tpcUserName(true), String::number(string() + 1), String::number(fret())); } else { - pitchName = tpcUserName(true); + pitchName = _headGroup == NoteHeadGroup::HEAD_NORMAL + ? tpcUserName(true) + //: head as in note head. %1 is head type (circle, cross, etc.). %2 is pitch (e.g. Db4). + : mtrc("engraving", "%1 head %2").arg(subtypeName()).arg(tpcUserName(true)); + if (chord()->staffMove() < 0) { + duration += u"; " + mtrc("engraving", "Cross-staff above"); + } else if (chord()->staffMove() > 0) { + duration += u"; " + mtrc("engraving", "Cross-staff below"); + } } return String(u"%1 %2 %3%4").arg(noteTypeUserName(), pitchName, duration, (chord()->isGrace() ? u"" : String(u"; %1").arg(voice))); } diff --git a/src/engraving/libmscore/rest.cpp b/src/engraving/libmscore/rest.cpp index 7df4ee8208..f978913ccd 100644 --- a/src/engraving/libmscore/rest.cpp +++ b/src/engraving/libmscore/rest.cpp @@ -863,8 +863,14 @@ String Rest::screenReaderInfo() const { Measure* m = measure(); bool voices = m ? m->hasVoices(staffIdx()) : false; - String voice = voices ? mtrc("engraving", "Voice: %1").arg(track() % VOICES + 1) : u""; - return String(u"%1 %2 %3").arg(EngravingItem::accessibleInfo(), durationUserName(), voice); + String voice = voices ? (u"; " + mtrc("engraving", "Voice: %1").arg(track() % VOICES + 1)) : u""; + String crossStaff; + if (staffMove() < 0) { + crossStaff = u"; " + mtrc("engraving", "Cross-staff above"); + } else if (staffMove() > 0) { + crossStaff = u"; " + mtrc("engraving", "Cross-staff below"); + } + return String(u"%1 %2%3%4").arg(EngravingItem::accessibleInfo(), durationUserName(), crossStaff, voice); } //---------------------------------------------------------