First pass at Windows multi-touch gesture support
authorSam Lantinga <slouken@libsdl.org>
Tue, 30 Nov 2010 17:58:51 -0800
changeset 4919 716b2cbf4c9e
parent 4918 f5f70fed2c4c
child 4920 a4032241deb5
First pass at Windows multi-touch gesture support
src/events/SDL_gesture.c
src/events/SDL_touch.c
src/video/win32/SDL_win32events.c
src/video/win32/SDL_win32video.c
src/video/win32/SDL_win32video.h
src/video/win32/SDL_win32window.c
--- a/src/events/SDL_gesture.c	Tue Nov 30 12:38:46 2010 -0800
+++ b/src/events/SDL_gesture.c	Tue Nov 30 17:58:51 2010 -0800
@@ -97,7 +97,7 @@
     if((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
       SDL_gestureTouch[i].recording = SDL_TRUE;
       if(touchId >= 0)
-	return 1;
+        return 1;
     }      
   }
   return (touchId < 0);
@@ -122,7 +122,7 @@
   //if(SDL_RWops.write(src,&(templ->hash),sizeof(templ->hash),1) != 1) return 0;
   
   if(SDL_RWwrite(src,templ->path,
-		 sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) 
+                 sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) 
     return 0;
 
   return 1;
@@ -134,7 +134,7 @@
   for(i = 0; i < SDL_numGestureTouches; i++) {
     SDL_GestureTouch* touch = &SDL_gestureTouch[i];
     for(j = 0;j < touch->numDollarTemplates; j++) {
-	rtrn += SaveTemplate(&touch->dollarTemplate[i],src);
+        rtrn += SaveTemplate(&touch->dollarTemplate[i],src);
     }
   }
   return rtrn;  
@@ -146,7 +146,7 @@
     SDL_GestureTouch* touch = &SDL_gestureTouch[i];
     for(j = 0;j < touch->numDollarTemplates; j++) {
       if(touch->dollarTemplate[i].hash == gestureId) {
-	return SaveTemplate(&touch->dollarTemplate[i],src);
+        return SaveTemplate(&touch->dollarTemplate[i],src);
       }
     }
   }
@@ -166,18 +166,18 @@
       inTouch = &SDL_gestureTouch[i];
 
     dollarTemplate = 
-	(SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
-		    (inTouch->numDollarTemplates + 1) * 
-		    sizeof(SDL_DollarTemplate));
+        (SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
+                    (inTouch->numDollarTemplates + 1) * 
+                    sizeof(SDL_DollarTemplate));
       if(!dollarTemplate) {
-	SDL_OutOfMemory();
-	return -1;
+        SDL_OutOfMemory();
+        return -1;
       }
-	
+        
       inTouch->dollarTemplate = dollarTemplate;
 
     templ = 
-	&inTouch->dollarTemplate[inTouch->numDollarTemplates];
+        &inTouch->dollarTemplate[inTouch->numDollarTemplates];
       SDL_memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
       templ->hash = SDL_HashDollar(templ->path);
       inTouch->numDollarTemplates++;    
@@ -186,8 +186,8 @@
   } else {
     SDL_DollarTemplate* dollarTemplate = 
       ( SDL_DollarTemplate *)SDL_realloc(inTouch->dollarTemplate,
-		  (inTouch->numDollarTemplates + 1) * 
-		  sizeof(SDL_DollarTemplate));
+                  (inTouch->numDollarTemplates + 1) * 
+                  sizeof(SDL_DollarTemplate));
     if(!dollarTemplate) {
       SDL_OutOfMemory();
       return -1;
@@ -212,7 +212,7 @@
   if(touchId >= 0) {
     for(i = 0;i < SDL_numGestureTouches; i++)
       if(SDL_gestureTouch[i].id == touchId)
-	touch = &SDL_gestureTouch[i];
+        touch = &SDL_gestureTouch[i];
     if(touch == NULL) return -1;
   }
 
@@ -229,10 +229,10 @@
     else {
       //printf("Adding to: %i touches\n",SDL_numGestureTouches);
       for(i = 0;i < SDL_numGestureTouches; i++) {
-	touch = &SDL_gestureTouch[i];
-	//printf("Adding loaded gesture to + touches\n");
-	//TODO: What if this fails?
-	SDL_AddDollarGesture(touch,templ.path);	
+        touch = &SDL_gestureTouch[i];
+        //printf("Adding loaded gesture to + touches\n");
+        //TODO: What if this fails?
+        SDL_AddDollarGesture(touch,templ.path);        
       }
       loaded++;
     }
@@ -251,7 +251,7 @@
     p.x = (float)(points[i].x * SDL_cos(ang) - points[i].y * SDL_sin(ang));
     p.y = (float)(points[i].x * SDL_sin(ang) + points[i].y * SDL_cos(ang));
     dist += (float)(SDL_sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
-		 (p.y-templ[i].y)*(p.y-templ[i].y)));
+                 (p.y-templ[i].y)*(p.y-templ[i].y)));
   }
   return dist/DOLLARNPOINTS;
   
