Skip to content
Closed
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
3 changes: 3 additions & 0 deletions source/config/configSpec.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@
enabled = boolean(default=true)
touchTyping = boolean(default=False)

[touchpad]
enabled = boolean(default=false)

#Settings for document reading (such as MS Word and wordpad)
[documentFormatting]
# These settings affect what information is reported when you navigate
Expand Down
7 changes: 7 additions & 0 deletions source/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,11 @@ def main():
touchHandler.initialize()
except NotImplementedError:
pass
import touchpadHandler

log.debug("Initializing touchpadHandler")
touchpadHandler.initialize()

import globalPluginHandler

log.debug("Initializing global plugin handler")
Expand Down Expand Up @@ -998,6 +1003,7 @@ def Notify(self):
try:
if touchHandler.handler:
touchHandler.handler.pump()
touchpadHandler.handler.pump()
JABHandler.pumpAll()
IAccessibleHandler.pumpAll()
queueHandler.pumpAll()
Expand Down Expand Up @@ -1088,6 +1094,7 @@ def _doPostNvdaStartupAction():
_terminate(appModuleHandler, name="app module handler")
_terminate(tones)
_terminate(touchHandler)
_terminate(touchpadHandler)
_terminate(keyboardHandler, name="keyboard handler")
_terminate(mouseHandler)
_terminate(inputCore)
Expand Down
202 changes: 186 additions & 16 deletions source/globalCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import audioDucking
import touchHandler
import touchpadHandler
import keyboardHandler
import mouseHandler
import eventHandler
Expand Down Expand Up @@ -108,6 +109,9 @@
#: Script category for touch commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_TOUCH = _("Touch screen")
#: Script category for touchpad commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_TOUCHPAD = _("Touchpad")
Comment on lines 109 to +114
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend to use only 1 category, since most of the touch scripts are common to touch screen and touch pad.

Suggested change
#: Script category for touch commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_TOUCH = _("Touch screen")
#: Script category for touchpad commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_TOUCHPAD = _("Touchpad")
#: Script category for touch commands (touch screen or touch pad).
# Translators: The name of a category of NVDA commands.
SCRCAT_TOUCH = _("Touch interaction")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well after looking better to your code, I realize that all scripts are duplicated. So having 2 categories for them is OK if you keep them duplicated.

But I wonder if it wouldn't be worth factorizing touch screen and touch pad scripts, since these are very similar. I have not looked at it in depth tough.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's an interesting idea.

However, I'm not sure whether NV Access is willing to accept this into the core.

In order to prevent gesture conflicts, the system's built-in touchpad gestures should be disabled first. If the user does this manually in Settings, it will take effect immediately. However, if NVDA tries to modify the registry key, the change won't take effect until explorer restarts.

I found that in order to apply the changes, an undocumented interface has to be used to inform explorer of the changes. Undocumented interfaces can be unstable, which is why I'd like NV Access to make a decision here (see discussion). Without this undocumented interface, it's required to either restart explorer or instruct users to change the settings manually.

