Skip to content

Commit a318b80

Browse files
authored
Merge 468d002 into c00a14f
2 parents c00a14f + 468d002 commit a318b80

7 files changed

Lines changed: 95 additions & 18 deletions

File tree

source/config/configSpec.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#possible log levels are DEBUG, IO, DEBUGWARNING, INFO
2828
loggingLevel = string(default="INFO")
2929
showWelcomeDialogAtStartup = boolean(default=true)
30+
preventDisplayTurnOff = featureFlag(optionsEnum="BoolFlag", behaviorOfDefault="enabled")
3031
3132
# Speech settings
3233
[speech]

source/gui/settingsDialogs.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,19 @@ def makeSettings(self, settingsSizer):
983983
if globalVars.appArgs.secure:
984984
mirrorBox.Disable()
985985

986+
self.preventDisplayTurnOffCombo: nvdaControls.FeatureFlagCombo = (
987+
settingsSizerHelper.addLabeledControl(
988+
labelText=_(
989+
# Translators: This is a label for a combo-box in the general settings panel.
990+
"Prevent &display from turning off during say all or reading with braille",
991+
),
992+
wxCtrlClass=nvdaControls.FeatureFlagCombo,
993+
keyPath=["general", "preventDisplayTurnOff"],
994+
conf=config.conf,
995+
)
996+
)
997+
self.bindHelpEvent("PreventDisplayTurnOff", self.preventDisplayTurnOffCombo)
998+
986999
def onChangeMirrorURL(self, evt: wx.CommandEvent | wx.KeyEvent):
9871000
"""Show the dialog to change the update mirror URL, and refresh the dialog in response to the URL being changed."""
9881001
# Import late to avoid circular dependency.
@@ -1104,6 +1117,8 @@ def onSave(self):
11041117
updateCheck.terminate()
11051118
updateCheck.initialize()
11061119

1120+
self.preventDisplayTurnOffCombo.saveCurrentValueToConf()
1121+
11071122
def onPanelActivated(self):
11081123
if updateCheck:
11091124
self._updateCurrentMirrorURL()

source/inputCore.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# A part of NonVisual Desktop Access (NVDA)
22
# This file is covered by the GNU General Public License.
33
# See the file COPYING for more details.
4-
# Copyright (C) 2010-2023 NV Access Limited, Babbage B.V., Mozilla Corporation, Cyrille Bougot,
4+
# Copyright (C) 2010-2025 NV Access Limited, Babbage B.V., Mozilla Corporation, Cyrille Bougot,
55
# Leonard de Ruijter
66