@@ -308,9 +308,9 @@
   if(path.length <= 0) {
     for(i=1;i<path.numPoints;i++) {
       float dx = path.p[i  ].x - 
-	         path.p[i-1].x;
+                 path.p[i-1].x;
       float dy = path.p[i  ].y - 
-	         path.p[i-1].y;
+                 path.p[i-1].y;
       path.length += (float)(SDL_sqrt(dx*dx+dy*dy));
     }
   }
@@ -324,13 +324,13 @@
   //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
   for(i = 1;i < path.numPoints;i++) {
     float d = (float)(SDL_sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
-		             (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y)));
+                             (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y)));
     //printf("d = %f dist = %f/%f\n",d,dist,interval);
     while(dist + d > interval) {
       points[numPoints].x = path.p[i-1].x + 
-	((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
+        ((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
       points[numPoints].y = path.p[i-1].y + 
-	((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
+        ((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
       centroid.x += points[numPoints].x;
       centroid.y += points[numPoints].y;
       numPoints++;
@@ -358,9 +358,9 @@
   ymax = centroid.y;
   
   ang = (float)(SDL_atan2(centroid.y - points[0].y,
-		    centroid.x - points[0].x));
+                    centroid.x - points[0].x));
 
-  for(i = 0;i<numPoints;i++) {					       
+  for(i = 0;i<numPoints;i++) {                                               
     float px = points[i].x;
     float py = points[i].y;
     points[i].x = (float)((px - centroid.x)*SDL_cos(ang) - 
@@ -387,25 +387,25 @@
 }
 
 float dollarRecognize(SDL_DollarPath path,int *bestTempl,SDL_GestureTouch* touch) {
-	
-	SDL_FloatPoint points[DOLLARNPOINTS];
-	int numPoints = dollarNormalize(path,points);
-	int i;
-	float bestDiff = 10000;
+        
+        SDL_FloatPoint points[DOLLARNPOINTS];
+        int numPoints = dollarNormalize(path,points);
+        int i;
+        float bestDiff = 10000;
 
-	//PrintPath(points);
-	*bestTempl = -1;
-	for(i = 0;i < touch->numDollarTemplates;i++) {
-		float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
-		if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
-	}
-	return bestDiff;
+        //PrintPath(points);
+        *bestTempl = -1;
+        for(i = 0;i < touch->numDollarTemplates;i++) {
+                float diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
+                if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
+        }
+        return bestDiff;
 }
 
 int SDL_GestureAddTouch(SDL_Touch* touch) {  
   SDL_GestureTouch *gestureTouch = (SDL_GestureTouch *)SDL_realloc(SDL_gestureTouch,
-					       (SDL_numGestureTouches + 1) *
-					       sizeof(SDL_GestureTouch));
+                                               (SDL_numGestureTouches + 1) *
+                                               sizeof(SDL_GestureTouch));
 
   if(!gestureTouch) {
     SDL_OutOfMemory();
@@ -464,7 +464,7 @@
 }
 
 int SDL_SendGestureDollar(SDL_GestureTouch* touch,
-			  SDL_GestureID gestureId,float error) {
+                          SDL_GestureID gestureId,float error) {
   SDL_Event event;
   event.dgesture.type = SDL_DOLLARGESTURE;
   event.dgesture.touchId = touch->id;
@@ -513,7 +513,7 @@
     if(inTouch == NULL) return;
     
     //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
-    //	   (int)event->tfinger.y,
+    //           (int)event->tfinger.y,
     //   (int)inTouch->res.x,(int)inTouch->res.y);
 
     
@@ -527,44 +527,44 @@
       
 #ifdef ENABLE_DOLLAR
       if(inTouch->recording) {
-	inTouch->recording = SDL_FALSE;	
-	dollarNormalize(inTouch->dollarPath,path);
-	//PrintPath(path);
-	if(recordAll) {
-	  index = SDL_AddDollarGesture(NULL,path);
-	  for(i = 0;i < SDL_numGestureTouches; i++)
-	    SDL_gestureTouch[i].recording = SDL_FALSE;
-	}
-	else {
-	  index = SDL_AddDollarGesture(inTouch,path);
-	}
-	
-	if(index >= 0) {
-	  SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
-	}
-	else {
-	  SDL_SendDollarRecord(inTouch,-1);
-	}
+        inTouch->recording = SDL_FALSE;        
+        dollarNormalize(inTouch->dollarPath,path);
+        //PrintPath(path);
+        if(recordAll) {
+          index = SDL_AddDollarGesture(NULL,path);
+          for(i = 0;i < SDL_numGestureTouches; i++)
+            SDL_gestureTouch[i].recording = SDL_FALSE;
+        }
+        else {
+          index = SDL_AddDollarGesture(inTouch,path);
+        }
+        
+        if(index >= 0) {
+          SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
+        }
+        else {
+          SDL_SendDollarRecord(inTouch,-1);
+        }
       }
-      else {	
-	int bestTempl;
-	float error;
-	error = dollarRecognize(inTouch->dollarPath,
-				&bestTempl,inTouch);
-	if(bestTempl >= 0){
-	  //Send Event
-	  unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
-	  SDL_SendGestureDollar(inTouch,gestureId,error);
-	  //printf ("%s\n",);("Dollar error: %f\n",error);
-	}
+      else {        
+        int bestTempl;
+        float error;
+        error = dollarRecognize(inTouch->dollarPath,
+                                &bestTempl,inTouch);
+        if(bestTempl >= 0){
+          //Send Event
+          unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
+          SDL_SendGestureDollar(inTouch,gestureId,error);
+          //printf ("%s\n",);("Dollar error: %f\n",error);
+        }
       }
 #endif 
       //inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
       if(inTouch->numDownFingers > 0) {
-	inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
-			       x)/inTouch->numDownFingers;
-	inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
-			       y)/inTouch->numDownFingers;
+        inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
+                               x)/inTouch->numDownFingers;
+        inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
+                               y)/inTouch->numDownFingers;
       }
     }
     else if(event->type == SDL_FINGERMOTION) {
@@ -574,14 +574,14 @@
 #ifdef ENABLE_DOLLAR
       SDL_DollarPath* path = &inTouch->dollarPath;
       if(path->numPoints < MAXPATHSIZE) {
-	path->p[path->numPoints].x = inTouch->centroid.x;
-	path->p[path->numPoints].y = inTouch->centroid.y;
-	pathDx = 
-	  (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
-	pathDy = 
-	  (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
-	path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
-	path->numPoints++;
+        path->p[path->numPoints].x = inTouch->centroid.x;
+        path->p[path->numPoints].y = inTouch->centroid.y;
+        pathDx = 
+          (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
+        pathDy = 
+          (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
+        path->length += (float)SDL_sqrt(pathDx*pathDx + pathDy*pathDy);
+        path->numPoints++;
       }
 #endif
       lastP.x = x - dx;
@@ -592,46 +592,46 @@
       inTouch->centroid.y += dy/inTouch->numDownFingers;
       //printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y);
       if(inTouch->numDownFingers > 1) {
-	SDL_FloatPoint lv; //Vector from centroid to last x,y position
-	SDL_FloatPoint v; //Vector from centroid to current x,y position
-	//lv = inTouch->gestureLast[j].cv;
-	lv.x = lastP.x - lastCentroid.x;
-	lv.y = lastP.y - lastCentroid.y;
-	lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
-	//printf("lDist = %f\n",lDist);
-	v.x = x - inTouch->centroid.x;
-	v.y = y - inTouch->centroid.y;
-	//inTouch->gestureLast[j].cv = v;
-	Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
-	// SDL_cos(dTheta) = (v . lv)/(|v| * |lv|)
-	
-	//Normalize Vectors to simplify angle calculation
-	lv.x/=lDist;
-	lv.y/=lDist;
-	v.x/=Dist;
-	v.y/=Dist;
-	dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
-	
-	dDist = (Dist - lDist);
-	if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
-	
-	//inTouch->gestureLast[j].dDist = dDist;
-	//inTouch->gestureLast[j].dtheta = dtheta;
-	
-	//printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
-	//gdtheta = gdtheta*.9 + dtheta*.1;
-	//gdDist  =  gdDist*.9 +  dDist*.1
-	//knob.r += dDist/numDownFingers;
-	//knob.ang += dtheta;
-	//printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
-	//printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
-	SDL_SendGestureMulti(inTouch,dtheta,dDist);
+        SDL_FloatPoint lv; //Vector from centroid to last x,y position
+        SDL_FloatPoint v; //Vector from centroid to current x,y position
+        //lv = inTouch->gestureLast[j].cv;
+        lv.x = lastP.x - lastCentroid.x;
+        lv.y = lastP.y - lastCentroid.y;
+        lDist = (float)SDL_sqrt(lv.x*lv.x + lv.y*lv.y);
+        //printf("lDist = %f\n",lDist);
+        v.x = x - inTouch->centroid.x;
+        v.y = y - inTouch->centroid.y;
+        //inTouch->gestureLast[j].cv = v;
+        Dist = (float)SDL_sqrt(v.x*v.x+v.y*v.y);
+        // SDL_cos(dTheta) = (v . lv)/(|v| * |lv|)
+        
+        //Normalize Vectors to simplify angle calculation
+        lv.x/=lDist;
+        lv.y/=lDist;
+        v.x/=Dist;
+        v.y/=Dist;
+        dtheta = (float)SDL_atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
+        
+        dDist = (Dist - lDist);
+        if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
+        
+        //inTouch->gestureLast[j].dDist = dDist;
+        //inTouch->gestureLast[j].dtheta = dtheta;
+        
+        //printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
+        //gdtheta = gdtheta*.9 + dtheta*.1;
+        //gdDist  =  gdDist*.9 +  dDist*.1
+        //knob.r += dDist/numDownFingers;
+        //knob.ang += dtheta;
+        //printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
+        //printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
+        SDL_SendGestureMulti(inTouch,dtheta,dDist);
       }
       else {
-	//inTouch->gestureLast[j].dDist = 0;
-	//inTouch->gestureLast[j].dtheta = 0;
-	//inTouch->gestureLast[j].cv.x = 0;
-	//inTouch->gestureLast[j].cv.y = 0;
+        //inTouch->gestureLast[j].dDist = 0;
+        //inTouch->gestureLast[j].dtheta = 0;
+        //inTouch->gestureLast[j].cv.x = 0;
+        //inTouch->gestureLast[j].cv.y = 0;
       }
       //inTouch->gestureLast[j].f.p.x = x;
       //inTouch->gestureLast[j].f.p.y = y;
@@ -643,9 +643,9 @@
 
       inTouch->numDownFingers++;
       inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
-			     x)/inTouch->numDownFingers;
+                             x)/inTouch->numDownFingers;
       inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
-			     y)/inTouch->numDownFingers;
+                             y)/inTouch->numDownFingers;
       //printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
       //     inTouch->centroid.x,inTouch->centroid.y);
 
--- a/src/events/SDL_touch.c	Tue Nov 30 12:38:46 2010 -0800
+++ b/src/events/SDL_touch.c	Tue Nov 30 17:58:51 2010 -0800
@@ -65,8 +65,8 @@
 {
     int i;
     for(i = 0;i < touch->num_fingers;i++)
-	if(touch->fingers[i]->id == fingerid)
-	    return i;
+        if(touch->fingers[i]->id == fingerid)
+            return i;
     return -1;
 }
 
@@ -76,7 +76,7 @@
 {
     int index = SDL_GetFingerIndexId(touch,id);
     if(index < 0 || index >= touch->num_fingers)
-	return NULL;
+        return NULL;
     return touch->fingers[index];
 }
 
@@ -259,22 +259,22 @@
     //printf("Adding Finger...\n");
     if (SDL_GetFingerIndexId(touch,finger->id) != -1) {
         SDL_SetError("Finger ID already in use");
-	}
+        }
 
     /* Add the touch to the list of touch */
     if(touch->num_fingers  >= touch->max_fingers){
-		//printf("Making room for it!\n");
-		fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
-  						   (touch->num_fingers + 1) * sizeof(SDL_Finger *));
-		touch->max_fingers = touch->num_fingers+1;
-		if (!fingers) {
-			SDL_OutOfMemory();
-			return -1;
-		} else {
-			touch->max_fingers = touch->num_fingers+1;
-			touch->fingers = fingers;
-		}
-	}
+                //printf("Making room for it!\n");
+                fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
+                                                     (touch->num_fingers + 1) * sizeof(SDL_Finger *));
+                touch->max_fingers = touch->num_fingers+1;
+                if (!fingers) {
+                        SDL_OutOfMemory();
+                        return -1;
+                } else {
+                        touch->max_fingers = touch->num_fingers+1;
+                        touch->fingers = fingers;
+                }
+        }
 
     index = touch->num_fingers;
     //printf("Max_Fingers: %i Index: %i\n",touch->max_fingers,index);
@@ -310,13 +310,13 @@
 
 int
 SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, 
-		   float xin, float yin, float pressurein)
+                   float xin, float yin, float pressurein)
 {
     int posted;
-	Uint16 x;
-	Uint16 y;
-	Uint16 pressure;
-	SDL_Finger *finger;
+        Uint16 x;
+        Uint16 y;
+        Uint16 pressure;
+        SDL_Finger *finger;
 
     SDL_Touch* touch = SDL_GetTouch(id);
 
@@ -332,68 +332,68 @@
     
     finger = SDL_GetFinger(touch,fingerid);
     if(down) {
-	if(finger == NULL) {
-	    SDL_Finger nf;
-	    nf.id = fingerid;
-	    nf.x = x;
-	    nf.y = y;
-	    nf.pressure = pressure;
-	    nf.xdelta = 0;
-	    nf.ydelta = 0;
-	    nf.last_x = x;
-	    nf.last_y = y;
-	    nf.last_pressure = pressure;
-	    nf.down = SDL_FALSE;
-	    if(SDL_AddFinger(touch,&nf) < 0) return 0;
-	    finger = SDL_GetFinger(touch,fingerid);
-	}
-	else if(finger->down) return 0;
-	if(xin < touch->x_min || yin < touch->y_min) return 0; //should defer if only a partial input
-	posted = 0;
-	if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
-	    SDL_Event event;
-	    event.tfinger.type = SDL_FINGERDOWN;
-	    event.tfinger.touchId = id;
-	    event.tfinger.x = x;
-	    event.tfinger.y = y;
-	    event.tfinger.pressure = pressure;
-	    event.tfinger.state = touch->buttonstate;
-	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
-	    event.tfinger.fingerId = fingerid;
-	    posted = (SDL_PushEvent(&event) > 0);
-	}
-	if(posted) finger->down = SDL_TRUE;
-	return posted;
+        if(finger == NULL) {
+            SDL_Finger nf;
+            nf.id = fingerid;
+            nf.x = x;
+            nf.y = y;
+            nf.pressure = pressure;
+            nf.xdelta = 0;
+            nf.ydelta = 0;
+            nf.last_x = x;
+            nf.last_y = y;
+            nf.last_pressure = pressure;
+            nf.down = SDL_FALSE;
+            if(SDL_AddFinger(touch,&nf) < 0) return 0;
+            finger = SDL_GetFinger(touch,fingerid);
+        }
+        else if(finger->down) return 0;
+        if(xin < touch->x_min || yin < touch->y_min) return 0; //should defer if only a partial input
+        posted = 0;
+        if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
+            SDL_Event event;
+            event.tfinger.type = SDL_FINGERDOWN;
+            event.tfinger.touchId = id;
+            event.tfinger.x = x;
+            event.tfinger.y = y;
+            event.tfinger.pressure = pressure;
+            event.tfinger.state = touch->buttonstate;
+            event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
+            event.tfinger.fingerId = fingerid;
+            posted = (SDL_PushEvent(&event) > 0);
+        }
+        if(posted) finger->down = SDL_TRUE;
+        return posted;
     }
     else {
         if(finger == NULL) {
             SDL_SetError("Finger not found.");
             return 0;
         }      
-	posted = 0;
-	if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
-	    SDL_Event event;
-	    event.tfinger.type = SDL_FINGERUP;
-	    event.tfinger.touchId =  id;
-	    event.tfinger.state = touch->buttonstate;
-	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
-	    event.tfinger.fingerId = fingerid;
-	    //I don't trust the coordinates passed on fingerUp
-	    event.tfinger.x = finger->x; 
-	    event.tfinger.y = finger->y;
-	    event.tfinger.dx = 0;
-	    event.tfinger.dy = 0;
+        posted = 0;
+        if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
+            SDL_Event event;
+            event.tfinger.type = SDL_FINGERUP;
+            event.tfinger.touchId =  id;
+            event.tfinger.state = touch->buttonstate;
+            event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
+            event.tfinger.fingerId = fingerid;
+            //I don't trust the coordinates passed on fingerUp
+            event.tfinger.x = finger->x; 
+            event.tfinger.y = finger->y;
+            event.tfinger.dx = 0;
+            event.tfinger.dy = 0;
 
-	    if(SDL_DelFinger(touch,fingerid) < 0) return 0;
-	    posted = (SDL_PushEvent(&event) > 0);
-	}	
-	return posted;
+            if(SDL_DelFinger(touch,fingerid) < 0) return 0;
+            posted = (SDL_PushEvent(&event) > 0);
+        }        
+        return posted;
     }
 }
 
 int
 SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, int relative, 
