Skip to content

Commit

Permalink
Fixes and improvements related to touch screen gestures.
Browse files Browse the repository at this point in the history
* All taps that overlap in time are correctly merged into one multi-finger tap. Previously tap A and B would be merged only if B started after A's start but before its end.
* Taps are only merged into plural (double, tripple, quadruple) taps if there are no other unknown trackers at the time. This stops a tap quickly followed by a tripple tap for example, from incorrectly turning into a quadruple tap.
* Plural tap and holds (e.g. double tap and hold) are now detected.
* Hover downs are no longer fired when part of a tapAndHold.
* Hovers are no longer reported in input help.
* MultitouchTracker objects now contain a childTrackers property which contains the multiTouchTrackers it is made up of (I.e. 2 finger double tap contains 2 2-finger taps. The 2-finger taps themselves contain 2 taps).
* MultiTouchTracker objects now also contain a rawSingleTouchTracker property, if this tracker is the result of one single finger doing a tap, flick or hover. The SingleTouchTracker allows access to the underlying Operating System assigned ID for the finger and whether or not the finger is still in contact at the current time.
* Added doc strings to MultiTouchTracker and SingleTouchTracker classes explaining all available properties
* Provide __slots__ on MultiTouchTracker and SingleTouchTracker classes to decrease their size.
* The Touch input Gesture class's doc string now explains all possible actions that can occur
* Touch input gestures now have x and y properties, removing the need to access the tracker in very simple cases.
* Gesturs now contain a preheldTracker property, which is a multitouchTracker object representing the other held fingers while this action was being performed.
* Gesture identifier IDs are now output in Python set order ensuring correct comparisons, allowing gestures such as "1finger_hold+hover" to be correctly bound.
* A generalized identifier with finger count removed is now included for holds (e.g. hold+hover for 1finger_hold+hover).

Fixes #5652.
  • Loading branch information
michaelDCurran authored and jcsteh committed Jan 22, 2016
1 parent fb0c328 commit d7014eb
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 111 deletions.
4 changes: 2 additions & 2 deletions source/globalCommands.py
Expand Up @@ -1816,13 +1816,13 @@ def script_touch_changeMode(self,gesture):


def script_touch_newExplore(self,gesture):
touchHandler.handler.screenExplorer.moveTo(gesture.tracker.x,gesture.tracker.y,new=True)
touchHandler.handler.screenExplorer.moveTo(gesture.x,gesture.y,new=True)
# Translators: Input help mode message for a touchscreen gesture.
script_touch_newExplore.__doc__=_("Reports the object and content directly under your finger")
script_touch_newExplore.category=SCRCAT_TOUCH

def script_touch_explore(self,gesture):
touchHandler.handler.screenExplorer.moveTo(gesture.tracker.x,gesture.tracker.y)
touchHandler.handler.screenExplorer.moveTo(gesture.x,gesture.y)
# Translators: Input help mode message for a touchscreen gesture.
script_touch_explore.__doc__=_("Reports the new object or content under your finger if different to where your finger was last")
script_touch_explore.category=SCRCAT_TOUCH
Expand Down
6 changes: 5 additions & 1 deletion source/inputCore.py
Expand Up @@ -58,6 +58,10 @@ class InputGesture(baseObject.AutoPropertyObject):
#: @type: bool
bypassInputHelp=False

#: Indicates that this gesture should be reported in Input help mode. This would only be false for floodding Gestures like touch screen hovers.
#: @type: bool
reportInInputHelp=True

