Skip to content

Commit

Permalink
FIX(a11y): Add semantic description to sliders in Settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Hartmnt committed Jan 3, 2024
1 parent 2d69a14 commit c193ba5
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 58 deletions.
32 changes: 8 additions & 24 deletions src/mumble/Accessibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
#include <QAbstractButton>
#include <QAccessible>
#include <QAccessibleInterface>
#include <QAccessibleValueChangeEvent>
#include <QAccessibleValueInterface>
#include <QAccessibleEvent>
#include <QDebug>
#include <QObject>
#include <QTimer>
#include <QWidget>

#include <queue>

#include <QDebug>

namespace Mumble {
namespace Accessibility {

Expand Down Expand Up @@ -144,32 +145,15 @@ namespace Accessibility {
return description;
}

void setSliderSemanticValue(QSlider *slider, QString value) {
// This does currently not work with Orca...
// It is unclear whether it is unintended behavior or not
// We set the value for the slider, any potential focus proxy,
// and the QAccessibleInterface. Orca will still read the
// raw slider value.
QVariant newValue = QVariant(value);
slider->setFocus();

QWidget *focusProxy = slider->focusProxy();
if (focusProxy) {
QAccessibleValueChangeEvent event(focusProxy, newValue);
QAccessible::updateAccessibility(&event);
}
void setSliderSemanticValue(SemanticSlider *slider, QString value) {
qDebug() << "setSemanticValue to " << value;
slider->m_semanticValue = value;

QAccessibleValueChangeEvent event(slider, newValue);
QAccessibleEvent event(slider, QAccessible::NameChanged);
QAccessible::updateAccessibility(&event);

QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(slider);
if (interface) {
QAccessibleValueChangeEvent event(interface, newValue);
QAccessible::updateAccessibility(&event);
}
}

void setSliderSemanticValue(QSlider *slider, SliderAccesibilityMode mode, QString suffix) {
void setSliderSemanticValue(SemanticSlider *slider, SliderAccesibilityMode mode, QString suffix) {
QString description = QString("%1 %2");

switch (mode) {
Expand Down
5 changes: 3 additions & 2 deletions src/mumble/Accessibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "Channel.h"
#include "ClientUser.h"
#include "widgets/SemanticSlider.h"

#include <QLabel>
#include <QSlider>
Expand All @@ -30,8 +31,8 @@ namespace Accessibility {
QString channelToText(const Channel *channel);
QString channelToDescription(const Channel *channel);

void setSliderSemanticValue(QSlider *slider, QString value);
void setSliderSemanticValue(QSlider *slider, SliderAccesibilityMode mode, QString suffix = "");
void setSliderSemanticValue(SemanticSlider *slider, QString value);
void setSliderSemanticValue(SemanticSlider *slider, SliderAccesibilityMode mode, QString suffix = "");

QWidget *getFirstFocusableChild(QObject *object);

Expand Down
51 changes: 44 additions & 7 deletions src/mumble/AudioConfigDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "AudioConfigDialog.h"

#include "Accessibility.h"
#include "AudioInput.h"
#include "AudioOutput.h"
#include "AudioOutputSample.h"
Expand Down Expand Up @@ -54,11 +55,7 @@ AudioInputDialog::AudioInputDialog(Settings &st) : ConfigWidget(st) {
qcbTransmit->setAccessibleName(tr("Transmission mode"));
qsDoublePush->setAccessibleName(tr("PTT lock threshold"));
qsPTTHold->setAccessibleName(tr("PTT hold threshold"));
qsTransmitHold->setAccessibleName(tr("Silence below"));
abSpeech->setAccessibleName(tr("Current speech detection chance"));
qsTransmitMin->setAccessibleName(tr("Silence below"));
qsTransmitMax->setAccessibleName(tr("Speech above"));
qsSpeexNoiseSupStrength->setAccessibleName(tr("Noise suppression"));
qsbIdle->setAccessibleName(tr("Initiate idle action after (in minutes)"));
qlInputHelp->setVisible(false);

Expand Down Expand Up @@ -287,8 +284,11 @@ void AudioInputDialog::save() const {
}

void AudioInputDialog::on_qsFrames_valueChanged(int v) {
qlFrames->setText(tr("%1 ms").arg((v == 1) ? 10 : (v - 1) * 20));
int val = (v == 1) ? 10 : (v - 1) * 20;
qlFrames->setText(tr("%1 ms").arg(val));
updateBitrate();

Mumble::Accessibility::setSliderSemanticValue(qsFrames, QString("%1 %2").arg(val).arg(tr("milliseconds")));
}

void AudioInputDialog::on_qsDoublePush_valueChanged(int v) {
Expand All @@ -299,21 +299,29 @@ void AudioInputDialog::on_qsDoublePush_valueChanged(int v) {
}

void AudioInputDialog::on_qsPTTHold_valueChanged(int v) {
if (v == 0)
if (v == 0) {
qlPTTHold->setText(tr("Off"));
else
Mumble::Accessibility::setSliderSemanticValue(qsPTTHold, tr("Off"));
} else {
qlPTTHold->setText(tr("%1 ms").arg(v));
Mumble::Accessibility::setSliderSemanticValue(qsPTTHold, QString("%1 %2").arg(v).arg(tr("milliseconds")));
}
}

void AudioInputDialog::on_qsTransmitHold_valueChanged(int v) {
float val = static_cast< float >(v * 10);
val = val / 1000.0f;
qlTransmitHold->setText(tr("%1 s").arg(val, 0, 'f', 2));
Mumble::Accessibility::setSliderSemanticValue(qsTransmitHold,
QString("%1 %2").arg(val, 0, 'f', 2).arg(tr("seconds")));
}

void AudioInputDialog::on_qsQuality_valueChanged(int v) {
qlQuality->setText(tr("%1 kb/s").arg(static_cast< float >(v) / 1000.0f, 0, 'f', 1));
updateBitrate();

Mumble::Accessibility::setSliderSemanticValue(
qsQuality, QString("%1 %2").arg(static_cast< float >(v) / 1000.0f, 0, 'f', 1).arg(tr("kilobit per second")));
}

void AudioInputDialog::on_qsSpeexNoiseSupStrength_valueChanged(int v) {
Expand All @@ -322,8 +330,11 @@ void AudioInputDialog::on_qsSpeexNoiseSupStrength_valueChanged(int v) {
if (v < 15) {
qlSpeexNoiseSupStrength->setText(tr("Off"));
pal.setColor(qlSpeexNoiseSupStrength->foregroundRole(), Qt::red);
Mumble::Accessibility::setSliderSemanticValue(qsSpeexNoiseSupStrength, tr("Off"));
} else {
qlSpeexNoiseSupStrength->setText(tr("-%1 dB").arg(v));
Mumble::Accessibility::setSliderSemanticValue(qsSpeexNoiseSupStrength,
QString("-%1 %2").arg(v).arg(tr("decibel")));
}
qlSpeexNoiseSupStrength->setPalette(pal);
}
Expand All @@ -332,6 +343,18 @@ void AudioInputDialog::on_qsAmp_valueChanged(int v) {
v = 18000 - v + 2000;
float d = 20000.0f / static_cast< float >(v);
qlAmp->setText(QString::fromLatin1("%1").arg(d, 0, 'f', 2));

Mumble::Accessibility::setSliderSemanticValue(qsAmp, QString("%1").arg(d, 0, 'f', 2));
}

void AudioInputDialog::on_qsTransmitMin_valueChanged() {
Mumble::Accessibility::setSliderSemanticValue(qsTransmitMin, Mumble::Accessibility::SliderAccesibilityMode::PERCENT,
"%");
}

void AudioInputDialog::on_qsTransmitMax_valueChanged() {
Mumble::Accessibility::setSliderSemanticValue(qsTransmitMax, Mumble::Accessibility::SliderAccesibilityMode::PERCENT,
"%");
}

void AudioInputDialog::updateBitrate() {
Expand Down Expand Up @@ -813,6 +836,7 @@ void AudioOutputDialog::on_qcbSystem_currentIndexChanged(int) {

void AudioOutputDialog::on_qsJitter_valueChanged(int v) {
qlJitter->setText(tr("%1 ms").arg(v * 10));
Mumble::Accessibility::setSliderSemanticValue(qsJitter, QString("%1 %2").arg(v * 10).arg(tr("milliseconds")));
}

void AudioOutputDialog::on_qsVolume_valueChanged(int v) {
Expand All @@ -824,22 +848,30 @@ void AudioOutputDialog::on_qsVolume_valueChanged(int v) {
qlVolume->setPalette(pal);

qlVolume->setText(tr("%1 %").arg(v));
Mumble::Accessibility::setSliderSemanticValue(qsVolume, Mumble::Accessibility::SliderAccesibilityMode::PERCENT,
"%");
}

void AudioOutputDialog::on_qsOtherVolume_valueChanged(int v) {
qlOtherVolume->setText(tr("%1 %").arg(v));
Mumble::Accessibility::setSliderSemanticValue(qsOtherVolume, Mumble::Accessibility::SliderAccesibilityMode::PERCENT,
"%");
}

void AudioOutputDialog::on_qsPacketDelay_valueChanged(int v) {
qlPacketDelay->setText(tr("%1 ms").arg(v));
Mumble::Accessibility::setSliderSemanticValue(qsPacketDelay, QString("%1 %2").arg(v).arg(tr("milliseconds")));
}

void AudioOutputDialog::on_qsPacketLoss_valueChanged(int v) {
qlPacketLoss->setText(tr("%1 %").arg(v));
Mumble::Accessibility::setSliderSemanticValue(qsPacketLoss, Mumble::Accessibility::SliderAccesibilityMode::PERCENT,
"%");
}

void AudioOutputDialog::on_qsDelay_valueChanged(int v) {
qlDelay->setText(tr("%1 ms").arg(v * 10));
Mumble::Accessibility::setSliderSemanticValue(qsDelay, QString("%1 %2").arg(v * 10).arg(tr("milliseconds")));
}

void AudioOutputDialog::on_qcbLoopback_currentIndexChanged(int v) {
Expand All @@ -864,6 +896,7 @@ void AudioOutputDialog::on_qsMinDistance_valueChanged(int value) {
void AudioOutputDialog::on_qsbMinimumDistance_valueChanged(double value) {
QSignalBlocker blocker(qsMinDistance);
qsMinDistance->setValue(value * 10);
Mumble::Accessibility::setSliderSemanticValue(qsMinDistance, QString("%1 %2").arg(value * 10).arg(tr("meters")));

// Ensure that max distance is always a least 1m larger than min distance
qsMaxDistance->setValue(std::max(qsMaxDistance->value(), static_cast< int >(value * 10) + 10));
Expand All @@ -879,6 +912,7 @@ void AudioOutputDialog::on_qsMaxDistance_valueChanged(int value) {
void AudioOutputDialog::on_qsbMaximumDistance_valueChanged(double value) {
QSignalBlocker blocker(qsMaxDistance);
qsMaxDistance->setValue(value * 10);
Mumble::Accessibility::setSliderSemanticValue(qsMaxDistance, QString("%1 %2").arg(value * 10).arg(tr("meters")));

// Ensure that min distance is always a least 1m less than max distance
qsMinDistance->setValue(std::min(qsMinDistance->value(), static_cast< int >(value * 10) - 10));
Expand All @@ -887,6 +921,8 @@ void AudioOutputDialog::on_qsbMaximumDistance_valueChanged(double value) {
void AudioOutputDialog::on_qsMinimumVolume_valueChanged(int value) {
QSignalBlocker blocker(qsbMinimumVolume);
qsbMinimumVolume->setValue(value);
Mumble::Accessibility::setSliderSemanticValue(qsMinimumVolume,
Mumble::Accessibility::SliderAccesibilityMode::PERCENT, "%");
}

void AudioOutputDialog::on_qsbMinimumVolume_valueChanged(int value) {
Expand All @@ -897,6 +933,7 @@ void AudioOutputDialog::on_qsbMinimumVolume_valueChanged(int value) {
void AudioOutputDialog::on_qsBloom_valueChanged(int value) {
QSignalBlocker blocker(qsbBloom);
qsbBloom->setValue(value);
Mumble::Accessibility::setSliderSemanticValue(qsBloom, Mumble::Accessibility::SliderAccesibilityMode::PERCENT, "%");
}

void AudioOutputDialog::on_qsbBloom_valueChanged(int value) {
Expand Down
2 changes: 2 additions & 0 deletions src/mumble/AudioConfigDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public slots:
void on_qsAmp_valueChanged(int v);
void on_qsDoublePush_valueChanged(int v);
void on_qsPTTHold_valueChanged(int v);
void on_qsTransmitMin_valueChanged();
void on_qsTransmitMax_valueChanged();
void on_qsSpeexNoiseSupStrength_valueChanged(int v);
void on_qcbTransmit_currentIndexChanged(int v);
void on_qcbSystem_currentIndexChanged(int);
Expand Down
23 changes: 14 additions & 9 deletions src/mumble/AudioInput.ui
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="qwPTT">
<layout class="QGridLayout" columnstretch="0,1,0,0">
Expand Down Expand Up @@ -263,7 +263,7 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="qsPTTHold">
<widget class="SemanticSlider" name="qsPTTHold">
<property name="toolTip">
<string>Time the microphone stays open after the PTT key is released</string>
</property>
Expand Down Expand Up @@ -303,7 +303,7 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="qsTransmitHold">
<widget class="SemanticSlider" name="qsTransmitHold">
<property name="toolTip">
<string>How long to keep transmitting after silence</string>
</property>
Expand Down Expand Up @@ -385,7 +385,7 @@
</widget>
</item>
<item row="3" column="1">
<widget class="QSlider" name="qsTransmitMin">
<widget class="SemanticSlider" name="qsTransmitMin">
<property name="toolTip">
<string>Signal values below this count as silence</string>
</property>
Expand All @@ -410,7 +410,7 @@
</widget>
</item>
<item row="4" column="1">
<widget class="QSlider" name="qsTransmitMax">
<widget class="SemanticSlider" name="qsTransmitMax">
<property name="toolTip">
<string>Signal values above this count as voice</string>
</property>
Expand Down Expand Up @@ -459,7 +459,7 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="qsFrames">
<widget class="SemanticSlider" name="qsFrames">
<property name="toolTip">
<string>How many audio frames to send per packet</string>
</property>
Expand Down Expand Up @@ -510,7 +510,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="qsQuality">
<widget class="SemanticSlider" name="qsQuality">
<property name="toolTip">
<string>Quality of compression (peak bandwidth)</string>
</property>
Expand Down Expand Up @@ -594,7 +594,7 @@
</property>
<layout class="QGridLayout">
<item row="2" column="1">
<widget class="QSlider" name="qsAmp">
<widget class="SemanticSlider" name="qsAmp">
<property name="toolTip">
<string>Maximum amplification of input sound</string>
</property>
Expand Down Expand Up @@ -720,7 +720,7 @@
</widget>
</item>
<item>
<widget class="QSlider" name="qsSpeexNoiseSupStrength">
<widget class="SemanticSlider" name="qsSpeexNoiseSupStrength">
<property name="toolTip">
<string>This controls the amount by which Speex will suppress noise.</string>
</property>
Expand Down Expand Up @@ -1072,6 +1072,11 @@
<extends>QComboBox</extends>
<header>widgets/MUComboBox.h</header>
</customwidget>
<customwidget>
<class>SemanticSlider</class>
<extends>QSlider</extends>
<header>widgets/SemanticSlider.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>qcbSystem</tabstop>
Expand Down
Loading

0 comments on commit c193ba5

Please sign in to comment.