-		    float xin, float yin, float pressurein)
+                    float xin, float yin, float pressurein)
 {
     int index = SDL_GetTouchIndexId(id);
     SDL_Touch *touch = SDL_GetTouch(id);
@@ -401,9 +401,9 @@
     int posted;
     Sint16 xrel, yrel;
     float x_max = 0, y_max = 0;
-	Uint16 x;
-	Uint16 y;
-	Uint16 pressure;
+        Uint16 x;
+        Uint16 y;
+        Uint16 pressure;
     
     if (!touch) {
       return SDL_TouchNotFoundError(id);
@@ -414,85 +414,85 @@
     y = (Uint16)((yin+touch->y_min)*(touch->yres)/(touch->native_yres));
     pressure = (Uint16)((yin+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres));
     if(touch->flush_motion) {
-	return 0;
+        return 0;
     }
     
     if(finger == NULL || !finger->down) {
-	return SDL_SendFingerDown(id,fingerid,SDL_TRUE,xin,yin,pressurein);	
+        return SDL_SendFingerDown(id,fingerid,SDL_TRUE,xin,yin,pressurein);        
     } else {
-	/* the relative motion is calculated regarding the last position */
-	if (relative) {
-	    xrel = x;
-	    yrel = y;
-	    x = (finger->last_x + x);
-	    y = (finger->last_y + y);
-	} else {
-	    if(xin < touch->x_min) x = finger->last_x; /*If movement is only in one axis,*/
-	    if(yin < touch->y_min) y = finger->last_y; /*The other is marked as -1*/
-	    if(pressurein < touch->pressure_min) pressure = finger->last_pressure;
-	    xrel = x - finger->last_x;
-	    yrel = y - finger->last_y;
-	    //printf("xrel,yrel (%i,%i)\n",(int)xrel,(int)yrel);
-	}
-	
-	/* Drop events that don't change state */
-	if (!xrel && !yrel) {
+        /* the relative motion is calculated regarding the last position */
+        if (relative) {
+            xrel = x;
+            yrel = y;
+            x = (finger->last_x + x);
+            y = (finger->last_y + y);
+        } else {
+            if(xin < touch->x_min) x = finger->last_x; /*If movement is only in one axis,*/
+            if(yin < touch->y_min) y = finger->last_y; /*The other is marked as -1*/
+            if(pressurein < touch->pressure_min) pressure = finger->last_pressure;
+            xrel = x - finger->last_x;
+            yrel = y - finger->last_y;
+            //printf("xrel,yrel (%i,%i)\n",(int)xrel,(int)yrel);
+        }
+        
+        /* Drop events that don't change state */
+        if (!xrel && !yrel) {
 #if 0
-	    printf("Touch event didn't change state - dropped!\n");
+            printf("Touch event didn't change state - dropped!\n");
 #endif
-	    return 0;
-	}
-	
-	/* Update internal touch coordinates */
-	
-	finger->x = x;
-	finger->y = y;
-	
-	/*Should scale to window? Normalize? Maintain Aspect?*/
-	//SDL_GetWindowSize(touch->focus, &x_max, &y_max);
-	
-	/* make sure that the pointers find themselves inside the windows */
-	/* only check if touch->xmax is set ! */
-	/*
-	  if (x_max && touch->x > x_max) {
-	  touch->x = x_max;
-	  } else if (touch->x < 0) {
-	  touch->x = 0;
-	  }
-	  
-	  if (y_max && touch->y > y_max) {
-	  touch->y = y_max;
-	  } else if (touch->y < 0) {
-	  touch->y = 0;
-	  }
-	*/
-	finger->xdelta = xrel;
-	finger->ydelta = yrel;
-	finger->pressure = pressure;
-	
-	
-	
-	/* Post the event, if desired */
-	posted = 0;
-	if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
-	    SDL_Event event;
-	    event.tfinger.type = SDL_FINGERMOTION;
-	    event.tfinger.touchId = id;
-	    event.tfinger.fingerId = fingerid;
-	    event.tfinger.x = x;
-	    event.tfinger.y = y;
-	    event.tfinger.dx = xrel;
-	    event.tfinger.dy = yrel;	    
-		
-	    event.tfinger.pressure = pressure;
-	    event.tfinger.state = touch->buttonstate;
-	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
-	    posted = (SDL_PushEvent(&event) > 0);
-	}
-	finger->last_x = finger->x;
-	finger->last_y = finger->y;
-	finger->last_pressure = finger->pressure;
-	return posted;
+            return 0;
+        }
+        
+        /* Update internal touch coordinates */
+        
+        finger->x = x;
+        finger->y = y;
+        
+        /*Should scale to window? Normalize? Maintain Aspect?*/
+        //SDL_GetWindowSize(touch->focus, &x_max, &y_max);
+        
+        /* make sure that the pointers find themselves inside the windows */
+        /* only check if touch->xmax is set ! */
+        /*
+          if (x_max && touch->x > x_max) {
+          touch->x = x_max;
+          } else if (touch->x < 0) {
+          touch->x = 0;
+          }
+          
+          if (y_max && touch->y > y_max) {
+          touch->y = y_max;
+          } else if (touch->y < 0) {
+          touch->y = 0;
+          }
+        */
+        finger->xdelta = xrel;
+        finger->ydelta = yrel;
+        finger->pressure = pressure;
+        
+        
+        
+        /* Post the event, if desired */
+        posted = 0;
+        if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
+            SDL_Event event;
+            event.tfinger.type = SDL_FINGERMOTION;
+            event.tfinger.touchId = id;
+            event.tfinger.fingerId = fingerid;
+            event.tfinger.x = x;
+            event.tfinger.y = y;
+            event.tfinger.dx = xrel;
+            event.tfinger.dy = yrel;            
+                
+            event.tfinger.pressure = pressure;
+            event.tfinger.state = touch->buttonstate;
+            event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
+            posted = (SDL_PushEvent(&event) > 0);
+        }
+        finger->last_x = finger->x;
+        finger->last_y = finger->y;
+        finger->last_pressure = finger->pressure;
+        return posted;
     }
 }
 int