def _get_identifiers(self):
"""The identifier(s) which will be used in input gesture maps to represent this gesture.
These identifiers will be looked up in order until a match is found.
Expand Down Expand Up @@ -460,7 +464,7 @@ def _set_isInputHelpActive(self, enable):

def _inputHelpCaptor(self, gesture):
bypass = gesture.bypassInputHelp or getattr(gesture.script, "bypassInputHelp", False)
queueHandler.queueFunction(queueHandler.eventQueue, self._handleInputHelp, gesture, onlyLog=bypass)
queueHandler.queueFunction(queueHandler.eventQueue, self._handleInputHelp, gesture, onlyLog=bypass or not gesture.reportInInputHelp)
return bypass

def _handleInputHelp(self, gesture, onlyLog=False):
Expand Down
59 changes: 45 additions & 14 deletions source/touchHandler.py
Expand Up @@ -99,6 +99,24 @@ class POINTER_TOUCH_INFO(Structure):
touchThread=None

class TouchInputGesture(inputCore.InputGesture):
"""
Represents a gesture performed on a touch screen.
Possible actions are:
* Tap: a finger touches the screen only for a very short amount of time.
* Flick{Left|Right|Up|Down}: a finger swipes the screen in a particular direction.
* Tap and hold: a finger taps the screen but then again touches the screen, this time remaining held.
* Hover down: A finger touches the screen long enough for the gesture to not be a tap, and it is also not already part of a tap and hold.
* Hover: a finger is still touching the screen, and may be moving around. Only the most recent finger to be hovering causes these gestures.
* Hover up: a finger that was classed as a hover, releases contact with the screen.
All actions accept for Hover down, Hover and Hover up, can be made up of multiple fingers. It is possible to have things such as a 3-finger tap, or a 2-finger Tap and Hold, or a 4 finger Flick right.
Taps maybe pluralized (I.e. a tap very quickly followed by another tap of the same number of fingers will be represented by a double tap, rather than two separate taps). Currently double, tripple and quadruple plural taps are detected.
Tap and holds can be pluralized also (E.g. a double tap and hold means that there were two taps before the hold).
Actions also communicate if other fingers are currently held while performing the action. E.g. a hold+tap is when a finger touches the screen long enough to become a hover, and a tap with another finger is performed, while the first finger remains on the screen. Holds themselves also can be made of multiple fingers.
Based on all of this, gestures could be as complicated as a 5-finger hold + 5-finger quadruple tap and hold.
To find out the generalized point on the screen at which the gesture was performed, use this gesture's x and y properties.
If low-level information about the fingers and sub-gestures making up this gesture is required, the gesture's tracker and preheldTracker properties can be accessed.
See touchHandler.MultitouchTracker for definitions of the available properties.
"""

counterNames=["single","double","tripple","quodruple"]

Expand All @@ -120,30 +138,43 @@ def _get_speechEffectWhenExecuted(self):
if self.tracker.action in (touchTracker.action_hover,touchTracker.action_hoverUp): return None
return super(TouchInputGesture,self).speechEffectWhenExecuted

def __init__(self,tracker,mode):
def _get_reportInInputHelp(self):
return self.tracker.action!=touchTracker.action_hover

def __init__(self,preheldTracker,tracker,mode):
super(TouchInputGesture,self).__init__()
self.tracker=tracker
self.preheldTracker=preheldTracker
self.mode=mode
self.x=tracker.x
self.y=tracker.y

def _get__rawIdentifiers(self):
ID=""
if self.tracker.numHeldFingers>0:
ID+="%dfinger_hold+"%self.tracker.numHeldFingers
if self.tracker.numFingers>1:
ID+="%dfinger_"%self.tracker.numFingers
if self.tracker.actionCount>1:
ID+="%s_"%self.counterNames[min(self.tracker.actionCount,4)-1]
ID+=self.tracker.action
IDs=[]
IDs.append("TS(%s):%s"%(self.mode,ID))
IDs.append("ts:%s"%ID)
for includeHeldFingers in ([True,False] if self.preheldTracker else [False]):
ID=""
if self.preheldTracker:
ID+=("%dfinger_hold+"%self.preheldTracker.numFingers) if includeHeldFingers else "hold+"
if self.tracker.numFingers>1:
ID+="%dfinger_"%self.tracker.numFingers
if self.tracker.actionCount>1:
ID+="%s_"%self.counterNames[min(self.tracker.actionCount,4)-1]
ID+=self.tracker.action
IDs.append("TS(%s):%s"%(self.mode,ID))
IDs.append("ts:%s"%ID)
return IDs

def _get_logIdentifier(self):
return self._rawIdentifiers[0]

def _get_identifiers(self):
return [x.lower() for x in self._rawIdentifiers]
identifiers=[]
for identifier in self._rawIdentifiers:
t,i=identifier.split(':')
# Force the ID in to Python set order so they are always comparable
i="+".join(set(i.split("+")))
identifiers.append("%s:%s"%(t.lower(),i.lower()))
return identifiers

RE_IDENTIFIER = re.compile(r"^ts(?:\((.+?)\))?:(.*)$")

Expand Down Expand Up @@ -244,8 +275,8 @@ def setMode(self,mode):
self._curTouchMode=mode

def pump(self):
for tracker in self.trackerManager.emitTrackers():
gesture=TouchInputGesture(tracker,self._curTouchMode)
for preheldTracker,tracker in self.trackerManager.emitTrackers():
gesture=TouchInputGesture(preheldTracker,tracker,self._curTouchMode)
try:
inputCore.manager.executeGesture(gesture)
except inputCore.NoInputGestureAction:
Expand Down

0 comments on commit d7014eb

Please sign in to comment.