B4A Library Gestures (multi-touch) library

This library allows a View to detect multi-touch gestures. Note that the demo does nothing on the device but logs the multiple touches to LogCat so you will need to be connected to the IDE and viewing filtered LogCat output to see the results of the demo.

The quality of multi-touch support appears variable across devices. Erel reports that this library works fine on his Nexus but my Orange San Francisco (ZTE Blade) is pretty rubbish at tracking pointers as you can see from the comments in the library. You get what you pay for I guess!

EDIT :- Version 1.1 posted. See post #18 for details.

EDIT :- Version 1.2 posted. See post #26 for details.
 

Attachments

  • Gestures1.2.zip
    10.4 KB · Views: 5,529
Last edited:

acorrias

Member
Licensed User
Longtime User
Multi touch

Hi Erel.
Yes. I have seen the tutorial and I have realized that an iteration allows to get TouchMap values. I have understood that example but I have read that there is the ACTION_MOVE among the the actions types. My goal was to experiment the underlaying model and to understand how to use also that action type.

I thought that android rises a Action_move actions for each touchmap point. If you see my sample code ... and wrong since it doesn't work, my select has also a Action_move branch. A switch distinguishes between pointerid=0 (main finger) and the second. But testing the app, I realized that that branch is never executed for the pointerid1 and that is esecuted for pointerid0. As a matter of fact, I can draw as the example tutorial with only one finger, but I cannot change brush size.

I did this mistake since I thought to listeners as autonomous and concurrent threads, each for a single touchmap value (or touch event).

Please, could you tell me why do the example tutorial doesn't use the action_move? Is it correct my assumption that the action_move doesn't rise for the touchs different from the first? My problem is that I cannot understand the following phrase "As pointers move during a gesture an ACTION_MOVE occurs for pointerID 0 with data available for all pointers." It seems confirm my assumption, but I don't know how to get the available data for all pointers. Should I have to get data with " p = TouchMap.GetValueAt(1): px = g.GetX(p.id): py = g.GetY(p.id)?
Thanks in advance. I apologize for my long post.

Alex
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
The tutorial code does use the ACTION_MOVE action. This is actually the most common action. However the map doesn't change in this action so you do not see it in the Select Case code. ACTION_MOVE is not raised for each pointer separately. Multiple pointers can be updated in a single event. Therefore you need to iterate over all the map keys and find their updated movement.
 

PaulR

Active Member
Licensed User
Longtime User
Hi

I am getting a crash when trying to start another activity based on screen events calculated using this excellent Gestures library.

I have tested with the MultiTouchExample code to make sure it wasn't a problem with mine. Adding in a StartActivity(X) within the GesturesTouch event Sub (or any Sub called by that) crashes the app, with a...
B4X:
java.lang.NullPointerException
... error in the Log.

Would there be anything I can do myself to prevent this happening ?

Thanks for any help!
 

PaulR

Active Member
Licensed User
Longtime User
Sure thing, thanks Erel - this crash is from adding StartActivity(TestActivity) into the GesturesTouch Sub in the Multitouch Example (Activities can be started from menu buttons, just not from within the Gestures code).....
B4X:
Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:anywheresoftware.b4a.samples.multitouch
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
java.lang.NullPointerException
   at anywheresoftware.b4a.agraham.gestures.Gestures$1.onTouch(Gestures.java:96)
   at android.view.View.dispatchTouchEvent(View.java:3928)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:955)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1015)
   at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1784)
   at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1157)
   at android.app.Activity.dispatchTouchEvent(Activity.java:2228)
   at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1759)
   at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2340)
   at android.view.ViewRoot.handleMessage(ViewRoot.java:1980)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   at android.os.Looper.loop(Looper.java:150)
   at android.app.ActivityThread.main(ActivityThread.java:4293)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:507)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
   at dalvik.system.NativeStart.main(Native Method)
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (main) Create, isFirst = false **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (main) Create, isFirst = false **
** Activity (main) Resume **
 

PaulR

Active Member
Licensed User
Longtime User
Thanks so much, that was a fast fix. :)

That has solved the crashing issue, but I am now seeing a different one. In this test activity, ACTION_DOWN/ACTION_POINTER_DOWN is only called once (ie TouchMap2.Size never gets bigger than 1) and none of the rest are called at all....
B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
   
   
End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim bgd2 As Panel
   Dim GG As Gestures
   Dim TouchMap2 As Map
   Type Point2(Id As Int, Zone As Int, X As Int, Y As Int, origX As Int, origY As Int, prevX As Int, prevY As Int, distFromPrev As Int, stepsComplete As Int, Color As Int)
   Dim Canvas2 As Canvas
   
End Sub

Sub Activity_Create(FirstTime As Boolean)

   'Create a panel and add it to the activity
   bgd2.Initialize("")
   Activity.AddView(bgd2, 0, 0, 100%x, 100%y)
   Canvas2.Initialize(bgd2)
   
   
   'Add a listener for this panel   
   GG.SetOnTouchListener(bgd2, "GesturesTouch2")
   TouchMap2.Initialize
   
   
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


