Question

Hi Geeks, I made an application which keeps running in the background for 1 hour(by playing music for 1 hour).Through this app i tried to simulate any touch events in another app. I followed the link http://blog.lazerwalker.com/blog/2013/10/16/faking-touch-events-on-ios-for-fun-and-profit to do GSSendEvent. I have implemented the method in my AppDelegate's

    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: 10.0
                                                          target:self
                                                        selector:@selector(invokeAction)
                                                        userInfo:nil
                                                         repeats:NO];

    }

THis method calls invokeAction after 10 seconds

     -(mach_port_t)getFrontMostAppPort{
    bool locked;
    bool passcode;
    void *lib = dlopen(SBSERVPATH, RTLD_LAZY);
    int (*SBSSpringBoardServerPort)() = dlsym(lib, "SBSSpringBoardServerPort");
    void* (*SBGetScreenLockStatus)(mach_port_t* port, bool *lockStatus, bool *passcodeEnabled) = dlsym(lib, "SBGetScreenLockStatus");
    machPort = (mach_port_t *)SBSSpringBoardServerPort();
    dlclose(lib);
    SBGetScreenLockStatus(machPort, &locked, &passcode);
    void *(*SBFrontmostApplicationDisplayIdentifier)(mach_port_t *port, char *result) = dlsym(lib, "SBFrontmostApplicationDisplayIdentifier");
    char appId[256];
    memset(appId, 0, sizeof(appId));
    SBFrontmostApplicationDisplayIdentifier(machPort, appId);
    NSString * frontmostApp=[NSString stringWithFormat:@"%s",appId];
    NSLog(@"app is %@",frontmostApp);
    if([frontmostApp length] == 0 || locked)
        return GSGetPurpleSystemEventPort();
    else
        return GSCopyPurpleNamedPort(appId);
    }



-(void)invokeAction{
        NSLog(@"1");
        CGPoint touchBeginPoint = CGPointMake(600.0,510.0);
        [self sendEventForPhase:UITouchPhaseBegan touchedPoint:touchBeginPoint];
        double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    CGPoint touchBeginPoint = CGPointMake(600.0,510.0);
    [self sendEventForPhase:UITouchPhaseEnded touchedPoint:touchBeginPoint];
});
    }

Here i construct a CGPoint and call sendEVentForPhase.

    - (void)sendEventForPhase:(UITouchPhase)phase touchedPoint:(CGPoint)point{
NSLog(@"called ");
static mach_port_t port_;

// structure of touch GSEvent
struct GSTouchEvent {
    GSEventRecord record;
    GSHandInfo    handInfo;
} ;
struct GSTouchEvent *touchEvent = (struct GSTouchEvent *) malloc(sizeof(struct GSTouchEvent));

bzero(touchEvent, sizeof(touchEvent));
touchEvent->record.type = kGSEventHand;
touchEvent->record.subtype = kGSEventSubTypeUnknown;
touchEvent->record.location = point;
touchEvent->record.windowLocation = point;
touchEvent->record.infoSize = sizeof(GSHandInfo) + sizeof(GSPathInfo);
NSLog(@"time %lld",GSCurrentEventTimestamp());
touchEvent->record.timestamp = GSCurrentEventTimestamp();
touchEvent->record.senderPID = getpid();

NSLog(@"pr is %d",getpid());
//touchEvent->record.window = (__bridge GSWindowRef)(self.window);
bzero(&touchEvent->handInfo, sizeof(GSHandInfo));
bzero(&touchEvent->handInfo.pathInfos[0], sizeof(GSPathInfo));
GSHandInfo touchEventHandInfo;
touchEventHandInfo._0x5C = 0;
touchEventHandInfo.deltaX = 0;
touchEventHandInfo.deltaY = 0;
touchEventHandInfo.height = 0;
touchEventHandInfo.width = 0; 
touchEvent->handInfo = touchEventHandInfo;
touchEvent->handInfo.type = (phase == UITouchPhaseBegan) ? kGSHandInfoTypeTouchDown : kGSHandInfoTypeTouchUp;
touchEvent->handInfo.deltaX = 1;
touchEvent->handInfo.deltaY = 1;

touchEvent->handInfo.pathInfosCount = 0;
touchEvent->handInfo.pathInfos[0].pathMajorRadius = 1.0;
touchEvent->handInfo.pathInfos[0].pathPressure = 1.0;
touchEvent->handInfo.pathInfos[0].pathIndex = 1;
touchEvent->handInfo.pathInfos[0].pathIdentity = 2;
touchEvent->handInfo.pathInfos[0].pathProximity = (phase == UITouchPhaseBegan) ? 0x03 : 0x00 ;
touchEvent->handInfo.pathInfos[0].pathLocation = point;

port_ = [self getFrontMostAppPort];
GSSendEvent((GSEventRecord*)touchEvent ,port_);

}

after 10 seconds that this application has gone to background the invokeAction method is triggered. BY that time i go to my desired app.Here while the application is running in background i access the application that is running in the foreground. I gave the CGPoint as centre of a button that is in the foreground application (I know this as i have the project code). Then I construct GSEventRecord. Now by getting purple port of the foreground application i send both those values (GSEventRecord and mach port) i made GSSendEvent. The function is called But,

Now I face many problems as follows 1. The touch invocation result is not consistent. At some times it just performs the complete touch event and everything is working fine. 2. sometimes only touchDown works and my background application quits before touchUp is invoked which makes the foreground application to just get struck with the button highlighted in blue as if the finger is not taken from the button.

I am testing it on ipad with ios 6.1.3

Why there is such an inconsistency. Do i miss something. Please help me out. A small help will take the hell out my hectic 3 days.

Was it helpful?

Solution

1) struct GSTouchEvent *touchEvent = (struct GSTouchEvent *) malloc(sizeof(struct GSTouchEvent));

memory is not enough need one more pathinfo for touchEvent->handInfo.pathInfos[0] as its define in struct has no memory, length of array "pathInfos" is 0, but you used 1struct GSTouchEvent

2) memory of GSHandInfo touchEventHandInfo should be reset

bzero(&touchEventHandInfo, sizeof(GSHandInfo));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top