Browse Source

Add screen reader support

pull/6658/head
Anders Jenbo 3 years ago
parent
commit
d725fdb4f3
  1. 2
      .github/workflows/Windows_MinGW_x64.yml
  2. 2
      .github/workflows/Windows_MinGW_x86.yml
  3. 25
      3rdParty/tolk/CMakeLists.txt
  4. 1
      CMake/Definitions.cmake
  5. 8
      CMake/Dependencies.cmake
  6. 17
      CMake/finders/FindSpeechd.cmake
  7. 8
      CMakeLists.txt
  8. 1
      Packaging/nix/debian-cross-aarch64-prep.sh
  9. 2
      Packaging/nix/debian-cross-i386-prep.sh
  10. 2
      Packaging/nix/debian-host-prep.sh
  11. 22
      Source/CMakeLists.txt
  12. 3
      Source/DiabloUI/diabloui.cpp
  13. 3
      Source/control.cpp
  14. 4
      Source/diablo.cpp
  15. 54
      Source/utils/screen_reader.cpp
  16. 25
      Source/utils/screen_reader.hpp

2
.github/workflows/Windows_MinGW_x64.yml

@ -36,7 +36,7 @@ jobs:
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc64.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc64.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON -DSCREEN_READER_INTEGRATION=ON
- name: Build
working-directory: ${{github.workspace}}

2
.github/workflows/Windows_MinGW_x86.yml

@ -36,7 +36,7 @@ jobs:
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON -DSCREEN_READER_INTEGRATION=ON
- name: Build
working-directory: ${{github.workspace}}

25
3rdParty/tolk/CMakeLists.txt vendored

@ -0,0 +1,25 @@
include(functions/FetchContent_MakeAvailableExcludeFromAll)
include(FetchContent)
FetchContent_Declare(Tolk
URL https://github.com/sig-a11y/tolk/archive/89de98779e3b6365dc1688538d5de4ecba3fdbab.tar.gz
URL_HASH MD5=724f6022186573dd9c5c2c92ed9e21e6
)
FetchContent_MakeAvailableExcludeFromAll(Tolk)
target_include_directories(Tolk PUBLIC ${libTolk_SOURCE_DIR}/src)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(TOLK_LIB_DIR "${Tolk_SOURCE_DIR}/libs/x86")
else()
set(TOLK_LIB_DIR "${Tolk_SOURCE_DIR}/libs/x64")
endif()
file(GLOB TOLK_DLLS
LIST_DIRECTORIES false
"${TOLK_LIB_DIR}/*.dll"
"${TOLK_LIB_DIR}/*.ini")
foreach(_TOLK_DLL_PATH ${TOLK_DLLS})
install(FILES "${_TOLK_DLL_PATH}"
DESTINATION "."
)
endforeach()

1
CMake/Definitions.cmake

@ -18,6 +18,7 @@ foreach(
DEVILUTIONX_RESAMPLER_SPEEX
DEVILUTIONX_RESAMPLER_SDL
DEVILUTIONX_PALETTE_TRANSPARENCY_BLACK_16_LUT
SCREEN_READER_INTEGRATION
UNPACKED_MPQS
UNPACKED_SAVES
DEVILUTIONX_WINDOWS_NO_WCHAR

8
CMake/Dependencies.cmake

@ -24,6 +24,14 @@ if(SUPPORTS_MPQ)
endif()
endif()
if(SCREEN_READER_INTEGRATION)
if(WIN32)
add_subdirectory(3rdParty/tolk)
else()
find_package(Speechd REQUIRED)
endif()
endif()
if(EMSCRIPTEN)
# We use `USE_PTHREADS=1` here to get a version of SDL2 that supports threads.
emscripten_system_library("SDL2" SDL2::SDL2 USE_SDL=2 USE_PTHREADS=1)

17
CMake/finders/FindSpeechd.cmake

@ -0,0 +1,17 @@
# find speech-dispatcher library and header if available
# Copyright (c) 2009, Jeremy Whiting <jpwhiting@kde.org>
# Copyright (c) 2011, Raphael Kubo da Costa <kubito@gmail.com>
# This module defines
# SPEECHD_INCLUDE_DIR, where to find libspeechd.h
# SPEECHD_LIBRARIES, the libraries needed to link against speechd
# SPEECHD_FOUND, If false, speechd was not found
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
find_path(SPEECHD_INCLUDE_DIR libspeechd.h PATH_SUFFIXES speech-dispatcher)
find_library(SPEECHD_LIBRARIES NAMES speechd)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Speechd REQUIRED_VARS SPEECHD_INCLUDE_DIR SPEECHD_LIBRARIES)