--- a/src/video/win32/SDL_win32events.c	Tue Nov 30 12:38:46 2010 -0800
+++ b/src/video/win32/SDL_win32events.c	Tue Nov 30 17:58:51 2010 -0800
@@ -27,6 +27,7 @@
 #include "SDL_syswm.h"
 #include "SDL_vkeys.h"
 #include "../../events/SDL_events_c.h"
+#include "../../events/SDL_touch_c.h"
 
 
 
@@ -55,12 +56,10 @@
 #ifndef WM_INPUT
 #define WM_INPUT 0x00ff
 #endif
-#ifndef WM_GESTURE
-#define WM_GESTURE 0x0119
-#endif
 #ifndef WM_TOUCH
 #define WM_TOUCH 0x0240
-#endif
+#endif
+
 
 static WPARAM
 RemapVKEY(WPARAM wParam, LPARAM lParam)
@@ -519,41 +518,70 @@
         }
         returnCode = 0;
         break;
+
 	case WM_TOUCH:
-		{
-			//printf("Got Touch Event!\n");
-    
-#ifdef WMMSG_DEBUG
-			FILE *log = fopen("wmmsg.txt", "a");
-			fprintf(log, "Received Touch Message: %p ", hwnd);
-			if (msg > MAX_WMMSG) {
-				fprintf(log, "%d", msg);
-			} else {
-				fprintf(log, "%s", wmtab[msg]);
-			}
-			fprintf(log, "WM_TOUCH = %d -- 0x%X, 0x%X\n",msg, wParam, lParam);
-			fclose(log);
-#endif
-    
+		{
+			UINT i, num_inputs = LOWORD(wParam);
+			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
+			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
+				RECT rect;
+				float x, y;
+
+				if (!GetClientRect(hwnd, &rect) ||
+				    (rect.right == rect.left && rect.bottom == rect.top)) {
+					break;
+				}
+				ClientToScreen(hwnd, (LPPOINT) & rect);
+				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
+				rect.top *= 100;
+				rect.left *= 100;
+				rect.bottom *= 100;
+				rect.right *= 100;
+
+				for (i = 0; i < num_inputs; ++i) {
+					PTOUCHINPUT input = &inputs[i];
+
+					SDL_TouchID touchId = (SDL_TouchID)input->hSource;
+					if (!SDL_GetTouch(touchId)) {
+						SDL_Touch touch;
+
+						touch.id = touchId;
+						touch.x_min = 0;
+						touch.x_max = 1;
+						touch.native_xres = touch.x_max - touch.x_min;
+						touch.y_min = 0;
+						touch.y_max = 1;
+						touch.native_yres = touch.y_max - touch.y_min;
+						touch.pressure_min = 0;
+						touch.pressure_max = 1;
+						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
+
+						if (SDL_AddTouch(&touch, "") < 0) {
+							continue;
+						}
+					}
+
+					// Get the normalized coordinates for the window
+					x = (float)(input->x - rect.left)/(rect.right - rect.left);
+					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
+
+					if (input->dwFlags & TOUCHEVENTF_DOWN) {
+						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
+					}
+					if (input->dwFlags & TOUCHEVENTF_MOVE) {
+						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
+					}
+					if (input->dwFlags & TOUCHEVENTF_UP) {
+						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
+					}
+				}
+			}
+			SDL_stack_free(inputs);
+
+			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
+			return 0;
 		}
 		break;
