C++ без барьеров: как сделать код доступным для всех

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему accessibility — это не про «слабаков», а про качество кода

Когда мы пишем на C++, мы привыкли думать о производительности, памяти и скорости. Но есть ещё один аспект, который часто упускают — accessibility. Это не просто модный термин из мира веб-разработки. В C++ доступность приложений — это возможность для людей с ограниченными возможностями (нарушения зрения, слуха, моторики) пользоваться вашим софтом наравне с другими.

Представьте: вы создали крутой графический редактор или консольную утилиту. Но если она не читается screen reader'ом или не управляется с клавиатуры — вы отсекаете 15–20% пользователей. А ещё accessibility — это часто требование закона (например, в США — Section 508, в Европе — EN 301 549).

В этой статье мы разберём, как внедрить a11y best practices (a11y — числовая аббревиатура accessibility) в C++ проекты, не жертвуя производительностью. Поехали!

С чего начать: базовые принципы инклюзивного кода

Прежде чем лезть в код, запомните три кита:

  • Воспринимаемость — информация должна быть доступна хотя бы через одно чувство (зрение, слух, тактильно).
  • Управляемость — интерфейс должен работать с клавиатуры, голосом или переключателями.
  • Понятность — поведение элементов предсказуемо, ошибки понятны.

В C++ это особенно важно, потому что мы часто работаем с низкоуровневыми API, где семантика теряется. Например, рисуя кнопку через OpenGL, вы не получите автоматической поддержки screen reader'ов — её нужно добавлять вручную.

Семантическая разметка в C++ GUI: Qt и не только

Самый распространённый способ добавить accessibility в C++ — использовать фреймворк Qt. Он имеет встроенную поддержку через QAccessibleInterface. Но даже если вы пишете на чистом WinAPI — есть IAccessible.

Пример: делаем кнопку доступной

Допустим, у вас есть кастомная кнопка, отрисованная через QPainter. Без accessibility screen reader увидит просто «прямоугольник». Исправляем:

#include <QAccessible>
#include <QAccessibleWidget>
#include <QPushButton>

class AccessibleButton : public QAccessibleWidget {
public:
    explicit AccessibleButton(QWidget* widget)
        : QAccessibleWidget(widget, QAccessible::Button) {}

    QString text(QAccessible::Text t) const override {
        if (t == QAccessible::Name) {
            auto* btn = qobject_cast<QPushButton*>(widget());
            return btn ? btn->text() : QString();
        }
        return QAccessibleWidget::text(t);
    }
};

// Использование:
QPushButton* btn = new QPushButton("Отправить");
QAccessible::registerAccessibleFactory(
    [](QObject* obj) -> QAccessibleInterface* {
        if (auto* btn = qobject_cast<QPushButton*>(obj)) {
            return new AccessibleButton(btn);
        }
        return nullptr;
    }
);

Теперь screen reader прочитает «Отправить, кнопка». Магия? Нет, просто инклюзивный код.

Accessibility в консольных приложениях C++

Казалось бы, консоль — это прошлый век. Но многие утилиты, CI/CD пайплайны и серверные приложения работают именно в терминале. Как сделать их доступными?

Правильный вывод для screen reader'ов

Screen reader (например, NVDA, JAWS) читает консоль построчно. Если вы выводите таблицу ASCII-символами — это кошмар. Лучше используйте структурный вывод:

#include <iostream>
#include <string>
#include <vector>

struct User {
    std::string name;
    int age;
};

void printAccessibleTable(const std::vector<User>& users) {
    // Screen reader friendly: сначала заголовок, потом данные
    std::cout << "Таблица пользователей:" << std::endl;
    for (const auto& u : users) {
        std::cout << "Имя: " << u.name 
                  << ", возраст: " << u.age << std::endl;
    }
}

int main() {
    std::vector<User> users = {{"Анна", 30}, {"Иван", 25}};
    printAccessibleTable(users);
    return 0;
}

Обратите внимание: мы не используем табуляцию или пробелы для выравнивания — это сбивает чтение. Вместо этого — естественный язык.

ARIA-аналоги для C++: как сообщить screen reader'у о состоянии

В вебе есть ARIA-атрибуты (role, aria-label, aria-live). В C++ десктопных приложениях их роль выполняют Accessible Role и State. Например, для индикатора загрузки:

class ProgressBarAccessible : public QAccessibleWidget {
public:
    explicit ProgressBarAccessible(QWidget* widget)
        : QAccessibleWidget(widget, QAccessible::ProgressBar) {}

    QAccessible::State state() const override {
        QAccessible::State s = QAccessibleWidget::state();
        auto* bar = qobject_cast<QProgressBar*>(widget());
        if (bar && bar->minimum() == 0 && bar->maximum() == 0) {
            s.busy = true; // Неопределённый прогресс
        }
        return s;
    }

    QString text(QAccessible::Text t) const override {
        if (t == QAccessible::Value) {
            auto* bar = qobject_cast<QProgressBar*>(widget());
            if (bar) return QString::number(bar->value()) + "%";
        }
        return QAccessibleWidget::text(t);
    }
};

Теперь screen reader объявит: «Прогресс: 45%» и, если нужно, «Занято» для неопределённого прогресс-бара.

Обработка ошибок с точки зрения accessibility

Ошибки — это не просто std::cerr. Пользователь с нарушением зрения может не увидеть красный текст. Добавьте звуковые сигналы (через Beep() в Windows или QSound) и обязательно выводите описание ошибки в лог, который читает screen reader.

#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif

void reportError(const std::string& message) {
    // Визуальный вывод
    std::cerr << "Ошибка: " << message << std::endl;
    
    // Звуковой сигнал для screen reader
#ifdef _WIN32
    Beep(440, 200); // Нота Ля, 200 мс
#endif
    
    // Логирование для дальнейшего анализа
    // logToFile(message);
}

Важно: не злоупотребляйте звуками — используйте их только для критических ошибок.

Тестирование доступности: как не накосячить

Вы всё написали, но как проверить? Есть несколько инструментов:

  • NVDA (бесплатный screen reader) — пройдитесь по всему интерфейсу.

Блоги

Рекомендаций по книгам