1

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.

Karthick Ramesh
  • 1,451
  • 20
  • 30
  • I have changed the question with the source code and description getting separated. Thank you for pointing out. – Karthick Ramesh Mar 17 '14 at 05:09
  • Can you help me on this... i am struck here for 2 days... – Karthick Ramesh Mar 18 '14 at 05:18
  • Hi Nate, I edited the question. NOw i could able to send events to the application but i am facing some problems over that. Please see through it. – Karthick Ramesh Mar 18 '14 at 11:30
  • Have you tried putting some time between your touch down and touch up events? It looks to me like `invokeAction` is injecting these two touch events right after one another. Put a delay between them. Note: do not do something like a thread `sleep()`. Schedule the second invocation 100 milliseconds or so later, by using something like `dispatch_after()`. – Nate Mar 19 '14 at 08:05
  • Also, which version of iOS are you testing on? – Nate Mar 19 '14 at 08:08
  • @Nate I tried the way you told by injecting touches Down after a delay but still i am facing problem. i am testing it on ios 6.1.3... I have changed the question too... – Karthick Ramesh Mar 19 '14 at 08:49
  • @Nate I am getting inconsistent results. The CGPoint that i gave is actually a centre of a button in my app. Some times i am getting the touch invoked, some times not. Even if the touch is getting invoked rarely the button gets tapped. Usually touchesBegan is getting called. Why is there such an inconstancy. – Karthick Ramesh Mar 19 '14 at 09:23
  • @Nate My background application also quits at times but nothing happens to my foreground app. Is there any delegate methods there that needs to be implemented? – Karthick Ramesh Mar 19 '14 at 09:29

1 Answers1

0

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));
Aniruddha
  • 4,477
  • 2
  • 21
  • 39
flysec
  • 16