Skip to content

Commit

Permalink
Revert "Revert "Don't announce 'selected' when the focus moves in Goo…
Browse files Browse the repository at this point in the history
…gle sheets if the focused cell is the only cell selected (#8879)" (#8893)"

This reverts commit b4e9e83.
  • Loading branch information
michaelDCurran authored Oct 31, 2018
1 parent fd24d81 commit 6c2ddf1
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 1 deletion.
43 changes: 43 additions & 0 deletions source/NVDAObjects/IAccessible/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.

from comtypes.automation import IEnumVARIANT, VARIANT
from comtypes import COMError, IServiceProvider, GUID
from comtypes.hresult import S_OK, S_FALSE
import ctypes
import os
import re
Expand Down Expand Up @@ -1214,6 +1216,47 @@ def _get_rowHeaderText(self):
def _get_columnHeaderText(self):
return self._tableHeaderTextHelper("column")

def _get_selectionContainer(self):
if self.table:
return self.table
return super(IAccessible,self).selectionContainer

def _getSelectedItemsCount_accSelection(self,maxCount):
sel=self.IAccessibleObject.accSelection
if not sel:
raise NotImplementedError
enumObj=sel.QueryInterface(IEnumVARIANT)
if not enumObj:
raise NotImplementedError
# Call the rawmethod for IEnumVARIANT::Next as COMTypes' overloaded version does not allow limiting the amount of items returned
numItemsFetched=ctypes.c_ulong()
itemsBuf=(VARIANT*(maxCount+1))()
res=enumObj._IEnumVARIANT__com_Next(maxCount,itemsBuf,ctypes.byref(numItemsFetched))
# IEnumVARIANT returns S_FALSE if the buffer is too small, although it still writes as many as it can.
# For our purposes, we can treat both S_OK and S_FALSE as success.
if res!=S_OK and res!=S_FALSE:
raise COMError(res,None,None)
return numItemsFetched.value if numItemsFetched.value<=maxCount else sys.maxint

def getSelectedItemsCount(self,maxCount):
# To fetch the number of selected items, we first try MSAA's accSelection, but if that fails in any way, we fall back to using IAccessibleTable2's nSelectedCells, if we are on an IAccessible2 table.
# Currently Chrome does not implement accSelection, thus for Google Sheets we must use nSelectedCells when on a table.
try:
return self._getSelectedItemsCount_accSelection(maxCount)
except (COMError,NotImplementedError) as e:
log.debug("Cannot fetch selected items count using accSelection, %s"%e)
pass
if self.IAccessibleTable2Object:
try:
return self.IAccessibleTable2Object.nSelectedCells
except COMError as e:
log.debug("Error calling IAccessibleTable2::nSelectedCells, %s"%e)
pass
else:
log.debug("No means of getting a selection count from this IAccessible")
return super(IAccessible,self).getSelectedItemsCount(maxCount)


def _get_table(self):
if not isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2):
return None
Expand Down
12 changes: 12 additions & 0 deletions source/NVDAObjects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1181,3 +1181,15 @@ def _get__hasNavigableText(self):
return True
else:
return False

def _get_selectionContainer(self):
""" An ancestor NVDAObject which manages the selection for this object and other descendants."""
return None

def getSelectedItemsCount(self,maxCount=2):
"""
Fetches the number of descendants currently selected.
For performance, this method will only count up to the given maxCount number, and if there is one more above that, then sys.maxint is returned stating that many items are selected.
"""
return 0

13 changes: 12 additions & 1 deletion source/controlTypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,18 @@ def processNegativeStates(role, states, reason, negativeStates=None):
# but only if it is either focused or this is something other than a change event.
# The condition stops "not selected" from being spoken in some broken controls
# when the state change for the previous focus is issued before the focus change.
if role in (ROLE_LISTITEM, ROLE_TREEVIEWITEM, ROLE_TABLEROW) and STATE_SELECTABLE in states and (reason != REASON_CHANGE or STATE_FOCUSED in states):
if (
STATE_SELECTABLE in states
and (reason != REASON_CHANGE or STATE_FOCUSED in states)
and role in (
ROLE_LISTITEM,
ROLE_TREEVIEWITEM,
ROLE_TABLEROW,
ROLE_TABLECELL,
ROLE_TABLECOLUMNHEADER,
ROLE_TABLEROWHEADER
)
):
speakNegatives.add(STATE_SELECTED)
# Restrict "not checked" in a similar way to "not selected".
if (role in (ROLE_CHECKBOX, ROLE_RADIOBUTTON, ROLE_CHECKMENUITEM) or STATE_CHECKABLE in states) and (STATE_HALFCHECKED not in states) and (reason != REASON_CHANGE or STATE_FOCUSED in states):
Expand Down
13 changes: 13 additions & 0 deletions source/speech.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,19 @@ def speakObjectProperties(obj,reason=controlTypes.REASON_QUERY,index=None,**allo
newPropertyValues['current']=obj.isCurrent
if allowedProperties.get('placeholder', False):
newPropertyValues['placeholder']=obj.placeholder
# When speaking an object due to a focus change, the 'selected' state should not be reported if only one item is selected.
# This is because that one item will be the focused object, and saying selected is redundant.
# Rather, 'unselected' will be spoken for an unselected object if 1 or more items are selected.
states=newPropertyValues.get('states')
if states is not None and reason==controlTypes.REASON_FOCUS:
if (
controlTypes.STATE_SELECTABLE in states
and controlTypes.STATE_SELECTED in states
and obj.selectionContainer
and obj.selectionContainer.getSelectedItemsCount(2)==1
):
states.discard(controlTypes.STATE_SELECTED)
states.discard(controlTypes.STATE_SELECTABLE)
#Get the speech text for the properties we want to speak, and then speak it
text=getSpeechTextForProperties(reason,**newPropertyValues)
if text:
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/changes.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ What's New in NVDA
- Replied / Forwarded status is now reported on mail items in the Microsoft Outlook message list. (#6911)
- NVDA is now able to read descriptions for emoji as well as other characters that are part of the Unicode Common Locale Data Repository. (#6523)
- In Microsoft Word, the cursor's distance from the top and left edges of the page can be reported by pressing NVDA+numpadDelete. (#1939)
- In Google Sheets with braille mode enabled, NVDA no longer announces 'selected' on every cell when moving focus between cells. (#8879)


== Changes ==
Expand Down

0 comments on commit 6c2ddf1

Please sign in to comment.