#: Script category for focus commands.
# Translators: The name of a category of NVDA commands.
SCRCAT_FOCUS = _("System focus")
Expand Down Expand Up @@ -1349,7 +1353,12 @@ def script_moveNavigatorObjectToMouse(self, gesture: inputCore.InputGesture):
"and positions the review position at the point of the navigator object",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:NVDA+numpad7", "kb(laptop):NVDA+pageUp", "ts(object):2finger_flickUp"),
gestures=(
"kb:NVDA+numpad7",
"kb(laptop):NVDA+pageUp",
"ts(object):2finger_flickUp",
"tp(object):2finger_flickUp",
),
)
def script_reviewMode_next(self, gesture):
label = review.nextMode()
Expand All @@ -1370,7 +1379,12 @@ def script_reviewMode_next(self, gesture):
"and positions the review position at the point of the navigator object",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:NVDA+numpad1", "kb(laptop):NVDA+pageDown", "ts(object):2finger_flickDown"),
gestures=(
"kb:NVDA+numpad1",
"kb(laptop):NVDA+pageDown",
"ts(object):2finger_flickDown",
"tp(object):2finger_flickDown",
),
)
def script_reviewMode_previous(self, gesture):
label = review.nextMode(prev=True)
Expand Down Expand Up @@ -1632,7 +1646,12 @@ def script_navigatorObject_moveFocus(self, gesture: inputCore.InputGesture):
# Translators: Input help mode message for move to parent object command.
description=_("Moves the navigator object to the object containing it"),
category=SCRCAT_OBJECTNAVIGATION,
gestures=("kb:NVDA+numpad8", "kb(laptop):NVDA+shift+upArrow", "ts(object):flickup"),
gestures=(
"kb:NVDA+numpad8",
"kb(laptop):NVDA+shift+upArrow",
"ts(object):flickup",
"tp(object):flickup",
),
)
def script_navigatorObject_parent(self, gesture: inputCore.InputGesture):
curObject = api.getNavigatorObject()
Expand Down Expand Up @@ -1663,7 +1682,12 @@ def script_navigatorObject_parent(self, gesture: inputCore.InputGesture):
# Translators: Input help mode message for move to next object command.
description=_("Moves the navigator object to the next object"),
category=SCRCAT_OBJECTNAVIGATION,
gestures=("kb:NVDA+numpad6", "kb(laptop):NVDA+shift+rightArrow", "ts(object):2finger_flickright"),
gestures=(
"kb:NVDA+numpad6",
"kb(laptop):NVDA+shift+rightArrow",
"ts(object):2finger_flickright",
"tp(object):2finger_flickright",
),
)
def script_navigatorObject_next(self, gesture: inputCore.InputGesture):
curObject = api.getNavigatorObject()
Expand Down Expand Up @@ -1693,7 +1717,12 @@ def script_navigatorObject_next(self, gesture: inputCore.InputGesture):
# Translators: Input help mode message for move to previous object command.
description=_("Moves the navigator object to the previous object"),
category=SCRCAT_OBJECTNAVIGATION,
gestures=("kb:NVDA+numpad4", "kb(laptop):NVDA+shift+leftArrow", "ts(object):2finger_flickleft"),
gestures=(
"kb:NVDA+numpad4",
"kb(laptop):NVDA+shift+leftArrow",
"ts(object):2finger_flickleft",
"tp(object):2finger_flickleft",
),
)
def script_navigatorObject_previous(self, gesture: inputCore.InputGesture):
curObject = api.getNavigatorObject()
Expand Down Expand Up @@ -1722,7 +1751,12 @@ def script_navigatorObject_previous(self, gesture: inputCore.InputGesture):
# Translators: Input help mode message for move to first child object command.
description=_("Moves the navigator object to the first object inside it"),
category=SCRCAT_OBJECTNAVIGATION,
gestures=("kb:NVDA+numpad2", "kb(laptop):NVDA+shift+downArrow", "ts(object):flickdown"),
gestures=(
"kb:NVDA+numpad2",
"kb(laptop):NVDA+shift+downArrow",
"ts(object):flickdown",
"tp(object):flickdown",
),
)
def script_navigatorObject_firstChild(self, gesture: inputCore.InputGesture):
curObject = api.getNavigatorObject()
Expand Down Expand Up @@ -1756,7 +1790,7 @@ def script_navigatorObject_firstChild(self, gesture: inputCore.InputGesture):
"(example: presses it if it is a button).",
),
category=SCRCAT_OBJECTNAVIGATION,
gestures=("kb:NVDA+numpadEnter", "kb(laptop):NVDA+enter", "ts:double_tap"),
gestures=("kb:NVDA+numpadEnter", "kb(laptop):NVDA+enter", "ts:double_tap", "tp:double_tap"),
)
def script_review_activate(self, gesture: inputCore.InputGesture):
# Translators: a message reported when the action at the position of the review cursor or navigator object is performed.
Expand Down Expand Up @@ -1833,7 +1867,12 @@ def script_review_top(self, gesture: inputCore.InputGesture):
),
resumeSayAllMode=sayAll.CURSOR.REVIEW,
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad7", "kb(laptop):NVDA+upArrow", "ts(text):flickUp"),
gestures=(
"kb:numpad7",
"kb(laptop):NVDA+upArrow",
"ts(text):flickUp",
"tp(text):flickUp",
),
)
def script_review_previousLine(self, gesture: inputCore.InputGesture):
info = api.getReviewPosition().copy()
Expand Down Expand Up @@ -1895,7 +1934,12 @@ def script_review_currentLine(self, gesture: inputCore.InputGesture):
),
resumeSayAllMode=sayAll.CURSOR.REVIEW,
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad9", "kb(laptop):NVDA+downArrow", "ts(text):flickDown"),
gestures=(
"kb:numpad9",
"kb(laptop):NVDA+downArrow",
"ts(text):flickDown",
"tp(text):flickDown",
),
)
def script_review_nextLine(self, gesture: inputCore.InputGesture):
origInfo = api.getReviewPosition().copy()
Expand Down Expand Up @@ -2031,7 +2075,12 @@ def script_review_bottom(self, gesture: inputCore.InputGesture):
"Moves the review cursor to the previous word of the current navigator object and speaks it",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad4", "kb(laptop):NVDA+control+leftArrow", "ts(text):2finger_flickLeft"),
gestures=(
"kb:numpad4",
"kb(laptop):NVDA+control+leftArrow",
"ts(text):2finger_flickLeft",
"tp(text):2finger_flickLeft",
),
)
def script_review_previousWord(self, gesture: inputCore.InputGesture):
info = api.getReviewPosition().copy()
Expand Down Expand Up @@ -2066,7 +2115,12 @@ def script_review_previousWord(self, gesture: inputCore.InputGesture):
"Pressing three times spells the word using character descriptions",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad5", "kb(laptop):NVDA+control+.", "ts(text):hoverUp"),
gestures=(
"kb:numpad5",
"kb(laptop):NVDA+control+.",
"ts(text):hoverUp",
"tp(text):hoverUp",
),
speakOnDemand=True,
)
def script_review_currentWord(self, gesture: inputCore.InputGesture):
Expand All @@ -2093,7 +2147,12 @@ def script_review_currentWord(self, gesture: inputCore.InputGesture):
"Moves the review cursor to the next word of the current navigator object and speaks it",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad6", "kb(laptop):NVDA+control+rightArrow", "ts(text):2finger_flickRight"),
gestures=(
"kb:numpad6",
"kb(laptop):NVDA+control+rightArrow",
"ts(text):2finger_flickRight",
"tp(text):2finger_flickRight",
),
)
def script_review_nextWord(self, gesture: inputCore.InputGesture):
origInfo = api.getReviewPosition().copy()
Expand Down Expand Up @@ -2160,7 +2219,12 @@ def script_review_startOfLine(self, gesture: inputCore.InputGesture):
"Moves the review cursor to the previous character of the current navigator object and speaks it",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad1", "kb(laptop):NVDA+leftArrow", "ts(text):flickLeft"),
gestures=(
"kb:numpad1",
"kb(laptop):NVDA+leftArrow",
"ts(text):flickLeft",
"tp(text):flickLeft",
),
)
def script_review_previousCharacter(self, gesture: inputCore.InputGesture):
lineInfo = api.getReviewPosition().copy()
Expand Down Expand Up @@ -2245,7 +2309,12 @@ def script_review_currentCharacter(self, gesture: inputCore.InputGesture):
"Moves the review cursor to the next character of the current navigator object and speaks it",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpad3", "kb(laptop):NVDA+rightArrow", "ts(text):flickRight"),
gestures=(
"kb:numpad3",
"kb(laptop):NVDA+rightArrow",
"ts(text):flickRight",
"tp(text):flickRight",
),
)
def script_review_nextCharacter(self, gesture: inputCore.InputGesture):
lineInfo = api.getReviewPosition().copy()
Expand Down Expand Up @@ -2529,7 +2598,7 @@ def script_restart(self, gesture):
@script(
# Translators: Input help mode message for show NVDA menu command.
description=_("Shows the NVDA menu"),
gestures=("kb:NVDA+n", "ts:2finger_double_tap"),
gestures=("kb:NVDA+n", "ts:2finger_double_tap", "tp:2finger_double_tap"),
)
@gui.blockAction.when(gui.blockAction.Context.MODAL_DIALOG_OPEN)
def script_showGui(self, gesture):
Expand All @@ -2542,7 +2611,12 @@ def script_showGui(self, gesture):
" moving the review cursor as it goes",
),
category=SCRCAT_TEXTREVIEW,
gestures=("kb:numpadPlus", "kb(laptop):NVDA+shift+a", "ts(text):3finger_flickDown"),
gestures=(
"kb:numpadPlus",
"kb(laptop):NVDA+shift+a",
"ts(text):3finger_flickDown",
"tp(text):3finger_flickDown",
),
speakOnDemand=True,
)
def script_review_sayAll(self, gesture: inputCore.InputGesture):
Expand Down Expand Up @@ -4482,6 +4556,7 @@ def script_reportLinkDestinationInWindow(self, gesture: inputCore.InputGesture)
category=SCRCAT_OBJECTNAVIGATION,
gestures=(
"ts(object):flickright",
"tp(object):flickright",
"kb:NVDA+numpad3",
"kb(laptop):shift+NVDA+]",
),
Expand Down Expand Up @@ -4520,6 +4595,7 @@ def script_navigatorObject_nextInFlow(self, gesture: inputCore.InputGesture):
category=SCRCAT_OBJECTNAVIGATION,
gestures=(
"ts(object):flickleft",
"tp(object):flickleft",
"kb:NVDA+numpad9",
"kb(laptop):shift+NVDA+[",
),
Expand Down Expand Up @@ -4661,6 +4737,100 @@ def script_touch_rightClick(self, gesture):
winUser.setCursorPos(x, y)
self.script_rightMouseClick(gesture)

