Skip to content

Commit 66cf02e

Browse files
authored
Merge d97430a into 856adec
2 parents 856adec + d97430a commit 66cf02e

10 files changed

Lines changed: 107 additions & 57 deletions

File tree

source/NVDAObjects/IAccessible/MSHTML.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -545,9 +545,11 @@ def _get_treeInterceptorClass(self):
545545

546546
def _get_isCurrent(self):
547547
isCurrent = self.HTMLAttributes["aria-current"]
548-
if isCurrent == "false":
549-
isCurrent = None
550-
return isCurrent
548+
try:
549+
return controlTypes.IsCurrent(isCurrent)
550+
except ValueError:
551+
log.debugWarning(f"Unknown aria-current value: {isCurrent}")
552+
return controlTypes.IsCurrent.NO
551553

552554
def _get_HTMLAttributes(self):
553555
return HTMLAttribCache(self.HTMLNode)

source/NVDAObjects/IAccessible/ia2Web.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ def _get_positionInfo(self):
3434
info['level']=level
3535
return info
3636

37-
def _get_isCurrent(self):
38-
current = self.IA2Attributes.get("current", None)
39-
if current == "false":
40-
current = None
41-
return current
37+
def _get_isCurrent(self) -> controlTypes.IsCurrent:
38+
ia2attrCurrent: str = self.IA2Attributes.get("current", "false")
39+
try:
40+
return controlTypes.IsCurrent(ia2attrCurrent)
41+
except ValueError:
42+
log.debugWarning(f"Unknown 'current' IA2Attribute value: {ia2attrCurrent}")
43+
return controlTypes.IsCurrent.NO
4244

4345
def _get_placeholder(self):
4446
placeholder = self.IA2Attributes.get('placeholder', None)

