Skip to content

Commit d136d6d

Browse files
authored
Merge c141b41 into fa89f05
2 parents fa89f05 + c141b41 commit d136d6d

2 files changed

Lines changed: 31 additions & 28 deletions

File tree

source/editableText.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ class EditableText(TextContainerObject,ScriptableObject):
4747
announceEntireNewLine=False
4848

4949
#: The minimum amount of time that should elapse before checking if the word under the caret has changed
50-
_hasCaretMoved_minWordTimeoutMs=30
50+
_hasCaretMoved_minWordTimeoutSec = 0.03
5151

5252
#: The maximum amount of time that may elapse before we no longer rely on caret events to detect movement.
53-
_useEvents_maxTimeoutMs = 10
53+
_useEvents_maxTimeoutSec = 0.01
5454

5555
_caretMovementTimeoutMultiplier = 1
5656

@@ -71,22 +71,18 @@ def _hasCaretMoved(self, bookmark, retryInterval=0.01, timeout=None, origWord=No
7171
@rtype: tuple
7272
"""
7373
if timeout is None:
74-
timeoutMs = config.conf["editableText"]["caretMoveTimeoutMs"]
75-
else:
76-
# This function's arguments are in seconds, but we want ms.
77-
timeoutMs = timeout * 1000
78-
timeoutMs *= self._caretMovementTimeoutMultiplier
79-
# time.sleep accepts seconds, so retryInterval is in seconds.
80-
# Convert to integer ms to avoid floating point precision errors when adding to elapsed.
81-
retryMs = int(retryInterval * 1000)
74+
timeout = config.conf["editableText"]["caretMoveTimeoutMs"] / 1000
75+
timeout *= self._caretMovementTimeoutMultiplier
76+
start = time.time()
8277
elapsed = 0
8378
newInfo=None
79+
retries = 0
8480
while True:
8581
if isScriptWaiting():
8682
return (False,None)
8783
api.processPendingEvents(processEventQueue=False)
8884
if eventHandler.isPendingEvents("gainFocus"):
89-
log.debug("Focus event. Elapsed: %d ms" % elapsed)
85+
log.debug("Focus event. Elapsed %g sec" % elapsed)
9086
return (True,None)
9187
# If the focus changes after this point, fetching the caret may fail,
9288
# but we still want to stay in this loop.
@@ -97,14 +93,17 @@ def _hasCaretMoved(self, bookmark, retryInterval=0.01, timeout=None, origWord=No
9793
else:
9894
# Caret events are unreliable in some controls.
9995
# Only use them if we consider them safe to rely on for a particular control,
100-
# and only if they arrive within C{_useEvents_maxTimeoutMs} mili seconds
96+
# and only if they arrive within C{_useEvents_maxTimeoutSec} seconds
10197
# after causing the event to occur.
10298
if (
103-
elapsed <= self._useEvents_maxTimeoutMs and
99+
elapsed <= self._useEvents_maxTimeoutSec and
104100
self.caretMovementDetectionUsesEvents and
105101
(eventHandler.isPendingEvents("caret") or eventHandler.isPendingEvents("textChange"))
106102
):
107-
log.debug("Caret move detected using event. Elapsed: %d ms" % elapsed)
103+
log.debug(
104+
"Caret move detected using event. Elapsed %g sec, retries %d"
105+
% (elapsed, retries)
106+
)
108107
return (True,newInfo)
109108
# Try to detect with bookmarks.
110109
newBookmark = None
@@ -114,9 +113,12 @@ def _hasCaretMoved(self, bookmark, retryInterval=0.01, timeout=None, origWord=No
114113
except (RuntimeError,NotImplementedError):
115114
pass
116115
if newBookmark and newBookmark!=bookmark:
117-
log.debug("Caret move detected using bookmarks. Elapsed: %d ms" % elapsed)
116+
log.debug(
117+
"Caret move detected using bookmarks. Elapsed %g sec, retries %d"
118+
% (elapsed, retries)
119+
)
118120
return (True, newInfo)
119-
if origWord is not None and newInfo and elapsed >= self._hasCaretMoved_minWordTimeoutMs:
121+
if origWord is not None and newInfo and elapsed >= self._hasCaretMoved_minWordTimeoutSec:
120122
# When pressing delete, bookmarks might not be enough to detect caret movement.
121123
# Therefore try detecting if the word under the caret has changed, such as when pressing delete.
122124
# some editors such as Mozilla Gecko can have text and units that get out of sync with eachother while a character is being deleted.
@@ -125,13 +127,21 @@ def _hasCaretMoved(self, bookmark, retryInterval=0.01, timeout=None, origWord=No
125127
wordInfo.expand(textInfos.UNIT_WORD)
126128
word = wordInfo.text
127129
if word != origWord:
128-
log.debug("Word at caret changed. Elapsed: %d ms" % elapsed)
130+
log.debug("Word at caret changed. Elapsed: %g sec" % elapsed)
129131
return (True, newInfo)
130-
if elapsed >= timeoutMs:
132+
elapsed = time.time() - start
133+
if elapsed >= timeout:
131134
break
132-
time.sleep(retryInterval)
133-
elapsed += retryMs
134-
log.debug("Caret didn't move before timeout. Elapsed: %d ms" % elapsed)
135+
# We spin the first few tries, as sleep is not accurate for tiny periods
136+
# and we might end up sleeping longer than we need to. Spinning improves
137+
# responsiveness in the case that the app responds fairly quickly.
138+
if retries > 2:
139+
# Don't spin too long, though. If we get to this point, the app is
140+
# probably taking a while to respond, so super fast response is
141+
# already lost.
142+
time.sleep(retryInterval)
143+
retries += 1
144+
log.debug("Caret didn't move before timeout. Elapsed: %g sec" % elapsed)
135145
return (False,newInfo)
136146

137147
def _caretScriptPostMovedHelper(self, speakUnit, gesture, info=None):

source/keyboardHandler.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -586,13 +586,6 @@ def send(self):
586586
for vk, scan, ext in reversed(keys):
587587
winUser.keybd_event(vk, scan, ext + 2, 0)
588588

589-
if not queueHandler.isPendingItems(queueHandler.eventQueue):
590-
# We want to guarantee that by the time that
591-
# this function returns,the keyboard input generated
592-
# has been injected and NVDA has received and processed it.
593-
time.sleep(0.01)
594-
wx.Yield()
595-
596589
@classmethod
597590
def fromName(cls, name):
598591
"""Create an instance given a key name.

0 commit comments

Comments
 (0)