From cfa7081212e5bda1bc7bf85dd1fe0abeef20f934 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 30 Nov 2010 17:58:51 -0800 Subject: [PATCH] First pass at Windows multi-touch gesture support --- src/events/SDL_gesture.c | 248 ++++++++++++------------- src/events/SDL_touch.c | 296 +++++++++++++++--------------- src/video/win32/SDL_win32events.c | 100 ++++++---- src/video/win32/SDL_win32video.c | 11 ++ src/video/win32/SDL_win32video.h | 34 +++- src/video/win32/SDL_win32window.c | 3 + 6 files changed, 383 insertions(+), 309 deletions(-) diff --git a/src/events/SDL_gesture.c b/src/events/SDL_gesture.c index 39ac76c2f..52510e9fe 100644 --- a/src/events/SDL_gesture.c +++ b/src/events/SDL_gesture.c @@ -97,7 +97,7 @@ int SDL_RecordGesture(SDL_TouchID touchId) { 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 @@ static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops * src) { //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 @@ int SDL_SaveAllDollarTemplates(SDL_RWops *src) { 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 @@ int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *src) { 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 @@ static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch,SDL_FloatPoint* path) 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 @@ static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch,SDL_FloatPoint* path) } 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 @@ int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) { 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 @@ int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) { 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 @@ float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang) { 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 @@ int dollarNormalize(SDL_DollarPath path,SDL_FloatPoint *points) { if(path.length <= 0) { for(i=1;i 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 @@ int dollarNormalize(SDL_DollarPath path,SDL_FloatPoint *points) { 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;inumDollarTemplates;i++) { - float diff = bestDollarDifference(points,touch->dollarTemplate[i].path); - if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;} - } - return bestDiff; + + 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; } 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_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist) { } 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 @@ void SDL_GestureProcessEvent(SDL_Event* event) 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 @@ void SDL_GestureProcessEvent(SDL_Event* event) #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 @@ void SDL_GestureProcessEvent(SDL_Event* event) #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 @@ void SDL_GestureProcessEvent(SDL_Event* event) 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 @@ void SDL_GestureProcessEvent(SDL_Event* event) 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); diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c index ec7b2e84a..41703da1a 100644 --- a/src/events/SDL_touch.c +++ b/src/events/SDL_touch.c @@ -65,8 +65,8 @@ SDL_GetFingerIndexId(SDL_Touch* touch,SDL_FingerID fingerid) { 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 @@ SDL_GetFinger(SDL_Touch* touch,SDL_FingerID id) { 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 @@ SDL_AddFinger(SDL_Touch* touch,SDL_Finger *finger) //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 @@ SDL_DelFinger(SDL_Touch* touch,SDL_FingerID fingerid) 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 @@ SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, 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; - - if(SDL_DelFinger(touch,fingerid) < 0) return 0; - posted = (SDL_PushEvent(&event) > 0); - } - return posted; + 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; } } 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 @@ SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, int relative, 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 @@ SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, int relative, 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 diff --git a/src/video/win32/SDL_win32events.c b/src/video/win32/SDL_win32events.c index c51c68111..42149023d 100644 --- a/src/video/win32/SDL_win32events.c +++ b/src/video/win32/SDL_win32events.c @@ -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 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } 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 */ diff --git a/src/video/win32/SDL_win32video.c b/src/video/win32/SDL_win32video.c index 96c885bb6..eaa820eed 100644 --- a/src/video/win32/SDL_win32video.c +++ b/src/video/win32/SDL_win32video.c @@ -82,6 +82,10 @@ WIN_DeleteDevice(SDL_VideoDevice * device) FreeLibrary(data->hAygShell); } #endif + if (data->userDLL) { + FreeLibrary(data->userDLL); + } + SDL_free(device->driverdata); SDL_free(device); } @@ -155,6 +159,13 @@ WIN_CreateDevice(int devindex) 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; diff --git a/src/video/win32/SDL_win32video.h b/src/video/win32/SDL_win32video.h index 8a20f3d5c..61c6fb54b 100644 --- a/src/video/win32/SDL_win32video.h +++ b/src/video/win32/SDL_win32video.h @@ -80,6 +80,32 @@ extern void WIN_SetError(const char *prefix); 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 @@ typedef struct SDL_VideoData #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; diff --git a/src/video/win32/SDL_win32window.c b/src/video/win32/SDL_win32window.c index 271b95744..317435509 100644 --- a/src/video/win32/SDL_win32window.c +++ b/src/video/win32/SDL_win32window.c @@ -144,6 +144,9 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created) } } + /* Enable multi-touch */ + videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM)); + /* All done! */ window->driverdata = data; return 0;