Compare commits
24
Commits
2026.01.26
...
c4890f31af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4890f31af | ||
|
|
c44245189a | ||
|
|
c7b8e4a30d | ||
|
|
20fe1a7e30 | ||
|
|
25931758f7 | ||
|
|
daf57ef22c | ||
|
|
1d2d727fa2 | ||
|
|
11bd7107d2 | ||
|
|
95d33047fa | ||
|
|
523b896053 | ||
|
|
9152455227 | ||
|
|
c0fdaca4d0 | ||
|
|
8312a842c1 | ||
|
|
07138197cb | ||
|
|
ed78ffc248 | ||
|
|
4add36f5ca | ||
|
|
40e63150a6 | ||
|
|
4dba0ec0cd | ||
|
|
e6f780c38b | ||
|
|
0f7f73a6a0 | ||
|
|
aa71d02036 | ||
|
|
f873fcee11 | ||
|
|
51ef3de672 | ||
|
|
13976b7235 |
@@ -8,13 +8,11 @@ set -e # Exit on error
|
|||||||
|
|
||||||
# Colors for output (only if stdout is a terminal)
|
# Colors for output (only if stdout is a terminal)
|
||||||
if [[ -t 1 ]]; then
|
if [[ -t 1 ]]; then
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
else
|
else
|
||||||
RED=''
|
|
||||||
GREEN=''
|
GREEN=''
|
||||||
YELLOW=''
|
YELLOW=''
|
||||||
BLUE=''
|
BLUE=''
|
||||||
@@ -56,12 +54,6 @@ if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|||||||
|
|
||||||
# Remove data files
|
# Remove data files
|
||||||
|
|
||||||
# Remove desktop files
|
|
||||||
if [[ -f "$HOME/.local/share/applications/cthulhu-autostart.desktop" ]]; then
|
|
||||||
rm -f "$HOME/.local/share/applications/cthulhu-autostart.desktop"
|
|
||||||
echo " Removed: ~/.local/share/applications/cthulhu-autostart.desktop"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove icons
|
# Remove icons
|
||||||
for size in 16x16 22x22 24x24 32x32 48x48 256x256 scalable symbolic; do
|
for size in 16x16 22x22 24x24 32x32 48x48 256x256 scalable symbolic; do
|
||||||
icon_path="$HOME/.local/share/icons/hicolor/$size/apps"
|
icon_path="$HOME/.local/share/icons/hicolor/$size/apps"
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Type=Application
|
|
||||||
Name=Cthulhu Screen Reader
|
|
||||||
Exec=cthulhu
|
|
||||||
NoDisplay=true
|
|
||||||
# Desktop-neutral autostart - no GNOME-specific conditions
|
|
||||||
# Users can enable/disable via their desktop environment's accessibility settings
|
|
||||||
# or by adding/removing this file from ~/.config/autostart/
|
|
||||||
X-GNOME-AutoRestart=true
|
|
||||||
Categories=Accessibility;
|
|
||||||
Keywords=screen;reader;accessibility;speech;braille;
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
# Maintainer: Storm Dragon <storm_dragon@stormux.org>
|
||||||
|
|
||||||
pkgname=cthulhu
|
pkgname=cthulhu
|
||||||
pkgver=2026.01.26
|
pkgver=2026.03.02
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Desktop-agnostic screen reader with plugin system, forked from Orca"
|
pkgdesc="Desktop-agnostic screen reader with plugin system, forked from Orca"
|
||||||
url="https://git.stormux.org/storm/cthulhu"
|
url="https://git.stormux.org/storm/cthulhu"
|
||||||
@@ -27,6 +27,7 @@ depends=(
|
|||||||
|
|
||||||
# Plugin system and D-Bus remote control
|
# Plugin system and D-Bus remote control
|
||||||
python-pluggy
|
python-pluggy
|
||||||
|
python-tomlkit
|
||||||
python-dasbus
|
python-dasbus
|
||||||
|
|
||||||
# AI Assistant dependencies (for screenshots, HTTP requests, and actions)
|
# AI Assistant dependencies (for screenshots, HTTP requests, and actions)
|
||||||
@@ -83,7 +84,7 @@ makedepends=(
|
|||||||
)
|
)
|
||||||
install=cthulhu.install
|
install=cthulhu.install
|
||||||
source=(
|
source=(
|
||||||
"git+https://git.stormux.org/storm/cthulhu.git"
|
"git+https://git.stormux.org/storm/cthulhu.git#tag=${pkgver}"
|
||||||
"cthulhu.install"
|
"cthulhu.install"
|
||||||
)
|
)
|
||||||
b2sums=(
|
b2sums=(
|
||||||
@@ -91,11 +92,6 @@ b2sums=(
|
|||||||
'SKIP'
|
'SKIP'
|
||||||
)
|
)
|
||||||
|
|
||||||
pkgver() {
|
|
||||||
cd cthulhu
|
|
||||||
grep "^version = " src/cthulhu/cthulhuVersion.py | sed 's/version = "\(.*\)"/\1/'
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd cthulhu
|
cd cthulhu
|
||||||
arch-meson _build
|
arch-meson _build
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Cthulhu Logging Guidelines
|
||||||
|
|
||||||
|
This document defines the preferred format for debug logging in Cthulhu.
|
||||||
|
The goal is to keep logs consistent, searchable, and easy to scan.
|
||||||
|
|
||||||
|
## Helpers
|
||||||
|
|
||||||
|
Use the helpers in `cthulhu.debug` for new logs:
|
||||||
|
|
||||||
|
- `debug.print_log(level, prefix, message, reason=None, timestamp=False, stack=False)`
|
||||||
|
- `debug.print_log_tokens(level, prefix, tokens, reason=None, timestamp=False, stack=False)`
|
||||||
|
|
||||||
|
These helpers ensure the prefix and optional reason tag are formatted consistently.
|
||||||
|
Timestamps are appended at the end of the message when enabled.
|
||||||
|
|
||||||
|
## Prefixes
|
||||||
|
|
||||||
|
Use short, uppercase prefixes that identify the subsystem:
|
||||||
|
|
||||||
|
- `EVENT MANAGER`
|
||||||
|
- `FOCUS MANAGER`
|
||||||
|
- `INPUT EVENT`
|
||||||
|
- `SCRIPT MANAGER`
|
||||||
|
- `WEB`
|
||||||
|
|
||||||
|
## Messages
|
||||||
|
|
||||||
|
- Keep messages short and action-focused.
|
||||||
|
- Do not include the prefix in the message.
|
||||||
|
- Prefer consistent verbs (e.g., "Not using …", "Setting …", "Ignoring …").
|
||||||
|
|
||||||
|
## Reason Tags
|
||||||
|
|
||||||
|
Use reason tags to explain decisions or early exits.
|
||||||
|
|
||||||
|
- Lowercase with hyphens (e.g., `focus-mode`, `no-active-script`).
|
||||||
|
- Use a short phrase rather than a full sentence.
|
||||||
|
- If a human-readable reason is already available, it can be used directly.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```text
|
||||||
|
WEB: Not using caret navigation (reason=disabled)
|
||||||
|
FOCUS MANAGER: Setting locus of focus to existing locus of focus (reason=no-change)
|
||||||
|
SCRIPT MANAGER: Setting active script to [script] (reason=focus: active-window)
|
||||||
|
```
|
||||||
+1
-1
@@ -290,7 +290,7 @@ toggle the reading of tables, either by single cell or whole row.
|
|||||||
.B Cthulhu
|
.B Cthulhu
|
||||||
user preferences directory
|
user preferences directory
|
||||||
.TP
|
.TP
|
||||||
.BI ~/.local/share/cthulhu/user-settings.conf
|
.BI ~/.local/share/cthulhu/user-settings.toml
|
||||||
.B Cthulhu
|
.B Cthulhu
|
||||||
user preferences configuration file.
|
user preferences configuration file.
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+1
-11
@@ -1,5 +1,5 @@
|
|||||||
project('cthulhu',
|
project('cthulhu',
|
||||||
version: '2026.01.26-master',
|
version: '2026.03.02-master',
|
||||||
meson_version: '>= 1.0.0',
|
meson_version: '>= 1.0.0',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -93,16 +93,6 @@ else
|
|||||||
summary += {'sound support': 'no (missing gstreamer)'}
|
summary += {'sound support': 'no (missing gstreamer)'}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Integration with session startup
|
|
||||||
i18n.merge_file(
|
|
||||||
input: 'cthulhu-autostart.desktop.in',
|
|
||||||
output: '@BASENAME@',
|
|
||||||
type: 'desktop',
|
|
||||||
po_dir: meson.project_source_root() / 'po',
|
|
||||||
install: true,
|
|
||||||
install_dir: get_option('sysconfdir') / 'xdg' / 'autostart',
|
|
||||||
)
|
|
||||||
|
|
||||||
# Update icon cache manually (desktop-neutral) - optional, ignore failures
|
# Update icon cache manually (desktop-neutral) - optional, ignore failures
|
||||||
gtk_update_icon_cache = find_program('gtk4-update-icon-cache', required: false)
|
gtk_update_icon_cache = find_program('gtk4-update-icon-cache', required: false)
|
||||||
if gtk_update_icon_cache.found()
|
if gtk_update_icon_cache.found()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# List of source files containing translatable strings.
|
# List of source files containing translatable strings.
|
||||||
# Please keep this file sorted alphabetically.
|
# Please keep this file sorted alphabetically.
|
||||||
cthulhu-autostart.desktop.in
|
|
||||||
src/cthulhu/braille_rolenames.py
|
src/cthulhu/braille_rolenames.py
|
||||||
src/cthulhu/brltablenames.py
|
src/cthulhu/brltablenames.py
|
||||||
src/cthulhu/chnames.py
|
src/cthulhu/chnames.py
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-DamnedLies-Scope: partial\n"
|
"X-DamnedLies-Scope: partial\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 1.6.10\n"
|
"X-Generator: Poedit 1.6.10\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lector de pantalla Cthulhu"
|
msgstr "Lector de pantalla Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "lector de pantalla; fabla; braille;"
|
msgstr "lector de pantalla; fabla; braille;"
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||||
"X-Poedit-Language: Arabic\n"
|
"X-Poedit-Language: Arabic\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "قارئ الشاشة Cthulhu"
|
msgstr "قارئ الشاشة Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "شاشة;قارئ;إمكانية الوصول;كلام;برايل;"
|
msgstr "شاشة;قارئ;إمكانية الوصول;كلام;برايل;"
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ msgstr ""
|
|||||||
"X-Poedit-Language: Asturian\n"
|
"X-Poedit-Language: Asturian\n"
|
||||||
"X-Poedit-SourceCharset: utf-8\n"
|
"X-Poedit-SourceCharset: utf-8\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Llector de pantalla d'Cthulhu"
|
msgstr "Llector de pantalla d'Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Чытач з экрана Cthulhu"
|
msgstr "Чытач з экрана Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "чытач з экрана;экран;голас;маўленне;Брайль;"
|
msgstr "чытач з экрана;экран;голас;маўленне;Брайль;"
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu — екранен четец"
|
msgstr "Cthulhu — екранен четец"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "екран;четец;достъпност;говор;брайл;"
|
msgstr "екран;четец;достъпност;говор;брайл;"
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,10 @@ msgstr ""
|
|||||||
"X-Generator: KBabel 1.9.1\n"
|
"X-Generator: KBabel 1.9.1\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "অর্কা স্ক্রীন রিডার / বিবর্ধন"
|
msgstr "অর্কা স্ক্রীন রিডার / বিবর্ধন"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ msgstr ""
|
|||||||
"X-Generator: KBabel 1.9.1\n"
|
"X-Generator: KBabel 1.9.1\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu'র বৈশিষ্ট্য"
|
msgstr "Cthulhu'র বৈশিষ্ট্য"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ msgstr ""
|
|||||||
"X-Launchpad-Export-Date: 2015-02-05 06:46+0000\n"
|
"X-Launchpad-Export-Date: 2015-02-05 06:46+0000\n"
|
||||||
"X-Generator: Poedit 1.7.4\n"
|
"X-Generator: Poedit 1.7.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu čitač ekrana"
|
msgstr "Cthulhu čitač ekrana"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "čitač ekrana;govor;brailleovo pismo;"
|
msgstr "čitač ekrana;govor;brailleovo pismo;"
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lector de pantalla Cthulhu"
|
msgstr "Lector de pantalla Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "pantalla;lector;accessibilitat;veu;braille;"
|
msgstr "pantalla;lector;accessibilitat;veu;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Poedit 1.8.11\n"
|
"X-Generator: Poedit 1.8.11\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lector de pantalla Cthulhu"
|
msgstr "Lector de pantalla Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "lector de pantalla;pronunciació;braille;"
|
msgstr "lector de pantalla;pronunciació;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,10 @@ msgstr ""
|
|||||||
"X-Launchpad-Export-Date: 2020-05-04 21:32+0000\n"
|
"X-Launchpad-Export-Date: 2020-05-04 21:32+0000\n"
|
||||||
"X-Generator: Poedit 2.3\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "خوێنەری پەردەی ئۆرکا"
|
msgstr "خوێنەری پەردەی ئۆرکا"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Čtečka obrazovky Cthulhu"
|
msgstr "Čtečka obrazovky Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "obrazovka;čtečka;přístupnost;řeč;braille;"
|
msgstr "obrazovka;čtečka;přístupnost;řeč;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,10 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=4; plural= (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != "
|
"Plural-Forms: nplurals=4; plural= (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != "
|
||||||
"11) ? 2 : 3;\n"
|
"11) ? 2 : 3;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Hoffterau Cthulhu"
|
msgstr "Hoffterau Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.0.1\n"
|
"X-Generator: Poedit 3.0.1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Skærmlæseren Cthulhu"
|
msgstr "Skærmlæseren Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "skærm;læser;tilgængelighed;tale;braille;"
|
msgstr "skærm;læser;tilgængelighed;tale;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -37,11 +37,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu-Bildschirmleser"
|
msgstr "Cthulhu-Bildschirmleser"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "bildschirm;leser;barrierefreiheit;sprache;braille;"
|
msgstr "bildschirm;leser;barrierefreiheit;sprache;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,10 @@ msgstr ""
|
|||||||
"X-Poedit-SourceCharset: utf-8\n"
|
"X-Poedit-SourceCharset: utf-8\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n!=1)\n"
|
"Plural-Forms: nplurals=2; plural=(n!=1)\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ཨོར་ཀ་གསལ་གཞི་ལྷག་བྱེད་/ཆེ་ཤེལ་"
|
msgstr "ཨོར་ཀ་གསལ་གཞི་ལྷག་བྱེད་/ཆེ་ཤེལ་"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 2.3\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Αναγνώστης οθόνης Cthulhu"
|
msgstr "Αναγνώστης οθόνης Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "οθόνη;αναγνώστης;προσβασιμότητα;ομιλία;μπράιγ;"
|
msgstr "οθόνη;αναγνώστης;προσβασιμότητα;ομιλία;μπράιγ;"
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Gtranslator 45.3\n"
|
"X-Generator: Gtranslator 45.3\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu Screen Reader"
|
msgstr "Cthulhu Screen Reader"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "screen reader;speech;braille;"
|
msgstr "screen reader;speech;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 3.2.2\n"
|
"X-Generator: Poedit 3.2.2\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Ekranlegilo Orko"
|
msgstr "Ekranlegilo Orko"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "ekranlegilo;parolo;brajlo;"
|
msgstr "ekranlegilo;parolo;brajlo;"
|
||||||
|
|||||||
@@ -28,11 +28,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||||
"X-Generator: Gtranslator 45.alpha0\n"
|
"X-Generator: Gtranslator 45.alpha0\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lector de pantalla Cthulhu"
|
msgstr "Lector de pantalla Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "lector;pantalla;accesibilidad;voz;braille;"
|
msgstr "lector;pantalla;accesibilidad;voz;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,10 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu ekraanilugeja ja luup"
|
msgstr "Cthulhu ekraanilugeja ja luup"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu pantaila-irakurlea"
|
msgstr "Cthulhu pantaila-irakurlea"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "pantaila;irakurlea;irisgarritasuna;mintzamena;braillea;"
|
msgstr "pantaila;irakurlea;irisgarritasuna;mintzamena;braillea;"
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 3.4\n"
|
"X-Generator: Poedit 3.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "صفحهخوان اورکا"
|
msgstr "صفحهخوان اورکا"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
"X-Poedit-Bookmarks: 814,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
|
"X-Poedit-Bookmarks: 814,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu-näytönlukija"
|
msgstr "Cthulhu-näytönlukija"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "näyttö;lukija;saavutettavuus;puhe;pistekirjoitus;"
|
msgstr "näyttö;lukija;saavutettavuus;puhe;pistekirjoitus;"
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lecteur d’écran Cthulhu"
|
msgstr "Lecteur d’écran Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "lecteur;écran;accessibilité;parole;braille;"
|
msgstr "lecteur;écran;accessibilité;parole;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 2.0.3\n"
|
"X-Generator: Poedit 2.0.3\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : (n%10==1 || n%10==2) ? 1 : "
|
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : (n%10==1 || n%10==2) ? 1 : "
|
||||||
"(n%10>=3 && n%10<= 6) ? 2 : ((n%10>=7 && n%10<=9) || n==10) ? 3 : 4;\n"
|
"(n%10>=3 && n%10<= 6) ? 2 : ((n%10>=7 && n%10<=9) || n==10) ? 3 : 4;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Léitheoir Scáileáin agus Formhéadaitheoir Cthulhu"
|
msgstr "Léitheoir Scáileáin agus Formhéadaitheoir Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,9 @@ msgstr ""
|
|||||||
"X-DL-Domain: po\n"
|
"X-DL-Domain: po\n"
|
||||||
"X-DL-State: Translating\n"
|
"X-DL-State: Translating\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lector da pantalla Cthulhu"
|
msgstr "Lector da pantalla Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "pantalla;lector;accesibilidade;fala;braille;"
|
msgstr "pantalla;lector;accesibilidade;fala;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,10 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu સ્ક્રીન વાંચક અને વિસ્તૃતકારક"
|
msgstr "Cthulhu સ્ક્રીન વાંચક અને વિસ્તૃતકારક"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,9 @@ msgstr ""
|
|||||||
"2 : 3);\n"
|
"2 : 3);\n"
|
||||||
"X-Generator: Poedit 3.4.1\n"
|
"X-Generator: Poedit 3.4.1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "מקריא המסך Cthulhu"
|
msgstr "מקריא המסך Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "מסך;קורא;נגישות;דיבור;ברייל;"
|
msgstr "מסך;קורא;נגישות;דיבור;ברייל;"
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,9 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"X-Generator: Lokalize 1.5\n"
|
"X-Generator: Lokalize 1.5\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu स्क्रीन वाचक"
|
msgstr "Cthulhu स्क्रीन वाचक"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "स्क्रीन रीडर;भाषण;ब्रेल;"
|
msgstr "स्क्रीन रीडर;भाषण;ब्रेल;"
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"X-Launchpad-Export-Date: 2016-09-15 12:40+0000\n"
|
"X-Launchpad-Export-Date: 2016-09-15 12:40+0000\n"
|
||||||
"X-Generator: Poedit 1.6.10\n"
|
"X-Generator: Poedit 1.6.10\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu čitač zaslona"
|
msgstr "Cthulhu čitač zaslona"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "čitač zaslona;govor;brajica;"
|
msgstr "čitač zaslona;govor;brajica;"
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 2.3\n"
|
"X-Generator: Poedit 2.3\n"
|
||||||
|
|
||||||
# Megjegyzés: Mivel mindenhol régóta Gáborral egyeztetve az Cthulhu nevet magyarosan Orkaként írjuk a fordításban, így a fordítást megváltoztattam Orka képernyőolvasóra az Cthulhu képernyőolvasó helyett.
|
# Megjegyzés: Mivel mindenhol régóta Gáborral egyeztetve az Cthulhu nevet magyarosan Orkaként írjuk a fordításban, így a fordítást megváltoztattam Orka képernyőolvasóra az Cthulhu képernyőolvasó helyett.
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Orka képernyőolvasó"
|
msgstr "Orka képernyőolvasó"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "képernyő;olvasó;akadálymentesítés;beszéd;braille;"
|
msgstr "képernyő;olvasó;akadálymentesítés;beszéd;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Pembaca Layar Cthulhu"
|
msgstr "Pembaca Layar Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "layar;pembaca;aksesibilitas;ucapan;braille;"
|
msgstr "layar;pembaca;aksesibilitas;ucapan;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Lokalize 1.5\n"
|
"X-Generator: Lokalize 1.5\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu skjálestur"
|
msgstr "Cthulhu skjálestur"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -39,11 +39,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||||
"X-Generator: Gtranslator 42.0\n"
|
"X-Generator: Gtranslator 42.0\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lettore schermo Cthulhu"
|
msgstr "Lettore schermo Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "lettore;schermo;accessibilità;voce;braille;"
|
msgstr "lettore;schermo;accessibilità;voce;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu スクリーンリーダー"
|
msgstr "Cthulhu スクリーンリーダー"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "スクリーン;リーダー;アクセシビリティ;音声;点字;"
|
msgstr "スクリーン;リーダー;アクセシビリティ;音声;点字;"
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu - ეკრანის მკითხველი"
|
msgstr "Cthulhu - ეკრანის მკითხველი"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "ეკრანი;მკითხველი;ხელმისაწვდომობა;მეტყველება;ბრაილი;"
|
msgstr "ეკრანი;მკითხველი;ხელმისაწვდომობა;მეტყველება;ბრაილი;"
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
"X-Generator: Poedit 3.0\n"
|
"X-Generator: Poedit 3.0\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu экраннан оқитын қолданбасы"
|
msgstr "Cthulhu экраннан оқитын қолданбасы"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: KBabel 1.11.4\n"
|
"X-Generator: KBabel 1.11.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ಆದ್ಯತೆಗಳು"
|
msgstr "ಆದ್ಯತೆಗಳು"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu 화면 낭독기"
|
msgstr "Cthulhu 화면 낭독기"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "화면;리더;접근성;음성;점자;"
|
msgstr "화면;리더;접근성;음성;점자;"
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,9 @@ msgstr ""
|
|||||||
"(n%100<10 || n%100>=20) ? 1 : 2);\n"
|
"(n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu ekrano skaityklė"
|
msgstr "Cthulhu ekrano skaityklė"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "ekrano skaityklė;kalba;brailio raštas;"
|
msgstr "ekrano skaityklė;kalba;brailio raštas;"
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ msgstr ""
|
|||||||
"2);\n"
|
"2);\n"
|
||||||
"X-Generator: Lokalize 21.12.3\n"
|
"X-Generator: Lokalize 21.12.3\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu ekrāna lasītājs"
|
msgstr "Cthulhu ekrāna lasītājs"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "ekrāna lasītājs;runa;Brails;"
|
msgstr "ekrāna lasītājs;runa;Brails;"
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,10 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu स्क्रीन पाठक / आवर्द्धक"
|
msgstr "Cthulhu स्क्रीन पाठक / आवर्द्धक"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural= n==1 || n%10==1 ? 0 : 1\n"
|
"Plural-Forms: nplurals=2; plural= n==1 || n%10==1 ? 0 : 1\n"
|
||||||
"X-Generator: KBabel 1.11.4\n"
|
"X-Generator: KBabel 1.11.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu читач на екранот"
|
msgstr "Cthulhu читач на екранот"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,10 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 2.0.1\n"
|
"X-Generator: Poedit 2.0.1\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "സ്ക്രീന് വായന അവസാനിപ്പിക്കാം."
|
msgstr "സ്ക്രീന് വായന അവസാനിപ്പിക്കാം."
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ msgstr ""
|
|||||||
"X-Generator: KBabel 1.9.1\n"
|
"X-Generator: KBabel 1.9.1\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "वर्धक भिंग"
|
msgstr "वर्धक भिंग"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 2.0.6\n"
|
"X-Generator: Poedit 2.0.6\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Pembaca skrin Cthulhu"
|
msgstr "Pembaca skrin Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "skrin;pembaca;kebolehcapaian;pertuturan;braille;"
|
msgstr "skrin;pembaca;kebolehcapaian;pertuturan;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu skjermleser"
|
msgstr "Cthulhu skjermleser"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "skjerm;leser;tilgjengelighet;tale;blindeskrift;"
|
msgstr "skjerm;leser;tilgjengelighet;tale;blindeskrift;"
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.0.1\n"
|
"X-Generator: Poedit 3.0.1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ओर्का दृष्टि वाचक"
|
msgstr "ओर्का दृष्टि वाचक"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "दृष्टि वाचक; वाचन;ब्रेल;"
|
msgstr "दृष्टि वाचक; वाचन;ब्रेल;"
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,9 @@ msgstr ""
|
|||||||
"X-Generator: Poedit 3.2.2\n"
|
"X-Generator: Poedit 3.2.2\n"
|
||||||
|
|
||||||
# vergrootglas/loep
|
# vergrootglas/loep
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu schermlezer"
|
msgstr "Cthulhu schermlezer"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "scherm;lezer;toegankelijkheid;spraak;braille;"
|
msgstr "scherm;lezer;toegankelijkheid;spraak;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu skjermlesar og forstørringsglas"
|
msgstr "Cthulhu skjermlesar og forstørringsglas"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ msgstr ""
|
|||||||
"X-Launchpad-Export-Date: 2015-05-21 18:05+0000\n"
|
"X-Launchpad-Export-Date: 2015-05-21 18:05+0000\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Lector d'ecran Cthulhu"
|
msgstr "Lector d'ecran Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"lector d'ecran;oral;braille;votz;sintèsi vocala;sintesi vocala;lector "
|
"lector d'ecran;oral;braille;votz;sintèsi vocala;sintesi vocala;lector "
|
||||||
|
|||||||
@@ -22,12 +22,10 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ଓର୍କା ସ୍କ୍ରିନ ପାଠକ /ଛୋଟକୁ ବଡ ଦେଖଉଥିବା ଉପକରଣ "
|
msgstr "ଓର୍କା ସ୍କ୍ରିନ ପାଠକ /ଛୋଟକୁ ବଡ ଦେଖଉଥିବା ଉପକରଣ "
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Poedit-Bookmarks: 589,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
|
"X-Poedit-Bookmarks: 589,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ਓਰਕਾ ਸਕਰੀਨ ਰੀਡਰ"
|
msgstr "ਓਰਕਾ ਸਕਰੀਨ ਰੀਡਰ"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||||
"|| n%100>=20) ? 1 : 2);\n"
|
"|| n%100>=20) ? 1 : 2);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Czytnik ekranowy Cthulhu"
|
msgstr "Czytnik ekranowy Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "czytnik;ekran;dostępność;mowa;braille;"
|
msgstr "czytnik;ekran;dostępność;mowa;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,9 @@ msgstr ""
|
|||||||
"X-Source-Language: C\n"
|
"X-Source-Language: C\n"
|
||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Leitor de ecrã Cthulhu"
|
msgstr "Leitor de ecrã Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "leitor;ecrã;acessibilidade;voz;braille;"
|
msgstr "leitor;ecrã;acessibilidade;voz;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -49,11 +49,9 @@ msgstr ""
|
|||||||
"X-DL-Domain: po\n"
|
"X-DL-Domain: po\n"
|
||||||
"X-DL-State: Translating\n"
|
"X-DL-State: Translating\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Leitor de tela Cthulhu"
|
msgstr "Leitor de tela Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "leitor;tela;acessibilidade;voz;braille;"
|
msgstr "leitor;tela;acessibilidade;voz;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
"X-Poedit-SourceCharset: UTF-8\n"
|
"X-Poedit-SourceCharset: UTF-8\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cititorul de ecran Cthulhu"
|
msgstr "Cititorul de ecran Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "ecran;cititor;accesibilitate;vorbire;braille;"
|
msgstr "ecran;cititor;accesibilitate;vorbire;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,9 @@ msgstr ""
|
|||||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Экранный диктор Cthulhu"
|
msgstr "Экранный диктор Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "экран;чтец;доступность;речь;брайль;"
|
msgstr "экран;чтец;доступность;речь;брайль;"
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: KBabel 1.11.4\n"
|
"X-Generator: KBabel 1.11.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
|
"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
|
||||||
"X-Generator: Gtranslator 2.91.7\n"
|
"X-Generator: Gtranslator 2.91.7\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Ukončí čítačku obrazovky"
|
msgstr "Ukončí čítačku obrazovky"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,9 @@ msgstr ""
|
|||||||
"X-Poedit-SourceCharset: utf-8\n"
|
"X-Poedit-SourceCharset: utf-8\n"
|
||||||
"X-Generator: Poedit 3.0.1\n"
|
"X-Generator: Poedit 3.0.1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Zaslonski bralnik Orka"
|
msgstr "Zaslonski bralnik Orka"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "govor;zaslonski bralnik;Braillova pisava;brajica;povečevalnik"
|
msgstr "govor;zaslonski bralnik;Braillova pisava;brajica;povečevalnik"
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,10 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Ekrani Zmadhues (Lupë)"
|
msgstr "Ekrani Zmadhues (Lupë)"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,9 @@ msgstr ""
|
|||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
"X-Generator: Poedit 3.1.1\n"
|
"X-Generator: Poedit 3.1.1\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Читач екрана Орка"
|
msgstr "Читач екрана Орка"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "читач екрана;говор;брајева азбука;"
|
msgstr "читач екрана;говор;брајева азбука;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"X-Project-Style: gnome\n"
|
"X-Project-Style: gnome\n"
|
||||||
"X-Generator: Poedit 2.0.3\n"
|
"X-Generator: Poedit 2.0.3\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Čitač ekrana Orka"
|
msgstr "Čitač ekrana Orka"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "čitač ekrana;govor;brajeva azbuka;"
|
msgstr "čitač ekrana;govor;brajeva azbuka;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu skärmläsare"
|
msgstr "Cthulhu skärmläsare"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "skärm;läsare;tillgänglighet;tal;punktskrift;"
|
msgstr "skärm;läsare;tillgänglighet;tal;punktskrift;"
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n!=1);\\n\n"
|
"Plural-Forms: nplurals=2; plural=(n!=1);\\n\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ஆர்கா திரை படிப்பி "
|
msgstr "ஆர்கா திரை படிப்பி "
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "திரைபடிப்பான்;பேசுதல்;ப்ரெய்ல்;"
|
msgstr "திரைபடிப்பான்;பேசுதல்;ப்ரெய்ல்;"
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
|
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
|
||||||
"X-Generator: KBabel 1.11.4\n"
|
"X-Generator: KBabel 1.11.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "ఓర్కా తెరచదువరి"
|
msgstr "ఓర్కా తెరచదువరి"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: Poedit 1.6.3\n"
|
"X-Generator: Poedit 1.6.3\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Хонандаи экрани Cthulhu"
|
msgstr "Хонандаи экрани Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "хонандаи экран;нутқ;брайл;"
|
msgstr "хонандаи экран;нутқ;брайл;"
|
||||||
|
|||||||
@@ -19,11 +19,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "โปรแกรมอ่านหน้าจอ Cthulhu"
|
msgstr "โปรแกรมอ่านหน้าจอ Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "หน้าจอ;อ่าน;การเข้าถึง;เสียงพูด;อักษรเบรลล์;"
|
msgstr "หน้าจอ;อ่าน;การเข้าถึง;เสียงพูด;อักษรเบรลล์;"
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 3.4\n"
|
"X-Generator: Poedit 3.4\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu Ekran Okuyucu"
|
msgstr "Cthulhu Ekran Okuyucu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "ekran;okuyucu;erişilebilirlik;konuşma;braille;"
|
msgstr "ekran;okuyucu;erişilebilirlik;konuşma;braille;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu ئېكران ئوقۇغۇ"
|
msgstr "Cthulhu ئېكران ئوقۇغۇ"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "screen reader;speech;braille;ئېكران ئوقۇغۇچ;تاۋۇش;ئەمالار ئېلىپبەسى;"
|
msgstr "screen reader;speech;braille;ئېكران ئوقۇغۇچ;تاۋۇش;ئەمالار ئېلىپبەسى;"
|
||||||
|
|||||||
@@ -26,11 +26,9 @@ msgstr ""
|
|||||||
"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||||
"X-Generator: Lokalize 20.12.0\n"
|
"X-Generator: Lokalize 20.12.0\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Інструмент читання з екрана «Cthulhu»"
|
msgstr "Інструмент читання з екрана «Cthulhu»"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "екран;читач;доступність;мовлення;брайль;"
|
msgstr "екран;читач;доступність;мовлення;брайль;"
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: LocFactoryEditor 1.8\n"
|
"X-Generator: LocFactoryEditor 1.8\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Trình đọc màn hình Cthulhu"
|
msgstr "Trình đọc màn hình Cthulhu"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "màn hình;đọc;trợ năng;giọng nói;chữ nổi;"
|
msgstr "màn hình;đọc;trợ năng;giọng nói;chữ nổi;"
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 3.3.2\n"
|
"X-Generator: Poedit 3.3.2\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu 屏幕阅读器"
|
msgstr "Cthulhu 屏幕阅读器"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "屏幕;阅读器;无障碍;语音;盲文;"
|
msgstr "屏幕;阅读器;无障碍;语音;盲文;"
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 1.6.5\n"
|
"X-Generator: Poedit 1.6.5\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu 螢幕閱讀器"
|
msgstr "Cthulhu 螢幕閱讀器"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "screen reader;speech;braille;螢幕閱讀器;語音;點字;"
|
msgstr "screen reader;speech;braille;螢幕閱讀器;語音;點字;"
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Poedit 1.8.12\n"
|
"X-Generator: Poedit 1.8.12\n"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:3
|
|
||||||
msgid "Cthulhu Screen Reader"
|
msgid "Cthulhu Screen Reader"
|
||||||
msgstr "Cthulhu 螢幕閱讀器"
|
msgstr "Cthulhu 螢幕閱讀器"
|
||||||
|
|
||||||
#: cthulhu-autostart.desktop.in:11
|
|
||||||
msgid "screen;reader;accessibility;speech;braille;"
|
msgid "screen;reader;accessibility;speech;braille;"
|
||||||
msgstr "螢幕;閱讀器;無障礙;語音;點字;"
|
msgstr "螢幕;閱讀器;無障礙;語音;點字;"
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ license = { text = "LGPL-2.1-or-later" }
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"pygobject>=3.18",
|
"pygobject>=3.18",
|
||||||
"pluggy",
|
"pluggy",
|
||||||
|
"tomlkit",
|
||||||
"brlapi; extra == 'braille'",
|
"brlapi; extra == 'braille'",
|
||||||
"python-speechd; extra == 'speech'",
|
"python-speechd; extra == 'speech'",
|
||||||
"piper-tts; extra == 'piper'",
|
"piper-tts; extra == 'piper'",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
backends_python_sources = files([
|
backends_python_sources = files([
|
||||||
'__init__.py',
|
'__init__.py',
|
||||||
'json_backend.py',
|
'toml_backend.py',
|
||||||
])
|
])
|
||||||
|
|
||||||
python3.install_sources(
|
python3.install_sources(
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
# Forked from Orca screen reader.
|
# Forked from Orca screen reader.
|
||||||
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
||||||
|
|
||||||
"""JSON backend for Cthulhu settings"""
|
"""TOML backend for Cthulhu settings"""
|
||||||
|
|
||||||
__id__ = "$Id$"
|
__id__ = "$Id$"
|
||||||
__version__ = "$Revision$"
|
__version__ = "$Revision$"
|
||||||
@@ -31,20 +31,22 @@ __date__ = "$Date$"
|
|||||||
__copyright__ = "Copyright (c) 2010-2011 Consorcio Fernando de los Rios."
|
__copyright__ = "Copyright (c) 2010-2011 Consorcio Fernando de los Rios."
|
||||||
__license__ = "LGPL"
|
__license__ = "LGPL"
|
||||||
|
|
||||||
from json import load, dump
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from tomlkit import parse, dumps, document
|
||||||
|
|
||||||
from cthulhu import settings, acss
|
from cthulhu import settings, acss
|
||||||
|
|
||||||
class Backend:
|
class Backend:
|
||||||
|
|
||||||
def __init__(self, prefsDir):
|
def __init__(self, prefsDir):
|
||||||
""" Initialize the JSON Backend.
|
""" Initialize the TOML Backend.
|
||||||
"""
|
"""
|
||||||
self.general = {}
|
self.general = {}
|
||||||
self.pronunciations = {}
|
self.pronunciations = {}
|
||||||
self.keybindings = {}
|
self.keybindings = {}
|
||||||
self.profiles = {}
|
self.profiles = {}
|
||||||
self.settingsFile = os.path.join(prefsDir, "user-settings.conf")
|
self.settingsFile = os.path.join(prefsDir, "user-settings.toml")
|
||||||
self.appPrefsDir = os.path.join(prefsDir, "app-settings")
|
self.appPrefsDir = os.path.join(prefsDir, "app-settings")
|
||||||
|
|
||||||
self._defaultProfiles = {'default': { 'profile': settings.profile,
|
self._defaultProfiles = {'default': { 'profile': settings.profile,
|
||||||
@@ -53,46 +55,105 @@ class Backend:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _stripNone(self, value):
|
||||||
|
if isinstance(value, dict):
|
||||||
|
cleaned = {}
|
||||||
|
for key, item in value.items():
|
||||||
|
if item is None:
|
||||||
|
continue
|
||||||
|
cleanedItem = self._stripNone(item)
|
||||||
|
if cleanedItem is None:
|
||||||
|
continue
|
||||||
|
cleaned[key] = cleanedItem
|
||||||
|
return cleaned
|
||||||
|
if isinstance(value, list):
|
||||||
|
cleanedList = []
|
||||||
|
for item in value:
|
||||||
|
if item is None:
|
||||||
|
continue
|
||||||
|
cleanedList.append(self._stripNone(item))
|
||||||
|
return cleanedList
|
||||||
|
return value
|
||||||
|
|
||||||
|
def _readDocument(self, fileName):
|
||||||
|
if os.path.exists(fileName):
|
||||||
|
with open(fileName, 'r', encoding='utf-8') as settingsFile:
|
||||||
|
return parse(settingsFile.read())
|
||||||
|
return document()
|
||||||
|
|
||||||
|
def _writeDocument(self, fileName, prefsDoc):
|
||||||
|
with open(fileName, 'w', encoding='utf-8') as settingsFile:
|
||||||
|
settingsFile.write(dumps(prefsDoc))
|
||||||
|
|
||||||
|
def _updateTable(self, targetTable, newValues, preserveMissingKeys=None):
|
||||||
|
if not isinstance(newValues, dict):
|
||||||
|
return
|
||||||
|
|
||||||
|
preserveMissingKeys = set(preserveMissingKeys or [])
|
||||||
|
|
||||||
|
for key in list(targetTable.keys()):
|
||||||
|
if key not in newValues:
|
||||||
|
if key in preserveMissingKeys:
|
||||||
|
continue
|
||||||
|
del targetTable[key]
|
||||||
|
continue
|
||||||
|
newValue = newValues[key]
|
||||||
|
existingValue = targetTable.get(key)
|
||||||
|
if isinstance(newValue, dict) and isinstance(existingValue, dict):
|
||||||
|
self._updateTable(existingValue, newValue)
|
||||||
|
continue
|
||||||
|
if existingValue != newValue:
|
||||||
|
targetTable[key] = newValue
|
||||||
|
|
||||||
|
for key, newValue in newValues.items():
|
||||||
|
if key not in targetTable:
|
||||||
|
targetTable[key] = newValue
|
||||||
|
|
||||||
def saveDefaultSettings(self, general, pronunciations, keybindings):
|
def saveDefaultSettings(self, general, pronunciations, keybindings):
|
||||||
""" Save default settings for all the properties from
|
""" Save default settings for all the properties from
|
||||||
cthulhu.settings. """
|
cthulhu.settings. """
|
||||||
prefs = {'general': general,
|
prefs = {'general': self._stripNone(general),
|
||||||
'profiles': self._defaultProfiles,
|
'profiles': self._stripNone(self._defaultProfiles),
|
||||||
'pronunciations': pronunciations,
|
'pronunciations': self._stripNone(pronunciations),
|
||||||
'keybindings': keybindings}
|
'keybindings': self._stripNone(keybindings)}
|
||||||
|
|
||||||
self.general = general
|
self.general = general
|
||||||
self.profiles = self._defaultProfiles
|
self.profiles = self._defaultProfiles
|
||||||
self.pronunciations = pronunciations
|
self.pronunciations = pronunciations
|
||||||
self.keybindings = keybindings
|
self.keybindings = keybindings
|
||||||
|
|
||||||
settingsFile = open(self.settingsFile, 'w')
|
prefsDoc = document()
|
||||||
dump(prefs, settingsFile, indent=4)
|
prefsDoc['general'] = prefs['general']
|
||||||
settingsFile.close()
|
prefsDoc['profiles'] = prefs['profiles']
|
||||||
|
prefsDoc['pronunciations'] = prefs['pronunciations']
|
||||||
|
prefsDoc['keybindings'] = prefs['keybindings']
|
||||||
|
|
||||||
|
self._writeDocument(self.settingsFile, prefsDoc)
|
||||||
|
|
||||||
def getAppSettings(self, appName):
|
def getAppSettings(self, appName):
|
||||||
fileName = os.path.join(self.appPrefsDir, f"{appName}.conf")
|
fileName = os.path.join(self.appPrefsDir, f"{appName}.toml")
|
||||||
if os.path.exists(fileName):
|
return self._readDocument(fileName)
|
||||||
settingsFile = open(fileName, 'r')
|
|
||||||
prefs = load(settingsFile)
|
|
||||||
settingsFile.close()
|
|
||||||
else:
|
|
||||||
prefs = {}
|
|
||||||
|
|
||||||
return prefs
|
|
||||||
|
|
||||||
def saveAppSettings(self, appName, profile, general, pronunciations, keybindings):
|
def saveAppSettings(self, appName, profile, general, pronunciations, keybindings):
|
||||||
prefs = self.getAppSettings(appName)
|
prefsDoc = self.getAppSettings(appName)
|
||||||
profiles = prefs.get('profiles', {})
|
profiles = prefsDoc.get('profiles')
|
||||||
profiles[profile] = {'general': general,
|
if profiles is None or not isinstance(profiles, dict):
|
||||||
'pronunciations': pronunciations,
|
prefsDoc['profiles'] = {}
|
||||||
'keybindings': keybindings}
|
profiles = prefsDoc['profiles']
|
||||||
prefs['profiles'] = profiles
|
|
||||||
|
|
||||||
fileName = os.path.join(self.appPrefsDir, f"{appName}.conf")
|
profileTable = profiles.get(profile)
|
||||||
settingsFile = open(fileName, 'w')
|
if profileTable is None or not isinstance(profileTable, dict):
|
||||||
dump(prefs, settingsFile, indent=4)
|
profiles[profile] = {}
|
||||||
settingsFile.close()
|
profileTable = profiles[profile]
|
||||||
|
|
||||||
|
self._updateTable(profileTable, {
|
||||||
|
'general': self._stripNone(general),
|
||||||
|
'pronunciations': self._stripNone(pronunciations),
|
||||||
|
'keybindings': self._stripNone(keybindings),
|
||||||
|
})
|
||||||
|
|
||||||
|
fileName = os.path.join(self.appPrefsDir, f"{appName}.toml")
|
||||||
|
self._writeDocument(fileName, prefsDoc)
|
||||||
|
|
||||||
def saveProfileSettings(self, profile, general,
|
def saveProfileSettings(self, profile, general,
|
||||||
pronunciations, keybindings):
|
pronunciations, keybindings):
|
||||||
@@ -103,25 +164,37 @@ class Backend:
|
|||||||
|
|
||||||
general['pronunciations'] = pronunciations
|
general['pronunciations'] = pronunciations
|
||||||
general['keybindings'] = keybindings
|
general['keybindings'] = keybindings
|
||||||
|
general = self._stripNone(general)
|
||||||
|
|
||||||
with open(self.settingsFile, 'r+') as settingsFile:
|
prefsDoc = self._readDocument(self.settingsFile)
|
||||||
prefs = load(settingsFile)
|
profiles = prefsDoc.get('profiles')
|
||||||
prefs['profiles'][profile] = general
|
if profiles is None or not isinstance(profiles, dict):
|
||||||
settingsFile.seek(0)
|
prefsDoc['profiles'] = {}
|
||||||
settingsFile.truncate()
|
profiles = prefsDoc['profiles']
|
||||||
dump(prefs, settingsFile, indent=4)
|
|
||||||
|
profileTable = profiles.get(profile)
|
||||||
|
if profileTable is None or not isinstance(profileTable, dict):
|
||||||
|
profiles[profile] = {}
|
||||||
|
profileTable = profiles[profile]
|
||||||
|
|
||||||
|
# Keep plugin persistence keys when callers provide partial updates.
|
||||||
|
self._updateTable(
|
||||||
|
profileTable,
|
||||||
|
general,
|
||||||
|
preserveMissingKeys={"activePlugins", "pluginSources"},
|
||||||
|
)
|
||||||
|
self._writeDocument(self.settingsFile, prefsDoc)
|
||||||
|
|
||||||
def _getSettings(self):
|
def _getSettings(self):
|
||||||
""" Load from config file all settings """
|
""" Load from config file all settings """
|
||||||
settingsFile = open(self.settingsFile)
|
prefsDoc = self._readDocument(self.settingsFile)
|
||||||
try:
|
try:
|
||||||
prefs = load(settingsFile)
|
self.general = dict(prefsDoc.get('general', {}))
|
||||||
except ValueError:
|
self.pronunciations = dict(prefsDoc.get('pronunciations', {}))
|
||||||
|
self.keybindings = dict(prefsDoc.get('keybindings', {}))
|
||||||
|
self.profiles = dict(prefsDoc.get('profiles', {}))
|
||||||
|
except Exception:
|
||||||
return
|
return
|
||||||
self.general = prefs['general'].copy()
|
|
||||||
self.pronunciations = prefs['pronunciations']
|
|
||||||
self.keybindings = prefs['keybindings']
|
|
||||||
self.profiles = prefs['profiles'].copy()
|
|
||||||
|
|
||||||
def _migrateSettings(self, settingsDict):
|
def _migrateSettings(self, settingsDict):
|
||||||
"""Migrate old setting names to new ones."""
|
"""Migrate old setting names to new ones."""
|
||||||
@@ -149,12 +222,33 @@ class Backend:
|
|||||||
|
|
||||||
return settingsDict
|
return settingsDict
|
||||||
|
|
||||||
|
def _hasLikelyCustomEchoVoice(self, echoVoice, defaultVoice):
|
||||||
|
"""Return True when echoVoice appears intentionally customized."""
|
||||||
|
|
||||||
|
if not echoVoice:
|
||||||
|
return False
|
||||||
|
|
||||||
|
echoEstablished = bool(echoVoice.get('established', False))
|
||||||
|
if not defaultVoice:
|
||||||
|
return echoEstablished or bool(echoVoice.get(acss.ACSS.FAMILY))
|
||||||
|
|
||||||
|
for key in [acss.ACSS.RATE, acss.ACSS.AVERAGE_PITCH, acss.ACSS.GAIN, acss.ACSS.FAMILY]:
|
||||||
|
echoValue = echoVoice.get(key)
|
||||||
|
defaultValue = defaultVoice.get(key)
|
||||||
|
if echoValue is not None and echoValue != defaultValue:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return echoEstablished and bool(echoVoice.get(acss.ACSS.FAMILY))
|
||||||
|
|
||||||
def getGeneral(self, profile=None):
|
def getGeneral(self, profile=None):
|
||||||
""" Get general settings from default settings and
|
""" Get general settings from default settings and
|
||||||
override with profile values. """
|
override with profile values. """
|
||||||
self._getSettings()
|
self._getSettings()
|
||||||
generalSettings = self.general.copy()
|
generalSettings = self.general.copy()
|
||||||
generalSettings = self._migrateSettings(generalSettings)
|
generalSettings = self._migrateSettings(generalSettings)
|
||||||
|
# Plugin state is profile-scoped; ignore legacy/global values.
|
||||||
|
generalSettings.pop('activePlugins', None)
|
||||||
|
generalSettings.pop('pluginSources', None)
|
||||||
defaultProfile = generalSettings.get('startingProfile',
|
defaultProfile = generalSettings.get('startingProfile',
|
||||||
['Default', 'default'])
|
['Default', 'default'])
|
||||||
if profile is None:
|
if profile is None:
|
||||||
@@ -165,8 +259,24 @@ class Backend:
|
|||||||
if key == 'voices':
|
if key == 'voices':
|
||||||
for voiceType, voiceDef in value.items():
|
for voiceType, voiceDef in value.items():
|
||||||
value[voiceType] = acss.ACSS(voiceDef)
|
value[voiceType] = acss.ACSS(voiceDef)
|
||||||
|
if key == 'echoVoice' and isinstance(value, dict):
|
||||||
|
value = acss.ACSS(value)
|
||||||
if key not in ['startingProfile', 'activeProfile']:
|
if key not in ['startingProfile', 'activeProfile']:
|
||||||
generalSettings[key] = value
|
generalSettings[key] = value
|
||||||
|
|
||||||
|
# Backward compatibility: recover custom echo behavior when legacy
|
||||||
|
# profiles have echoVoice but are missing custom-echo toggle keys.
|
||||||
|
if 'useCustomEchoVoice' not in profileSettings:
|
||||||
|
voices = generalSettings.get('voices') or {}
|
||||||
|
defaultVoice = voices.get(settings.DEFAULT_VOICE)
|
||||||
|
echoVoice = generalSettings.get('echoVoice')
|
||||||
|
if self._hasLikelyCustomEchoVoice(echoVoice, defaultVoice):
|
||||||
|
generalSettings['useCustomEchoVoice'] = True
|
||||||
|
if 'useCustomEchoForKey' not in profileSettings:
|
||||||
|
generalSettings['useCustomEchoForKey'] = True
|
||||||
|
if 'useCustomEchoForCharacter' not in profileSettings:
|
||||||
|
generalSettings['useCustomEchoForCharacter'] = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
generalSettings['activeProfile'] = profileSettings['profile']
|
generalSettings['activeProfile'] = profileSettings['profile']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -201,12 +311,18 @@ class Backend:
|
|||||||
def _setProfileKey(self, key, value):
|
def _setProfileKey(self, key, value):
|
||||||
self.general[key] = value
|
self.general[key] = value
|
||||||
|
|
||||||
with open(self.settingsFile, 'r+') as settingsFile:
|
prefsDoc = self._readDocument(self.settingsFile)
|
||||||
prefs = load(settingsFile)
|
general = prefsDoc.get('general')
|
||||||
prefs['general'][key] = value
|
if general is None or not isinstance(general, dict):
|
||||||
settingsFile.seek(0)
|
prefsDoc['general'] = {}
|
||||||
settingsFile.truncate()
|
general = prefsDoc['general']
|
||||||
dump(prefs, settingsFile, indent=4)
|
|
||||||
|
if value is None:
|
||||||
|
if key in general:
|
||||||
|
del general[key]
|
||||||
|
else:
|
||||||
|
general[key] = value
|
||||||
|
self._writeDocument(self.settingsFile, prefsDoc)
|
||||||
|
|
||||||
def setFirstStart(self, value=False):
|
def setFirstStart(self, value=False):
|
||||||
"""Set firstStart. This user-configurable setting is primarily
|
"""Set firstStart. This user-configurable setting is primarily
|
||||||
@@ -238,10 +354,8 @@ class Backend:
|
|||||||
if profile in self.profiles:
|
if profile in self.profiles:
|
||||||
removeProfileFrom(self.profiles)
|
removeProfileFrom(self.profiles)
|
||||||
|
|
||||||
with open(self.settingsFile, 'r+') as settingsFile:
|
prefsDoc = self._readDocument(self.settingsFile)
|
||||||
prefs = load(settingsFile)
|
profiles = prefsDoc.get('profiles')
|
||||||
if profile in prefs['profiles']:
|
if isinstance(profiles, dict) and profile in profiles:
|
||||||
removeProfileFrom(prefs['profiles'])
|
removeProfileFrom(profiles)
|
||||||
settingsFile.seek(0)
|
self._writeDocument(self.settingsFile, prefsDoc)
|
||||||
settingsFile.truncate()
|
|
||||||
dump(prefs, settingsFile, indent=4)
|
|
||||||
@@ -136,6 +136,24 @@
|
|||||||
<property name="step_increment">0.10000000149</property>
|
<property name="step_increment">0.10000000149</property>
|
||||||
<property name="page_increment">1</property>
|
<property name="page_increment">1</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="echoPitchAdjustment">
|
||||||
|
<property name="upper">10</property>
|
||||||
|
<property name="value">5</property>
|
||||||
|
<property name="step_increment">0.10000000149</property>
|
||||||
|
<property name="page_increment">1</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="echoRateAdjustment">
|
||||||
|
<property name="upper">100</property>
|
||||||
|
<property name="value">50</property>
|
||||||
|
<property name="step_increment">1</property>
|
||||||
|
<property name="page_increment">10</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="echoVolumeAdjustment">
|
||||||
|
<property name="upper">10</property>
|
||||||
|
<property name="value">10</property>
|
||||||
|
<property name="step_increment">0.10000000149</property>
|
||||||
|
<property name="page_increment">1</property>
|
||||||
|
</object>
|
||||||
<object class="GtkDialog" id="cthulhuSetupWindow">
|
<object class="GtkDialog" id="cthulhuSetupWindow">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="title" translatable="yes">Cthulhu Preferences</property>
|
<property name="title" translatable="yes">Cthulhu Preferences</property>
|
||||||
@@ -3037,6 +3055,295 @@
|
|||||||
<property name="top_attach">1</property>
|
<property name="top_attach">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkFrame" id="echoVoiceFrame">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label_xalign">0</property>
|
||||||
|
<property name="shadow_type">none</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAlignment" id="echoVoiceAlignment">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="left_padding">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="echoVoiceGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="row_spacing">10</property>
|
||||||
|
<property name="column_spacing">8</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="useCustomEchoVoiceCheckButton">
|
||||||
|
<property name="label" translatable="yes">Use c_ustom echo voice settings</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="useCustomEchoVoiceToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="useCustomEchoSpeechServerCheckButton">
|
||||||
|
<property name="label" translatable="yes">Use custom _speech-dispatcher module for echo</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="useCustomEchoSpeechServerToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="echoSpeechServersLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">1</property>
|
||||||
|
<property name="label" translatable="yes">Echo _module:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">echoSpeechServers</property>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="label-for" target="echoSpeechServers"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="echoSpeechServers">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<signal name="changed" handler="echoSpeechServersChanged" swapped="no"/>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="labelled-by" target="echoSpeechServersLabel"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="echoSpeechFamiliesLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">1</property>
|
||||||
|
<property name="label" translatable="yes">Echo _voice:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">echoSpeechFamilies</property>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="label-for" target="echoSpeechFamilies"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="echoSpeechFamilies">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<signal name="changed" handler="echoSpeechFamiliesChanged" swapped="no"/>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="labelled-by" target="echoSpeechFamiliesLabel"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="echoRateLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">1</property>
|
||||||
|
<property name="label" translatable="yes">Echo ra_te:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">echoRateScale</property>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="label-for" target="echoRateScale"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="echoRateScale">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">echoRateAdjustment</property>
|
||||||
|
<property name="round_digits">0</property>
|
||||||
|
<property name="digits">0</property>
|
||||||
|
<property name="value_pos">right</property>
|
||||||
|
<signal name="value-changed" handler="echoRateValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="echoPitchLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">1</property>
|
||||||
|
<property name="label" translatable="yes">Echo pi_tch:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">echoPitchScale</property>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="label-for" target="echoPitchScale"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="echoPitchScale">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">echoPitchAdjustment</property>
|
||||||
|
<property name="round_digits">1</property>
|
||||||
|
<property name="value_pos">right</property>
|
||||||
|
<signal name="value-changed" handler="echoPitchValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="echoVolumeLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="xalign">1</property>
|
||||||
|
<property name="label" translatable="yes">Echo vo_lume:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">echoVolumeScale</property>
|
||||||
|
<accessibility>
|
||||||
|
<relation type="label-for" target="echoVolumeScale"/>
|
||||||
|
</accessibility>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">6</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="echoVolumeScale">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="adjustment">echoVolumeAdjustment</property>
|
||||||
|
<property name="round_digits">1</property>
|
||||||
|
<property name="value_pos">right</property>
|
||||||
|
<signal name="value-changed" handler="echoVolumeValueChanged" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">6</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="useCustomEchoForKeyCheckButton">
|
||||||
|
<property name="label" translatable="yes">Use custom voice for _key echo</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="checkButtonToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">7</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="useCustomEchoForCharacterCheckButton">
|
||||||
|
<property name="label" translatable="yes">Use custom voice for _character echo</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="checkButtonToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">8</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="useCustomEchoForWordCheckButton">
|
||||||
|
<property name="label" translatable="yes">Use custom voice for _word echo</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="checkButtonToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">9</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="useCustomEchoForSentenceCheckButton">
|
||||||
|
<property name="label" translatable="yes">Use custom voice for _sentence echo</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="checkButtonToggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">10</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="label">
|
||||||
|
<object class="GtkLabel" id="echoVoiceLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Echo Voice</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="enableEchoByCharacterCheckButton">
|
<object class="GtkCheckButton" id="enableEchoByCharacterCheckButton">
|
||||||
<property name="label" translatable="yes" comments="Translators: When this option is enabled, inserted text of length 1 is spoken.">Enable echo by cha_racter</property>
|
<property name="label" translatable="yes" comments="Translators: When this option is enabled, inserted text of length 1 is spoken.">Enable echo by cha_racter</property>
|
||||||
@@ -3049,7 +3356,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
<property name="top_attach">2</property>
|
<property name="top_attach">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
@@ -3064,7 +3371,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
<property name="top_attach">3</property>
|
<property name="top_attach">4</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
@@ -3079,7 +3386,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
<property name="top_attach">4</property>
|
<property name="top_attach">5</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
@@ -23,5 +23,5 @@
|
|||||||
# Forked from Orca screen reader.
|
# Forked from Orca screen reader.
|
||||||
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
# Cthulhu project: https://git.stormux.org/storm/cthulhu
|
||||||
|
|
||||||
version = "2026.01.26"
|
version = "2026.03.02"
|
||||||
codeName = "master"
|
codeName = "master"
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ gi.require_version("Gtk", "3.0")
|
|||||||
from gi.repository import Atspi
|
from gi.repository import Atspi
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
from gi.repository import Gdk
|
from gi.repository import Gdk
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
@@ -173,6 +176,16 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self.speechSystemsChoice = None
|
self.speechSystemsChoice = None
|
||||||
self.speechSystemsChoices = None
|
self.speechSystemsChoices = None
|
||||||
self.speechSystemsModel = None
|
self.speechSystemsModel = None
|
||||||
|
self.echoVoice = None
|
||||||
|
self.echoSpeechFamiliesChoice = None
|
||||||
|
self.echoSpeechFamiliesChoices = None
|
||||||
|
self.echoSpeechFamiliesModel = None
|
||||||
|
self.echoSpeechServersChoice = None
|
||||||
|
self.echoSpeechServersChoices = None
|
||||||
|
self.echoSpeechServersModel = None
|
||||||
|
self.initializingEchoSpeech = False
|
||||||
|
self._echoVoiceFetchToken = 0
|
||||||
|
self._updatingEchoSpeechFamilies = False
|
||||||
self.systemVoice = None
|
self.systemVoice = None
|
||||||
self.uppercaseVoice = None
|
self.uppercaseVoice = None
|
||||||
self.window = None
|
self.window = None
|
||||||
@@ -180,7 +193,10 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self.savedGain = None
|
self.savedGain = None
|
||||||
self.savedPitch = None
|
self.savedPitch = None
|
||||||
self.savedRate = None
|
self.savedRate = None
|
||||||
|
self.soundThemeCombo = None
|
||||||
|
self.roleSoundPresentationCombo = None
|
||||||
self._isInitialSetup = False
|
self._isInitialSetup = False
|
||||||
|
self._updatingSpeechFamilies = False
|
||||||
self.selectedFamilyChoices = {}
|
self.selectedFamilyChoices = {}
|
||||||
self.selectedLanguageChoices = {}
|
self.selectedLanguageChoices = {}
|
||||||
self.profilesCombo = None
|
self.profilesCombo = None
|
||||||
@@ -383,7 +399,12 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self._initComboBox(self.get_widget("speechLanguages"))
|
self._initComboBox(self.get_widget("speechLanguages"))
|
||||||
self.speechFamiliesModel = \
|
self.speechFamiliesModel = \
|
||||||
self._initComboBox(self.get_widget("speechFamilies"))
|
self._initComboBox(self.get_widget("speechFamilies"))
|
||||||
|
self.echoSpeechServersModel = \
|
||||||
|
self._initComboBox(self.get_widget("echoSpeechServers"))
|
||||||
|
self.echoSpeechFamiliesModel = \
|
||||||
|
self._initComboBox(self.get_widget("echoSpeechFamilies"))
|
||||||
self._initSpeechState()
|
self._initSpeechState()
|
||||||
|
self._initEchoSpeechState()
|
||||||
|
|
||||||
# TODO - JD: Will this ever be the case??
|
# TODO - JD: Will this ever be the case??
|
||||||
self._isInitialSetup = \
|
self._isInitialSetup = \
|
||||||
@@ -1269,7 +1290,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
for familyChoice in self.speechFamiliesChoices:
|
for familyChoice in self.speechFamiliesChoices:
|
||||||
name = familyChoice[speechserver.VoiceFamily.NAME]
|
name = familyChoice[speechserver.VoiceFamily.NAME]
|
||||||
if name == familyName:
|
if name == familyName:
|
||||||
self.get_widget("speechFamilies").set_active(i)
|
self._setSpeechFamiliesActive(i)
|
||||||
self.speechFamiliesChoice = self.speechFamiliesChoices[i]
|
self.speechFamiliesChoice = self.speechFamiliesChoices[i]
|
||||||
familySet = True
|
familySet = True
|
||||||
break
|
break
|
||||||
@@ -1293,13 +1314,22 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
if not familySet:
|
if not familySet:
|
||||||
tokens = ["PREFERENCES DIALOG: Could not find speech family match for", familyName]
|
tokens = ["PREFERENCES DIALOG: Could not find speech family match for", familyName]
|
||||||
debug.printTokens(debug.LEVEL_INFO, tokens, True)
|
debug.printTokens(debug.LEVEL_INFO, tokens, True)
|
||||||
self.get_widget("speechFamilies").set_active(0)
|
self._setSpeechFamiliesActive(0)
|
||||||
self.speechFamiliesChoice = self.speechFamiliesChoices[0]
|
self.speechFamiliesChoice = self.speechFamiliesChoices[0]
|
||||||
|
|
||||||
if familySet:
|
if familySet:
|
||||||
self.selectedFamilyChoices[self.speechServersChoice,
|
self.selectedFamilyChoices[self.speechServersChoice,
|
||||||
self.speechLanguagesChoice] = i
|
self.speechLanguagesChoice] = i
|
||||||
|
|
||||||
|
def _setSpeechFamiliesActive(self, index):
|
||||||
|
"""Sets speechFamilies active index while suppressing preview chatter."""
|
||||||
|
|
||||||
|
self._updatingSpeechFamilies = True
|
||||||
|
try:
|
||||||
|
self.get_widget("speechFamilies").set_active(index)
|
||||||
|
finally:
|
||||||
|
self._updatingSpeechFamilies = False
|
||||||
|
|
||||||
def _setupFamilies(self):
|
def _setupFamilies(self):
|
||||||
"""Gets the list of voice variants for the current speech server and
|
"""Gets the list of voice variants for the current speech server and
|
||||||
current language.
|
current language.
|
||||||
@@ -1351,7 +1381,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
selectedIndex = self.selectedFamilyChoices[self.speechServersChoice,
|
selectedIndex = self.selectedFamilyChoices[self.speechServersChoice,
|
||||||
self.speechLanguagesChoice]
|
self.speechLanguagesChoice]
|
||||||
|
|
||||||
self.get_widget("speechFamilies").set_active(selectedIndex)
|
self._setSpeechFamiliesActive(selectedIndex)
|
||||||
|
|
||||||
def _setSpeechLanguagesChoice(self, languageName):
|
def _setSpeechLanguagesChoice(self, languageName):
|
||||||
"""Sets the active item in the languages ("Language:") combo box
|
"""Sets the active item in the languages ("Language:") combo box
|
||||||
@@ -1659,6 +1689,261 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self._setupSpeechSystems(factories)
|
self._setupSpeechSystems(factories)
|
||||||
self.initializingSpeech = False
|
self.initializingSpeech = False
|
||||||
|
|
||||||
|
def _getSpeechDispatcherFactory(self):
|
||||||
|
"""Returns the Speech Dispatcher factory if available."""
|
||||||
|
|
||||||
|
factories = cthulhu.cthulhuApp.settingsManager.getSpeechServerFactories()
|
||||||
|
for factory in factories:
|
||||||
|
try:
|
||||||
|
if factory.SpeechServer.getFactoryName() == guilabels.SPEECH_DISPATCHER:
|
||||||
|
return factory
|
||||||
|
except Exception:
|
||||||
|
debug.printException(debug.LEVEL_FINEST)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _setEchoVoiceFamily(self, family):
|
||||||
|
"""Sets echo voice family from the selected server family object."""
|
||||||
|
|
||||||
|
if not family:
|
||||||
|
return
|
||||||
|
|
||||||
|
name = family.get(speechserver.VoiceFamily.NAME)
|
||||||
|
language = family.get(speechserver.VoiceFamily.LANG)
|
||||||
|
dialect = family.get(speechserver.VoiceFamily.DIALECT)
|
||||||
|
variant = family.get(speechserver.VoiceFamily.VARIANT)
|
||||||
|
self.echoVoice[acss.ACSS.FAMILY] = {
|
||||||
|
speechserver.VoiceFamily.NAME: name,
|
||||||
|
speechserver.VoiceFamily.LANG: language,
|
||||||
|
speechserver.VoiceFamily.DIALECT: dialect,
|
||||||
|
speechserver.VoiceFamily.VARIANT: variant,
|
||||||
|
}
|
||||||
|
self.echoVoice['established'] = True
|
||||||
|
|
||||||
|
def _populateEchoSpeechFamilies(self, families):
|
||||||
|
"""Populate the echo family combobox from the provided families list."""
|
||||||
|
|
||||||
|
combobox = self.get_widget("echoSpeechFamilies")
|
||||||
|
combobox.set_model(None)
|
||||||
|
self.echoSpeechFamiliesModel.clear()
|
||||||
|
self.echoSpeechFamiliesChoices = list(families or [])
|
||||||
|
self.echoSpeechFamiliesChoice = None
|
||||||
|
|
||||||
|
selectedIndex = 0
|
||||||
|
selectedMatchFound = False
|
||||||
|
selectedFamily = self.echoVoice.get(acss.ACSS.FAMILY)
|
||||||
|
selectedName = selectedLanguage = selectedDialect = selectedVariant = None
|
||||||
|
if selectedFamily:
|
||||||
|
selectedName = selectedFamily.get(speechserver.VoiceFamily.NAME)
|
||||||
|
selectedLanguage = selectedFamily.get(speechserver.VoiceFamily.LANG)
|
||||||
|
selectedDialect = selectedFamily.get(speechserver.VoiceFamily.DIALECT)
|
||||||
|
selectedVariant = selectedFamily.get(speechserver.VoiceFamily.VARIANT)
|
||||||
|
|
||||||
|
for i, family in enumerate(self.echoSpeechFamiliesChoices):
|
||||||
|
name = family.get(speechserver.VoiceFamily.NAME) or ""
|
||||||
|
language = family.get(speechserver.VoiceFamily.LANG) or ""
|
||||||
|
dialect = family.get(speechserver.VoiceFamily.DIALECT) or ""
|
||||||
|
variant = family.get(speechserver.VoiceFamily.VARIANT)
|
||||||
|
display = name
|
||||||
|
locale = language
|
||||||
|
if dialect:
|
||||||
|
locale = f"{language}-{dialect}" if language else dialect
|
||||||
|
if locale:
|
||||||
|
display = f"{name} ({locale})"
|
||||||
|
self.echoSpeechFamiliesModel.append((i, display))
|
||||||
|
if selectedName == name and selectedLanguage == language \
|
||||||
|
and selectedDialect == dialect and selectedVariant == variant:
|
||||||
|
selectedIndex = i
|
||||||
|
selectedMatchFound = True
|
||||||
|
|
||||||
|
combobox.set_model(self.echoSpeechFamiliesModel)
|
||||||
|
if self.echoSpeechFamiliesChoices:
|
||||||
|
self._updatingEchoSpeechFamilies = True
|
||||||
|
try:
|
||||||
|
combobox.set_active(selectedIndex)
|
||||||
|
finally:
|
||||||
|
self._updatingEchoSpeechFamilies = False
|
||||||
|
self.echoSpeechFamiliesChoice = self.echoSpeechFamiliesChoices[selectedIndex]
|
||||||
|
|
||||||
|
def _fetchEchoSpeechFamiliesWorker(self, serverInfo, requestToken):
|
||||||
|
"""Fetch module-specific voices in a subprocess and apply asynchronously."""
|
||||||
|
|
||||||
|
queryScript = """
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from cthulhu import speechdispatcherfactory
|
||||||
|
from cthulhu import speechserver
|
||||||
|
|
||||||
|
serverInfo = json.loads(sys.argv[1])
|
||||||
|
if isinstance(serverInfo, list):
|
||||||
|
serverInfo = tuple(serverInfo)
|
||||||
|
|
||||||
|
server = speechdispatcherfactory.SpeechServer.getSpeechServer(serverInfo)
|
||||||
|
families = server.getVoiceFamilies() if server else []
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for family in families:
|
||||||
|
result.append({
|
||||||
|
"name": family.get(speechserver.VoiceFamily.NAME),
|
||||||
|
"lang": family.get(speechserver.VoiceFamily.LANG),
|
||||||
|
"dialect": family.get(speechserver.VoiceFamily.DIALECT),
|
||||||
|
"variant": family.get(speechserver.VoiceFamily.VARIANT),
|
||||||
|
})
|
||||||
|
|
||||||
|
print(json.dumps(result))
|
||||||
|
"""
|
||||||
|
|
||||||
|
familyDefs = None
|
||||||
|
try:
|
||||||
|
completed = subprocess.run(
|
||||||
|
[sys.executable, "-c", queryScript, json.dumps(serverInfo)],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=4.0,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
if completed.returncode == 0 and completed.stdout.strip():
|
||||||
|
familyDefs = json.loads(completed.stdout.strip())
|
||||||
|
else:
|
||||||
|
tokens = [
|
||||||
|
"PREFERENCES DIALOG: Echo voice fetch failed for",
|
||||||
|
serverInfo,
|
||||||
|
"rc=",
|
||||||
|
completed.returncode,
|
||||||
|
]
|
||||||
|
debug.printTokens(debug.LEVEL_WARNING, tokens, True)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
tokens = ["PREFERENCES DIALOG: Echo voice fetch timed out for", serverInfo]
|
||||||
|
debug.printTokens(debug.LEVEL_WARNING, tokens, True)
|
||||||
|
except Exception:
|
||||||
|
debug.printException(debug.LEVEL_WARNING)
|
||||||
|
|
||||||
|
GLib.idle_add(self._applyFetchedEchoSpeechFamilies, requestToken, familyDefs)
|
||||||
|
|
||||||
|
def _applyFetchedEchoSpeechFamilies(self, requestToken, familyDefs):
|
||||||
|
"""Apply fetched echo families if this is still the active request."""
|
||||||
|
|
||||||
|
if requestToken != self._echoVoiceFetchToken:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not isinstance(familyDefs, list):
|
||||||
|
return False
|
||||||
|
|
||||||
|
families = []
|
||||||
|
for familyDef in familyDefs:
|
||||||
|
if not isinstance(familyDef, dict):
|
||||||
|
continue
|
||||||
|
families.append(
|
||||||
|
speechserver.VoiceFamily({
|
||||||
|
speechserver.VoiceFamily.NAME: familyDef.get("name"),
|
||||||
|
speechserver.VoiceFamily.LANG: familyDef.get("lang"),
|
||||||
|
speechserver.VoiceFamily.DIALECT: familyDef.get("dialect"),
|
||||||
|
speechserver.VoiceFamily.VARIANT: familyDef.get("variant"),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
if not families:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._populateEchoSpeechFamilies(families)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _setupEchoSpeechFamilies(self):
|
||||||
|
"""Populate echo voice family list for the current echo server."""
|
||||||
|
self._echoVoiceFetchToken += 1
|
||||||
|
requestToken = self._echoVoiceFetchToken
|
||||||
|
useCustomModule = self.get_widget("useCustomEchoSpeechServerCheckButton").get_active()
|
||||||
|
fallbackFamilies = list(self.speechFamiliesChoices or [])
|
||||||
|
self._populateEchoSpeechFamilies(fallbackFamilies)
|
||||||
|
|
||||||
|
if useCustomModule and self.echoSpeechServersChoice:
|
||||||
|
serverInfo = self.echoSpeechServersChoice.getInfo()
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=self._fetchEchoSpeechFamiliesWorker,
|
||||||
|
args=(serverInfo, requestToken),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def _setEchoSpeechServersChoice(self, serverInfo):
|
||||||
|
"""Set the active echo module based on stored server info."""
|
||||||
|
|
||||||
|
if not self.echoSpeechServersChoices:
|
||||||
|
self.echoSpeechServersChoice = None
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
return
|
||||||
|
|
||||||
|
valueSet = False
|
||||||
|
for i, server in enumerate(self.echoSpeechServersChoices):
|
||||||
|
info = server.getInfo()
|
||||||
|
if serverInfo and info == serverInfo:
|
||||||
|
self.get_widget("echoSpeechServers").set_active(i)
|
||||||
|
self.echoSpeechServersChoice = server
|
||||||
|
valueSet = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not valueSet:
|
||||||
|
self.get_widget("echoSpeechServers").set_active(0)
|
||||||
|
self.echoSpeechServersChoice = self.echoSpeechServersChoices[0]
|
||||||
|
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
|
||||||
|
def _setupEchoSpeechServers(self):
|
||||||
|
"""Populate available speech-dispatcher modules for echo."""
|
||||||
|
|
||||||
|
combobox = self.get_widget("echoSpeechServers")
|
||||||
|
combobox.set_model(None)
|
||||||
|
self.echoSpeechServersModel.clear()
|
||||||
|
self.echoSpeechServersChoices = []
|
||||||
|
self.echoSpeechServersChoice = None
|
||||||
|
|
||||||
|
if not self.prefsDict.get('enableSpeech', True):
|
||||||
|
combobox.set_model(self.echoSpeechServersModel)
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
return
|
||||||
|
|
||||||
|
factory = self._getSpeechDispatcherFactory()
|
||||||
|
if factory is None:
|
||||||
|
combobox.set_model(self.echoSpeechServersModel)
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.echoSpeechServersChoices = factory.SpeechServer.getSpeechServers()
|
||||||
|
except Exception:
|
||||||
|
debug.printException(debug.LEVEL_WARNING)
|
||||||
|
self.echoSpeechServersChoices = []
|
||||||
|
|
||||||
|
for i, server in enumerate(self.echoSpeechServersChoices):
|
||||||
|
name = server.getInfo()[0]
|
||||||
|
self.echoSpeechServersModel.append((i, name))
|
||||||
|
|
||||||
|
combobox.set_model(self.echoSpeechServersModel)
|
||||||
|
self._setEchoSpeechServersChoice(self.prefsDict.get("echoSpeechServerInfo"))
|
||||||
|
|
||||||
|
def _initEchoSpeechState(self):
|
||||||
|
"""Initialize echo voice controls and choices."""
|
||||||
|
|
||||||
|
self.echoVoice = acss.ACSS(
|
||||||
|
self.prefsDict.get("echoVoice", settings.echoVoice) or {})
|
||||||
|
|
||||||
|
baseVoice = self.defaultVoice or acss.ACSS(
|
||||||
|
self.prefsDict.get("voices", {}).get(settings.DEFAULT_VOICE, {}))
|
||||||
|
|
||||||
|
rate = self.echoVoice.get(acss.ACSS.RATE, baseVoice.get(acss.ACSS.RATE, 50.0))
|
||||||
|
pitch = self.echoVoice.get(acss.ACSS.AVERAGE_PITCH, baseVoice.get(acss.ACSS.AVERAGE_PITCH, 5.0))
|
||||||
|
volume = self.echoVoice.get(acss.ACSS.GAIN, baseVoice.get(acss.ACSS.GAIN, 10.0))
|
||||||
|
|
||||||
|
self.get_widget("echoRateScale").set_value(rate)
|
||||||
|
self.get_widget("echoPitchScale").set_value(pitch)
|
||||||
|
self.get_widget("echoVolumeScale").set_value(volume)
|
||||||
|
|
||||||
|
self.initializingEchoSpeech = True
|
||||||
|
self._setupEchoSpeechServers()
|
||||||
|
self.initializingEchoSpeech = False
|
||||||
|
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
def _setSpokenTextAttributes(self, view, setAttributes,
|
def _setSpokenTextAttributes(self, view, setAttributes,
|
||||||
state, moveToTop=False):
|
state, moveToTop=False):
|
||||||
"""Given a set of spoken text attributes, update the model used by the
|
"""Given a set of spoken text attributes, update the model used by the
|
||||||
@@ -2392,6 +2677,19 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
prefs["enableEchoByWord"])
|
prefs["enableEchoByWord"])
|
||||||
self.get_widget("enableEchoBySentenceCheckButton").set_active( \
|
self.get_widget("enableEchoBySentenceCheckButton").set_active( \
|
||||||
prefs["enableEchoBySentence"])
|
prefs["enableEchoBySentence"])
|
||||||
|
self.get_widget("useCustomEchoVoiceCheckButton").set_active(
|
||||||
|
prefs.get("useCustomEchoVoice", settings.useCustomEchoVoice))
|
||||||
|
self.get_widget("useCustomEchoSpeechServerCheckButton").set_active(
|
||||||
|
prefs.get("useCustomEchoSpeechServer", settings.useCustomEchoSpeechServer))
|
||||||
|
self.get_widget("useCustomEchoForKeyCheckButton").set_active(
|
||||||
|
prefs.get("useCustomEchoForKey", settings.useCustomEchoForKey))
|
||||||
|
self.get_widget("useCustomEchoForCharacterCheckButton").set_active(
|
||||||
|
prefs.get("useCustomEchoForCharacter", settings.useCustomEchoForCharacter))
|
||||||
|
self.get_widget("useCustomEchoForWordCheckButton").set_active(
|
||||||
|
prefs.get("useCustomEchoForWord", settings.useCustomEchoForWord))
|
||||||
|
self.get_widget("useCustomEchoForSentenceCheckButton").set_active(
|
||||||
|
prefs.get("useCustomEchoForSentence", settings.useCustomEchoForSentence))
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
# Text attributes pane.
|
# Text attributes pane.
|
||||||
#
|
#
|
||||||
@@ -2551,20 +2849,18 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self._updateAIControlsState(enabled)
|
self._updateAIControlsState(enabled)
|
||||||
|
|
||||||
def _updateAIControlsState(self, enabled):
|
def _updateAIControlsState(self, enabled):
|
||||||
"""Enable or disable AI controls based on AI enabled state."""
|
"""Refresh AI controls while keeping configuration fields editable."""
|
||||||
self.aiProviderCombo.set_sensitive(enabled)
|
_ = enabled # kept for signal/call compatibility
|
||||||
self.aiApiKeyEntry.set_sensitive(enabled)
|
# Keep settings editable even when AI assistant is disabled so users
|
||||||
self.aiOllamaModelEntry.set_sensitive(enabled)
|
# can configure providers/keys before enabling it.
|
||||||
self.aiOllamaEndpointEntry.set_sensitive(enabled)
|
self.aiProviderCombo.set_sensitive(True)
|
||||||
self.aiConfirmationCheckButton.set_sensitive(enabled)
|
self.aiConfirmationCheckButton.set_sensitive(True)
|
||||||
self.aiScreenshotQualityCombo.set_sensitive(enabled)
|
self.aiScreenshotQualityCombo.set_sensitive(True)
|
||||||
try:
|
try:
|
||||||
self.get_widget("aiGetClaudeKeyButton").set_sensitive(enabled)
|
self.get_widget("aiGetClaudeKeyButton").set_sensitive(True)
|
||||||
except:
|
except:
|
||||||
pass # Button might not exist in older UI files
|
pass # Button might not exist in older UI files
|
||||||
|
|
||||||
# Update provider-specific controls if AI is enabled
|
|
||||||
if enabled:
|
|
||||||
current_provider = self.prefsDict.get("aiProvider", settings.aiProvider)
|
current_provider = self.prefsDict.get("aiProvider", settings.aiProvider)
|
||||||
self._updateProviderControls(current_provider)
|
self._updateProviderControls(current_provider)
|
||||||
|
|
||||||
@@ -2671,6 +2967,8 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
# Get widget references
|
# Get widget references
|
||||||
self.soundThemeCombo = self.get_widget("soundThemeCombo")
|
self.soundThemeCombo = self.get_widget("soundThemeCombo")
|
||||||
self.roleSoundPresentationCombo = self.get_widget("roleSoundPresentationCombo")
|
self.roleSoundPresentationCombo = self.get_widget("roleSoundPresentationCombo")
|
||||||
|
self.soundThemeCombo.set_can_focus(False)
|
||||||
|
self.roleSoundPresentationCombo.set_can_focus(False)
|
||||||
|
|
||||||
# Populate sound theme combo box
|
# Populate sound theme combo box
|
||||||
themeManager = sound_theme_manager.getManager()
|
themeManager = sound_theme_manager.getManager()
|
||||||
@@ -2728,6 +3026,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
value = self._roleSoundPresentationChoices[activeIndex][0]
|
value = self._roleSoundPresentationChoices[activeIndex][0]
|
||||||
self.prefsDict["roleSoundPresentation"] = value
|
self.prefsDict["roleSoundPresentation"] = value
|
||||||
|
|
||||||
|
|
||||||
def _updateCthulhuModifier(self):
|
def _updateCthulhuModifier(self):
|
||||||
combobox = self.get_widget("cthulhuModifierComboBox")
|
combobox = self.get_widget("cthulhuModifierComboBox")
|
||||||
keystring = ", ".join(self.prefsDict["cthulhuModifierKeys"])
|
keystring = ", ".join(self.prefsDict["cthulhuModifierKeys"])
|
||||||
@@ -2893,22 +3192,91 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self.get_widget("enableNavigationKeysCheckButton").set_sensitive(enable)
|
self.get_widget("enableNavigationKeysCheckButton").set_sensitive(enable)
|
||||||
self.get_widget("enableDiacriticalKeysCheckButton").set_sensitive( \
|
self.get_widget("enableDiacriticalKeysCheckButton").set_sensitive( \
|
||||||
enable)
|
enable)
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
def _presentMessage(self, text, interrupt=False):
|
def _setEchoVoiceItems(self):
|
||||||
|
"""[In]sensitize echo voice controls based on current state."""
|
||||||
|
|
||||||
|
useCustomVoice = self.get_widget("useCustomEchoVoiceCheckButton").get_active()
|
||||||
|
useCustomModule = self.get_widget("useCustomEchoSpeechServerCheckButton").get_active()
|
||||||
|
keyEchoEnabled = self.get_widget("keyEchoCheckButton").get_active()
|
||||||
|
charEchoEnabled = self.get_widget("enableEchoByCharacterCheckButton").get_active()
|
||||||
|
wordEchoEnabled = self.get_widget("enableEchoByWordCheckButton").get_active()
|
||||||
|
sentenceEchoEnabled = self.get_widget("enableEchoBySentenceCheckButton").get_active()
|
||||||
|
speechEnabled = self.get_widget("speechSupportCheckButton").get_active()
|
||||||
|
|
||||||
|
speechSystemIsDispatcher = False
|
||||||
|
if self.speechSystemsChoice:
|
||||||
|
try:
|
||||||
|
speechSystemIsDispatcher = \
|
||||||
|
self.speechSystemsChoice.SpeechServer.getFactoryName() == guilabels.SPEECH_DISPATCHER
|
||||||
|
except Exception:
|
||||||
|
speechSystemIsDispatcher = False
|
||||||
|
|
||||||
|
voiceControlsEnabled = useCustomVoice and speechEnabled
|
||||||
|
moduleOverrideAvailable = voiceControlsEnabled and speechSystemIsDispatcher
|
||||||
|
moduleControlsEnabled = moduleOverrideAvailable and useCustomModule
|
||||||
|
|
||||||
|
self.get_widget("useCustomEchoSpeechServerCheckButton").set_sensitive(moduleOverrideAvailable)
|
||||||
|
self.get_widget("echoSpeechServers").set_sensitive(moduleControlsEnabled)
|
||||||
|
self.get_widget("echoSpeechFamilies").set_sensitive(voiceControlsEnabled)
|
||||||
|
|
||||||
|
self.get_widget("echoRateScale").set_sensitive(useCustomVoice)
|
||||||
|
self.get_widget("echoPitchScale").set_sensitive(useCustomVoice)
|
||||||
|
self.get_widget("echoVolumeScale").set_sensitive(useCustomVoice)
|
||||||
|
|
||||||
|
self.get_widget("useCustomEchoForKeyCheckButton").set_sensitive(useCustomVoice and keyEchoEnabled)
|
||||||
|
self.get_widget("useCustomEchoForCharacterCheckButton").set_sensitive(
|
||||||
|
useCustomVoice and charEchoEnabled)
|
||||||
|
self.get_widget("useCustomEchoForWordCheckButton").set_sensitive(useCustomVoice and wordEchoEnabled)
|
||||||
|
self.get_widget("useCustomEchoForSentenceCheckButton").set_sensitive(
|
||||||
|
useCustomVoice and sentenceEchoEnabled)
|
||||||
|
|
||||||
|
def _presentMessage(self, text, interrupt=False, voice=None):
|
||||||
"""If the text field is not None, presents the given text, optionally
|
"""If the text field is not None, presents the given text, optionally
|
||||||
interrupting anything currently being spoken.
|
interrupting anything currently being spoken.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- text: the text to present
|
- text: the text to present
|
||||||
- interrupt: if True, interrupt any speech currently being spoken
|
- interrupt: if True, interrupt any speech currently being spoken
|
||||||
|
- voice: the voice to use; if None, use the default system voice
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.script.speakMessage(text, interrupt=interrupt)
|
self.script.speakMessage(text, voice=voice, interrupt=interrupt)
|
||||||
try:
|
try:
|
||||||
self.script.displayBrailleMessage(text, flashTime=-1)
|
self.script.displayBrailleMessage(text, flashTime=-1)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _previewVoiceSelection(self, voiceType, name):
|
||||||
|
"""Present a short preview in the currently selected voice."""
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
return
|
||||||
|
|
||||||
|
voice = self._getACSSForVoiceType(voiceType)
|
||||||
|
if not voice:
|
||||||
|
return
|
||||||
|
|
||||||
|
previewVoice = acss.ACSS(voice)
|
||||||
|
if self.speechSystemsChoice \
|
||||||
|
and self.speechSystemsChoice.SpeechServer.getFactoryName() == guilabels.SPEECH_DISPATCHER:
|
||||||
|
previewMessage = messages.SPEECH_VOICE_VALUE % name
|
||||||
|
else:
|
||||||
|
previewMessage = messages.SPEECH_VOICE_VALUE_GENERIC % name
|
||||||
|
|
||||||
|
# Speak through the currently-selected preferences speech server so
|
||||||
|
# preview uses the chosen module/voice, not the globally-active one.
|
||||||
|
server = self.speechServersChoice
|
||||||
|
if server and hasattr(server, "speak"):
|
||||||
|
try:
|
||||||
|
server.speak(previewMessage, previewVoice, interrupt=True)
|
||||||
|
return
|
||||||
|
except Exception:
|
||||||
|
debug.printException(debug.LEVEL_WARNING)
|
||||||
|
|
||||||
|
self._presentMessage(previewMessage, interrupt=True, voice=previewVoice)
|
||||||
|
|
||||||
def _createNode(self, appName):
|
def _createNode(self, appName):
|
||||||
"""Create a new root node in the TreeStore model with the name of the
|
"""Create a new root node in the TreeStore model with the name of the
|
||||||
application.
|
application.
|
||||||
@@ -3189,6 +3557,8 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
enable = widget.get_active()
|
enable = widget.get_active()
|
||||||
self.prefsDict["enableSpeech"] = enable
|
self.prefsDict["enableSpeech"] = enable
|
||||||
self.get_widget("speechOptionsGrid").set_sensitive(enable)
|
self.get_widget("speechOptionsGrid").set_sensitive(enable)
|
||||||
|
self._setupEchoSpeechServers()
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
def onlySpeakDisplayedTextToggled(self, widget):
|
def onlySpeakDisplayedTextToggled(self, widget):
|
||||||
"""Signal handler for the "toggled" signal for the GtkCheckButton
|
"""Signal handler for the "toggled" signal for the GtkCheckButton
|
||||||
@@ -3220,6 +3590,8 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
selectedIndex = widget.get_active()
|
selectedIndex = widget.get_active()
|
||||||
self.speechSystemsChoice = self.speechSystemsChoices[selectedIndex]
|
self.speechSystemsChoice = self.speechSystemsChoices[selectedIndex]
|
||||||
self._setupSpeechServers()
|
self._setupSpeechServers()
|
||||||
|
self._setupEchoSpeechServers()
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
def speechServersChanged(self, widget):
|
def speechServersChanged(self, widget):
|
||||||
"""Signal handler for the "changed" signal for the speechServers
|
"""Signal handler for the "changed" signal for the speechServers
|
||||||
@@ -3252,6 +3624,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
self._setupVoices()
|
self._setupVoices()
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
def speechLanguagesChanged(self, widget):
|
def speechLanguagesChanged(self, widget):
|
||||||
"""Signal handler for the "value_changed" signal for the languages
|
"""Signal handler for the "value_changed" signal for the languages
|
||||||
@@ -3311,6 +3684,8 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
variant = family[speechserver.VoiceFamily.VARIANT]
|
variant = family[speechserver.VoiceFamily.VARIANT]
|
||||||
voiceType = self.get_widget("voiceTypesCombo").get_active()
|
voiceType = self.get_widget("voiceTypesCombo").get_active()
|
||||||
self._setFamilyNameForVoiceType(voiceType, name, language, dialect, variant)
|
self._setFamilyNameForVoiceType(voiceType, name, language, dialect, variant)
|
||||||
|
if not self._updatingSpeechFamilies:
|
||||||
|
self._previewVoiceSelection(voiceType, name)
|
||||||
except Exception:
|
except Exception:
|
||||||
debug.printException(debug.LEVEL_SEVERE)
|
debug.printException(debug.LEVEL_SEVERE)
|
||||||
|
|
||||||
@@ -3388,6 +3763,75 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
voices.get(settings.DEFAULT_VOICE, {})[acss.ACSS.GAIN] = volume
|
voices.get(settings.DEFAULT_VOICE, {})[acss.ACSS.GAIN] = volume
|
||||||
cthulhu.cthulhuApp.settingsManager.setSetting('voices', voices)
|
cthulhu.cthulhuApp.settingsManager.setSetting('voices', voices)
|
||||||
|
|
||||||
|
def useCustomEchoVoiceToggled(self, widget):
|
||||||
|
"""Signal handler for enabling/disabling custom echo voice settings."""
|
||||||
|
|
||||||
|
self.prefsDict["useCustomEchoVoice"] = widget.get_active()
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
|
||||||
|
def useCustomEchoSpeechServerToggled(self, widget):
|
||||||
|
"""Signal handler for enabling/disabling custom echo module override."""
|
||||||
|
|
||||||
|
self.prefsDict["useCustomEchoSpeechServer"] = widget.get_active()
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
|
||||||
|
def echoSpeechServersChanged(self, widget):
|
||||||
|
"""Signal handler for selecting the echo speech-dispatcher module."""
|
||||||
|
|
||||||
|
if self.initializingEchoSpeech:
|
||||||
|
return
|
||||||
|
|
||||||
|
selectedIndex = widget.get_active()
|
||||||
|
if selectedIndex < 0:
|
||||||
|
self.echoSpeechServersChoice = None
|
||||||
|
self.prefsDict["echoSpeechServerInfo"] = None
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.echoSpeechServersChoice = self.echoSpeechServersChoices[selectedIndex]
|
||||||
|
self.prefsDict["echoSpeechServerInfo"] = self.echoSpeechServersChoice.getInfo()
|
||||||
|
self._setupEchoSpeechFamilies()
|
||||||
|
|
||||||
|
def echoSpeechFamiliesChanged(self, widget):
|
||||||
|
"""Signal handler for selecting the echo voice family."""
|
||||||
|
|
||||||
|
if self.initializingEchoSpeech or self._updatingEchoSpeechFamilies:
|
||||||
|
return
|
||||||
|
|
||||||
|
selectedIndex = widget.get_active()
|
||||||
|
if selectedIndex < 0:
|
||||||
|
self.echoSpeechFamiliesChoice = None
|
||||||
|
return
|
||||||
|
|
||||||
|
self.echoSpeechFamiliesChoice = self.echoSpeechFamiliesChoices[selectedIndex]
|
||||||
|
self._setEchoVoiceFamily(self.echoSpeechFamiliesChoice)
|
||||||
|
|
||||||
|
def echoRateValueChanged(self, widget):
|
||||||
|
"""Signal handler for changing custom echo rate."""
|
||||||
|
|
||||||
|
if self.echoVoice is None:
|
||||||
|
self.echoVoice = acss.ACSS({})
|
||||||
|
self.echoVoice[acss.ACSS.RATE] = widget.get_value()
|
||||||
|
self.echoVoice['established'] = True
|
||||||
|
|
||||||
|
def echoPitchValueChanged(self, widget):
|
||||||
|
"""Signal handler for changing custom echo pitch."""
|
||||||
|
|
||||||
|
if self.echoVoice is None:
|
||||||
|
self.echoVoice = acss.ACSS({})
|
||||||
|
self.echoVoice[acss.ACSS.AVERAGE_PITCH] = widget.get_value()
|
||||||
|
self.echoVoice['established'] = True
|
||||||
|
|
||||||
|
def echoVolumeValueChanged(self, widget):
|
||||||
|
"""Signal handler for changing custom echo volume."""
|
||||||
|
|
||||||
|
if self.echoVoice is None:
|
||||||
|
self.echoVoice = acss.ACSS({})
|
||||||
|
self.echoVoice[acss.ACSS.GAIN] = widget.get_value()
|
||||||
|
self.echoVoice['established'] = True
|
||||||
|
|
||||||
def checkButtonToggled(self, widget):
|
def checkButtonToggled(self, widget):
|
||||||
"""Signal handler for "toggled" signal for basic GtkCheckButton
|
"""Signal handler for "toggled" signal for basic GtkCheckButton
|
||||||
widgets. The user has altered the state of the checkbox.
|
widgets. The user has altered the state of the checkbox.
|
||||||
@@ -3405,6 +3849,15 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
# strip "CheckButton" from the end.
|
# strip "CheckButton" from the end.
|
||||||
settingName = settingName[:-11]
|
settingName = settingName[:-11]
|
||||||
self.prefsDict[settingName] = widget.get_active()
|
self.prefsDict[settingName] = widget.get_active()
|
||||||
|
if settingName in [
|
||||||
|
"enableEchoByCharacter",
|
||||||
|
"enableEchoByWord",
|
||||||
|
"enableEchoBySentence",
|
||||||
|
"useCustomEchoForKey",
|
||||||
|
"useCustomEchoForCharacter",
|
||||||
|
"useCustomEchoForWord",
|
||||||
|
"useCustomEchoForSentence"]:
|
||||||
|
self._setEchoVoiceItems()
|
||||||
|
|
||||||
def keyEchoChecked(self, widget):
|
def keyEchoChecked(self, widget):
|
||||||
"""Signal handler for the "toggled" signal for the
|
"""Signal handler for the "toggled" signal for the
|
||||||
@@ -4207,6 +4660,35 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
settings.SYSTEM_VOICE: acss.ACSS(self.systemVoice),
|
settings.SYSTEM_VOICE: acss.ACSS(self.systemVoice),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.prefsDict["useCustomEchoVoice"] = \
|
||||||
|
self.get_widget("useCustomEchoVoiceCheckButton").get_active()
|
||||||
|
self.prefsDict["useCustomEchoSpeechServer"] = \
|
||||||
|
self.get_widget("useCustomEchoSpeechServerCheckButton").get_active()
|
||||||
|
self.prefsDict["useCustomEchoForKey"] = \
|
||||||
|
self.get_widget("useCustomEchoForKeyCheckButton").get_active()
|
||||||
|
self.prefsDict["useCustomEchoForCharacter"] = \
|
||||||
|
self.get_widget("useCustomEchoForCharacterCheckButton").get_active()
|
||||||
|
self.prefsDict["useCustomEchoForWord"] = \
|
||||||
|
self.get_widget("useCustomEchoForWordCheckButton").get_active()
|
||||||
|
self.prefsDict["useCustomEchoForSentence"] = \
|
||||||
|
self.get_widget("useCustomEchoForSentenceCheckButton").get_active()
|
||||||
|
|
||||||
|
if self.echoVoice is None:
|
||||||
|
self.echoVoice = acss.ACSS({})
|
||||||
|
|
||||||
|
# Persist slider values directly so saving does not depend on
|
||||||
|
# value-changed signal timing.
|
||||||
|
self.echoVoice[acss.ACSS.RATE] = self.get_widget("echoRateScale").get_value()
|
||||||
|
self.echoVoice[acss.ACSS.AVERAGE_PITCH] = self.get_widget("echoPitchScale").get_value()
|
||||||
|
self.echoVoice[acss.ACSS.GAIN] = self.get_widget("echoVolumeScale").get_value()
|
||||||
|
self.echoVoice['established'] = True
|
||||||
|
self.prefsDict["echoVoice"] = acss.ACSS(self.echoVoice)
|
||||||
|
|
||||||
|
if self.echoSpeechServersChoice:
|
||||||
|
self.prefsDict["echoSpeechServerInfo"] = self.echoSpeechServersChoice.getInfo()
|
||||||
|
else:
|
||||||
|
self.prefsDict["echoSpeechServerInfo"] = None
|
||||||
|
|
||||||
def applyButtonClicked(self, widget):
|
def applyButtonClicked(self, widget):
|
||||||
"""Signal handler for the "clicked" signal for the applyButton
|
"""Signal handler for the "clicked" signal for the applyButton
|
||||||
GtkButton widget. The user has clicked the Apply button.
|
GtkButton widget. The user has clicked the Apply button.
|
||||||
@@ -4239,6 +4721,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
self._refresh_dynamic_plugin_tabs()
|
self._refresh_dynamic_plugin_tabs()
|
||||||
braille.checkBrailleSetting()
|
braille.checkBrailleSetting()
|
||||||
self._initSpeechState()
|
self._initSpeechState()
|
||||||
|
self._initEchoSpeechState()
|
||||||
self._populateKeyBindings()
|
self._populateKeyBindings()
|
||||||
self.__initProfileCombo()
|
self.__initProfileCombo()
|
||||||
|
|
||||||
@@ -4501,6 +4984,7 @@ class CthulhuSetupGUI(cthulhu_gtkbuilder.GtkBuilderWrapper):
|
|||||||
braille.checkBrailleSetting()
|
braille.checkBrailleSetting()
|
||||||
|
|
||||||
self._initSpeechState()
|
self._initSpeechState()
|
||||||
|
self._initEchoSpeechState()
|
||||||
|
|
||||||
self._populateKeyBindings()
|
self._populateKeyBindings()
|
||||||
|
|
||||||
|
|||||||
@@ -844,6 +844,11 @@ class KeyboardEvent(InputEvent):
|
|||||||
"shouldConsume: No handler found",
|
"shouldConsume: No handler found",
|
||||||
reason="no-handler", timestamp=True)
|
reason="no-handler", timestamp=True)
|
||||||
|
|
||||||
|
if self._isSleepModeActive():
|
||||||
|
if self._isSleepModeToggleHandler():
|
||||||
|
return True, 'Sleep mode toggle command'
|
||||||
|
return False, 'Sleep mode active'
|
||||||
|
|
||||||
self._script.updateKeyboardEventState(self, self._handler)
|
self._script.updateKeyboardEventState(self, self._handler)
|
||||||
scriptConsumes = self._script.shouldConsumeKeyboardEvent(self, self._handler)
|
scriptConsumes = self._script.shouldConsumeKeyboardEvent(self, self._handler)
|
||||||
if globalHandlerUsed:
|
if globalHandlerUsed:
|
||||||
@@ -881,6 +886,35 @@ class KeyboardEvent(InputEvent):
|
|||||||
return None
|
return None
|
||||||
return global_bindings.getInputHandler(self)
|
return global_bindings.getInputHandler(self)
|
||||||
|
|
||||||
|
def _isSleepModeActive(self):
|
||||||
|
"""Returns True if the script for this event is in sleep mode."""
|
||||||
|
|
||||||
|
if not self._script:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if "scripts.sleepmode" in self._script.__module__:
|
||||||
|
return True
|
||||||
|
|
||||||
|
app = getattr(self._script, "app", None)
|
||||||
|
if app is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import sleep_mode_manager
|
||||||
|
manager = sleep_mode_manager.getManager()
|
||||||
|
return bool(manager and manager.isActiveForApp(app))
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _isSleepModeToggleHandler(self):
|
||||||
|
"""Returns True if the resolved handler toggles sleep mode."""
|
||||||
|
|
||||||
|
if not self._handler or not self._handler.function:
|
||||||
|
return False
|
||||||
|
|
||||||
|
functionName = getattr(self._handler.function, "__name__", "")
|
||||||
|
return "toggleSleepMode" in functionName
|
||||||
|
|
||||||
def didConsume(self):
|
def didConsume(self):
|
||||||
"""Returns True if this event was consumed."""
|
"""Returns True if this event was consumed."""
|
||||||
|
|
||||||
@@ -1139,7 +1173,7 @@ class RemoteControllerEvent(InputEvent):
|
|||||||
|
|
||||||
class InputEventHandler:
|
class InputEventHandler:
|
||||||
|
|
||||||
def __init__(self, function, description, learnModeEnabled=True):
|
def __init__(self, function, description, learnModeEnabled=True, enabled=True):
|
||||||
"""Creates a new InputEventHandler instance. All bindings
|
"""Creates a new InputEventHandler instance. All bindings
|
||||||
(e.g., key bindings and braille bindings) will be handled
|
(e.g., key bindings and braille bindings) will be handled
|
||||||
by an instance of an InputEventHandler.
|
by an instance of an InputEventHandler.
|
||||||
@@ -1159,6 +1193,15 @@ class InputEventHandler:
|
|||||||
self.function = function
|
self.function = function
|
||||||
self.description = description
|
self.description = description
|
||||||
self.learnModeEnabled = learnModeEnabled
|
self.learnModeEnabled = learnModeEnabled
|
||||||
|
self._enabled = enabled
|
||||||
|
|
||||||
|
def is_enabled(self):
|
||||||
|
"""Returns True if this handler is enabled."""
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
def set_enabled(self, enabled):
|
||||||
|
"""Sets enabled state of this handler."""
|
||||||
|
self._enabled = enabled
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""Compares one input handler to another."""
|
"""Compares one input handler to another."""
|
||||||
|
|||||||
@@ -74,7 +74,10 @@ class InputEventManager:
|
|||||||
|
|
||||||
msg = "INPUT EVENT MANAGER: Starting key watcher."
|
msg = "INPUT EVENT MANAGER: Starting key watcher."
|
||||||
debug.print_message(debug.LEVEL_INFO, msg, True)
|
debug.print_message(debug.LEVEL_INFO, msg, True)
|
||||||
|
if Atspi.get_version() >= (2, 55, 90):
|
||||||
self._device = Atspi.Device.new_full("org.stormux.Cthulhu")
|
self._device = Atspi.Device.new_full("org.stormux.Cthulhu")
|
||||||
|
else:
|
||||||
|
self._device = Atspi.Device.new()
|
||||||
self._device.add_key_watcher(self.process_keyboard_event)
|
self._device.add_key_watcher(self.process_keyboard_event)
|
||||||
|
|
||||||
def stop_key_watcher(self) -> None:
|
def stop_key_watcher(self) -> None:
|
||||||
@@ -100,43 +103,30 @@ class InputEventManager:
|
|||||||
msg = f"INPUT EVENT MANAGER: {grab_id} for: {binding}"
|
msg = f"INPUT EVENT MANAGER: {grab_id} for: {binding}"
|
||||||
debug.print_message(debug.LEVEL_INFO, msg, True)
|
debug.print_message(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
def _get_key_definitions(self, binding: keybindings.KeyBinding) -> List[Atspi.KeyDefinition]:
|
|
||||||
if hasattr(binding, "key_definitions"):
|
|
||||||
return list(binding.key_definitions())
|
|
||||||
if hasattr(binding, "keyDefs"):
|
|
||||||
return list(binding.keyDefs())
|
|
||||||
return []
|
|
||||||
|
|
||||||
def add_grabs_for_keybinding(self, binding: keybindings.KeyBinding) -> List[int]:
|
def add_grabs_for_keybinding(self, binding: keybindings.KeyBinding) -> List[int]:
|
||||||
"""Adds grabs for binding if it is enabled, returns grab IDs."""
|
"""Adds grabs for binding if it is enabled, returns grab IDs."""
|
||||||
|
|
||||||
|
if not (binding.is_enabled() and binding.is_bound()):
|
||||||
|
return []
|
||||||
|
|
||||||
|
if binding.has_grabs():
|
||||||
|
tokens = ["INPUT EVENT MANAGER:", binding, "already has grabs."]
|
||||||
|
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
||||||
|
return []
|
||||||
|
|
||||||
if self._device is None:
|
if self._device is None:
|
||||||
tokens = ["INPUT EVENT MANAGER: No device to add grab for", binding]
|
tokens = ["INPUT EVENT MANAGER: No device to add grab for", binding]
|
||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
grab_ids = []
|
grab_ids = []
|
||||||
key_definitions = self._get_key_definitions(binding)
|
for kd in binding.key_definitions():
|
||||||
if not key_definitions:
|
|
||||||
tokens = ["INPUT EVENT MANAGER: No key definitions for", binding]
|
|
||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
|
||||||
return []
|
|
||||||
|
|
||||||
for kd in key_definitions:
|
|
||||||
grab_id = self._device.add_key_grab(kd, None)
|
grab_id = self._device.add_key_grab(kd, None)
|
||||||
# When we have double/triple-click bindings, the single-click binding will be
|
|
||||||
# registered first, and subsequent attempts to register what is externally the
|
|
||||||
# same grab will fail. If we only have a double/triple-click, it succeeds.
|
|
||||||
# A grab id of 0 indicates failure.
|
|
||||||
if grab_id == 0:
|
if grab_id == 0:
|
||||||
continue
|
continue
|
||||||
grab_ids.append(grab_id)
|
grab_ids.append(grab_id)
|
||||||
self._grabbed_bindings[grab_id] = binding
|
self._grabbed_bindings[grab_id] = binding
|
||||||
|
|
||||||
if grab_ids:
|
|
||||||
tokens = ["INPUT EVENT MANAGER: Added grabs", grab_ids, "for", binding]
|
|
||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
|
||||||
|
|
||||||
return grab_ids
|
return grab_ids
|
||||||
|
|
||||||
def remove_grabs_for_keybinding(self, binding: keybindings.KeyBinding) -> None:
|
def remove_grabs_for_keybinding(self, binding: keybindings.KeyBinding) -> None:
|
||||||
@@ -147,30 +137,18 @@ class InputEventManager:
|
|||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
||||||
return
|
return
|
||||||
|
|
||||||
grab_ids = None
|
|
||||||
if hasattr(binding, "get_grab_ids"):
|
|
||||||
grab_ids = binding.get_grab_ids()
|
grab_ids = binding.get_grab_ids()
|
||||||
elif hasattr(binding, "_grab_ids"):
|
|
||||||
grab_ids = list(binding._grab_ids)
|
|
||||||
|
|
||||||
if not grab_ids:
|
if not grab_ids:
|
||||||
tokens = ["INPUT EVENT MANAGER:", binding, "doesn't have grabs to remove."]
|
tokens = ["INPUT EVENT MANAGER:", binding, "doesn't have grabs to remove."]
|
||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
||||||
return
|
return
|
||||||
|
|
||||||
tokens = ["INPUT EVENT MANAGER: Removing grabs", grab_ids, "for", binding]
|
|
||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
|
||||||
|
|
||||||
for grab_id in grab_ids:
|
for grab_id in grab_ids:
|
||||||
self._device.remove_key_grab(grab_id)
|
self._device.remove_key_grab(grab_id)
|
||||||
removed = self._grabbed_bindings.pop(grab_id, None)
|
removed = self._grabbed_bindings.pop(grab_id, None)
|
||||||
if removed is None:
|
if removed is None:
|
||||||
msg = f"INPUT EVENT MANAGER: No key binding for grab id {grab_id}"
|
msg = f"INPUT EVENT MANAGER: No key binding for grab id {grab_id}"
|
||||||
debug.print_message(debug.LEVEL_INFO, msg, True)
|
debug.print_message(debug.LEVEL_INFO, msg, True)
|
||||||
if hasattr(binding, "_grab_ids") and grab_id in binding._grab_ids:
|
|
||||||
binding._grab_ids.remove(grab_id)
|
|
||||||
if hasattr(binding, "_grab_ids") and not binding._grab_ids:
|
|
||||||
delattr(binding, "_grab_ids")
|
|
||||||
|
|
||||||
def remove_grab_by_id(self, grab_id: int) -> None:
|
def remove_grab_by_id(self, grab_id: int) -> None:
|
||||||
"""Removes a grab by id."""
|
"""Removes a grab by id."""
|
||||||
@@ -182,10 +160,8 @@ class InputEventManager:
|
|||||||
|
|
||||||
self._device.remove_key_grab(grab_id)
|
self._device.remove_key_grab(grab_id)
|
||||||
binding = self._grabbed_bindings.pop(grab_id, None)
|
binding = self._grabbed_bindings.pop(grab_id, None)
|
||||||
if binding and hasattr(binding, "_grab_ids") and grab_id in binding._grab_ids:
|
if binding and grab_id in binding._grab_ids:
|
||||||
binding._grab_ids.remove(grab_id)
|
binding._grab_ids.remove(grab_id)
|
||||||
if not binding._grab_ids:
|
|
||||||
delattr(binding, "_grab_ids")
|
|
||||||
if binding:
|
if binding:
|
||||||
tokens = ["INPUT EVENT MANAGER: Removed grab", grab_id, "for", binding]
|
tokens = ["INPUT EVENT MANAGER: Removed grab", grab_id, "for", binding]
|
||||||
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
debug.print_tokens(debug.LEVEL_INFO, tokens, True)
|
||||||
|
|||||||
+161
-152
@@ -26,6 +26,8 @@
|
|||||||
"""Provides support for defining keybindings and matching them to input
|
"""Provides support for defining keybindings and matching them to input
|
||||||
events."""
|
events."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
__id__ = "$Id$"
|
__id__ = "$Id$"
|
||||||
__version__ = "$Revision$"
|
__version__ = "$Revision$"
|
||||||
__date__ = "$Date$"
|
__date__ = "$Date$"
|
||||||
@@ -39,6 +41,7 @@ from gi.repository import Gdk
|
|||||||
from gi.repository import Atspi
|
from gi.repository import Atspi
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from . import debug
|
from . import debug
|
||||||
from . import settings
|
from . import settings
|
||||||
@@ -46,6 +49,9 @@ from . import cthulhu_state
|
|||||||
|
|
||||||
from .cthulhu_i18n import _
|
from .cthulhu_i18n import _
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .input_event import KeyboardEvent, InputEventHandler
|
||||||
|
|
||||||
_keysymsCache = {}
|
_keysymsCache = {}
|
||||||
_keycodeCache = {}
|
_keycodeCache = {}
|
||||||
|
|
||||||
@@ -80,63 +86,35 @@ NON_LOCKING_MODIFIER_MASK = (1 << Atspi.ModifierType.SHIFT |
|
|||||||
1 << MODIFIER_CTHULHU)
|
1 << MODIFIER_CTHULHU)
|
||||||
defaultModifierMask = NON_LOCKING_MODIFIER_MASK
|
defaultModifierMask = NON_LOCKING_MODIFIER_MASK
|
||||||
|
|
||||||
def getKeycode(keysym):
|
CAN_USE_KEYSYMS = Atspi.get_version() >= (2, 55, 0)
|
||||||
"""Converts an XKeysym string (e.g., 'KP_Enter') to a keycode that
|
|
||||||
should match the event.hw_code for key events.
|
|
||||||
|
|
||||||
This whole situation is caused by the fact that Solaris chooses
|
|
||||||
to give us different keycodes for the same key, and the keypad
|
|
||||||
is the primary place where this happens: if NumLock is not on,
|
|
||||||
there is no telling the difference between keypad keys and the
|
|
||||||
other navigation keys (e.g., arrows, page up/down, etc.). One,
|
|
||||||
for example, would expect to get KP_End for the '1' key on the
|
|
||||||
keypad if NumLock were not on. Instead, we get 'End' and the
|
|
||||||
keycode for it matches the keycode for the other 'End' key. Odd.
|
|
||||||
If NumLock is on, we at least get KP_* keys.
|
|
||||||
|
|
||||||
So...when setting up keybindings, we say we're interested in
|
|
||||||
KeySyms, but those keysyms are carefully chosen so as to result
|
|
||||||
in a keycode that matches the actual key on the keyboard. This
|
|
||||||
is why we use KP_1 instead of KP_End and so on in our keybindings.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
- keysym: a string that is a valid representation of an XKeysym.
|
|
||||||
|
|
||||||
Returns an integer representing a key code that should match the
|
|
||||||
event.hw_code for key events.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
def get_keycodes(keysym):
|
||||||
|
"""Converts an XKeysym string to a (keyval, keycode) tuple."""
|
||||||
if not keysym:
|
if not keysym:
|
||||||
return 0
|
return (0, 0)
|
||||||
|
|
||||||
if keysym not in _keycodeCache:
|
if keysym not in _keycodeCache:
|
||||||
keymap = Gdk.Keymap.get_default()
|
keymap = Gdk.Keymap.get_default()
|
||||||
|
|
||||||
# Find the numerical value of the keysym
|
|
||||||
#
|
|
||||||
keyval = Gdk.keyval_from_name(keysym)
|
keyval = Gdk.keyval_from_name(keysym)
|
||||||
if keyval == 0:
|
if keyval == 0:
|
||||||
return 0
|
return (0, 0)
|
||||||
|
|
||||||
# Now find the keycodes for the keysym. Since a keysym can
|
_keycodeCache[keysym] = (keyval, 0)
|
||||||
# be associated with more than one key, we'll shoot for the
|
_success, entries = keymap.get_entries_for_keyval(keyval)
|
||||||
# keysym that's in group 0, regardless of shift level (each
|
|
||||||
# entry is of the form [keycode, group, level]).
|
|
||||||
#
|
|
||||||
_keycodeCache[keysym] = 0
|
|
||||||
success, entries = keymap.get_entries_for_keyval(keyval)
|
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
if entry.group == 0:
|
if entry.group == 0:
|
||||||
_keycodeCache[keysym] = entry.keycode
|
_keycodeCache[keysym] = (keyval, entry.keycode)
|
||||||
break
|
break
|
||||||
if _keycodeCache[keysym] == 0:
|
if _keycodeCache[keysym] == (keyval, 0):
|
||||||
_keycodeCache[keysym] = entries[0].keycode
|
_keycodeCache[keysym] = (keyval, entries[0].keycode)
|
||||||
|
|
||||||
#print keysym, keyval, entries, _keycodeCache[keysym]
|
|
||||||
|
|
||||||
return _keycodeCache[keysym]
|
return _keycodeCache[keysym]
|
||||||
|
|
||||||
|
def getKeycode(keysym):
|
||||||
|
"""Converts an XKeysym string to a keycode. Legacy wrapper."""
|
||||||
|
return get_keycodes(keysym)[1]
|
||||||
|
|
||||||
def getModifierNames(mods):
|
def getModifierNames(mods):
|
||||||
"""Gets the modifier names of a numeric modifier mask as a human
|
"""Gets the modifier names of a numeric modifier mask as a human
|
||||||
consumable string.
|
consumable string.
|
||||||
@@ -211,13 +189,43 @@ def get_click_countString(count):
|
|||||||
return _("triple click")
|
return _("triple click")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def create_key_definitions(keycode, keyval, modifiers):
|
||||||
|
"""Returns a list of Atspi key definitions for the given keycode, keyval, and modifiers."""
|
||||||
|
ret = []
|
||||||
|
if modifiers & CTHULHU_MODIFIER_MASK:
|
||||||
|
modifier_list = []
|
||||||
|
other_modifiers = modifiers & ~CTHULHU_MODIFIER_MASK
|
||||||
|
from . import input_event_manager
|
||||||
|
manager = input_event_manager.get_manager()
|
||||||
|
for key in settings.cthulhuModifierKeys:
|
||||||
|
mod_keyval, mod_keycode = get_keycodes(key)
|
||||||
|
if mod_keycode == 0 and key == "Shift_Lock":
|
||||||
|
mod_keyval, mod_keycode = get_keycodes("Caps_Lock")
|
||||||
|
if CAN_USE_KEYSYMS:
|
||||||
|
mod = manager.map_keysym_to_modifier(mod_keyval)
|
||||||
|
else:
|
||||||
|
mod = manager.map_keycode_to_modifier(mod_keycode)
|
||||||
|
if mod:
|
||||||
|
modifier_list.append(mod | other_modifiers)
|
||||||
|
else:
|
||||||
|
modifier_list = [modifiers]
|
||||||
|
for mod in modifier_list:
|
||||||
|
kd = Atspi.KeyDefinition()
|
||||||
|
if CAN_USE_KEYSYMS:
|
||||||
|
kd.keysym = keyval
|
||||||
|
else:
|
||||||
|
kd.keycode = keycode
|
||||||
|
kd.modifiers = mod
|
||||||
|
ret.append(kd)
|
||||||
|
return ret
|
||||||
|
|
||||||
class KeyBinding:
|
class KeyBinding:
|
||||||
"""A single key binding, consisting of a keycode, a modifier mask,
|
"""A single key binding, consisting of a keycode, a modifier mask,
|
||||||
and the InputEventHandler.
|
and the InputEventHandler.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, keysymstring, modifier_mask, modifiers, handler,
|
def __init__(self, keysymstring, modifier_mask, modifiers, handler,
|
||||||
click_count = 1):
|
click_count = 1, enabled=True):
|
||||||
"""Creates a new key binding.
|
"""Creates a new key binding.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@@ -237,41 +245,21 @@ class KeyBinding:
|
|||||||
self.modifiers = modifiers
|
self.modifiers = modifiers
|
||||||
self.handler = handler
|
self.handler = handler
|
||||||
self.click_count = click_count
|
self.click_count = click_count
|
||||||
self.keycode = None
|
self.keycode = 0
|
||||||
|
self.keyval = 0
|
||||||
|
self._enabled = enabled
|
||||||
|
self._grab_ids = []
|
||||||
|
|
||||||
def matches(self, keycode, modifiers):
|
def matches(self, keyval, keycode, modifiers):
|
||||||
"""Returns true if this key binding matches the given keycode and
|
"""Returns true if this key binding matches the given keyval/keycode and modifier state."""
|
||||||
modifier state.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# We lazily bind the keycode. The primary reason for doing this
|
|
||||||
# is so that atspi does not have to be initialized before setting
|
|
||||||
# keybindings in the user's preferences file.
|
|
||||||
#
|
|
||||||
if not self.keycode:
|
if not self.keycode:
|
||||||
self.keycode = getKeycode(self.keysymstring)
|
self.keyval, self.keycode = get_keycodes(self.keysymstring)
|
||||||
|
|
||||||
# Debug logging for DisplayVersion plugin specifically
|
if self.keycode == keycode or self.keyval == keyval:
|
||||||
if self.keysymstring == 'v' and self.modifiers == 257:
|
|
||||||
with open('/tmp/displayversion_matches.log', 'a') as f:
|
|
||||||
f.write(f"=== DisplayVersion matches() debug ===\n")
|
|
||||||
f.write(f"Self keycode: {self.keycode}\n")
|
|
||||||
f.write(f"Self keysymstring: {self.keysymstring}\n")
|
|
||||||
f.write(f"Self modifiers: {self.modifiers}\n")
|
|
||||||
f.write(f"Self modifier_mask: {self.modifier_mask}\n")
|
|
||||||
f.write(f"Input keycode: {keycode}\n")
|
|
||||||
f.write(f"Input modifiers: {modifiers}\n")
|
|
||||||
f.write(f"Keycode match: {self.keycode == keycode}\n")
|
|
||||||
if self.keycode == keycode:
|
|
||||||
result = modifiers & self.modifier_mask
|
|
||||||
f.write(f"Modifier calculation: {modifiers} & {self.modifier_mask} = {result}\n")
|
|
||||||
f.write(f"Modifier match: {result == self.modifiers}\n")
|
|
||||||
f.write(f"Overall match: {self.keycode == keycode and (modifiers & self.modifier_mask) == self.modifiers}\n")
|
|
||||||
|
|
||||||
if self.keycode == keycode:
|
|
||||||
result = modifiers & self.modifier_mask
|
result = modifiers & self.modifier_mask
|
||||||
return result == self.modifiers
|
return result == self.modifiers
|
||||||
else:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def description(self):
|
def description(self):
|
||||||
@@ -292,41 +280,52 @@ class KeyBinding:
|
|||||||
|
|
||||||
return string.strip()
|
return string.strip()
|
||||||
|
|
||||||
def keyDefs(self):
|
def is_bound(self):
|
||||||
""" return a list of Atspi key definitions for the given binding.
|
"""Returns True if this KeyBinding is bound to a key."""
|
||||||
This may return more than one binding if the Cthulhu modifier is bound
|
return bool(self.keysymstring)
|
||||||
to more than one key.
|
|
||||||
If AT-SPI is older than 2.40, then this function will not work and
|
def is_enabled(self):
|
||||||
will return an empty set.
|
"""Returns True if this KeyBinding is enabled."""
|
||||||
"""
|
return self._enabled
|
||||||
|
|
||||||
|
def set_enabled(self, enabled):
|
||||||
|
"""Set this KeyBinding's enabled state."""
|
||||||
|
self._enabled = enabled
|
||||||
|
|
||||||
|
def get_grab_ids(self):
|
||||||
|
"""Returns the grab IDs for this KeyBinding."""
|
||||||
|
return self._grab_ids
|
||||||
|
|
||||||
|
def has_grabs(self):
|
||||||
|
"""Returns True if there are existing grabs associated with this KeyBinding."""
|
||||||
|
return bool(self._grab_ids)
|
||||||
|
|
||||||
|
def add_grabs(self):
|
||||||
|
"""Adds key grabs for this KeyBinding."""
|
||||||
|
from . import input_event_manager
|
||||||
|
self._grab_ids = input_event_manager.get_manager().add_grabs_for_keybinding(self)
|
||||||
|
|
||||||
|
def remove_grabs(self):
|
||||||
|
"""Removes key grabs for this KeyBinding."""
|
||||||
|
from . import input_event_manager
|
||||||
|
input_event_manager.get_manager().remove_grabs_for_keybinding(self)
|
||||||
|
self._grab_ids = []
|
||||||
|
|
||||||
|
def key_definitions(self):
|
||||||
|
"""Return a list of Atspi key definitions for the given binding."""
|
||||||
ret = []
|
ret = []
|
||||||
if not self.keycode:
|
if not self.keycode:
|
||||||
self.keycode = getKeycode(self.keysymstring)
|
self.keyval, self.keycode = get_keycodes(self.keysymstring)
|
||||||
|
ret.extend(create_key_definitions(self.keycode, self.keyval, self.modifiers))
|
||||||
|
if CAN_USE_KEYSYMS and self.modifiers & SHIFT_MODIFIER_MASK:
|
||||||
|
upper_keyval = Gdk.keyval_to_upper(self.keyval)
|
||||||
|
if upper_keyval != self.keyval:
|
||||||
|
ret.extend(create_key_definitions(self.keycode, upper_keyval, self.modifiers))
|
||||||
|
return ret
|
||||||
|
|
||||||
if self.modifiers & CTHULHU_MODIFIER_MASK:
|
def keyDefs(self):
|
||||||
device = cthulhu_state.device
|
"""Legacy wrapper. Use key_definitions() instead."""
|
||||||
if device is None:
|
return self.key_definitions()
|
||||||
return ret
|
|
||||||
modList = []
|
|
||||||
otherMods = self.modifiers & ~CTHULHU_MODIFIER_MASK
|
|
||||||
numLockMod = device.get_modifier(getKeycode("Num_Lock"))
|
|
||||||
lockedMods = device.get_locked_modifiers()
|
|
||||||
numLockOn = lockedMods & numLockMod
|
|
||||||
for key in settings.cthulhuModifierKeys:
|
|
||||||
keycode = getKeycode(key)
|
|
||||||
if keycode == 0 and key == "Shift_Lock":
|
|
||||||
keycode = getKeycode("Caps_Lock")
|
|
||||||
mod = device.map_modifier(keycode)
|
|
||||||
if key != "KP_Insert" or not numLockOn:
|
|
||||||
modList.append(mod | otherMods)
|
|
||||||
else:
|
|
||||||
modList = [self.modifiers]
|
|
||||||
for mod in modList:
|
|
||||||
kd = Atspi.KeyDefinition()
|
|
||||||
kd.keycode = self.keycode
|
|
||||||
kd.modifiers = mod
|
|
||||||
ret.append(kd)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
class KeyBindings:
|
class KeyBindings:
|
||||||
"""Structure that maintains a set of KeyBinding instances.
|
"""Structure that maintains a set of KeyBinding instances.
|
||||||
@@ -347,7 +346,7 @@ class KeyBindings:
|
|||||||
result += "]"
|
result += "]"
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def add(self, keyBinding):
|
def add(self, keyBinding, include_grabs=False):
|
||||||
"""Adds the given KeyBinding instance to this set of keybindings.
|
"""Adds the given KeyBinding instance to this set of keybindings.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -359,17 +358,29 @@ class KeyBindings:
|
|||||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
self.keyBindings.append(keyBinding)
|
self.keyBindings.append(keyBinding)
|
||||||
|
if include_grabs:
|
||||||
|
keyBinding.add_grabs()
|
||||||
|
|
||||||
def remove(self, keyBinding):
|
def remove(self, keyBinding, include_grabs=False):
|
||||||
"""Removes the given KeyBinding instance from this set of keybindings.
|
"""Removes the given KeyBinding instance from this set of keybindings.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if keyBinding not in self.keyBindings:
|
||||||
|
candidates = self.getBindingsForHandler(keyBinding.handler)
|
||||||
|
if not candidates:
|
||||||
|
return
|
||||||
|
for candidate in self.getBindingsForHandler(keyBinding.handler):
|
||||||
|
self.remove(candidate, include_grabs)
|
||||||
|
return
|
||||||
|
|
||||||
|
if keyBinding.has_grabs():
|
||||||
|
if include_grabs:
|
||||||
|
keyBinding.remove_grabs()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
i = self.keyBindings.index(keyBinding)
|
self.keyBindings.remove(keyBinding)
|
||||||
except Exception:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
else:
|
|
||||||
del self.keyBindings[i]
|
|
||||||
|
|
||||||
def removeByHandler(self, handler):
|
def removeByHandler(self, handler):
|
||||||
"""Removes the given KeyBinding instance from this set of keybindings.
|
"""Removes the given KeyBinding instance from this set of keybindings.
|
||||||
@@ -380,6 +391,38 @@ class KeyBindings:
|
|||||||
del self.keyBindings[i - 1]
|
del self.keyBindings[i - 1]
|
||||||
i = i - 1
|
i = i - 1
|
||||||
|
|
||||||
|
def add_key_grabs(self, reason=""):
|
||||||
|
"""Adds grabs for all enabled bindings in this set of keybindings."""
|
||||||
|
msg = "KEYBINDINGS: Adding key grabs"
|
||||||
|
if reason:
|
||||||
|
msg += f": {reason}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for binding in self.keyBindings:
|
||||||
|
if binding.is_enabled() and not binding.has_grabs():
|
||||||
|
count += 1
|
||||||
|
binding.add_grabs()
|
||||||
|
|
||||||
|
msg = f"KEYBINDINGS: {count} key grabs added (total bindings: {len(self.keyBindings)})."
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
def remove_key_grabs(self, reason=""):
|
||||||
|
"""Removes all grabs for this set of keybindings."""
|
||||||
|
msg = "KEYBINDINGS: Removing key grabs"
|
||||||
|
if reason:
|
||||||
|
msg += f": {reason}"
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for binding in self.keyBindings:
|
||||||
|
if binding.has_grabs():
|
||||||
|
count += 1
|
||||||
|
binding.remove_grabs()
|
||||||
|
|
||||||
|
msg = f"KEYBINDINGS: {count} key grabs removed (total bindings: {len(self.keyBindings)})."
|
||||||
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|
||||||
def hasKeyBinding (self, newKeyBinding, typeOfSearch="strict"):
|
def hasKeyBinding (self, newKeyBinding, typeOfSearch="strict"):
|
||||||
"""Return True if keyBinding is already in self.keyBindings.
|
"""Return True if keyBinding is already in self.keyBindings.
|
||||||
|
|
||||||
@@ -461,6 +504,13 @@ class KeyBindings:
|
|||||||
|
|
||||||
return [kb for kb in self.keyBindings if kb.handler == handler]
|
return [kb for kb in self.keyBindings if kb.handler == handler]
|
||||||
|
|
||||||
|
def has_enabled_handler(self, handler):
|
||||||
|
"""Returns True if the handler is found in this set of keybindings and is enabled."""
|
||||||
|
for binding in self.keyBindings:
|
||||||
|
if binding.handler == handler and binding.is_enabled():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _checkMatchingBindings(self, keyboardEvent, result):
|
def _checkMatchingBindings(self, keyboardEvent, result):
|
||||||
if debug.debugLevel > debug.LEVEL_INFO:
|
if debug.debugLevel > debug.LEVEL_INFO:
|
||||||
return
|
return
|
||||||
@@ -487,39 +537,11 @@ class KeyBindings:
|
|||||||
given keycode and modifiers, or None if no match exists.
|
given keycode and modifiers, or None if no match exists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Check if this might be the DisplayVersion key combination
|
|
||||||
event_str = keyboardEvent.event_string if hasattr(keyboardEvent, 'event_string') else 'unknown'
|
|
||||||
if event_str.lower() == 'v':
|
|
||||||
logger.info(f"=== KeyBindings.getInputHandler: Looking for handler ===")
|
|
||||||
logger.info(f"Event string: {event_str}")
|
|
||||||
logger.info(f"Hardware code: {keyboardEvent.hw_code}")
|
|
||||||
logger.info(f"Modifiers: {keyboardEvent.modifiers}")
|
|
||||||
logger.info(f"Total keybindings to check: {len(self.keyBindings)}")
|
|
||||||
|
|
||||||
with open('/tmp/keybinding_lookup.log', 'a') as f:
|
|
||||||
f.write(f"=== Looking for 'v' key handler ===\n")
|
|
||||||
f.write(f"Event string: {event_str}\n")
|
|
||||||
f.write(f"Hardware code: {keyboardEvent.hw_code}\n")
|
|
||||||
f.write(f"Modifiers: {keyboardEvent.modifiers}\n")
|
|
||||||
f.write(f"Total keybindings: {len(self.keyBindings)}\n")
|
|
||||||
|
|
||||||
# Log all keybindings for comparison
|
|
||||||
for i, kb in enumerate(self.keyBindings):
|
|
||||||
if 'v' in kb.keysymstring.lower() or 'version' in kb.handler.description.lower():
|
|
||||||
logger.info(f"Binding {i}: keysym={kb.keysymstring}, modifiers={kb.modifiers}, mask={kb.modifier_mask}, desc={kb.handler.description}")
|
|
||||||
with open('/tmp/keybinding_lookup.log', 'a') as f:
|
|
||||||
f.write(f"Found V-related binding {i}: keysym={kb.keysymstring}, modifiers={kb.modifiers}, mask={kb.modifier_mask}, desc={kb.handler.description}\n")
|
|
||||||
|
|
||||||
matches = []
|
matches = []
|
||||||
candidates = []
|
candidates = []
|
||||||
clickCount = keyboardEvent.get_click_count()
|
clickCount = keyboardEvent.get_click_count()
|
||||||
for keyBinding in self.keyBindings:
|
for keyBinding in self.keyBindings:
|
||||||
if keyBinding.matches(keyboardEvent.hw_code, keyboardEvent.modifiers):
|
if keyBinding.matches(keyboardEvent.id, keyboardEvent.hw_code, keyboardEvent.modifiers):
|
||||||
if event_str.lower() == 'v':
|
|
||||||
logger.info(f"MATCH found! keysym={keyBinding.keysymstring}, desc={keyBinding.handler.description}")
|
|
||||||
if (keyboardEvent.modifiers & keyBinding.modifier_mask) == keyBinding.modifiers and \
|
if (keyboardEvent.modifiers & keyBinding.modifier_mask) == keyBinding.modifiers and \
|
||||||
keyBinding.click_count == clickCount:
|
keyBinding.click_count == clickCount:
|
||||||
matches.append(keyBinding)
|
matches.append(keyBinding)
|
||||||
@@ -529,17 +551,8 @@ class KeyBindings:
|
|||||||
if keyBinding.keysymstring:
|
if keyBinding.keysymstring:
|
||||||
candidates.append(keyBinding)
|
candidates.append(keyBinding)
|
||||||
|
|
||||||
if event_str.lower() == 'v':
|
|
||||||
logger.info(f"Exact matches: {len(matches)}")
|
|
||||||
logger.info(f"Candidates: {len(candidates)}")
|
|
||||||
with open('/tmp/keybinding_lookup.log', 'a') as f:
|
|
||||||
f.write(f"Exact matches: {len(matches)}\n")
|
|
||||||
f.write(f"Candidates: {len(candidates)}\n")
|
|
||||||
|
|
||||||
self._checkMatchingBindings(keyboardEvent, matches)
|
self._checkMatchingBindings(keyboardEvent, matches)
|
||||||
if matches:
|
if matches:
|
||||||
if event_str.lower() == 'v':
|
|
||||||
logger.info(f"Returning exact match handler: {matches[0].handler.description}")
|
|
||||||
return matches[0].handler
|
return matches[0].handler
|
||||||
|
|
||||||
if keyboardEvent.isKeyPadKeyWithNumlockOn():
|
if keyboardEvent.isKeyPadKeyWithNumlockOn():
|
||||||
@@ -553,12 +566,8 @@ class KeyBindings:
|
|||||||
self._checkMatchingBindings(keyboardEvent, candidates)
|
self._checkMatchingBindings(keyboardEvent, candidates)
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
if candidate.click_count <= clickCount:
|
if candidate.click_count <= clickCount:
|
||||||
if event_str.lower() == 'v':
|
|
||||||
logger.info(f"Returning candidate handler: {candidate.handler.description}")
|
|
||||||
return candidate.handler
|
return candidate.handler
|
||||||
|
|
||||||
if event_str.lower() == 'v':
|
|
||||||
logger.info("No handler found!")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def load(self, keymap, handlers):
|
def load(self, keymap, handlers):
|
||||||
|
|||||||
@@ -276,7 +276,9 @@ class LiveRegionManager:
|
|||||||
utts = message['labels'] + message['content']
|
utts = message['labels'] + message['content']
|
||||||
|
|
||||||
if self.monitoring:
|
if self.monitoring:
|
||||||
self._script.presentMessage(utts)
|
# Live region content is user-generated text, not system messages.
|
||||||
|
# Use resetStyles=False to preserve the user's punctuation settings.
|
||||||
|
self._script.presentMessage(utts, resetStyles=False)
|
||||||
else:
|
else:
|
||||||
msg = "INFO: Not presenting message because monitoring is off"
|
msg = "INFO: Not presenting message because monitoring is off"
|
||||||
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
debug.printMessage(debug.LEVEL_INFO, msg, True)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user