@@ -1324,18 +1324,23 @@ def script_review_currentLine(self,gesture):
13241324 category = SCRCAT_TEXTREVIEW ,
13251325 gestures = ("kb:numpad9" , "kb(laptop):NVDA+downArrow" , "ts(text):flickDown" )
13261326 )
1327- def script_review_nextLine (self ,gesture ):
1328- info = api .getReviewPosition ().copy ()
1329- info .expand (textInfos .UNIT_LINE )
1330- info .collapse ()
1331- res = info .move (textInfos .UNIT_LINE ,1 )
1332- if res == 0 :
1327+ def script_review_nextLine (self , gesture ):
1328+ origInfo = api .getReviewPosition ().copy ()
1329+ origInfo .collapse ()
1330+ info = origInfo .copy ()
1331+ res = info .move (textInfos .UNIT_LINE , 1 )
1332+ newLine = info .copy ()
1333+ newLine .expand (textInfos .UNIT_LINE )
1334+ # #12808: Some implementations of move forward by one line may succeed one more time than expected,
1335+ # landing on the exclusive end of the document.
1336+ # Therefore, verify that expanding after the move does result in being on a new line,
1337+ # i.e. the new line starts after the original review cursor position.
1338+ if res == 0 or newLine .start <= origInfo .start :
13331339 # Translators: a message reported when review cursor is at the bottom line of the current navigator object.
13341340 ui .reviewMessage (_ ("Bottom" ))
13351341 else :
13361342 api .setReviewPosition (info )
1337- info .expand (textInfos .UNIT_LINE )
1338- speech .speakTextInfo (info , unit = textInfos .UNIT_LINE , reason = controlTypes .OutputReason .CARET )
1343+ speech .speakTextInfo (newLine , unit = textInfos .UNIT_LINE , reason = controlTypes .OutputReason .CARET )
13391344
13401345 @script (
13411346 # Translators: Input help mode message for move review cursor to bottom line command.
@@ -1395,18 +1400,23 @@ def script_review_currentWord(self,gesture):
13951400 category = SCRCAT_TEXTREVIEW ,
13961401 gestures = ("kb:numpad6" , "kb(laptop):NVDA+control+rightArrow" , "ts(text):2finger_flickRight" )
13971402 )
1398- def script_review_nextWord (self ,gesture ):
1399- info = api .getReviewPosition ().copy ()
1400- info .expand (textInfos .UNIT_WORD )
1401- info .collapse ()
1402- res = info .move (textInfos .UNIT_WORD ,1 )
1403- if res == 0 :
1403+ def script_review_nextWord (self , gesture ):
1404+ origInfo = api .getReviewPosition ().copy ()
1405+ origInfo .collapse ()
1406+ info = origInfo .copy ()
1407+ res = info .move (textInfos .UNIT_WORD , 1 )
1408+ newWord = info .copy ()
1409+ newWord .expand (textInfos .UNIT_WORD )
1410+ # #12808: Some implementations of move forward by one word may succeed one more time than expected,
1411+ # landing on the exclusive end of the document.
1412+ # Therefore, verify that expanding after the move does result in being on a new word,
1413+ # i.e. the new word starts after the original review cursor position.
1414+ if res == 0 or newWord .start <= origInfo .start :
14041415 # Translators: a message reported when review cursor is at the bottom line of the current navigator object.
14051416 ui .reviewMessage (_ ("Bottom" ))
14061417 else :
14071418 api .setReviewPosition (info )
1408- info .expand (textInfos .UNIT_WORD )
1409- speech .speakTextInfo (info , reason = controlTypes .OutputReason .CARET , unit = textInfos .UNIT_WORD )
1419+ speech .speakTextInfo (newWord , unit = textInfos .UNIT_WORD , reason = controlTypes .OutputReason .CARET )
14101420
14111421 @script (
14121422 description = _ (
0 commit comments