77
"""Core framework for handling input from the user.
@@ -36,12 +36,12 @@
3636
import characterProcessing
3737
import config
3838
from fileUtils import FaultTolerantFile
39+
import systemUtils
3940
import watchdog
4041
from logHandler import log
4142
import globalVars
4243
import languageHandler
4344
import controlTypes
44-
import winKernel
4545
import extensionPoints
4646
from NVDAState import WritePaths
4747

@@ -577,7 +577,7 @@ def suppressCancelSpeech():
577577
)
578578

579579
if gesture.shouldPreventSystemIdle:
580-
winKernel.SetThreadExecutionState(winKernel.ES_SYSTEM_REQUIRED)
580+
systemUtils.preventSystemIdle()
581581

582582
if log.isEnabledFor(log.IO) and not gesture.isModifier:
583583
self._lastInputTime = time.time()

source/speech/sayAll.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# A part of NonVisual Desktop Access (NVDA)
22
# This file is covered by the GNU General Public License.
33
# See the file COPYING for more details.
4-
# Copyright (C) 2006-2024 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Babbage B.V., Bill Dengler,
5-
# Julien Cochuyt, Cyrille Bougot
4+
# Copyright (C) 2006-2025 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Babbage B.V., Bill Dengler,
5+
# Julien Cochuyt, Cyrille Bougot, Leonard de Ruijter
66

77
from abc import ABCMeta, abstractmethod
88
from enum import IntEnum
@@ -13,9 +13,9 @@
1313
import config
1414
import controlTypes
1515
import api
16+
import systemUtils
1617
import textInfos
1718
import queueHandler
18-
import winKernel
1919
from utils.security import objectBelowLockScreenAndWindowsIsLocked
2020

2121
from .commands import CallbackCommand, EndUtteranceCommand
@@ -137,12 +137,33 @@ def readText(
137137
log.debugWarning("Unable to make reader", exc_info=True)
138138
return
139139
self._getActiveSayAll = weakref.ref(reader)
140-
reader.nextLine()
140+
reader.next()
141141

142142

143-
class _ObjectsReader(garbageHandler.TrackedObject):
144-
def __init__(self, handler: _SayAllHandler, root: "NVDAObjects.NVDAObject"):
143+
class _Reader(garbageHandler.TrackedObject, metaclass=ABCMeta):
144+
"""Base class for readers in say all."""
145+
146+
def __init__(self, handler: _SayAllHandler):
145147
self.handler = handler
148+
systemUtils.preventSystemIdle(persistent=True)
149+
150+
@abstractmethod
151+
def next(self): ...
152+
153+
@abstractmethod
154+
def stop(self):
155+
"""Stops the reader."""
156+
systemUtils.resetThreadExecutionState()
157+
158+
def __del__(self):
159+
self.stop()
160+
161+
162+
class _ObjectsReader(_Reader):
163+
"""Manages continuous reading of objects."""
164+
165+
def __init__(self, handler: _SayAllHandler, root: "NVDAObjects.NVDAObject"):
166+
super().__init__(handler)
146167
self.walker = self.walk(root)
147168
self.prevObj = None
148169

@@ -165,7 +186,6 @@ def next(self):
165186
isFocus=self.handler.lastSayAllMode == CURSOR.CARET,
166187
):
167188
return
168-
winKernel.SetThreadExecutionState(winKernel.ES_SYSTEM_REQUIRED)
169189
# Move onto the next object.
170190
self.prevObj = obj = next(self.walker, None)
171191
if not obj:
@@ -179,10 +199,13 @@ def next(self):
179199
)
180200

181201
def stop(self):
202+
if not self.walker:
203+
return
182204
self.walker = None
205+
super().stop()
183206

184207

185-
class _TextReader(garbageHandler.TrackedObject, metaclass=ABCMeta):
208+
class _TextReader(_Reader):
186209
"""Manages continuous reading of text.
187210
This is intended for internal use only.
188211
@@ -207,7 +230,7 @@ class _TextReader(garbageHandler.TrackedObject, metaclass=ABCMeta):
207230

208231
def __init__(self, handler: _SayAllHandler):
209232
self.reader = None
210-
self.handler = handler
233+
super().__init__(handler)
211234
self.trigger = SayAllProfileTrigger()
212235
self.reader = self.getInitialTextInfo()
213236
# #10899: SayAll profile can't be activated earlier because they may not be anything to read
@@ -263,6 +286,9 @@ def collapseLineImpl(self) -> bool:
263286
self.finish()
264287
return False
265288

289+
def next(self):
290+
self.nextLine()
291+
266292
def nextLine(self):
267293
if not self.reader:
268294
log.debug("no self.reader")
@@ -339,7 +365,6 @@ def lineReached(self, obj, bookmark, state):
339365
state.updateObj()
340366
updater = obj.makeTextInfo(bookmark)
341367
self.updateCaret(updater)
342-
winKernel.SetThreadExecutionState(winKernel.ES_SYSTEM_REQUIRED)
343368
if self.numBufferedLines == 0:
344369
# This was the last line spoken, so move on.
345370
self.nextLine()
@@ -378,9 +403,7 @@ def stop(self):
378403
self.reader = None
379404
self.trigger.exit()
380405
self.trigger = None
381-
382-
def __del__(self):
383-
self.stop()
406+
super().stop()
384407

385408

386409
class _CaretTextReader(_TextReader):