8
CMakeLists.txt

@ -153,6 +153,8 @@ mark_as_advanced(DEVILUTIONX_PALETTE_TRANSPARENCY_BLACK_16_LUT)
# Additional features
option(DISABLE_DEMOMODE "Disable demo mode support" OFF)
option(DISCORD_INTEGRATION "Build with Discord SDK for rich presence support" OFF)
option(SCREEN_READER_INTEGRATION "Build with screen reader support" OFF)
mark_as_advanced(SCREEN_READER_INTEGRATION)
# If both UNPACKED_MPQS and UNPACKED_SAVES are enabled, we completely remove MPQ support.
if(UNPACKED_MPQS AND UNPACKED_SAVES)
@ -550,6 +552,12 @@ if(CPACK AND (APPLE OR BUILD_ASSETS_MPQ OR SRC_DIST))
)
endif()
if(SCREEN_READER_INTEGRATION)
install(FILES "${Tolk_BINARY_DIR}/libTolk.dll"
DESTINATION "."
)
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
string(TOLOWER ${PROJECT_NAME} project_name)
set(CPACK_PACKAGE_NAME ${project_name})

1
Packaging/nix/debian-cross-aarch64-prep.sh

@ -23,6 +23,7 @@ PACKAGES=(
cmake git smpq gettext dpkg-cross libc-dev-arm64-cross
libsdl2-dev:arm64 libsdl2-image-dev:arm64 libsodium-dev:arm64
libsimpleini-dev:arm64 libpng-dev:arm64 libbz2-dev:arm64 libfmt-dev:arm64
libspeechd-dev:arm64
)
if (( $# < 1 )) || [[ "$1" != --no-gcc ]]; then

2
Packaging/nix/debian-cross-i386-prep.sh

@ -5,7 +5,7 @@ set -x
PACKAGES=(
cmake git smpq gettext
libsdl2-dev:i386 libsdl2-image-dev:i386 libsodium-dev:i386
libpng-dev:i386 libbz2-dev:i386 libfmt-dev:i386
libpng-dev:i386 libbz2-dev:i386 libfmt-dev:i386 libspeechd-dev:i386
)
if (( $# < 1 )) || [[ "$1" != --no-gcc ]]; then

2
Packaging/nix/debian-host-prep.sh

@ -4,7 +4,7 @@ set -x
PACKAGES=(
rpm pkg-config cmake git smpq gettext libsdl2-dev libsdl2-image-dev libsodium-dev
libpng-dev libbz2-dev libfmt-dev
libpng-dev libbz2-dev libfmt-dev libspeechd-dev
)
if (( $# < 1 )) || [[ "$1" != --no-gcc ]]; then

22
Source/CMakeLists.txt

@ -251,9 +251,19 @@ if(DISCORD_INTEGRATION)
)
endif()
if(SCREEN_READER_INTEGRATION)
list(APPEND libdevilutionx_SRCS
utils/screen_reader.cpp
)
endif()
add_devilutionx_library(libdevilutionx OBJECT ${libdevilutionx_SRCS})
target_include_directories(libdevilutionx PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
if(SCREEN_READER_INTEGRATION AND NOT WIN32)
target_include_directories(libdevilutionx PUBLIC ${Speechd_INCLUDE_DIRS})
endif()
# Use file GENERATE instead of configure_file because configure_file
# does not support generator expressions.
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
@ -277,6 +287,10 @@ if(DISCORD_INTEGRATION)
target_link_libraries(libdevilutionx PRIVATE discord discord_game_sdk)
endif()
if(SCREEN_READER_INTEGRATION AND WIN32)
target_compile_definitions(libdevilutionx PRIVATE Tolk)
endif()
target_link_libraries(libdevilutionx PUBLIC
Threads::Threads
DevilutionX::SDL
@ -288,6 +302,14 @@ target_link_libraries(libdevilutionx PUBLIC
${libdevilutionx_DEPS}
)
if(SCREEN_READER_INTEGRATION)
if(WIN32)
target_link_libraries(libdevilutionx PUBLIC Tolk)
else()
target_link_libraries(libdevilutionx PUBLIC speechd)
endif()
endif()
if(NOT USE_SDL1)
target_link_libraries(libdevilutionx PUBLIC SDL2::SDL2_image)
endif()

3
Source/DiabloUI/diabloui.cpp

@ -24,6 +24,7 @@
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/pcx_to_clx.hpp"
#include "utils/screen_reader.hpp"
#include "utils/sdl_compat.h"
#include "utils/sdl_geometry.h"
#include "utils/sdl_wrap.h"
@ -151,6 +152,7 @@ void UiInitList(void (*fnFocus)(int value), void (*fnSelect)(int value), void (*
gUiList = uiList;
if (selectedItem <= SelectedItemMax && HasAnyOf(uiList->GetItem(selectedItem)->uiFlags, UiFlags::NeedsNextElement))
AdjustListOffset(selectedItem + 1);
SpeakText(uiList->GetItem(selectedItem)->m_text);
} else if (item->IsType(UiType::Scrollbar)) {
uiScrollbar = static_cast<UiScrollbar *>(item.get());
}
@ -225,6 +227,7 @@ void UiFocus(std::size_t itemIndex, bool checkUp, bool ignoreItemsWraps = false)
}
pItem = gUiList->GetItem(itemIndex);
}
SpeakText(pItem->m_text);
if (HasAnyOf(pItem->uiFlags, UiFlags::NeedsNextElement))
AdjustListOffset(itemIndex + 1);

3
Source/control.cpp

@ -50,6 +50,7 @@
#include "utils/language.h"
#include "utils/log.hpp"
#include "utils/parse_int.hpp"
#include "utils/screen_reader.hpp"
#include "utils/sdl_geometry.h"
#include "utils/str_case.hpp"
#include "utils/str_cat.hpp"
@ -269,6 +270,8 @@ void PrintInfo(const Surface &out)
// which throws off the vertical centering
infoArea.position.y += spacing / 2;
SpeakText(InfoString);
DrawString(out, InfoString, infoArea, InfoColor | UiFlags::AlignCenter | UiFlags::VerticalCenter | UiFlags::KerningFitSpacing, 2, lineHeight);
}

4
Source/diablo.cpp

@ -83,6 +83,7 @@
#include "utils/language.h"
#include "utils/parse_int.hpp"
#include "utils/paths.h"
#include "utils/screen_reader.hpp"
#include "utils/str_cat.hpp"
#include "utils/utf8.hpp"
@ -1141,6 +1142,7 @@ void ApplicationInit()
init_create_window();
was_window_init = true;
InitializeScreenReader();
LanguageInitialize();
SetApplicationVersions();
@ -1228,6 +1230,8 @@ void DiabloDeinit()
{
FreeItemGFX();
ShutDownScreenReader();
if (gbSndInited)
effects_cleanup_sfx();
snd_deinit();

54
Source/utils/screen_reader.cpp

@ -0,0 +1,54 @@
#include "utils/screen_reader.hpp"
#include <string>
#include <string_view>
#ifdef _WIN32
#include "utils/file_util.h"
#include <Tolk.h>
#else
#include <speech-dispatcher/libspeechd.h>
#endif
namespace devilution {
#ifndef _WIN32
SPDConnection *Speechd;
#endif
void InitializeScreenReader()
{
#ifdef _WIN32
Tolk_Load();
#else
Speechd = spd_open("DevilutionX", "DevilutionX", NULL, SPD_MODE_SINGLE);
#endif
}
void ShutDownScreenReader()
{
#ifdef _WIN32
Tolk_Unload();
#else
spd_close(Speechd);
#endif
}
void SpeakText(std::string_view text)
{
static std::string SpokenText;
if (SpokenText == text)
return;
SpokenText = text;
#ifdef _WIN32
const auto textUtf16 = ToWideChar(SpokenText);
Tolk_Output(&textUtf16[0], true);
#else
spd_say(Speechd, SPD_TEXT, SpokenText.c_str());
#endif
}
} // namespace devilution

25
Source/utils/screen_reader.hpp

@ -0,0 +1,25 @@
#pragma once
#include <string_view>
namespace devilution {
#ifdef SCREEN_READER_INTEGRATION
void InitializeScreenReader();
void ShutDownScreenReader();
void SpeakText(std::string_view text);
#else
constexpr void InitializeScreenReader()
{
}
constexpr void ShutDownScreenReader()
{
}
constexpr void SpeakText(std::string_view text)
{
}
#endif
} // namespace devilution
Loading…
Cancel
Save