source/NVDAObjects/UIA/edge.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def _getControlFieldForObject(self,obj,isEmbedded=False,startOfNode=False,endOfN
156156
if obj.role==controlTypes.ROLE_COMBOBOX and obj.UIATextPattern:
157157
field['states'].add(controlTypes.STATE_EDITABLE)
158158
# report if the field is 'current'
159-
field['current']=obj.isCurrent
159+
field['current'] = obj.isCurrent
160160
if obj.placeholder and obj._isTextEmpty:
161161
field['placeholder']=obj.placeholder
162162
# For certain controls, if ARIA overrides the label, then force the field's content (value) to the label
@@ -470,15 +470,18 @@ def _get_ariaProperties(self):
470470
# "false" is ignored by the regEx and will not produce a match
471471
RE_ARIA_CURRENT_PROP_VALUE = re.compile("current=(?!false)(\w+);")
472472

473-
def _get_isCurrent(self):
473+
def _get_isCurrent(self) -> controlTypes.IsCurrent:
474474
ariaProperties=self._getUIACacheablePropertyValue(UIAHandler.UIA_AriaPropertiesPropertyId)
475475
match = self.RE_ARIA_CURRENT_PROP_VALUE.search(ariaProperties)
476-
log.debug("aria props = %s" % ariaProperties)
477476
if match:
478477
valueOfAriaCurrent = match.group(1)
479-
log.debug("aria current value = %s" % valueOfAriaCurrent)
480-
return valueOfAriaCurrent
481-
return None
478+
try:
479+
return controlTypes.IsCurrent(valueOfAriaCurrent)
480+
except ValueError:
481+
log.debugWarning(
482+
f"Unknown aria-current value: {valueOfAriaCurrent}, ariaProperties: {ariaProperties}"
483+
)
484+
return controlTypes.IsCurrent.NO
482485

483486
def _get_roleText(self):
484487
roleText = self.ariaProperties.get('roledescription', None)

source/NVDAObjects/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -975,12 +975,13 @@ def _get_statusBar(self):
975975
"""
976976
return None
977977

978-
def _get_isCurrent(self):
978+
isCurrent: controlTypes.IsCurrent #: type info for auto property _get_isCurrent
979+
980+
def _get_isCurrent(self) -> controlTypes.IsCurrent:
979981
"""Gets the value that indicates whether this object is the current element in a set of related
980-
elements. This maps to aria-current. Normally returns None. If this object is current
981-
it will return one of the following values: "true", "page", "step", "location", "date", "time"
982+
elements. This maps to aria-current.
982983
"""
983-
return None
984+
return controlTypes.IsCurrent.NO
984985

985986
def _get_shouldAcceptShowHideCaretEvent(self):
986987
"""Some objects/applications send show/hide caret events when we don't expect it, such as when the cursor is blinking.

source/braille.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -579,13 +579,9 @@ def getPropertiesBraille(**propertyValues) -> str: # noqa: C901
579579
# %s is replaced with the column number.
580580
columnStr = _("c{columnNumber}").format(columnNumber=columnNumber)
581581
textList.append(columnStr)
582-
current = propertyValues.get('current', False)
583-
if current:
584-
try:
585-
textList.append(controlTypes.isCurrentLabels[current])
586-
except KeyError:
587-
log.debugWarning("Aria-current value not handled: %s"%current)
588-
textList.append(controlTypes.isCurrentLabels[True])
582+
isCurrent = propertyValues.get('current', controlTypes.IsCurrent.NO)
583+
if isCurrent != controlTypes.IsCurrent.NO:
584+
textList.append(isCurrent.displayString)
589585
placeholder = propertyValues.get('placeholder', None)
590586
if placeholder:
591587
textList.append(placeholder)
@@ -670,7 +666,7 @@ def getControlFieldBraille(info, field, ancestors, reportStart, formatConfig):
670666

671667
states = field.get("states", set())
672668
value=field.get('value',None)
673-
current=field.get('current', None)
669+
current = field.get('current', controlTypes.IsCurrent.NO)
674670
placeholder=field.get('placeholder', None)
675671
roleText = field.get('roleTextBraille', field.get('roleText'))
676672
landmark = field.get("landmark")

source/controlTypes.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from typing import Dict, Union, Set, Any, Optional, List
77
from enum import Enum, auto
88

9+
from logHandler import log
10+
911
ROLE_UNKNOWN=0
1012
ROLE_WINDOW=1
1113
ROLE_TITLEBAR=2
@@ -649,21 +651,50 @@ class OutputReason(Enum):
649651
QUICKNAV = auto()
650652

651653

652-
#: Text to use for 'current' values. These describe if an item is the current item
653-
#: within a particular kind of selection.
654-
isCurrentLabels: Dict[Union[bool, str], str] = {
654+
655+
class IsCurrent(Enum):
656+
"""Values to use within NVDA to denote 'current' values.
657+
These describe if an item is the current item within a particular kind of selection.
658+
EG aria-current
659+
"""
660+
NO = "false"
661+
YES = "true"
662+
PAGE = "page"
663+
STEP = "step"
664+
LOCATION = "location"
665+
DATE = "date"
666+
TIME = "time"
667+
668+
@property
669+
def displayString(self):
670+
"""
671+
@return: The translated UI display string that should be used for this value of the IsCurrent enum
672+
"""
673+
try:
674+
return _isCurrentLabels[self]
675+
except KeyError:
676+
log.debugWarning(f"No translation mapping for: {self}")
677+
# there is a value for 'current' but NVDA hasn't learned about it yet,
678+
# at least describe in the general sense that this item is 'current'
679+
return _isCurrentLabels[IsCurrent.YES]
680+
681+
682+
#: Text to use for 'current' values. These describe if an item is the current item
683+
#: within a particular kind of selection. EG aria-current
684+
_isCurrentLabels: Dict[Enum, str] = {
685+
IsCurrent.NO: "", # There is nothing extra to say for items that are not current.
655686
# Translators: Presented when an item is marked as current in a collection of items
656-
True:_("current"),
687+
IsCurrent.YES: _("current"),
657688
# Translators: Presented when a page item is marked as current in a collection of page items
658-
"page":_("current page"),
689+
IsCurrent.PAGE: _("current page"),
659690
# Translators: Presented when a step item is marked as current in a collection of step items
660-
"step":_("current step"),
691+
IsCurrent.STEP: _("current step"),
661692
# Translators: Presented when a location item is marked as current in a collection of location items
662-
"location":_("current location"),
693+
IsCurrent.LOCATION: _("current location"),
663694
# Translators: Presented when a date item is marked as current in a collection of date items
664-
"date":_("current date"),
695+
IsCurrent.DATE: _("current date"),
665696
# Translators: Presented when a time item is marked as current in a collection of time items
666-
"time":_("current time"),
697+
IsCurrent.TIME: _("current time"),
667698
}
668699

669700

source/speech/__init__.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def getObjectPropertiesSpeech( # noqa: C901
362362
positionInfo=obj.positionInfo
363363
elif value and name == "current":
364364
# getPropertiesSpeech names this "current", but the NVDAObject property is
365-
# named "isCurrent".
365+
# named "isCurrent", it's type should always be controltypes.IsCurrent
366366
newPropertyValues['current'] = obj.isCurrent
367367
elif value:
368368
# Certain properties such as row and column numbers have presentational versions, which should be used for speech if they are available.
@@ -1611,15 +1611,12 @@ def getPropertiesSpeech( # noqa: C901
16111611
if rowCount or columnCount:
16121612
# The caller is entering a table, so ensure that it is treated as a new table, even if the previous table was the same.
16131613
oldTableID = None
1614-
ariaCurrent = propertyValues.get('current', False)
1615-
if ariaCurrent:
1616-
try:
1617-
ariaCurrentLabel = controlTypes.isCurrentLabels[ariaCurrent]
1618-
textList.append(ariaCurrentLabel)
1619-
except KeyError:
1620-
log.debugWarning("Aria-current value not handled: %s"%ariaCurrent)
1621-
ariaCurrentLabel = controlTypes.isCurrentLabels[True]
1622-
textList.append(ariaCurrentLabel)
1614+
1615+
# speak isCurrent property EG aria-current
1616+
isCurrent = propertyValues.get('current', controlTypes.IsCurrent.NO)
1617+
if isCurrent != controlTypes.IsCurrent.NO:
1618+
textList.append(isCurrent.displayString)
1619+
16231620
placeholder: Optional[str] = propertyValues.get('placeholder', None)
16241621
if placeholder:
16251622
textList.append(placeholder)
@@ -1682,7 +1679,7 @@ def getControlFieldSpeech( # noqa: C901
16821679
name = ""
16831680
states=attrs.get('states',set())
16841681
keyboardShortcut=attrs.get('keyboardShortcut', "")
1685-
ariaCurrent=attrs.get('current', None)
1682+
isCurrent = attrs.get('current', controlTypes.IsCurrent.NO)
16861683
placeholderValue=attrs.get('placeholder', None)
16871684
value=attrs.get('value',"")
16881685
if reason == OutputReason.FOCUS or attrs.get('alwaysReportDescription', False):
@@ -1712,7 +1709,7 @@ def getControlFieldSpeech( # noqa: C901
17121709
keyboardShortcutSequence = getPropertiesSpeech(
17131710
reason=reason, keyboardShortcut=keyboardShortcut
17141711
)
1715-
ariaCurrentSequence = getPropertiesSpeech(reason=reason, current=ariaCurrent)
1712+
isCurrentSequence = getPropertiesSpeech(reason=reason, current=isCurrent)
17161713
placeholderSequence = getPropertiesSpeech(reason=reason, placeholder=placeholderValue)
17171714
nameSequence = getPropertiesSpeech(reason=reason, name=name)
17181715
valueSequence = getPropertiesSpeech(reason=reason, value=value)
@@ -1829,7 +1826,7 @@ def getControlFieldSpeech( # noqa: C901
18291826
getProps['columnHeaderText'] = attrs.get("table-columnheadertext")
18301827
tableCellSequence = getPropertiesSpeech(_tableID=tableID, **getProps)
18311828
tableCellSequence.extend(stateTextSequence)
1832-
tableCellSequence.extend(ariaCurrentSequence)
1829+
tableCellSequence.extend(isCurrentSequence)
18331830
types.logBadSequenceTypes(tableCellSequence)
18341831
return tableCellSequence
18351832

@@ -1878,7 +1875,7 @@ def getControlFieldSpeech( # noqa: C901
18781875
out.extend(stateTextSequence if speakStatesFirst else roleTextSequence)
18791876
out.extend(roleTextSequence if speakStatesFirst else stateTextSequence)
18801877
out.append(containerContainsText)
1881-
out.extend(ariaCurrentSequence)
1878+
out.extend(isCurrentSequence)
18821879
out.extend(valueSequence)
18831880
out.extend(descriptionSequence)
18841881
out.extend(levelSequence)
@@ -1913,8 +1910,8 @@ def getControlFieldSpeech( # noqa: C901
19131910
# Special cases
19141911
elif not speakEntry and fieldType in ("start_addedToControlFieldStack","start_relative"):
19151912
out = []
1916-
if ariaCurrent:
1917-
out.extend(ariaCurrentSequence)
1913+
if isCurrent != controlTypes.IsCurrent.NO:
1914+
out.extend(isCurrentSequence)
19181915
# Speak expanded / collapsed / level for treeview items (in ARIA treegrids)
19191916
if role == controlTypes.ROLE_TREEVIEWITEM:
19201917
if controlTypes.STATE_EXPANDED in states:

source/virtualBuffers/MSHTML.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,17 @@ def _normalizeFormatField(self, attrs):
4848

4949
def _normalizeControlField(self,attrs):
5050
level=None
51-
ariaCurrent = attrs.get('HTMLAttrib::aria-current', None)
52-
if ariaCurrent not in (None, "false"):
53-
attrs['current']=ariaCurrent
51+
52+
ariaCurrentValue = attrs.get('HTMLAttrib::aria-current', 'false')
53+
try:
54+
ariaCurrent = controlTypes.IsCurrent(ariaCurrentValue)
55+
except ValueError:
56+
log.debugWarning(f"Unknown aria-current value: {ariaCurrentValue}")
57+
ariaCurrent = controlTypes.IsCurrent.NO
58+
59+
if ariaCurrent != controlTypes.IsCurrent.NO:
60+
attrs['current'] = ariaCurrent
61+
5462
placeholder = self._getPlaceholderAttribute(attrs, 'HTMLAttrib::aria-placeholder')
5563
if placeholder:
5664
attrs['placeholder']=placeholder

source/virtualBuffers/gecko_ia2.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,14 @@ def _normalizeControlField(self,attrs):
5252
if attrVal is not None:
5353
attrs[attr]=int(attrVal)
5454

55-
current = attrs.get("IAccessible2::attribute_current")
56-
if current not in (None, 'false'):
57-
attrs['current']= current
55+
valForCurrent = attrs.get("IAccessible2::attribute_current", "false")
56+
try:
57+
isCurrent = controlTypes.IsCurrent(valForCurrent)
58+
except ValueError:
59+
log.debugWarning(f"Unknown isCurrent value: {valForCurrent}")
60+
isCurrent = controlTypes.IsCurrent.NO
61+
if isCurrent != controlTypes.IsCurrent.NO:
62+
attrs['current'] = isCurrent
5863
placeholder = self._getPlaceholderAttribute(attrs, "IAccessible2::attribute_placeholder")
5964
if placeholder is not None:
6065
attrs['placeholder']= placeholder

user_docs/en/changes.t2t

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ What's New in NVDA
3737
- getConfigDirs - use globalVars.appArgs.configPath instead
3838
- Module level REASON_* constants are removed from controlTypes - please use controlTypes.OutputReason instead. (#11969)
3939
- REASON_QUICKNAV has been removed from browseMode - use controlTypes.OutputReason.QUICKNAV instead. (#11969)
40+
- 'NVDAObject' (and derivatives) property 'isCurrent' now strictly returns Enum class 'controlTypes.IsCurrent'. (#11782)
41+
- 'isCurrent' is no longer Optional, and thus will not return None.
42+
- When an object is not current 'controlTypes.IsCurrent.NO' is returned.
43+
- The 'controlTypes.isCurrentLabels' mapping has been removed. (#11782)
44+
- Instead use the 'displayString' property on a 'controlTypes.IsCurrent' enum value. EG 'controlTypes.IsCurrent.YES.displayString'
4045

4146

4247
= 2020.4 =

0 commit comments

Comments
 (0)