Hi Noelia, I've merged latest master branch code from NV Access server, so you can work from latest revisions. Cheers, Joseph -----Original Message----- From: nvda-addons-commits-bounce@xxxxxxxxxxxxx [mailto:nvda-addons-commits-bounce@xxxxxxxxxxxxx] On Behalf Of commits-noreply@xxxxxxxxxxxxx Sent: Sunday, October 26, 2014 3:28 PM To: nvda-addons-commits@xxxxxxxxxxxxx Subject: commit/nvda: josephsl: Merge branch 'master' into t4354 1 new commit in nvda: https://bitbucket.org/nvdaaddonteam/nvda/commits/ddd4982e4dfe/ Changeset: ddd4982e4dfe Branch: t4354 User: josephsl Date: 2014-10-26 22:27:58+00:00 Summary: Merge branch 'master' into t4354 Affected #: 34 files diff --git a/contributors.txt b/contributors.txt index 615b079..51d90a1 100644 --- a/contributors.txt +++ b/contributors.txt @@ -146,3 +146,6 @@ Dr. Mireia Ribera Ruben Alcaraz Nikos Demetriou Daniel Johansson +Manish Agrawal +Aaron Cannon +derek riemer diff --git a/include/liblouis b/include/liblouis index 1e1e758..5f9c03f 160000 --- a/include/liblouis +++ b/include/liblouis @@ -1 +1 @@ -Subproject commit 1e1e7587cfbc263b351644e52fdaf2684103d6c8 +Subproject commit 5f9c03f2a3478561deb6ae4798175094be8a26c2 diff --git a/include/minhook b/include/minhook index e21b54a..ed5b511 160000 --- a/include/minhook +++ b/include/minhook @@ -1 +1 @@ -Subproject commit e21b54a88190ca477ed73fb7ab24203dfaef28a0 +Subproject commit ed5b5119afb4127dd66905e2899c3265d8040aea diff --git a/miscDeps b/miscDeps index 6fbd449..eee6560 160000 --- a/miscDeps +++ b/miscDeps @@ -1 +1 @@ -Subproject commit 6fbd44904c8debe4cf5a73e62a91ac8a00d1860c +Subproject commit eee6560e4ae4de5455e94dfb99ba596f36bb21f5 diff --git a/nvdaHelper/archBuild_sconscript b/nvdaHelper/archBuild_sconscript index 1c63dcc..fd45e07 100644 --- a/nvdaHelper/archBuild_sconscript +++ b/nvdaHelper/archBuild_sconscript @@ -26,6 +26,7 @@ Import( TARGET_ARCH=env['TARGET_ARCH'] debug=env['nvdaHelperDebugFlags'] release=env['release'] +signExec=env['signExec'] if env['certFile'] else None #Some defines and includes for the environment env.Append(CPPDEFINES=['UNICODE','_CRT_SECURE_NO_DEPRECATE',('LOGLEVEL','${nvdaHelperLogLevel}'),('_WIN32_WINNT','_WIN32_WINNT_WINXP')]) @@ -66,6 +67,8 @@ if TARGET_ARCH=='x86': ia2RPCStubs=env.SConscript('ia2_sconscript') Export('ia2RPCStubs') +if signExec: + env.AddPostAction(ia2RPCStubs[0],[signExec]) env.Install(libInstallDir,ia2RPCStubs[0]) #proxy dll if TARGET_ARCH=='x86': env.Install(sourceTypelibDir,ia2RPCStubs[1]) #typelib @@ -73,43 +76,65 @@ if TARGET_ARCH=='x86': if TARGET_ARCH=='x86': localLib=env.SConscript('local/sconscript') Export('localLib') + if signExec: + env.AddPostAction(localLib[0],[signExec]) env.Install(libInstallDir,localLib) clientLib=env.SConscript('client/sconscript') Export('clientLib') +if signExec: + env.AddPostAction(clientLib[0],[signExec]) env.Install(clientInstallDir,clientLib) minHookLib=env.SConscript('minHook/sconscript') Export('minHookLib') +if signExec: + env.AddPostAction(minHookLib[0],[signExec]) env.Install(libInstallDir,minHookLib) remoteLib=env.SConscript('remote/sconscript') Export('remoteLib') +if signExec: + env.AddPostAction(remoteLib[0],[signExec]) env.Install(libInstallDir,remoteLib) if TARGET_ARCH=='x86_64': remoteLoaderProgram=env.SConscript('remoteLoader/sconscript') + if signExec: + env.AddPostAction(remoteLoaderProgram,[signExec]) env.Install(libInstallDir,remoteLoaderProgram) vbufBaseStaticLib=env.SConscript('vbufBase/sconscript') Export('vbufBaseStaticLib') adobeAcrobatVBufBackend=env.SConscript('vbufBackends/adobeAcrobat/sconscript') +if signExec: + env.AddPostAction(adobeAcrobatVBufBackend[0],[signExec]) env.Install(libInstallDir,adobeAcrobatVBufBackend) adobeFlashVBufBackend=env.SConscript('vbufBackends/adobeFlash/sconscript') +if signExec: + env.AddPostAction(adobeFlashVBufBackend[0],[signExec]) env.Install(libInstallDir,adobeFlashVBufBackend) lotusNotesRichTextVBufBackend=env.SConscript('vbufBackends/lotusNotesRichText/sconscript') +if signExec: + env.AddPostAction(lotusNotesRichTextVBufBackend[0],[signExec]) env.Install(libInstallDir,lotusNotesRichTextVBufBackend) geckoVBufBackend=env.SConscript('vbufBackends/gecko_ia2/sconscript') +if signExec: + env.AddPostAction(geckoVBufBackend[0],[signExec]) env.Install(libInstallDir,geckoVBufBackend) mshtmlVBufBackend=env.SConscript('vbufBackends/mshtml/sconscript') +if signExec: + env.AddPostAction(mshtmlVBufBackend[0],[signExec]) env.Install(libInstallDir,mshtmlVBufBackend) webKitVBufBackend=env.SConscript('vbufBackends/webKit/sconscript') +if signExec: + env.AddPostAction(webKitVBufBackend[0],[signExec]) env.Install(libInstallDir,webKitVBufBackend) if TARGET_ARCH=='x86': diff --git a/nvdaHelper/building.txt b/nvdaHelper/building.txt deleted file mode 100644 index 09cc81f..0000000 --- a/nvdaHelper/building.txt +++ /dev/null @@ -1,45 +0,0 @@ -Build Instructions - -Prerequisites: - -NVDAHelper needs The Microsoft Windows SDK, version 6.1 or later. You can find it here: -http://msdn.microsoft.com/en-us/windows/bb980924.aspx - - The gecko_ia2 virtual buffer backend requires the IAccessible2 IDL, version 1.2 or later. You can obtain it here: -http://www.linuxfoundation.org/en/Accessibility/IAccessible2 -Download the merged IDL and copy it to ..\include\ia2\ia2.idl. - -The adobeAcrobat virtual buffer backend requires the Adobe Acrobat accessibility IDL, version 9.1 or later. This can be found in the client files archive available from http://www.adobe.com/devnet/acrobat/interapplication_communication.html -The archive is named something like Acrobat_Accessibility_9.1.zip. -Extract the AcrobatAccess.idl file into ..\include\AcrobatAccess. - -The apiHook module requires MinHook 1.1.0 or later: http://www.codeproject.com/KB/winsdk/LibMinHook.aspx - * Download the source archive. The file name is something like MinHook_110_src.zip depending on exact version. - * You will need an account on CodeProject to download from there. - * extract the source archive, and from it copy the libMinHook directory to NVDA's source/include directory. - -minHook (and possibly in future nvdaHelper) depends on the Boost c++ library 1.42 or later: - * you can download the latest Windows installer from http://www.boostpro.com/download - * On the components page of the installer, make sure to install all the defaults (what ever is already checked), along with anything else you may wish to have for other projects. - * So far only boost headers are used, none of the pre-compiled libraries are necessary for nvda/minHook. - -The NVDAHelper build is managed by the SCons build system, version 1.3.0 or later: http://www.scons.org/ - -Building the library: - -There is no need to use the MSVC environment command prompt when building, as scons will locate what it needs automatically in any standard environment. - -To build and install the library and all virtual buffer backends, open a command prompt, cd to the top-level directory of nvdaHelper and run the command: -scons install -By default a version with debugging symbols will be generated. To build a release version, provide release=1 on the command line when running scons: -scons install release=1 - -Note that now both x86 and x64 versions of the libraries are automatically built, there is no need to supply any target arch variables by default. - -However, if you specifically only want to build certain architectures, you can provide a comma separated list of the required architectures to the targetArchitectures variable on the commandline, like so: -scons targetArchitectures=x86 -or -scons targetArchitectures=x86_64 -or -scons targetArchitectures=x86,x86_64 - \ No newline at end of file diff --git a/nvdaHelper/contributors.txt b/nvdaHelper/contributors.txt deleted file mode 100755 index 5c0a415..0000000 --- a/nvdaHelper/contributors.txt +++ /dev/null @@ -1,3 +0,0 @@ -Michael Curran <mick@xxxxxxxxxx> -James Teh <jamie@xxxxxxxxxxx> -Aleksey Sadovoy <lex@xxxxxx> diff --git a/nvdaHelper/liblouis/sconscript b/nvdaHelper/liblouis/sconscript index 72cdef4..1050407 100644 --- a/nvdaHelper/liblouis/sconscript +++ b/nvdaHelper/liblouis/sconscript @@ -24,7 +24,7 @@ louisRootDir = env.Dir("#include/liblouis") louisSourceDir = louisRootDir.Dir("liblouis") outDir = sourceDir.Dir("louis") -RE_AC_INIT = re.compile(r"^AC_INIT\((?P<name>.*), (?P<version>.*), (?P<maintainer>.*)\)") +RE_AC_INIT = re.compile(r"^AC_INIT\(\[(?P<package>.*)\], \[(?P<version>.*)\], \[(?P<bugReport>.*)\], \[(?P<tarName>.*)\], \[(?P<url>.*)\]\)") def getLouisVersion(): # Get the version from configure.ac. with file(louisRootDir.File("configure.ac").abspath) as f: @@ -50,6 +50,7 @@ sourceFiles = [ "lou_translateString.c", "lou_backTranslateString.c", "wrappers.c", + "logging.c", ] objs = [env.Object("%s.obj" % f, louisSourceDir.File(f)) for f in sourceFiles] louisLib = env.SharedLibrary("liblouis", objs + ["liblouis.def"]) diff --git a/nvdaHelper/minHook/dllmain.cpp b/nvdaHelper/minHook/dllmain.cpp index 25d6823..07a9e41 100644 --- a/nvdaHelper/minHook/dllmain.cpp +++ b/nvdaHelper/minHook/dllmain.cpp @@ -18,7 +18,7 @@ http://www.gnu.org/licenses/old-licenses/gpl-2.0.html BOOL WINAPI DllMain(HINSTANCE hModule,DWORD reason,LPVOID lpReserved) { //Process exiting, we must clean up any pending hooks if(reason==DLL_PROCESS_DETACH&&lpReserved) { - if(MH_DisableAllHooks()!=MH_ERROR_NOT_INITIALIZED) { + if(MH_DisableHook(MH_ALL_HOOKS)!=MH_ERROR_NOT_INITIALIZED) { //Give enough time for all hook functions to complete. Sleep(250); MH_Uninitialize(); diff --git a/nvdaHelper/minHook/sconscript b/nvdaHelper/minHook/sconscript index 497a242..886b606 100644 --- a/nvdaHelper/minHook/sconscript +++ b/nvdaHelper/minHook/sconscript @@ -19,10 +19,11 @@ sourceFiles=[ objFiles=[env.Object('_minHook_%s.obj'%x.replace('/','_'),minhookPath.File('src/%s'%x)) for x in sourceFiles] objFiles.append('dllmain.cpp') +resFile=env.RES('_minHook',minhookPath.File('dll_resources/minHook.rc')) minHookLib=env.SharedLibrary( target='minHook', - source=objFiles+[minhookPath.File('dll_resources/minHook.def')], + source=objFiles+[resFile,minhookPath.File('dll_resources/minHook.def')], ) Return('minHookLib') diff --git a/nvdaHelper/remote/apiHook.cpp b/nvdaHelper/remote/apiHook.cpp index 0a3430b..4c9848e 100644 --- a/nvdaHelper/remote/apiHook.cpp +++ b/nvdaHelper/remote/apiHook.cpp @@ -39,8 +39,6 @@ typedef MH_STATUS(WINAPI *MH_Uninitialize_funcType)(); typedef MH_STATUS(WINAPI *MH_CreateHook_funcType)(void*,void*,void**); typedef MH_STATUS(WINAPI *MH_EnableHook_funcType)(void*); typedef MH_STATUS(WINAPI *MH_DisableHook_funcType)(void*); -typedef MH_STATUS(*MH_EnableAllHooks_funcType)(); -typedef MH_STATUS(*MH_DisableAllHooks_funcType)(); #define defMHFP(funcName) funcName##_funcType funcName##_fp=NULL @@ -55,8 +53,8 @@ typedef MH_STATUS(*MH_DisableAllHooks_funcType)(); defMHFP(MH_Initialize); defMHFP(MH_Uninitialize); defMHFP(MH_CreateHook); -defMHFP(MH_EnableAllHooks); -defMHFP(MH_DisableAllHooks); +defMHFP(MH_EnableHook); +defMHFP(MH_DisableHook); bool apiHook_initialize() { LOG_DEBUG("calling MH_Initialize"); @@ -71,8 +69,8 @@ defMHFP(MH_DisableAllHooks); setMHFP(MH_Initialize); setMHFP(MH_Uninitialize); setMHFP(MH_CreateHook); - setMHFP(MH_EnableAllHooks); - setMHFP(MH_DisableAllHooks); + setMHFP(MH_EnableHook); + setMHFP(MH_DisableHook); if(error_setNHFP) { LOG_ERROR(L"Error setting minHook function pointers"); FreeLibrary(minhookLibHandle); @@ -124,7 +122,7 @@ bool apiHook_enableHooks() { LOG_ERROR(L"apiHooks not initialized"); return false; } - res=MH_EnableAllHooks_fp(); + res=MH_EnableHook_fp(MH_ALL_HOOKS); nhAssert(res==MH_OK); return TRUE; } @@ -137,7 +135,7 @@ bool apiHook_terminate() { LOG_ERROR(L"apiHooks not initialized"); return false; } - res=MH_DisableAllHooks_fp(); + res=MH_DisableHook_fp(MH_ALL_HOOKS); nhAssert(res==MH_OK); g_hookedFunctions.clear(); //Give enough time for all hook functions to complete. diff --git a/nvdaHelper/remote/ia2LiveRegions.cpp b/nvdaHelper/remote/ia2LiveRegions.cpp index a3c584d..df389fe 100644 --- a/nvdaHelper/remote/ia2LiveRegions.cpp +++ b/nvdaHelper/remote/ia2LiveRegions.cpp @@ -23,6 +23,17 @@ http://www.gnu.org/licenses/old-licenses/gpl-2.0.html using namespace std; +bool fetchIA2Attributes(IAccessible2* pacc2, map<wstring,wstring>& attribsMap) { + BSTR attribs=NULL; + pacc2->get_attributes(&attribs); + if(!attribs) { + return false; + } + IA2AttribsToMap(attribs,attribsMap); + SysFreeString(attribs); + return true; +} + IAccessible2* findAriaAtomic(IAccessible2* pacc2,map<wstring,wstring>& attribsMap) { map<wstring,wstring>::iterator i=attribsMap.find(L"atomic"); bool atomic=(i!=attribsMap.end()&&i->second.compare(L"true")==0); @@ -38,12 +49,8 @@ IAccessible2* findAriaAtomic(IAccessible2* pacc2,map<wstring,wstring>& attribsMa if(pdispParent) { IAccessible2* pacc2Parent=NULL; if(pdispParent->QueryInterface(IID_IAccessible2,(void**)&pacc2Parent)==S_OK&&pacc2Parent) { - BSTR parentAttribs=NULL; - pacc2Parent->get_attributes(&parentAttribs); - if(parentAttribs) { - map<wstring,wstring> parentAttribsMap; - IA2AttribsToMap(parentAttribs,parentAttribsMap); - SysFreeString(parentAttribs); + map<wstring,wstring> parentAttribsMap; + if(fetchIA2Attributes(pacc2Parent,parentAttribsMap)) { pacc2Atomic=findAriaAtomic(pacc2Parent,parentAttribsMap); } pacc2Parent->Release(); @@ -71,8 +78,13 @@ bool getTextFromIAccessible(wstring& textBuf, IAccessible2* pacc2, bool useNewTe if(varChildren[i].vt==VT_DISPATCH) { IAccessible2* pacc2Child=NULL; if(varChildren[i].pdispVal&&varChildren[i].pdispVal->QueryInterface(IID_IAccessible2,(void**)&pacc2Child)==S_OK) { - if(getTextFromIAccessible(textBuf,pacc2Child)) { - gotText=true; + map<wstring,wstring> childAttribsMap; + fetchIA2Attributes(pacc2Child,childAttribsMap); + auto i=childAttribsMap.find(L"live"); + if(i==childAttribsMap.end()||i->second.compare(L"off")!=0) { + if(getTextFromIAccessible(textBuf,pacc2Child)) { + gotText=true; + } } pacc2Child->Release(); } @@ -110,8 +122,13 @@ bool getTextFromIAccessible(wstring& textBuf, IAccessible2* pacc2, bool useNewTe if(paccHypertext->get_hyperlink(hyperlinkIndex,&paccHyperlink)==S_OK) { IAccessible2* pacc2Child=NULL; if(paccHyperlink->QueryInterface(IID_IAccessible2,(void**)&pacc2Child)==S_OK) { - if(getTextFromIAccessible(textBuf,pacc2Child)) { - gotText=true; + map<wstring,wstring> childAttribsMap; + fetchIA2Attributes(pacc2Child,childAttribsMap); + auto i=childAttribsMap.find(L"live"); + if(i==childAttribsMap.end()||i->second.compare(L"off")!=0) { + if(getTextFromIAccessible(textBuf,pacc2Child)) { + gotText=true; + } } charAdded=true; pacc2Child->Release(); @@ -217,19 +234,12 @@ void CALLBACK winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, l pserv->Release(); if(!pacc2) return; //Retreave the IAccessible2 attributes, and if the object is not a live region then ignore the event. - BSTR attribs=NULL; - pacc2->get_attributes(&attribs); - if(!attribs) { + map<wstring,wstring> attribsMap; + if(!fetchIA2Attributes(pacc2,attribsMap)) { pacc2->Release(); return; } - map<wstring,wstring> attribsMap; - IA2AttribsToMap(attribs,attribsMap); - SysFreeString(attribs); - map<wstring,wstring>::iterator i; - i=attribsMap.find(L"live"); - bool isRegionRoot=(i!=attribsMap.end()); - i=attribsMap.find(L"container-live"); + auto i=attribsMap.find(L"container-live"); bool live=(i!=attribsMap.end()&&(i->second.compare(L"polite")==0||i->second.compare(L"assertive")==0||i->second.compare(L"rude")==0)); if(!live) { pacc2->Release(); @@ -251,23 +261,41 @@ void CALLBACK winEventProcHook(HWINEVENTHOOK hookID, DWORD eventID, HWND hwnd, l allowText=(i->second.find(L"text",0)!=wstring::npos); allowAdditions=(i->second.find(L"additions",0)!=wstring::npos); } - //Only handle show events if additions are allowed and this is not the root of a region. - if(eventID==EVENT_OBJECT_SHOW&&(!allowAdditions||isRegionRoot)) { + attribsMap.clear(); + //Only handle show events if additions are allowed + if(eventID==EVENT_OBJECT_SHOW&&!allowAdditions) { pacc2->Release(); return; } // If this is a show event and this is not the root of the region and there is a text parent, // We can ignore this event as there will be text events which can handle this better if(eventID==EVENT_OBJECT_SHOW) { - bool ignoreShowEvent=false; + bool ignoreShowEvent=false; IDispatch* pdispParent=NULL; pacc2->get_accParent(&pdispParent); if(pdispParent) { + // check for text on parent IAccessibleText* paccTextParent=NULL; if(pdispParent->QueryInterface(IID_IAccessibleText,(void**)&paccTextParent)==S_OK&&paccTextParent) { ignoreShowEvent=true; paccTextParent->Release(); } + if(!ignoreShowEvent) { + // Check for useful container-live on parent, as if missing or off, then child must be the root + // Firstly, we assume we are the root of the region and therefore should ignore the event + ignoreShowEvent=true; + IAccessible2* pacc2Parent=NULL; + if(pdispParent->QueryInterface(IID_IAccessible2,(void**)&pacc2Parent)==S_OK) { + if(fetchIA2Attributes(pacc2Parent,attribsMap)) { + i=attribsMap.find(L"container-live"); + if(i!=attribsMap.end()&&(i->second.compare(L"polite")==0||i->second.compare(L"assertive")==0||i->second.compare(L"rude")==0)) { + // There is a valid container-live that is not off, so therefore the child is definitly not the root + ignoreShowEvent=false; + } + } + pacc2Parent->Release(); + } + } pdispParent->Release(); } if(ignoreShowEvent) { diff --git a/nvdaHelper/vbufBackends/mshtml/node.cpp b/nvdaHelper/vbufBackends/mshtml/node.cpp index 7bd5a9a..3e42b09 100755 --- a/nvdaHelper/vbufBackends/mshtml/node.cpp +++ b/nvdaHelper/vbufBackends/mshtml/node.cpp @@ -385,9 +385,17 @@ void MshtmlVBufStorage_controlFieldNode_t::reportLiveText(wstring& text) { } } +bool isNodeInLiveRegion(VBufStorage_fieldNode_t* node) { + if(!node) return false; + if(node->getFirstChild()) { + return ((MshtmlVBufStorage_controlFieldNode_t*)node)->ariaLiveNode!=NULL; + } + return true; +} + void MshtmlVBufStorage_controlFieldNode_t::reportLiveAddition() { wstring text; //=(this->ariaLiveAtomicNode==this)?L"atomic: ":L"additions: "; - this->getTextInRange(0,this->getLength(),text,false); + this->getTextInRange(0,this->getLength(),text,false,isNodeInLiveRegion); this->reportLiveText(text); } diff --git a/nvdaHelper/vbufBase/storage.cpp b/nvdaHelper/vbufBase/storage.cpp index ed7fbd3..d99dfb8 100644 --- a/nvdaHelper/vbufBase/storage.cpp +++ b/nvdaHelper/vbufBase/storage.cpp @@ -239,7 +239,7 @@ void VBufStorage_fieldNode_t::generateMarkupClosingTag(std::wstring& text) { text+=L">"; } -void VBufStorage_fieldNode_t::getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup) { +void VBufStorage_fieldNode_t::getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup, bool(*filter)(VBufStorage_fieldNode_t*)) { if(this->length==0) { LOG_DEBUG(L"node has 0 length, not collecting text"); return; @@ -260,9 +260,9 @@ void VBufStorage_fieldNode_t::getTextInRange(int startOffset, int endOffset, std nhAssert(childLength>=0); //length can't be negative childEnd+=childLength; LOG_DEBUG(L"child with offsets of "<<childStart<<L" and "<<childEnd); - if(childEnd>startOffset&&endOffset>childStart) { + if(childEnd>startOffset&&endOffset>childStart&&(!filter||filter(child))) { LOG_DEBUG(L"child offsets overlap requested offsets"); - child->getTextInRange(max(startOffset,childStart)-childStart,min(endOffset-childStart,childLength),text,useMarkup); + child->getTextInRange(max(startOffset,childStart)-childStart,min(endOffset-childStart,childLength),text,useMarkup,filter); } childStart+=childLength; LOG_DEBUG(L"childStart is now "<<childStart); @@ -358,7 +358,7 @@ void VBufStorage_textFieldNode_t::generateMarkupTagName(std::wstring& text) { text+=L"text"; } -void VBufStorage_textFieldNode_t::getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup) { +void VBufStorage_textFieldNode_t::getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup, bool(*filter)(VBufStorage_fieldNode_t*)) { LOG_DEBUG(L"getting text between offsets "<<startOffset<<L" and "<<endOffset); if(useMarkup) { this->generateMarkupOpeningTag(text,startOffset,endOffset); diff --git a/nvdaHelper/vbufBase/storage.h b/nvdaHelper/vbufBase/storage.h index 3456584..795d9f4 100644 --- a/nvdaHelper/vbufBase/storage.h +++ b/nvdaHelper/vbufBase/storage.h @@ -286,9 +286,10 @@ class VBufStorage_fieldNode_t { * @param endOffset the offset to end at. Use -1 to mean node's end offset. * @param text a string in whish to append the text. * @param useMarkup if true then markup indicating opening and closing of fields will be included. + * @param filter: a function that takes the current recursive node and returns true if text should be fetched and false if it should be skipped. * @return true if successfull, false otherwize. */ - virtual void getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup=false); + virtual void getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup=false,bool(*filter)(VBufStorage_fieldNode_t*)=NULL); /** * @return a string providing information about this node's type, and its state. @@ -359,7 +360,7 @@ class VBufStorage_textFieldNode_t : public VBufStorage_fieldNode_t { virtual void generateMarkupTagName(std::wstring& text); - virtual void getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup=false); + virtual void getTextInRange(int startOffset, int endOffset, std::wstring& text, bool useMarkup=false,bool(*filter)(VBufStorage_fieldNode_t*)=NULL); /** * constructor. diff --git a/readme.txt b/readme.txt index e667fe3..d5b79d3 100644 --- a/readme.txt +++ b/readme.txt @@ -27,18 +27,19 @@ The following dependencies are included in Git submodules: * eSpeak, version 1.48.03: http://espeak.sourceforge.net/ * IAccessible2, version 1.3: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2 * ConfigObj, version 4.6.0: http://www.voidspace.org.uk/python/configobj.html -* liblouis, version 2.5.4: http://www.liblouis.org/ +* liblouis, version 2.6.0: http://www.liblouis.org/ * NVDA images and sounds * System dlls not present on many systems: mfc90.dll, msvcp90.dll, msvcr90.dll, Microsoft.VC90.CRT.manifest * Adobe Acrobat accessibility interface, version XI: http://download.macromedia.com/pub/developer/acrobat/AcrobatAccess.zip * Adobe FlashAccessibility interface typelib * txt2tags, version 2.5: http://txt2tags.sourceforge.net/ -* MinHook, rev e21b54a: https://github.com/RaMMicHaeL/minhook -* SCons, version 2.3.0: http://www.scons.org/ +* MinHook, tagged version 1.2.2: https://github.com/RaMMicHaeL/minhook +* SCons, version 2.3.2: http://www.scons.org/ * brlapi Python bindings, version 0.5.7 or later, distributed with BRLTTY for Windows, version 4.2-2: http://brl.thefreecat.org/brltty/ * ALVA BC6 generic dll, version 3.0.4.1 * lilli.dll, version 2.1.0.0 * Handy Tech Braille SDK, version 1.4.2.0: ftp://ftp.handytech.de/public/Software/BrailleDriver/HTBrailleSDK_1420a.zip +* Updated Handy Tech sbsupport.dll and dealers.dat received on 2014-09-09 * pyserial, version 2.5: http://pypi.python.org/pypi/pyserial * HanSoneConnect.dll, version 2.0.0.1 * SyncBraille.dll, version 1.0.0.1 diff --git a/sconstruct b/sconstruct index c79a5e0..87d9934 100755 --- a/sconstruct +++ b/sconstruct @@ -14,6 +14,7 @@ import sys import os +import time import _winreg from glob import glob @@ -112,12 +113,35 @@ outFilePrefix = "nvda{type}_{version}".format(type="" if release else "_snapshot outputDir=Dir(env['outputDir']) devDocsOutputDir=outputDir.Dir('devDocs') +# An action to sign an executable with certFile. +signExecCmd = ["signtool", "sign", "/f", certFile] +if certPassword: + signExecCmd.extend(("/p", certPassword)) +if certTimestampServer: + signExecCmd.extend(("/t", certTimestampServer)) +def signExec(target,source,env): + print [str(x) for x in target] + #sys.exit(1) + # #3795: signtool can quite commonly fail with timestamping, so allow it to try up to 3 times with a 1 second delay between each try. + res=0 + for count in xrange(3): + res=env.Execute([signExecCmd+[target[0].abspath]]) + if not res: + return 0 # success + time.sleep(1) + return res # failed +#Export via scons environment so other libraries can be signed +env['signExec']=signExec + #architecture-specific environments archTools=['default','windowsSdk','midl','msrpc'] env32=env.Clone(TARGET_ARCH='x86',tools=archTools) env64=env.Clone(TARGET_ARCH='x86_64',tools=archTools) -env=env32 +# Hack around odd bug where some tool [after] msvc states that static and shared objects are different +env32['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 +env64['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 +env=env32 #Fill sourceDir with anything provided for it by miscDeps env.recursiveCopy(sourceDir,Dir('miscdeps/source')) @@ -195,8 +219,8 @@ def NVDADistGenerator(target, source, env, for_signature): if env.get("uiAccess"): buildCmd.append("--enable-uiAccess") if certFile: - for prog in "nvda_noUIAccess", "nvda_uiAccess", "nvda_slave", "nvda_service": - action.append(signExec[:-1] + [os.path.join(target[0].path, "%s.exe" % prog)]) + for prog in "nvda_noUIAccess.exe", "nvda_uiAccess.exe", "nvda_slave.exe", "nvda_service.exe": + action.append(lambda target,source,env, progByVal=prog: signExec([target[0].File(progByVal)],source,env)) for ext in "", "c", "o": action.append(Delete(buildVersionFn + ext)) @@ -247,14 +271,6 @@ def ZipArchiveAction(target, source, env): env["BUILDERS"]["ZipArchive"] = Builder(action=ZipArchiveAction) -# An action to sign an executable with certFile. -signExec = ["signtool", "sign", "/f", certFile] -if certPassword: - signExec.extend(("/p", certPassword)) -if certTimestampServer: - signExec.extend(("/t", certTimestampServer)) -signExec.append("$TARGET") - uninstFile=File("dist/uninstall.exe") uninstGen = env.Command(File("uninstaller/uninstGen.exe"), "uninstaller/uninst.nsi", [[makensis, "/V2", diff --git a/source/NVDAObjects/IAccessible/MSHTML.py b/source/NVDAObjects/IAccessible/MSHTML.py index a6bf4ee..a8e6ffb 100644 --- a/source/NVDAObjects/IAccessible/MSHTML.py +++ b/source/NVDAObjects/IAccessible/MSHTML.py @@ -386,7 +386,12 @@ class MSHTML(IAccessible): if nodeName=="SELECT" and self.windowStyle&winUser.WS_POPUP: clsList.append(PopupList) elif nodeNamesToNVDARoles.get(nodeName) == controlTypes.ROLE_DOCUMENT: - clsList.append(Body) + try: + isBodyNode=self.HTMLNodeUniqueNumber==self.HTMLNode.document.body.uniqueNumber + except (COMError,NameError): + isBodyNode=False + if isBodyNode: + clsList.append(Body) elif nodeName == "OBJECT": clsList.append(Object) elif nodeName=="FIELDSET": @@ -879,11 +884,12 @@ class Fieldset(MSHTML): class Body(MSHTML): def _get_parent(self): - # The parent of the body accessible is an irrelevant client object (description: MSAAHTML Registered Handler). + # The parent of the body accessible may be an irrelevant client object (description: MSAAHTML Registered Handler). # This object isn't returned when requesting OBJID_CLIENT, nor is it returned as a child of its parent. # Therefore, eliminate it from the ancestry completely. + # However it is possible that this body is a child document of a parent frame. In this case don't skip it. parent = super(Body, self).parent - if parent: + if parent and not isinstance(parent,MSHTML): return parent.parent else: return parent diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py index 7214a75..4826b01 100644 --- a/source/NVDAObjects/IAccessible/__init__.py +++ b/source/NVDAObjects/IAccessible/__init__.py @@ -511,14 +511,15 @@ the NVDAObject for IAccessible clsList.append(IAccessible) - - if self.event_objectID==winUser.OBJID_CLIENT and self.event_childID==0: + if self.event_objectID==winUser.OBJID_CLIENT and self.event_childID==0 and not isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2): # This is the main (client) area of the window, so we can use other classes at the window level. + # #3872: However, don't do this for IAccessible2 because + # IA2 supersedes window level APIs and might conflict with them. super(IAccessible,self).findOverlayClasses(clsList) #Generic client IAccessibles with no children should be classed as content and should use displayModel if clsList[0]==IAccessible and len(clsList)==3 and self.IAccessibleRole==oleacc.ROLE_SYSTEM_CLIENT and self.childCount==0: clsList.insert(0,ContentGenericClient) - + def __init__(self,windowHandle=None,IAccessibleObject=None,IAccessibleChildID=None,event_windowHandle=None,event_objectID=None,event_childID=None): """ @param pacc: a pointer to an IAccessible object diff --git a/source/NVDAObjects/window/__init__.py b/source/NVDAObjects/window/__init__.py index 1b95c3d..e7afcee 100644 --- a/source/NVDAObjects/window/__init__.py +++ b/source/NVDAObjects/window/__init__.py @@ -114,7 +114,7 @@ An NVDAObject for a window from .edit import Edit as newCls elif windowClassName=="RichEdit": from .edit import RichEdit as newCls - elif windowClassName=="RichEdit20": + elif windowClassName in ("RichEdit20","REComboBox20W"): from .edit import RichEdit20 as newCls elif windowClassName=="RICHEDIT50W": from .edit import RichEdit50 as newCls diff --git a/source/NVDAObjects/window/winword.py b/source/NVDAObjects/window/winword.py index 61078f2..c66e7ef 100755 --- a/source/NVDAObjects/window/winword.py +++ b/source/NVDAObjects/window/winword.py @@ -477,7 +477,6 @@ class WordDocumentTextInfo(textInfos.TextInfo): elif which=="startToEnd": self._rangeObj.Start=other._rangeObj.End elif which=="endToStart": - print "start %s, end %s, otherStart %s, otherEnd %s"%(self._rangeObj.start,self._rangeObj.end,other._rangeObj.start,other._rangeObj.end) self._rangeObj.End=other._rangeObj.Start elif which=="endToEnd": self._rangeObj.End=other._rangeObj.End diff --git a/source/addonHandler.py b/source/addonHandler.py index 8f4fc17..0c135a3 100644 --- a/source/addonHandler.py +++ b/source/addonHandler.py @@ -155,7 +155,7 @@ def getAvailableAddons(refresh=False): return _availableAddons.itervalues() def installAddonBundle(bundle): - """Extracts an Addon bundle in to a unique subdirectory of the user addons directory, marking the addon as needing install completion on NVDA restart.""" + """Extracts an Addon bundle in to a unique subdirectory of the user addons directory, marking the addon as needing install completion on NVDA restart.""" addonPath = os.path.join(globalVars.appArgs.configPath, "addons",bundle.manifest['name']+ADDON_PENDINGINSTALL_SUFFIX) bundle.extract(addonPath) addon=Addon(addonPath) @@ -391,7 +391,7 @@ def _translatedManifestPaths(lang=None, forBundle=False): class AddonBundle(object): - """ Represents the contents of an NVDA addon in a for suitable for distribution. + """ Represents the contents of an NVDA addon suitable for distribution. The bundle is compressed using the zip file format. Manifest information is available without the need for extraction.""" def __init__(self, bundlePath): diff --git a/source/api.py b/source/api.py index c829f3b..77eb33e 100644 --- a/source/api.py +++ b/source/api.py @@ -218,19 +218,12 @@ def setNavigatorObject(obj,isFocus=False): # #3320: If in document review yet there is no document to review the mode should be forced to object. if reviewMode=='document' and (not obj.treeInterceptor or not obj.treeInterceptor.isReady or obj.treeInterceptor.passThrough): review.setCurrentMode('object',False) - elif isFocus and reviewMode=='object' and obj.treeInterceptor and obj.treeInterceptor.isReady and not obj.treeInterceptor.passThrough: - review.setCurrentMode('document',False) - #Specifically handle when the navigator object is set due to a focus change in a virtualBuffer - #The focus change may have been becaus the caret was moved, which caused the focus change. - #If so, don't clober the review position as it will have been already set to a more accurate position. - if isFocus and oldPos and oldPos.obj is obj.treeInterceptor and isinstance(obj.treeInterceptor,virtualBuffers.VirtualBuffer): - try: - objPos=obj.treeInterceptor.makeTextInfo(obj) - except LookupError: - objPos=None - if objPos and objPos.isOverlapping(oldPos): - globalVars.reviewPosition=oldPos - globalVars.reviewPositionObj=oldPosObj + elif obj.treeInterceptor and obj.treeInterceptor.isReady and not obj.treeInterceptor.passThrough: + if reviewMode=='object': + review.setCurrentMode('document',False) + if isFocus: + globalVars.reviewPosition=obj.treeInterceptor.makeTextInfo(textInfos.POSITION_CARET) + globalVars.reviewPositionObj=globalVars.reviewPosition eventHandler.executeEvent("becomeNavigatorObject",obj) def isTypingProtected(): @@ -341,9 +334,9 @@ def getStatusBarText(obj): @return: The status bar text. @rtype: str """ - text = obj.name - if text is None: - text = "" + text = obj.name or "" + if text: + text += " " return text + " ".join(chunk for child in obj.children for chunk in (child.name, child.value) if chunk and isinstance(chunk, basestring) and not chunk.isspace()) def filterFileName(name): diff --git a/source/appModules/eclipse.py b/source/appModules/eclipse.py index fb258e7..49d02ff 100644 --- a/source/appModules/eclipse.py +++ b/source/appModules/eclipse.py @@ -2,10 +2,20 @@ #A part of NonVisual Desktop Access (NVDA) #This file is covered by the GNU General Public License. #See the file COPYING for more details. -#Copyright (C) 2010 James Teh <jamie@xxxxxxxxxxx> +#Copyright (C) 2010-2014 NV Access Limited import controlTypes import appModuleHandler +from NVDAObjects.IAccessible import IAccessible + +class EclipseTextArea(IAccessible): + + def event_valueChange(self): + # #2314: Eclipse incorrectly fires valueChange when the selection changes. + # Unfortunately, this causes us to speak the entire selection + # instead of just the changed selection. + # Therefore, just drop this event. + pass class AppModule(appModuleHandler.AppModule): @@ -14,3 +24,7 @@ class AppModule(appModuleHandler.AppModule): # Eclipse tree views seem to fire a focus event on the previously focused item before firing focus on the new item (EclipseBug:315339). # Try to filter this out. obj.shouldAllowIAccessibleFocusEvent = False + + def chooseNVDAObjectOverlayClasses(self, obj, clsList): + if obj.windowClassName == "SWT_Window0" and obj.role == controlTypes.ROLE_EDITABLETEXT: + clsList.insert(0, EclipseTextArea) diff --git a/source/appModules/outlook.py b/source/appModules/outlook.py index f0dabc0..09f3e75 100644 --- a/source/appModules/outlook.py +++ b/source/appModules/outlook.py @@ -433,6 +433,8 @@ class UIAGridRow(RowWithFakeNavigation,UIA): role=super(UIAGridRow,self).role if role==controlTypes.ROLE_TREEVIEW: role=controlTypes.ROLE_TREEVIEWITEM + elif role==controlTypes.ROLE_DATAITEM: + role=controlTypes.ROLE_LISTITEM return role def setFocus(self): diff --git a/source/braille.py b/source/braille.py index 6971d81..e845eaa 100644 --- a/source/braille.py +++ b/source/braille.py @@ -309,6 +309,8 @@ def _getDisplayDriver(name): def getDisplayList(): displayList = [] + # The display that should be placed at the end of the list. + lastDisplay = None for loader, name, isPkg in pkgutil.iter_modules(brailleDisplayDrivers.__path__): if name.startswith('_'): continue @@ -320,11 +322,17 @@ def getDisplayList(): continue try: if display.check(): - displayList.append((display.name, display.description)) + if display.name == "noBraille": + lastDisplay = (display.name, display.description) + else: + displayList.append((display.name, display.description)) else: log.debugWarning("Braille display driver %s reports as unavailable, excluding" % name) except: log.error("", exc_info=True) + displayList.sort(key=lambda d : d[1].lower()) + if lastDisplay: + displayList.append(lastDisplay) return displayList class Region(object): diff --git a/source/cursorManager.py b/source/cursorManager.py index 492b36c..d4aae44 100644 --- a/source/cursorManager.py +++ b/source/cursorManager.py @@ -13,6 +13,7 @@ import wx import baseObject import gui import sayAllHandler +import review from scriptHandler import willSayAllResume import textInfos import api @@ -343,4 +344,5 @@ class ReviewCursorManager(CursorManager): def _set_selection(self, info): self._selection = info.copy() + review.handleCaretMove(info) braille.handler.handleCaretMove(self) diff --git a/source/gui/__init__.py b/source/gui/__init__.py index 5929f08..fc8271b 100644 --- a/source/gui/__init__.py +++ b/source/gui/__init__.py @@ -458,6 +458,7 @@ class SysTrayIcon(wx.TaskBarIcon): item = self.menu.Append(wx.ID_EXIT, _("E&xit"),_("Exit NVDA")) self.Bind(wx.EVT_MENU, frame.onExitCommand, item) + self.Bind(wx.EVT_TASKBAR_LEFT_DOWN, self.onActivate) self.Bind(wx.EVT_TASKBAR_RIGHT_DOWN, self.onActivate) def Destroy(self): diff --git a/source/installer.py b/source/installer.py index 47a963d..8f67787 100644 --- a/source/installer.py +++ b/source/installer.py @@ -144,6 +144,12 @@ def removeOldProgramFiles(destPath): else: os.remove(fn) + # #4235: mpr.dll is a Windows system dll accidentally included with + # earlier versions of NVDA. Its presence causes problems in Windows Vista. + fn = os.path.join(destPath, "mpr.dll") + if os.path.isfile(fn): + tryRemoveFile(fn) + uninstallerRegInfo={ "DisplayName":versionInfo.name, "DisplayVersion":versionInfo.version, diff --git a/source/setup.py b/source/setup.py index 752d1cb..b27e129 100755 --- a/source/setup.py +++ b/source/setup.py @@ -1,7 +1,7 @@ # -*- coding: UTF-8 -*- #setup.py #A part of NonVisual Desktop Access (NVDA) -#Copyright (C) 2006-2013 NV Access Limited, Peter Vágner +#Copyright (C) 2006-2014 NV Access Limited, Peter Vágner #This file is covered by the GNU General Public License. #See the file COPYING for more details. @@ -71,7 +71,7 @@ def isSystemDLL(pathname): if dll in ("msvcp71.dll", "msvcp90.dll", "gdiplus.dll","mfc71.dll", "mfc90.dll"): # These dlls don't exist on many systems, so make sure they're included. return 0 - elif dll.startswith("api-ms-win-") or dll == "powrprof.dll": + elif dll.startswith("api-ms-win-") or dll in ("powrprof.dll", "mpr.dll"): # These are definitely system dlls available on all systems and must be excluded. # Including them can cause serious problems when a binary build is run on a different version of Windows. return 1 diff --git a/source/speech.py b/source/speech.py index add2bbb..a201cd4 100755 --- a/source/speech.py +++ b/source/speech.py @@ -536,7 +536,8 @@ def speakSelectionChange(oldInfo,newInfo,speakSelected=True,speakUnselected=True def speakTypedCharacters(ch): global curWordChars; - if api.isTypingProtected(): + typingIsProtected=api.isTypingProtected() + if typingIsProtected: realChar="*" else: realChar=ch @@ -553,7 +554,7 @@ def speakTypedCharacters(ch): curWordChars=[] if log.isEnabledFor(log.IO): log.io("typed word: %s"%typedWord) - if config.conf["keyboard"]["speakTypedWords"]: + if config.conf["keyboard"]["speakTypedWords"] and not typingIsProtected: speakText(typedWord) if config.conf["keyboard"]["speakTypedCharacters"] and ord(ch)>=32: speakSpelling(realChar) diff --git a/source/synthDriverHandler.py b/source/synthDriverHandler.py index 7c2ed9d..417c114 100644 --- a/source/synthDriverHandler.py +++ b/source/synthDriverHandler.py @@ -39,6 +39,8 @@ def _getSynthDriver(name): def getSynthList(): synthList=[] + # The synth that should be placed at the end of the list. + lastSynth = None for loader, name, isPkg in pkgutil.iter_modules(synthDrivers.__path__): if name.startswith('_'): continue @@ -49,11 +51,17 @@ def getSynthList(): continue try: if synth.check(): - synthList.append((synth.name,synth.description)) + if synth.name == "silence": + lastSynth = (synth.name,synth.description) + else: + synthList.append((synth.name,synth.description)) else: log.debugWarning("Synthesizer '%s' doesn't pass the check, excluding from list"%name) except: log.error("",exc_info=True) + synthList.sort(key=lambda s : s[1].lower()) + if lastSynth: + synthList.append(lastSynth) return synthList def getSynth(): diff --git a/source/versionInfo.py b/source/versionInfo.py index de3b859..428e54a 100644 --- a/source/versionInfo.py +++ b/source/versionInfo.py @@ -29,7 +29,7 @@ def _updateVersionFromVCS(): name="NVDA" longName=_("NonVisual Desktop Access") -version="2014.3dev" +version="2014.4dev" publisher="unknown" updateVersionType=None try: diff --git a/source/virtualBuffers/MSHTML.py b/source/virtualBuffers/MSHTML.py index d35ff64..afd6d92 100644 --- a/source/virtualBuffers/MSHTML.py +++ b/source/virtualBuffers/MSHTML.py @@ -238,7 +238,7 @@ class MSHTML(VirtualBuffer): elif nodeType=="button": attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_PUSHBUTTON]} elif nodeType=="edit": - attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_TEXT],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_READONLY:[None],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} + attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_TEXT,oleacc.ROLE_SYSTEM_COMBOBOX],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_READONLY:[None],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1],"IHTMLElement::%s"%"isContentEditable":[1]} elif nodeType=="radioButton": attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_RADIOBUTTON],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_FOCUSABLE:[1]} elif nodeType=="comboBox": diff --git a/source/virtualBuffers/gecko_ia2.py b/source/virtualBuffers/gecko_ia2.py index 31f8c57..f61007f 100755 --- a/source/virtualBuffers/gecko_ia2.py +++ b/source/virtualBuffers/gecko_ia2.py @@ -209,7 +209,7 @@ class Gecko_ia2(VirtualBuffer): elif nodeType=="button": attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_PUSHBUTTON,oleacc.ROLE_SYSTEM_BUTTONMENU,IAccessibleHandler.IA2_ROLE_TOGGLE_BUTTON]} elif nodeType=="edit": - attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_TEXT],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_READONLY:[None]} + attrs={"IAccessible::role":[oleacc.ROLE_SYSTEM_TEXT,oleacc.ROLE_SYSTEM_COMBOBOX],"IAccessible::state_%s"%oleacc.STATE_SYSTEM_READONLY:[None],"IAccessible2::state_%s"%IAccessibleHandler.IA2_STATE_EDITABLE:[1]} elif nodeType=="frame": attrs={"IAccessible::role":[IAccessibleHandler.IA2_ROLE_INTERNAL_FRAME]} elif nodeType=="separator": diff --git a/user_docs/en/changes.t2t b/user_docs/en/changes.t2t index d07340e..a677322 100644 --- a/user_docs/en/changes.t2t +++ b/user_docs/en/changes.t2t @@ -3,6 +3,32 @@ %!includeconf: ../changes.t2tconf += 2014.4 = + +== Changes == +- If an object you have moved to with object navigation is inside a browse mode document, but the object you were on previously was not, the review mode is automatically set to document. Previously this only happened if the navigator object was moved due to the focus changing. (#4369) +- The Braille display and Synthesizer lists in the respective settings dialogs are now alphabetically sorted except for No braille/No speech, which are now at the bottom. (#2724) +- Updated liblouis braille translator to 2.6.0. (#4434, #3835) +- In browse mode, pressing e and shift+e to navigate to edit fields now includes editable combo boxes. This includes the search box in the latest versionn of Google Search. (#4436) +- Clicking the NVDA icon in the Notification Area with the left mouse button now opens the NVDA menu instead of doing nothing. (#4459) + + +== Bug Fixes == +- When moving focus back to a browse mode document (e.g. alt tabbing to an already opened web page) the review cursor is properly positioned at the virtual caret, rather than the focused control (e.g. a near by link). (#4369) +- In Powerpoint slide shows, the review cursor correctly follows the virtual caret. (#4370) +- In Mozilla Firefox and other Gecko-based browsers, new content within a live region will be announced even if the new content has a usable ARIA live type different to the parent live region. E.g. Content marked as assertive is added to a live region marked as polite. (#4169). +- In Internet Explorer and other MSHTML controls, some cases where a document is contained within another document no longer prevent the user from accessing some of the content (specifically, framesets inside framesets). (#4418) +- NVDA no longer crashes when attempting to use a Handy Tech braille display in some cases. (#3709) +- In Windows Vista, a spurious "Entry Point Not Found" dialog is no longer displayed in several cases such as when starting NVDA from the Desktop shortcut or via the shortcut key. (#4235) +- Serious problems with editable text controls in dialogs in recent versions of Eclipse have been fixed. (#3872) +- In Outlook 2010, moving the caret now works as expected in the location field of appointments and meeting requests. (#4126) +- Inside a live region, content which is marked as not being live (e.g. aria-live="off") is now correctly ignored. (#4405) +- When reporting the text of a status bar that has a name, the name is now correctly separated from the first word of the status bar text. (#4430) +- In password entry fields with speaking of typed words enabled, multiple asterisks are no longer pointlessly reported when beginning new words. (#4402) +- In the Microsoft Outlook message list, items are no longer pointlessly announced as Data Items. (#4439) +- When selecting text in the code editing control in the Eclipse IDE, the entire selection is no longer announced every time the selection changes. (#2314) + + = 2014.3 = == New Features == diff --git a/user_docs/en/userGuide.t2t b/user_docs/en/userGuide.t2t index 77966c9..0560398 100644 --- a/user_docs/en/userGuide.t2t +++ b/user_docs/en/userGuide.t2t @@ -84,7 +84,7 @@ Running the portable version directly from read-only media is not supported at t Using the temporary copy of NVDA is also an option (e.g. for demonstration purposes), though starting NVDA in this way each time can become very time consuming. ++ Portable and Temporary Copy Restrictions ++ -Apart from the inability to automatically start during and or after log-on, the portable and temporary copies of NVDA also have the following restrictions: +Apart from the inability to automatically start during and/or after log-on, the portable and temporary copies of NVDA also have the following restrictions: - The inability to interact with applications running with administrative privileges, unless of course NVDA itself has been run also with these privileges (not recommended). - The inability to read User Account Control (UAC) screens when trying to start an application with administrative privileges. - Windows 8: the inability to support input from a touch screen. @@ -107,7 +107,7 @@ This also includes UAC control and other secure screens. +++ Create Desktop Shortcut (ctrl+alt+n) +++ This option allows you to choose whether or not NVDA should create a shortcut on the desktop to start NVDA. -This shortcut if created will also be assigned a shortcut key of control+alt+n allowing you to start NVDA at any time with this key stroke. +If created, this shortcut will also be assigned a shortcut key of control+alt+n, allowing you to start NVDA at any time with this key stroke. +++ Copy Portable Configuration to Current User Account +++ This option allows you to choose whether or not NVDA should copy the user configuration from the currently running NVDA into the configuration for the currently logged on user, for the installed copy of NVDA. @@ -152,22 +152,20 @@ The third lets you control if this Welcome dialog should appear each time NVDA s +++ The NVDA Modifier Key +++ Most NVDA-specific keyboard commands consist of pressing a particular key called the NVDA modifier key in conjunction with one or more other keys. -Notable exceptions to this are the text review commands for desktop keyboards which just use the numpad keys by themselves, but there are some other exceptions as well. - -NVDA can be configured so that either the numpad Insert, Extended Insert, or capslock key can be used as the NVDA modifier key. +Notable exceptions to this are the text review commands for the desktop keyboard layout which just use the numpad keys by themselves, but there are some other exceptions as well. +NVDA can be configured so that the numpad Insert, Extended Insert and/or capslock key can be used as the NVDA modifier key. By default, both the numpad Insert and Extended Insert keys are set as NVDA modifier keys. -If you wish to cause one of the NVDA modifier keys to act like its original key (for instance you wish to turn capslock on when you have set capslock to be an NVDA modifier key) you can press the key twice in quick succession. +If you wish to cause one of the NVDA modifier keys to behave as it usually would if NVDA were not running (e.g. you wish to turn capslock on when you have set capslock to be an NVDA modifier key), you can press the key twice in quick succession. +++ Keyboard Layouts +++ -NVDA currently comes with two sets of key commands. -There is a layout for Desktops and a layout for Laptops. -NVDA by default is set to use the Desktop layout, though you can switch to the Laptop layout in the Keyboard Settings, found under Preferences in the NVDA menu. +NVDA currently comes with two sets of key commands (known as keyboard layouts): the desktop layout and the laptop layout. +By default, NVDA is set to use the Desktop layout, though you can switch to the Laptop layout in the Keyboard Settings, found under Preferences in the NVDA menu. -The Desktop layout makes heavy use of the numberpad (with numlock off). -Although most laptops do not have a physical numberpad, some laptops can emulate one by holding down the FN key and pressing letters and numbers on the right-hand side of the keyboard (7 8 9 u i o j k l etc). -If your laptop can not do this, or does not allow you to turn numlock off, you may want to switch to the Laptop layout instead. +The Desktop layout makes heavy use of the numpad (with numlock off). +Although most laptops do not have a physical numpad, some laptops can emulate one by holding down the FN key and pressing letters and numbers on the right-hand side of the keyboard (7, 8, 9, u, i, o, j, k, l, etc.). +If your laptop cannot do this or does not allow you to turn numlock off, you may want to switch to the Laptop layout instead. ++ NVDA Touch Gestures ++ If you are running NVDA on a device with a touch screen and running Windows 8 or higher, you can also control NVDA directly via the touch screen. @@ -234,7 +232,7 @@ When the menu comes up, You can use the arrow keys to navigate the menu, and the || Name | Desktop key | Laptop key | Touch | Description | | Stop speech | Control | control | 2-finger tap | Instantly stops speaking | | Pause Speech | shift | shift | none | Instantly pauses speech. Pressing it again will continue speaking where it left off (if pausing is supported by the current synthesizer) | -| NVDA Menu | NVDA+n | NVDA+n | 2-finger double tap | Pops up the NVDA menu to allow you to access preferences, tools and help etc | +| NVDA Menu | NVDA+n | NVDA+n | 2-finger double tap | Pops up the NVDA menu to allow you to access preferences, tools, help, etc. | | Toggle Speech Mode | NVDA+s | NVDA+s | none | Toggles speech mode between speech, beeps and off. | | Toggle Input Help Mode | NVDA+1 | NVDA+1 | none | Pressing any key in this mode will report the key, and the description of any NVDA command associated with it | | Quit NVDA | NVDA+q | NVDA+q | none | Exits NVDA | @@ -669,12 +667,13 @@ This option is a slider which goes from 0 to 100, (0 being the lowest volume and This option is a slider that lets you choose how much inflection (rise and fall in pitch) the synthesizer should use to speak with. (The only synthesizer that provides this option at the present time is eSpeak). ==== Automatic Language switching ==== -This checkbox allows you to toggle whether or not NVDA should switch speech synthesizer languages on the fly, if language markup is available in the text being read. +This checkbox allows you to toggle whether NVDA should switch speech synthesizer languages automatically if the text being read specifies its language. This option is enabled by default. Currently only the eSpeak synthesizer supports automatic language switching. ==== Automatic Dialect switching ==== -If automatic language switching is turned on, this checkbox allows you to toggle whether or not dialect changes should be made, rather than just actual language changes. E.g. If reading in an English U.S. voice but a document states some text is in English U.K. then if this feature is enabled the synthesizer will switch accents. +This checkbox allows you to toggle whether or not dialect changes should be made, rather than just actual language changes. +For example, if reading in an English U.S. voice but a document specifies that some text is in English U.K., then the synthesizer will switch accents if this option is enabled. This option is disabled by default. %kc:setting @@ -880,7 +879,7 @@ Key: NVDA+6 When enabled, the review cursor will automatically be moved to the position of the System caret each time it moves. -==== Follow mouse ==== +==== Follow mouse cursor ==== When enabled, the review cursor will follow the mouse as it moves. ==== Simple Review mode ==== @@ -1718,8 +1717,8 @@ These are (ordered from left to right): Currently, the right thumb key is not in use. The inner keys are both mapped to space. -%kc:beginInclude || Name | Key | +%kc:beginInclude | backspace key | dot 7 | | enter key | dot 8 | | escape key | space with dot 7 | @@ -1882,6 +1881,43 @@ Please see the [BRLTTY key tables documentation http://mielke.cc/brltty/doc/driv | Route to braille cell | route (bring cursor to character) | %kc:endInclude ++ Braille control type and state abbreviations + +In order to fit as much information as possible on a braille display, The folowing abbreviations have been defined to indicate control type and state. + +|| Abbreviation | Control type | +| btn | button | +| cbo | combo box | +| chk | check box | +| dlg | dialog | +| edt | editable text field | +| gra | graphic | +| cN | table column number n, e.g. c1, c2. | +| rN | table row number n, e.g. r1, r2. | +| hN | heading at level n, e.g. h1, h2. | +| lnk | link | +| lst | list | +| vlnk | visited link | +| mnu | menu | +| mnubar | menu bar | +| rbtn | radio button | +| tb | table | +| tv | treeview | +| lv N | a tree view item has a hierarchical level N| +| ``-----`` | seperator | + +The following state indicators are also defined: +|| Abbreviation | Control state | +| ... | displayed when an object supports autocompletion | +| ( ) | displayed when an object (e.g. a check box) is not checked | +| (x) | displayed when an object (e.g. a check box) is checked | +| (-) | displayed when an object (e.g. a check box) is half checked | +| - | displayed when an object (e.g. a tree view item) is collapsible | +| + | displayed when an object (e.g. a tree view item) is Expandable | +| clk | displayed when an object is clickable | +| ro | displayed when an object (e.g. an editable text field) is read-only | +| sel | displayed when an object is selected | +| submnu | displayed when an object has a popup (usually a sub-menu) | + + Advanced Topics + ++ Advanced Customization of Symbol Pronunciation ++ Repository URL: https://bitbucket.org/nvdaaddonteam/nvda/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. ---------------------------------------------------------------- NVDA add-ons Central: A list for discussing NVDA add-ons To post a message, send an email to nvda-addons@xxxxxxxxxxxxx. To unsubscribe, send an email with the subject line of "unsubscribe" (without quotes) to nvda-addons-request@xxxxxxxxxxxxx. If you have questions for list moderators, please send a message to nvda-addons-moderators@xxxxxxxxxxxxx. Community addons can be found here: http://addons.nvda-project.org