@script(
# Translators: Describes a command.
description=_("Toggles the support of touchpad interaction"),
category=SCRCAT_TOUCHPAD,
gesture="kb:NVDA+control+alt+p",
)
def script_toggleTouchpadSupport(self, gesture):
enabled = not bool(config.conf["touchpad"]["enabled"])
touchpadHandler.handler.enabled = enabled
# Set configuration upon success
config.conf["touchpad"]["enabled"] = enabled
if enabled:
# Translators: Presented when support of touch interaction has been enabled
ui.message(_("Touchpad interaction enabled"))
else:
# Translators: Presented when support of touch interaction has been disabled
ui.message(_("Touchpad interaction disabled"))

@script(
# Translators: Input help mode message for a touchpad gesture.
description=_("Cycles between available touchpad modes"),
category=SCRCAT_TOUCHPAD,
gesture="tp:3finger_tap",
)
def script_touchpad_changeMode(self, gesture):
mode = touchpadHandler.handler._curTouchMode
index = touchpadHandler.availableTouchModes.index(mode)
index = (index + 1) % len(touchpadHandler.availableTouchModes)
newMode = touchpadHandler.availableTouchModes[index]
touchpadHandler.handler._curTouchMode = newMode
try:
newModeLabel = touchpadHandler.touchModeLabels[newMode]
except KeyError:
# Translators: Cycles through available touch modes (a group of related touch gestures; example output: "object mode"; see the user guide for more information on touch modes).
newModeLabel = _("%s mode") % newMode
ui.message(newModeLabel)

