Skip to content

Commit cb7b9b2

Browse files
authored
Merge 75197fa into aead5ce
2 parents aead5ce + 75197fa commit cb7b9b2

File tree

14 files changed

+133
-48
lines changed

14 files changed

+133
-48
lines changed

nvdaHelper/interfaces/nvdaControllerInternal/nvdaControllerInternal.acf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
1717
]
1818
interface NvdaControllerInternal {
1919
[fault_status,comm_status] requestRegistration();
20+
[fault_status,comm_status] reportLiveRegion();
2021
[fault_status,comm_status] inputLangChangeNotify();
2122
[fault_status,comm_status] typedCharacterNotify();
2223
[fault_status,comm_status] displayModelTextChangeNotify();

nvdaHelper/interfaces/nvdaControllerInternal/nvdaControllerInternal.idl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2010 NVDA contributers.
4+
Copyright 2006-2018 NV Access Limited, rui Batista, Google LLC.
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -15,7 +15,7 @@ http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
1515
cpp_quote("/*")
1616
cpp_quote("This file is a part of the NVDA project.")
1717
cpp_quote("URL: http://www.nvda-project.org/")
18-
cpp_quote("Copyright 2006-2010 NVDA contributers.")
18+
cpp_quote("Copyright 2006-2018 NV Access Limited, rui Batista, Google LLC.")
1919
cpp_quote("This program is free software: you can redistribute it and/or modify")
2020
cpp_quote("it under the terms of the GNU General Public License version 2.0, as published by")
2121
cpp_quote("the Free Software Foundation.")
@@ -37,6 +37,13 @@ interface NvdaControllerInternal {
3737

3838
error_status_t __stdcall requestRegistration([in,string] const wchar_t* uuidString);
3939

40+
/**
41+
* Notifies NVDA that a live region was updated.
42+
* @param text the text to report for the live region.
43+
* @param level The level of live region, I.E. "polite"
44+
*/
45+
error_status_t __stdcall reportLiveRegion([in,string] const wchar_t* text, [in,string] const wchar_t* level);
46+
4047
/**
4148
* Notifies NVDA that the keyboard layout has changed for this thread.
4249
* @param threadID the thread the layout change occured in

nvdaHelper/local/nvdaControllerInternal.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2010 NVDA contributers.
4+
Copyright 2006-2018 NV Access Limited, rui Batista, Google LLC.
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -19,6 +19,11 @@ error_status_t __stdcall nvdaControllerInternal_requestRegistration(const wchar_
1919
return _nvdaControllerInternal_requestRegistration(uuidString);
2020
}
2121

22+
error_status_t(__stdcall *_nvdaControllerInternal_reportLiveRegion)(const wchar_t*, const wchar_t*);
23+
error_status_t __stdcall nvdaControllerInternal_reportLiveRegion(const wchar_t* text, const wchar_t* politeness) {
24+
return _nvdaControllerInternal_reportLiveRegion(text, politeness);
25+
}
26+
2227
error_status_t(__stdcall *_nvdaControllerInternal_inputLangChangeNotify)(const long, const unsigned long, const wchar_t*);
2328
error_status_t __stdcall nvdaControllerInternal_inputLangChangeNotify(const long threadID, const unsigned long hkl, const wchar_t* layoutString) {
2429
return _nvdaControllerInternal_inputLangChangeNotify(threadID,hkl,layoutString);

nvdaHelper/local/nvdaHelperLocal.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ EXPORTS
3333
VBuf_locateTextFieldNodeAtOffset
3434
VBuf_setSelectionOffsets
3535
_nvdaControllerInternal_requestRegistration
36+
_nvdaControllerInternal_reportLiveRegion
3637
_nvdaControllerInternal_displayModelTextChangeNotify
3738
_nvdaControllerInternal_inputLangChangeNotify
3839
_nvdaControllerInternal_inputCompositionUpdate

nvdaHelper/remote/ia2LiveRegions.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2010 NVDA contributers.
4+
Copyright 2006-2020 NV Access Limited, Google LLC, Leonard de Ruijter
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -18,7 +18,7 @@ This license can be found at:
1818
#include <windows.h>
1919
#include <atlcomcli.h>
2020
#include <ia2.h>
21-
#include "nvdaController.h"
21+
#include "nvdaControllerInternal.h"
2222
#include <common/ia2utils.h>
2323
#include "nvdaHelperRemote.h"
2424

@@ -308,6 +308,7 @@ void CALLBACK winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, l
308308
pacc2->Release();
309309
return;
310310
}
311+
wstring politeness = i->second;
311312
i=attribsMap.find(L"container-busy");
312313
bool busy=(i!=attribsMap.end()&&i->second.compare(L"true")==0);
313314
if(busy) {
@@ -410,7 +411,9 @@ void CALLBACK winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, l
410411
gotText=getTextFromIAccessible(textBuf,pacc2,true,allowAdditions,allowText);
411412
}
412413
pacc2->Release();
413-
if(gotText&&!textBuf.empty()) nvdaController_speakText(textBuf.c_str());
414+
if (gotText && !textBuf.empty()) {
415+
nvdaControllerInternal_reportLiveRegion(textBuf.c_str(), politeness.c_str());
416+
}
414417
}
415418

416419
void ia2LiveRegions_inProcess_initialize() {

nvdaHelper/remote/nvdaHelperRemote.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ EXPORTS
1212
logMessage
1313
NVDALogCrtReportHook
1414
nvdaInProcUtils_winword_expandToLine
15+
nvdaControllerInternal_reportLiveRegion
1516
nvdaControllerInternal_logMessage
1617
nvdaControllerInternal_vbufChangeNotify
1718
nvdaControllerInternal_installAddonPackageFromPath

nvdaHelper/vbufBackends/mshtml/node.cpp

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2015 NVDA contributers.
4+
Copyright 2006-2020 NV Access Limited, Google LLC, Leonard de Ruijter
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -20,7 +20,7 @@ This license can be found at:
2020
#include <mshtmdid.h>
2121
#include <common/log.h>
2222
#include "mshtml.h"
23-
#include <remote/nvdaController.h>
23+
#include <remote/nvdaControllerInternal.h>
2424
#include <common/xml.h>
2525
#include "node.h"
2626

@@ -124,7 +124,15 @@ class CDispatchChangeSink : public IDispatch {
124124
if(dispIdMember==DISPID_EVMETH_ONPROPERTYCHANGE||dispIdMember==DISPID_EVMETH_ONLOAD) {
125125
this->storageNode->backend->invalidateSubtree(this->storageNode);
126126
// Force the update to happen with no delay if we happen to be in a live region
127-
if(this->storageNode->ariaLiveNode&&this->storageNode->ariaLiveNode!=this->storageNode&&!this->storageNode->ariaLiveIsBusy&&(this->storageNode->ariaLiveIsTextRelevant||this->storageNode->ariaLiveIsAdditionsRelevant)) {
127+
if (
128+
this->storageNode->ariaLiveNode
129+
&& this->storageNode->ariaLiveNode != this->storageNode
130+
&& !this->storageNode->ariaLiveIsBusy
131+
&& (
132+
this->storageNode->ariaLiveIsTextRelevant
133+
|| this->storageNode->ariaLiveIsAdditionsRelevant
134+
)
135+
) {
128136
this->storageNode->backend->forceUpdate();
129137
}
130138
return S_OK;
@@ -266,7 +274,15 @@ class CHTMLChangeSink : public IHTMLChangeSink {
266274
this->storageNode->backend->invalidateSubtree(invalidNode);
267275
MshtmlVBufStorage_controlFieldNode_t* invalidMshtmlNode=(MshtmlVBufStorage_controlFieldNode_t*)invalidNode;
268276
// Force the update to happen with no delay if we happen to be in a live region
269-
if(invalidMshtmlNode->ariaLiveNode&&invalidMshtmlNode->ariaLiveNode!=invalidMshtmlNode&&!invalidMshtmlNode->ariaLiveIsBusy&&(invalidMshtmlNode->ariaLiveIsTextRelevant||invalidMshtmlNode->ariaLiveIsAdditionsRelevant)) {
277+
if (
278+
invalidMshtmlNode->ariaLiveNode
279+
&& invalidMshtmlNode->ariaLiveNode != invalidMshtmlNode
280+
&& !invalidMshtmlNode->ariaLiveIsBusy
281+
&& (
282+
invalidMshtmlNode->ariaLiveIsTextRelevant
283+
|| invalidMshtmlNode->ariaLiveIsAdditionsRelevant
284+
)
285+
) {
270286
this->storageNode->backend->forceUpdate();
271287
}
272288
}
@@ -353,11 +369,18 @@ MshtmlVBufStorage_controlFieldNode_t::~MshtmlVBufStorage_controlFieldNode_t() {
353369
}
354370

355371
void MshtmlVBufStorage_controlFieldNode_t::preProcessLiveRegion(const MshtmlVBufStorage_controlFieldNode_t* parent, const std::map<std::wstring,std::wstring>& attribsMap) {
356-
auto i=attribsMap.find(L"HTMLAttrib::aria-live");
372+
auto i=attribsMap.find(L"HTMLAttrib::aria-live");
357373
if(i!=attribsMap.end()&&!i->second.empty()) {
358-
this->ariaLiveNode=((i->second.compare(L"polite")==0)||(i->second.compare(L"assertive")==0))?this:NULL;
374+
bool isAriaLiveEnabled = i->second == L"polite" || i->second == L"assertive";
375+
this->ariaLiveNode = isAriaLiveEnabled ? this : nullptr;
376+
this->ariaLivePoliteness = i->second;
359377
} else {
360-
this->ariaLiveNode=parent?parent->ariaLiveNode:NULL;
378+
this->ariaLiveNode = parent? parent->ariaLiveNode : nullptr;
379+
if (this->ariaLiveNode) {
380+
this->ariaLivePoliteness = this->ariaLiveNode->ariaLivePoliteness;
381+
} else {
382+
this->ariaLivePoliteness = nullptr;
383+
}
361384
}
362385
i=attribsMap.find(L"HTMLAttrib::aria-relevant");
363386
if(i!=attribsMap.end()&&!i->second.empty()) {
@@ -384,13 +407,13 @@ void MshtmlVBufStorage_controlFieldNode_t::preProcessLiveRegion(const MshtmlVBuf
384407
} else {
385408
this->ariaLiveAtomicNode=parent?parent->ariaLiveAtomicNode:NULL;
386409
}
387-
//LOG_INFO(L"preProcessLiveRegion: ariaLiveNode "<<ariaLiveNode<<L", ariaLiveIsTextRelevant "<<ariaLiveIsTextRelevant<<L", ariaLiveIsAdditionsRelevant "<<ariaLiveIsAdditionsRelevant<<L", ariaLiveIsBusy "<<ariaLiveIsBusy<<L", ariaLiveAtomicNode "<<ariaLiveAtomicNode);
410+
LOG_DEBUG(L"preProcessLiveRegion: ariaLiveNode "<<ariaLiveNode<<L", ariaLiveIsTextRelevant "<<ariaLiveIsTextRelevant<<L", ariaLiveIsAdditionsRelevant "<<ariaLiveIsAdditionsRelevant<<L", ariaLiveIsBusy "<<ariaLiveIsBusy<<L", ariaLiveAtomicNode "<<ariaLiveAtomicNode);
388411
}
389412

390-
void MshtmlVBufStorage_controlFieldNode_t::reportLiveText(wstring& text) {
413+
void MshtmlVBufStorage_controlFieldNode_t::reportLiveText(wstring& text, wstring& politeness) {
391414
for(auto c: text) {
392415
if(!iswspace(c)) {
393-
nvdaController_speakText(text.c_str());
416+
nvdaControllerInternal_reportLiveRegion(text.c_str(), politeness.c_str());
394417
break;
395418
}
396419
}
@@ -399,21 +422,23 @@ void MshtmlVBufStorage_controlFieldNode_t::reportLiveText(wstring& text) {
399422
bool isNodeInLiveRegion(VBufStorage_fieldNode_t* node) {
400423
if(!node) return false;
401424
if(node->getFirstChild()) {
402-
return ((MshtmlVBufStorage_controlFieldNode_t*)node)->ariaLiveNode!=NULL;
425+
return ((MshtmlVBufStorage_controlFieldNode_t*)node)->ariaLiveNode != nullptr;
403426
}
404427
return true;
405428
}
406429

407430
void MshtmlVBufStorage_controlFieldNode_t::reportLiveAddition() {
408431
wstring text; //=(this->ariaLiveAtomicNode==this)?L"atomic: ":L"additions: ";
409432
this->getTextInRange(0,this->getLength(),text,false,isNodeInLiveRegion);
410-
this->reportLiveText(text);
433+
this->reportLiveText(text, this->ariaLivePoliteness);
411434
}
412435

413436
void MshtmlVBufStorage_controlFieldNode_t::postProcessLiveRegion(VBufStorage_controlFieldNode_t* oldNode, set<VBufStorage_controlFieldNode_t*>& atomicNodes) {
414-
//LOG_INFO(L"preProcessLiveRegion: ariaLiveNode "<<ariaLiveNode<<L", ariaLiveIsTextRelevant "<<ariaLiveIsTextRelevant<<L", ariaLiveIsAdditionsRelevant "<<ariaLiveIsAdditionsRelevant<<L", ariaLiveIsBusy "<<ariaLiveIsBusy<<L", ariaLiveAtomicNode "<<ariaLiveAtomicNode);
415-
if(!this->ariaLiveNode||this->ariaLiveIsBusy) return;
416-
bool reportNode=!oldNode&&this->ariaLiveIsAdditionsRelevant&&this->ariaLiveNode!=this;
437+
LOG_DEBUG(L"postProcessLiveRegion: ariaLiveNode "<<ariaLiveNode<<L", ariaLiveIsTextRelevant "<<ariaLiveIsTextRelevant<<L", ariaLiveIsAdditionsRelevant "<<ariaLiveIsAdditionsRelevant<<L", ariaLiveIsBusy "<<ariaLiveIsBusy<<L", ariaLiveAtomicNode "<<ariaLiveAtomicNode);
438+
if (!this->ariaLiveNode || this->ariaLiveIsBusy) {
439+
return;
440+
}
441+
bool reportNode=!oldNode && this->ariaLiveIsAdditionsRelevant && this->ariaLiveNode != this;
417442
wstring newChildrenText;
418443
if(!reportNode&&oldNode&&ariaLiveIsTextRelevant) {
419444
// Find the first new text child
@@ -469,7 +494,7 @@ void MshtmlVBufStorage_controlFieldNode_t::postProcessLiveRegion(VBufStorage_con
469494
} else if(reportNode) {
470495
this->reportLiveAddition();
471496
} else if(!newChildrenText.empty()) {
472-
this->reportLiveText(newChildrenText);
497+
this->reportLiveText(newChildrenText, this->ariaLivePoliteness);
473498
}
474499
}
475500

nvdaHelper/vbufBackends/mshtml/node.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This file is a part of the NVDA project.
33
URL: http://www.nvda-project.org/
4-
Copyright 2006-2015 NVDA contributers.
4+
Copyright 2006-2020 NV Access Limited, Google LLC, Leonard de Ruijter
55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License version 2.0, as published by
77
the Free Software Foundation.
@@ -31,13 +31,14 @@ class MshtmlVBufStorage_controlFieldNode_t : public VBufStorage_controlFieldNode
3131
IHTMLChangeSink* pHTMLChangeSink;
3232
DWORD HTMLChangeSinkCookey;
3333
std::wstring language;
34-
VBufStorage_controlFieldNode_t* ariaLiveNode;
34+
MshtmlVBufStorage_controlFieldNode_t* ariaLiveNode;
35+
std::wstring ariaLivePoliteness;
3536
unsigned int formatState;
3637
bool ariaLiveIsTextRelevant;
3738
bool ariaLiveIsAdditionsRelevant;
3839
bool ariaLiveIsBusy;
3940
VBufStorage_controlFieldNode_t* ariaLiveAtomicNode;
40-
void reportLiveText(std::wstring& text);
41+
void reportLiveText(std::wstring& text, std::wstring& politeness);
4142
void reportLiveAddition();
4243
void preProcessLiveRegion(const MshtmlVBufStorage_controlFieldNode_t* parent, const std::map<std::wstring,std::wstring>& attribsMap);
4344
void postProcessLiveRegion(VBufStorage_controlFieldNode_t* oldNode, std::set<VBufStorage_controlFieldNode_t*>& atomicNodes);

source/NVDAHelper.py

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
#NVDAHelper.py
2-
#A part of NonVisual Desktop Access (NVDA)
3-
#Copyright (C) 2008-2019 NV Access Limited, Peter Vagner, Davy Kager, Mozilla Corporation
4-
#This file is covered by the GNU General Public License.
5-
#See the file COPYING for more details.
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# Copyright (C) 2008-2020 NV Access Limited, Peter Vagner, Davy Kager, Mozilla Corporation, Google LLC,
3+
# Leonard de Ruijter
4+
# This file is covered by the GNU General Public License.
5+
# See the file COPYING for more details.
66

77
import os
88
import sys
@@ -16,6 +16,7 @@
1616
from ctypes import (
1717
WINFUNCTYPE,
1818
c_long,
19+
c_wchar_p,
1920
c_wchar,
2021
windll,
2122
)
@@ -120,6 +121,39 @@ def nvdaControllerInternal_requestRegistration(uuidString):
120121
queueHandler.queueFunction(queueHandler.eventQueue,appModuleHandler.update,pid,helperLocalBindingHandle=bindingHandle,inprocRegistrationHandle=registrationHandle)
121122
return 0
122123

124+
125+
@WINFUNCTYPE(c_long, c_wchar_p, c_wchar_p)
126+
def nvdaControllerInternal_reportLiveRegion(text: str, politeness: str):
127+
assert(isinstance(text, str), "Text isn't a string")
128+
assert isinstance(politeness, str), "Politeness isn't a string"
129+
if not config.conf["presentation"]["reportDynamicContentChanges"]:
130+
return -1
131+
focus = api.getFocusObject()
132+
if focus.sleepMode == focus.SLEEP_FULL:
133+
return -1
134+
import queueHandler
135+
import speech
136+
from aria import AriaLivePoliteness
137+
from speech.priorities import Spri
138+
try:
139+
politenessValue = AriaLivePoliteness(politeness.lower())
140+
except ValueError:
141+
log.error(f"nvdaControllerInternal_reportLiveRegion got unknown politeness of {politeness}", exc_info=True)
142+
return -1
143+
if politenessValue == AriaLivePoliteness.OFF:
144+
log.error(f"nvdaControllerInternal_reportLiveRegion got unexpected politeness of {politeness}")
145+
queueHandler.queueFunction(
146+
queueHandler.eventQueue,
147+
speech.speakText,
148+
text,
149+
priority=(
150+
Spri.NEXT
151+
if politenessValue == AriaLivePoliteness.ASSERTIVE
152+
else Spri.NORMAL
153+
)
154+
)
155+
return 0
156+
123157
@WINFUNCTYPE(c_long,c_long,c_long,c_long,c_long,c_long)
124158
def nvdaControllerInternal_displayModelTextChangeNotify(hwnd, left, top, right, bottom):
125159
import displayModel
@@ -482,6 +516,7 @@ def initialize():
482516
("nvdaController_cancelSpeech",nvdaController_cancelSpeech),
483517
("nvdaController_brailleMessage",nvdaController_brailleMessage),
484518
("nvdaControllerInternal_requestRegistration",nvdaControllerInternal_requestRegistration),
519+
("nvdaControllerInternal_reportLiveRegion", nvdaControllerInternal_reportLiveRegion),
485520
("nvdaControllerInternal_inputLangChangeNotify",nvdaControllerInternal_inputLangChangeNotify),
486521
("nvdaControllerInternal_typedCharacterNotify",nvdaControllerInternal_typedCharacterNotify),
487522
("nvdaControllerInternal_displayModelTextChangeNotify",nvdaControllerInternal_displayModelTextChangeNotify),

source/NVDAObjects/IAccessible/MSHTML.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,10 +1039,11 @@ def _get_language(self):
10391039

10401040
def _get_liveRegionPoliteness(self) -> aria.AriaLivePoliteness:
10411041
politeness = self.HTMLAttributes["aria-live"] or "off"
1042-
return next(
1043-
(v for v in aria.AriaLivePoliteness if v._name_.lower() == politeness.lower()),
1044-
aria.AriaLivePoliteness.OFF
1045-
)
1042+
try:
1043+
return aria.AriaLivePoliteness(politeness.lower())
1044+
except ValueError:
1045+
log.error(f"Unknown live politeness of {politeness}", exc_info=True)
1046+
super().liveRegionPoliteness
10461047

10471048
def event_liveRegionChange(self):
10481049
# MSHTML live regions are currently handled with custom code in-process

0 commit comments

Comments
 (0)