Sub GesturesTouch2(View As Object, PointerID As Int, Action As Int, X As Float, Y As Float) As Boolean

   Dim p As Point2
      
   Select Action
      Case GG.ACTION_DOWN, GG.ACTION_POINTER_DOWN
         'New Point is assigned to the new touch
         
         p.Id = PointerID
         p.Color = Colors.RGB(Rnd(0, 255), Rnd(0, 255), Rnd(0, 255))
         
         TouchMap2.Put(PointerID, p)
                  
         p.origX = GG.GetX(PointerID)
         p.origY = GG.GetY(PointerID)
         Log (p.origX)
         
         Log("Action/Pointer Down")
         Log("TouchMap2.Size = " & TouchMap2.Size)
         
            
         
      Case GG.ACTION_POINTER_UP
         TouchMap2.Remove(PointerID)
         Log("ACTION_POINTER_UP Called")
         
         
      Case GG.ACTION_MOVE
         Log("ACTION_MOVE Called")
         
         
      Case GG.ACTION_UP
         'This is the end of this gesture
         Log("ACTION_UP Called")
         TouchMap2.Clear
         
                  
   End Select
   
   For i = 0 To TouchMap2.Size - 1
      Dim p As Point2
      p = TouchMap2.GetValueAt(i)
      Log("--------------")
      Log("Point " & i & " X: " & GG.GetX(p.id))
      Log("Point " & i & " Y: " & GG.GetY(p.id))
   Next
   
   DoSomething
   
End Sub

Sub DoSomething
   Dim a As Int
   a = 1
End Sub
.... which is weird because simply copying the MultiTouch Example activity to a new one works. I only changed the names of all of the variables to try and eliminate problems.

Is there a schoolboy error in there or is this something deeper?
 

PaulR

Active Member
Licensed User
Longtime User
Hi, really sorry.. that was a clear brain fart on my behalf. :eek:

The one last thing that I can't do is to make a DOWN gesture persistant across activities.

For example, I press an area of the screen in Activity 1 which shows a graphic in the area of the touch and starts Activity 2. In Activity 2, I can copy the TouchMap stored in Activity 1 (or elsewhere) but unfortunately no gesture is raised when that existing (physical) gesture is moved or lifted, making me unable to make everything look continuous.

Would it be possible to add a method to force the library to work with a existing points?

Thanks again.
 

tamadon

Active Member
Licensed User
Longtime User
Hi I am testing the demo and replaced the label with a button.

However, the movement of the button seem lagging and blurry and it isn't located where I touch it while moving. The label demo was working fine though on my test device.

What could be the problem?
 

tamadon

Active Member
Licensed User
Longtime User
My mistake, I should have set the SetOnTouchListener on a panel instead of the button itself!
 

gerth6000

Member
Licensed User
Longtime User
How do I catch a LongClick?

By looking at the timing of ACTION_DOWN and ACTION_UP I can set up my own events for SingleTap and DoubleTap, but I don't know how to do LongClicks. LongClicks depend on the finger staying in one spot, but Gestures only activates its event when the finger moves....
 

pwme

Member
Licensed User
Longtime User
scrollview2D with gesture

I would like to use with library with scrollview2d.

Private SV As ScrollView2D

Public Sub Initialize (Act As Activity)

SV.Initialize(0, 0, "SV")
Act.AddView(SV,0, 0dip, 100%x, 100%y)
Gesture.SetOnTouchListener(SV, "pnl_gesture")

End Sub

I recieve this error:

null id1 PtrDown x255 y755 cnt2 : id0 x300 y892 : id1 x255 y755


null id0 Move x316 y915 cnt2 : id0 x316 y915 : id1 x241 y715


null id0 Move x328 y927 cnt2 : id0 x328 y927 : id1 x222 y671


null id0 PtrUp x342 y934 cnt2 : id0 x342 y934 : id1 x207 y659


java.lang.IllegalArgumentException: pointerIndex out of range


at android.view.MotionEvent.nativeGetAxisValue(Native Method)
at android.view.MotionEvent.getX(MotionEvent.java:2013)
at flm.b4a.scrollview2d.TwoDScrollView.onTouchEvent(TwoDScrollView.java:611)
at android.view.View.dispatchTouchEvent(View.java:5724)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1964)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1725)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1970)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1739)


at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2071)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1405)
at android.app.Activity.dispatchTouchEvent(Activity.java:2426)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2019)
at android.view.View.dispatchPointerEvent(View.java:5904)
at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3189)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2704)
at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:1034)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2713)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4514)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
at dalvik.system.NativeStart.main(Native Method)

Would you mind to help me?

Thanks in advance

William
 

Informatix

Expert
Licensed User
Longtime User
I would like to use with library with scrollview2d.

The following code works well, so I have no idea why you get an error.

B4X:
Sub Globals
   Dim SV As ScrollView2D
   Dim Ge As Gestures
End Sub

Sub Activity_Create(FirstTime As Boolean)
   SV.Initialize(0, 0, "SV")
   Activity.AddView(SV, 0, 0, 100%x, 100%y)
   Ge.SetOnTouchListener(SV, "pnl_gesture")
End Sub

Sub pnl_gesture(View As Object, PointerID As Int, Action As Int, X As Float, Y As Float) As Boolean
   Log(PointerID)
   Log(Action)
End Sub
 

demasi

Active Member
Licensed User
Longtime User
Rotate

Hello,
I loved this library, thank you.:sign0098:
I need a rotate method to rotate the views. Is it possible to implement via gestures>
 
Top