Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions source/UIAHandler/browseMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,19 @@ def _iterNodesByType(self, nodeType, direction="next", pos=None):
UIAHandler.UIA_SliderControlTypeId,
)
return UIAControlQuicknavIterator(nodeType, self, pos, condition, direction)
elif nodeType == "clickable":
# Match the generic control types which UIAWeb exposes with State.CLICKABLE.
condition = createUIAMultiPropertyCondition(
{
UIAHandler.UIA_ControlTypePropertyId: [
UIAHandler.UIA_TextControlTypeId,
UIAHandler.UIA_GroupControlTypeId,
UIAHandler.UIA_ImageControlTypeId,
],
UIAHandler.UIA_IsInvokePatternAvailablePropertyId: True,
},
)
return UIAControlQuicknavIterator(nodeType, self, pos, condition, direction)
elif nodeType == "nonTextContainer":
condition = createUIAMultiPropertyCondition(
{
Expand Down
15 changes: 15 additions & 0 deletions source/browseMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,21 @@ def script_prevSelectedElement(self, gesture: inputCore.InputGesture) -> None:
# Translators: Label announced when cycling browse mode touch navigation element types in browse mode.
touchLabel=_("sliders"),
)
qn(
"clickable",
key=None,
# Translators: Input help message for a quick navigation command in browse mode.
nextDoc=_("moves to the next clickable element"),
# Translators: Message presented when the browse mode element is not found.
nextError=_("no next clickable element"),
# Translators: Input help message for a quick navigation command in browse mode.
prevDoc=_("moves to the previous clickable element"),
# Translators: Message presented when the browse mode element is not found.
prevError=_("no previous clickable element"),
readUnit=textInfos.UNIT_LINE,
# Translators: Label announced when cycling browse mode touch navigation element types in browse mode.
touchLabel=_("clickable elements"),
)
qn(
"article",
key=None,
Expand Down
6 changes: 6 additions & 0 deletions source/virtualBuffers/MSHTML.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ def _searchableAttribsForNodeType(self, nodeType):
{"IAccessible::role": [oleacc.ROLE_SYSTEM_SLIDER]},
{"HTMLAttrib::role": ["slider"]},
]
elif nodeType == "clickable":
attrs = [
{"HTMLAttrib::onclick": [VBufStorage_findMatch_notEmpty]},
{"HTMLAttrib::onmousedown": [VBufStorage_findMatch_notEmpty]},
{"HTMLAttrib::onmouseup": [VBufStorage_findMatch_notEmpty]},
]
elif nodeType == "table":
attrs = {"IHTMLDOMNode::nodeName": ["TABLE"]}
if not config.conf["documentFormatting"]["includeLayoutTables"]:
Expand Down
2 changes: 2 additions & 0 deletions source/virtualBuffers/gecko_ia2.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ def _searchableAttribsForNodeType(self, nodeType):
{"IAccessible::role": [oleacc.ROLE_SYSTEM_SLIDER]},
{"IAccessible2::attribute_xml-roles": [VBufStorage_findMatch_word("slider")]},
]
elif nodeType == "clickable":
attrs = {"IAccessibleAction_click": [VBufStorage_findMatch_notEmpty]}
elif nodeType == "graphic":
attrs = {"IAccessible::role": [oleacc.ROLE_SYSTEM_GRAPHIC]}
elif nodeType == "blockQuote":
Expand Down
38 changes: 38 additions & 0 deletions tests/system/robot/chromeTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2760,6 +2760,44 @@ def test_styleNav():
_asserts.strings_match(actualSpeech, "No next same style text")


def test_clickableNavigation() -> None:
"""Tests that unassigned quick navigation commands move between clickable elements."""
spy: "NVDASpyLib" = _NvdaLib.getSpyLib()
spy.assignGesture(
"kb:z",
"browseMode",
"BrowseModeTreeInterceptor",
"nextClickable",
)
spy.assignGesture(
"kb:shift+z",
"browseMode",
"BrowseModeTreeInterceptor",
"previousClickable",
)
# The navigation must use the clickable metadata even when its speech reporting is disabled.
spy.set_configValue(["documentFormatting", "reportClickable"], False)
_chrome.prepareChrome("""
<p>Before the custom controls</p>
<button>Semantic button</button>
<div tabindex="0" onclick="void(0)">First custom control</div>
<p>Between the custom controls</p>
<div tabindex="0" onclick="void(0)">Second custom control</div>
<p>After the custom controls</p>
""")

actualSpeech = _chrome.getSpeechAfterKey("z")
_asserts.strings_match(actualSpeech, "First custom control")
actualSpeech = _chrome.getSpeechAfterKey("z")
_asserts.strings_match(actualSpeech, "Second custom control")
actualSpeech = _chrome.getSpeechAfterKey("z")
_asserts.strings_match(actualSpeech, "no next clickable element")
actualSpeech = _chrome.getSpeechAfterKey("shift+z")
_asserts.strings_match(actualSpeech, "First custom control")
actualSpeech = _chrome.getSpeechAfterKey("shift+z")
_asserts.strings_match(actualSpeech, "no previous clickable element")


def test_ariaErrorMessage():
_chrome.prepareChrome("""
<h2>Native valid</h2>
Expand Down
4 changes: 4 additions & 0 deletions tests/system/robot/chromeTests.robot
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ styleNav
[Documentation] Same style navigation
[Tags] chrome_misc
test_styleNav
Clickable navigation
[Documentation] Navigate between clickable elements using unassigned quick navigation commands
[Tags] chrome_misc
test_clickableNavigation
Native selection mode focus mode caret movement
[Documentation] The caret can be moved in focus mode while native selection mode is enabled (#19075)
[Tags] chrome_misc
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* All four edges are supported.
Note that the Windows taskbar may override gestures on an edge.
Gestures from the taskbar edge open the Start menu or Action Center, NVDA will not receive them.
* Added an unassigned Quick Navigation Command for jumping to next/previous clickable element in browse mode. (#14429, @cary-rowen)
* On supported braille displays, pressing multiple routing keys simultaneously can now be bound to a new "multi routing" gesture. (#20001, @LeonarddeR)
* The "select range" command, which selects the text from the first up to the last pressed routing key, is bound to this gesture by default on supporting drivers.
* Drivers with built-in support for multi routing: ALVA, Albatross (only when combined with `home1` or `home2`), Baum (and compatible), Freedom Scientific Focus/PAC Mate, HumanWare Brailliant BI/B series, Handy Tech, NLS eReader Zoomax, Seika Notetaker, and Standard HID Braille displays.
Expand Down
1 change: 1 addition & 0 deletions user_docs/en/userGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,7 @@ Here is a list of available commands:
* Toggle button
* Progress bar
* Slider
* Clickable element
* Reference
* Math formula
* Vertically aligned paragraph
Expand Down