-	case WM_GESTURE:
-		{
-			//printf("Got Touch Event!\n");
-    
-#ifdef WMMSG_DEBUG
-			FILE *log = fopen("wmmsg.txt", "a");
-			fprintf(log, "Received Gesture Message: %p ", hwnd);
-			if (msg > MAX_WMMSG) {
-				fprintf(log, "%d", msg);
-			} else {
-				fprintf(log, "%s", wmtab[msg]);
-			}
-			fprintf(log, "WM_GESTURE = %d -- 0x%X, 0x%X\n",msg, wParam, lParam);
-			fclose(log);
-#endif
-		}
-		break;		
 	}
 
     /* If there's a window proc, assume it's going to handle messages */
--- a/src/video/win32/SDL_win32video.c	Tue Nov 30 12:38:46 2010 -0800
+++ b/src/video/win32/SDL_win32video.c	Tue Nov 30 17:58:51 2010 -0800
@@ -82,6 +82,10 @@
        FreeLibrary(data->hAygShell);
     }
 #endif
+	if (data->userDLL) {
+		FreeLibrary(data->userDLL);
+	}
+
     SDL_free(device->driverdata);
     SDL_free(device);
 }
@@ -155,6 +159,13 @@
     data->CoordTransform = NULL;
 #endif
 