@script(
# Translators: Input help mode message for a touchpad gesture.
description=_("Reports the object and content directly under your finger"),
category=SCRCAT_TOUCHPAD,
gestures=("tp:tap", "tp:hoverDown"),
)
def script_touchpad_newExplore(self, gesture):
touchpadHandler.handler.screenExplorer.moveTo(gesture.x, gesture.y, new=True)

@script(
description=_(
# Translators: Input help mode message for a touchpad gesture.
"Reports the new object or content under your finger if different to where your finger was last",
),
category=SCRCAT_TOUCHPAD,
gesture="tp:hover",
)
def script_touchpad_explore(self, gesture):
touchpadHandler.handler.screenExplorer.moveTo(gesture.x, gesture.y)

@script(
description=_(
# Translators: Input help mode message for touchpad right click command.
"Clicks the right mouse button at the current touch position. "
"This is generally used to activate a context menu.",
),
category=SCRCAT_TOUCHPAD,
gesture="tp:tapAndHold",
)
def script_touchpad_rightClick(self, gesture):
obj = api.getNavigatorObject()
# Ignore invisible or offscreen objects as they cannot even be navigated with touch gestures.
if controlTypes.State.INVISIBLE in obj.states or controlTypes.State.OFFSCREEN in obj.states:
return
try:
p = api.getReviewPosition().pointAtStart
except (NotImplementedError, LookupError):
p = None
if p:
x = p.x
y = p.y
else:
try:
(left, top, width, height) = obj.location
# Flake8/E722: stems from object location script.
except: # noqa
# Translators: Reported when the object has no location for the mouse to move to it.
ui.message(_("object has no location"))
return
# Don't bother clicking when parts or the entire object is offscreen.
if min(left, top, width, height) < 0:
return
x = left + (width // 2)
y = top + (height // 2)
winUser.setCursorPos(x, y)
self.script_rightMouseClick(gesture)

@script(
# Translators: Describes the command to open the Configuration Profiles dialog.
description=_("Shows the NVDA Configuration Profiles dialog"),
Expand Down
2 changes: 1 addition & 1 deletion source/hidpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class HIDP_VALUE_CAPS(Structure):
("Reserved2", USHORT * 5),
("UnitsExp", ULONG),
("Units", ULONG),
("LogiclMin", LONG),
("LogicalMin", LONG),
("LogicalMax", LONG),
("PhysicalMin", LONG),
("PhysicalMax", LONG),
Expand Down
Loading
Loading