Archive for December, 2010

Android Adventures, part 7: Multi-touch in Processing

Go to part 6…, part 7.5…

Screenshot from my Samsung Captivate

One of the main reasons I got the phone was do to multi-touch apps.  The Processing for Android wiki points to some work done here to make this implementation easier.  But its a straight Android\Java implementation, and I really didn’t feel like trying to hack that into Processing.  Maybe it’s easy, but not for my brain a few days after Christmas.

I thought I’d see what it would take to code this from scratch, and it was surprisingly easy, at least for my needs.  All I wanted was a way to track multiple touch-points on screen.  The below code does that, plus tracks their ID’s, and their ‘size’.

Code Update: Previously I was pulling this info from the Android MotionEvent class that is returned by the sketche’s parental Activity class dispatchTouchEvent method.  However, this disabled Processings own motionX\motionY, mouseX\mouseY variables from ever getting populated.  Looking at the ‘Android – Processing’ wiki (here) it describes how you can can override Processings own surfaceTouchEvent function, which also accepts a MotionEvent as a argument.  This works the exact same as my original code, but no longer blocks the population of Procesisng variables.  So find updates in the source below.

surfaceTouchEvent is only triggered by pressure or motion change on the screen.  So it won’t execute if you’re not touching the screen, or if your finger is touching the screen, but stopped moving.  It is however, a good start 😉

The below Processing sketch will draw a circle under each touch point, along with the id, x, & y positions, and scale the circle based on the touch pressure.

// Eric Pavey - AkEric.com - 2010-12-29
// Example showing simple multi-touch detection in 'Processing - Android'.
// My Samsung Captivate (Galaxy S) can track 5 touch-points.
// Updated to work with Processing's surfaceTouchEvent instead of
// Android's dispatchTouchEvent.

// Should point out that API Level 9 has MotionEvent.PointerCoords class that
// expose some cool functionality, but I'm only on Level 7.

String[] fontList;
PFont androidFont;
int circleBaseSize = 512; // change this to make the touche circles bigger\smaller.

void setup() {
  size(screenWidth, screenHeight, A2D);
  // Fix the orientation so the sketch won't reset when rotated.
  orientation(PORTRAIT);
  stroke(255);
  smooth();
  // Setup Fonts:
  fontList = PFont.list();
  androidFont = createFont(fontList[0], 16, true);
  textFont(androidFont);
  textAlign(LEFT);
}

void draw() {
  background(0);
}

void infoCircle(float x, float y, float siz, int id) {
  // What is drawn on sceen when touched.
  float diameter = circleBaseSize * siz;
  noFill();
  ellipse(x, y, diameter, diameter);
  fill(0,255,0);
  ellipse(x, y, 8, 8);
  text( ("ID:"+ id + " " + int(x) + ", " + int(y) ), x-128, y-64);
}

//-----------------------------------------------------------------------------------------
// Override Processing's surfaceTouchEvent, which will intercept all
// screen touch events.  This code only runs when the screen is touched.

public boolean surfaceTouchEvent(MotionEvent me) {
  // Number of places on the screen being touched:
  int numPointers = me.getPointerCount();
  for(int i=0; i < numPointers; i++) {
    int pointerId = me.getPointerId(i);
    float x = me.getX(i);
    float y = me.getY(i);
    float siz = me.getSize(i);
    infoCircle(x, y, siz, pointerId);
  }
  // If you want the variables for motionX/motionY, mouseX/mouseY etc.
  // to work properly, you'll need to call super.surfaceTouchEvent().
  return super.surfaceTouchEvent(me);
}

Go to part 6…, part 7.5…

A walk in the clouds