Skip to content

Commit 621b8a7

Browse files
authored
Merge b9a245f into 0f18da3
2 parents 0f18da3 + b9a245f commit 621b8a7

5 files changed

Lines changed: 69 additions & 15 deletions

File tree

source/globalCommands.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Copyright (C) 2006-2023 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Rui Batista, Joseph Lee,
66
# Leonard de Ruijter, Derek Riemer, Babbage B.V., Davy Kager, Ethan Holliger, Łukasz Golonka, Accessolutions,
77
# Julien Cochuyt, Jakub Lukowicz, Bill Dengler, Cyrille Bougot, Rob Meredith, Luke Davis,
8-
# Burman's Computer and Education Ltd.
8+
# Burman's Computer and Education Ltd, Beka Gozalishvili.
99

1010
import itertools
1111
from typing import (
@@ -66,6 +66,7 @@
6666
from base64 import b16encode
6767
import vision
6868
from utils.security import objectBelowLockScreenAndWindowsIsLocked
69+
from utils.synth import getOutputDeviceNames, setOutputDevice
6970

7071

7172
#: Script category for text review commands.
@@ -4289,6 +4290,37 @@ def script_cycleParagraphStyle(self, gesture: "inputCore.InputGesture") -> None:
42894290
config.conf["documentNavigation"]["paragraphStyle"] = newFlag.name
42904291
ui.message(newFlag.displayString)
42914292

4293+
def cycleOutputAudioDevices(self, direction: int):
4294+
deviceNames = getOutputDeviceNames()
4295+
try:
4296+
index = deviceNames.index(config.conf["speech"]["outputDevice"])
4297+
newIndex = (index + direction) % len(deviceNames)
4298+
except ValueError:
4299+
newIndex = 0
4300+
device = deviceNames[newIndex]
4301+
setOutputDevice(device)
4302+
ui.message(device)
4303+
4304+
@script(
4305+
description=_(
4306+
# Translators: Describes the switch to next output device command.
4307+
"switches to the next output device"
4308+
),
4309+
category=SCRCAT_SPEECH,
4310+
)
4311+
def script_switchToNextOutputDevice(self, gesture: "inputCore.InputGesture") -> None:
4312+
self.cycleOutputAudioDevices(1)
4313+
4314+
@script(
4315+
description=_(
4316+
# Translators: Describes the switch to previous output device command.
4317+
"switches to the previous output device"
4318+
),
4319+
category=SCRCAT_SPEECH,
4320+
)
4321+
def script_switchToPreviousOutputDevice(self, gesture: "inputCore.InputGesture") -> None:
4322+
self.cycleOutputAudioDevices(-1)
4323+
42924324

42934325
#: The single global commands instance.
42944326
#: @type: L{GlobalCommands}

source/gui/settingsDialogs.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import updateCheck
6868
except RuntimeError:
6969
updateCheck = None
70+
from utils.synth import getOutputDeviceNames, setOutputDevice
7071
from . import nvdaControls
7172
from autoSettingsUtils.utils import UnsupportedConfigParameterError
7273
from autoSettingsUtils.autoSettings import AutoSettings
@@ -2577,11 +2578,7 @@ def makeSettings(self, settingsSizer: wx.BoxSizer) -> None:
25772578
# Translators: This is the label for the select output device combo in the synthesizer dialog.
25782579
# Examples of an output device are default soundcard, usb headphones, etc.
25792580
deviceListLabelText = _("Audio output &device:")
2580-
deviceNames = nvwave.getOutputDeviceNames()
2581-
# #11349: On Windows 10 20H1 and 20H2, Microsoft Sound Mapper returns an empty string.
2582-
if deviceNames[0] in ("", "Microsoft Sound Mapper"):
2583-
# Translators: name for default (Microsoft Sound Mapper) audio output device.
2584-
deviceNames[0] = _("Microsoft Sound Mapper")
2581+
deviceNames = getOutputDeviceNames()
25852582
self.deviceList = sHelper.addLabeledControl(deviceListLabelText, wx.Choice, choices=deviceNames)
25862583
self.bindHelpEvent("SelectSynthesizerOutputDevice", self.deviceList)
25872584
try:
@@ -2628,15 +2625,7 @@ def makeSettings(self, settingsSizer: wx.BoxSizer) -> None:
26282625
def onSave(self):
26292626
if config.conf["speech"]["outputDevice"] != self.deviceList.GetStringSelection():
26302627
# Synthesizer must be reload if output device changes
2631-
config.conf["speech"]["outputDevice"] = self.deviceList.GetStringSelection()
2632-
currentSynth = getSynth()
2633-
if not setSynth(currentSynth.name):
2634-
_synthWarningDialog(currentSynth.name)
2635-
2636-
# Reinitialize the tones module to update the audio device
2637-
import tones
2638-
tones.terminate()
2639-
tones.initialize()
2628+
setOutputDevice(self.deviceList.GetStringSelection())
26402629

26412630
config.conf["audio"]["soundVolumeFollowsVoice"] = self.soundVolFollowCheckBox.IsChecked()
26422631
config.conf["audio"]["soundVolume"] = self.soundVolSlider.GetValue()

source/utils/synth.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# Copyright (C) 2023 Beka Gozalishvili
3+
# This file may be used under the terms of the GNU General Public License, version 2 or later.
4+
# For more details see: https://www.gnu.org/licenses/gpl-2.0.html
5+
6+
7+
import config
8+
from gui.settingsDialogs import _synthWarningDialog
9+
import nvwave
10+
from synthDriverHandler import getSynth, setSynth
11+
import tones
12+
13+
14+
def getOutputDeviceNames():
15+
deviceNames = nvwave.getOutputDeviceNames()
16+
# #11349: On Windows 10 20H1 and 20H2, Microsoft Sound Mapper returns an empty string.
17+
if deviceNames[0] in ("", "Microsoft Sound Mapper"):
18+
# Translators: name for default (Microsoft Sound Mapper) audio output device.
19+
deviceNames[0] = _("Microsoft Sound Mapper")
20+
return deviceNames
21+
22+
23+
def setOutputDevice(device: str):
24+
config.conf["speech"]["outputDevice"] = device
25+
currentSynth = getSynth()
26+
if not setSynth(currentSynth.name):
27+
_synthWarningDialog(currentSynth.name)
28+
29+
# Reinitialize the tones module to update the audio device
30+
tones.terminate()
31+
tones.initialize()

user_docs/en/changes.t2t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ What's New in NVDA
88

99
== New Features ==
1010
- Added support for Bluetooth Low Energy HID Braille displays. (#15470)
11+
- Added unassigned gestures to to quickly cycle through output devices forward and backward. (#8801)
1112
-
1213

1314

user_docs/en/userGuide.t2t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,7 @@ The Audio category in the NVDA Settings dialog contains options that let you cha
17751775

17761776
==== Output device ====[SelectSynthesizerOutputDevice]
17771777
This option allows you to choose the audio device that NVDA should instruct the selected synthesizer to speak through.
1778+
To switch to the next or previous output device, pleas assign custom shortcuts from [Input Gestures dialog #InputGestures].
17781779

17791780
%kc:setting
17801781
==== Audio Ducking Mode ====[SelectSynthesizerDuckingMode]

0 commit comments

Comments
 (0)