source/systemUtils.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
# -*- coding: UTF-8 -*-
21
# A part of NonVisual Desktop Access (NVDA)
3-
# Copyright (C) 2020-2025 NV Access Limited, Łukasz Golonka, Luke Davis
2+
# Copyright (C) 2020-2025 NV Access Limited, Łukasz Golonka, Luke Davis, Leonard de Ruijter
43
# This file may be used under the terms of the GNU General Public License, version 2 or later.
54
# For more details see: https://www.gnu.org/licenses/gpl-2.0.html
65

@@ -246,3 +245,27 @@ def run(self):
246245
except Exception as e:
247246
self.threadExc = e
248247
log.debugWarning("task had errors", exc_info=True)
248+
249+
250+
def preventSystemIdle(preventDisplayTurnOff: bool | None = None, persistent: bool = False) -> None:
251+
"""
252+
Prevent the system from locking the screen or going to sleep.
253+
:param preventDisplayTurnOff: If `True`, keep the display awake as well.
254+
if `False`, only avoid system sleep.
255+
if `None`, the general setting "prevent display turn off" will be used.
256+
:param persistent: If `True`, the state will be maintained until calling :func:`resetThreadExecutionState` is called.
257+
"""
258+
if preventDisplayTurnOff is None:
259+
import config
260+
261+
preventDisplayTurnOff = bool(config.conf["general"]["preventDisplayTurnOff"])
262+
windll.kernel32.SetThreadExecutionState(
263+
winKernel.ES_SYSTEM_REQUIRED
264+
| (winKernel.ES_DISPLAY_REQUIRED if preventDisplayTurnOff else 0)
265+
| (winKernel.ES_CONTINUOUS if persistent else 0),
266+
)
267+
268+
269+
def resetThreadExecutionState() -> None:
270+
"""Reset the thread execution state to the default."""
271+
windll.kernel32.SetThreadExecutionState(winKernel.ES_CONTINUOUS)

user_docs/en/changes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ As a consequence, announcement of first line indent is now supported for LibreOf
3636
* In Word, the selection update is now reported when using Word commands to extend or reduce the selection (`f8` or `shift+f8`). (#3293, @CyrilleB79)
3737
* In Microsoft Word 16.0.18226 and higher or when using Word object model, NVDA will now report if a heading is collapsed in both speech and braille. (#17499)
3838
* NVDA is now able to report caret changes when pressing `alt+upArrow` or `alt+downArrow` gestures, for example in Visual Studio. (#17652, @LeonarddeR)
39+
* Added a general setting to prevent the display turning off during say all or reading with braille.
40+
This option is enabled by default, but can possibly result in shorter battery life.
41+
If you suspect this option is negatively impacting your battery life, you're advised to disable it. (#17649@LeonarddeR)
3942
* Rate boost is now supported when using Microsoft Speech API version 5 (SAPI5) and Microsoft Speech Platform voices, which supports up to 6X speed. (#17606, @gexgd0419)
4043

4144
### Changes

user_docs/en/userGuide.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,18 @@ If you wish to change the update mirror, press the "Change..." button to open th
18461846
Please note that when using an update mirror, the operator of the mirror has access to all [information sent with update checks](#GeneralSettingsCheckForUpdates).
18471847
Contact the operator of the update mirror for details of their data handling policies to ensure you are comfortable with the way your information will be handled before setting an update mirror.
18481848

1849+
##### Prevent display from turning off during say all or reading with braille {#PreventDisplayTurnOff}
1850+
1851+
This option ensures that the display stays on when reading with say all or with braille (e.g. when pressing scroll buttons).
1852+
This avoids the situation where the screen unexpectedly locks during a say all.
1853+
This option is enabled by default.
1854+
Consider disabling this option if you are suffering from a shorter battery life.
1855+
1856+
| . {.hideHeaderRow} |.|
1857+
|---|---|
1858+
|Options |Default (Enabled), Disabled, Enabled|
1859+
|Default |Enabled|
1860+
18491861
#### Speech Settings {#SpeechSettings}
18501862

18511863
<!-- KC:setting -->

0 commit comments

Comments
 (0)