+	data->userDLL = LoadLibrary(TEXT("USER32.DLL"));
+	if (data->userDLL) {
+		data->CloseTouchInputHandle = (BOOL (WINAPI *)( HTOUCHINPUT )) GetProcAddress(data->userDLL, "CloseTouchInputHandle");
+		data->GetTouchInputInfo = (BOOL (WINAPI *)( HTOUCHINPUT, UINT, PTOUCHINPUT, int )) GetProcAddress(data->userDLL, "GetTouchInputInfo");
+		data->RegisterTouchWindow = (BOOL (WINAPI *)( HWND, ULONG )) GetProcAddress(data->userDLL, "RegisterTouchWindow");
+	}
+
     /* Set the function pointers */
     device->VideoInit = WIN_VideoInit;
     device->VideoQuit = WIN_VideoQuit;
--- a/src/video/win32/SDL_win32video.h	Tue Nov 30 12:38:46 2010 -0800
+++ b/src/video/win32/SDL_win32video.h	Tue Nov 30 17:58:51 2010 -0800
@@ -80,6 +80,32 @@
 
 enum { RENDER_NONE, RENDER_D3D, RENDER_DDRAW, RENDER_GDI, RENDER_GAPI, RENDER_RAW };
 
+#if WINVER < 0x0601
+/* Touch input definitions */
+#define TWF_FINETOUCH	1
+#define TWF_WANTPALM	2
+
+#define TOUCHEVENTF_MOVE 0x0001
+#define TOUCHEVENTF_DOWN 0x0002
+#define TOUCHEVENTF_UP   0x0004
+
+DECLARE_HANDLE(HTOUCHINPUT);
+
+typedef struct _TOUCHINPUT {
+	LONG      x;
+	LONG      y;
+	HANDLE    hSource;
+	DWORD     dwID;
+	DWORD     dwFlags;
+	DWORD     dwMask;
+	DWORD     dwTime;
+	ULONG_PTR dwExtraInfo;
+	DWORD     cxContact;
+	DWORD     cyContact;
+} TOUCHINPUT, *PTOUCHINPUT;
+
+#endif /* WINVER < 0x0601 */
+
 typedef BOOL  (*PFNSHFullScreen)(HWND, DWORD);
 typedef void  (*PFCoordTransform)(SDL_Window*, POINT*);
 
@@ -135,7 +161,13 @@
 #endif
 
     const SDL_scancode *key_layout;
-    DWORD clipboard_count;
+	DWORD clipboard_count;
+
+	/* Touch input functions */
+	HANDLE userDLL;
+	BOOL (WINAPI *CloseTouchInputHandle)( HTOUCHINPUT );
+	BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int );
+	BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG );
 
     SDL_bool ime_com_initialized;
     struct ITfThreadMgr *ime_threadmgr;
--- a/src/video/win32/SDL_win32window.c	Tue Nov 30 12:38:46 2010 -0800
+++ b/src/video/win32/SDL_win32window.c	Tue Nov 30 17:58:51 2010 -0800
@@ -144,6 +144,9 @@
         }
     }
 
+	/* Enable multi-touch */
+	videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
+
     /* All done! */
     window->driverdata = data;
     return 0;