3

I want to simulate a click on the icon of an app on the home screen of jailbroken iPhone. I used the code below, but it could not take effect. Did I do something wrong?

Is the method to getFrontMostAppPort() right? Event if I tried to use GSSendSystemEvent(), it had no effect.

BTW, I mean jailbroken device. Could anyone give me a help? I very much appreciate it.

// Framework Paths
#define SBSERVPATH  "/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices"

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

static void sendTouchEvent(GSHandInfoType handInfoType, CGPoint point) {

    uint8_t touchEvent[sizeof(GSEventRecord) + sizeof(GSHandInfo) + sizeof(GSPathInfo)];

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

    // set up GSEvent
    event->record.type = kGSEventHand;
    event->record.subtype = kGSEventSubTypeUnknown;
    event->record.windowLocation = point;
    event->record.timestamp = GSCurrentEventTimestamp();
    event->record.infoSize = sizeof(GSHandInfo) + sizeof(GSPathInfo);
    event->handInfo.type = handInfoType;
    event->handInfo.x52 = 1;

    bzero(&event->handInfo.pathInfos[0], sizeof(GSPathInfo));
    event->handInfo.pathInfos[0].pathIndex     = 1;
    event->handInfo.pathInfos[0].pathIdentity  = 2;
    event->handInfo.pathInfos[0].pathProximity = (handInfoType == kGSHandInfoTypeTouchDown || handInfoType == kGSHandInfoTypeTouchDragged || handInfoType == kGSHandInfoTypeTouchMoved) ? 0x03 : 0x00;;
    event->handInfo.pathInfos[0].pathLocation  = point;


    mach_port_t port = (mach_port_t)getFrontMostAppPort();
    GSSendEvent((GSEventRecord *)event, port);
}

// why nothing happened?
static clickOnHome() {
    sendTouchEvent(kGSHandInfoTypeTouchDown, CGPointMake(100, 200));
    sleep(1);
    sendTouchEvent(kGSHandInfoTypeTouchUp, CGPointMake(100, 200));
}
Nate
  • 31,017
  • 13
  • 83
  • 207
Suge
  • 2,808
  • 3
  • 48
  • 79
  • iOS apps are not permitted to interact with the home screen, which is outside of the app sandbox. – BergQuester Jul 29 '13 at 02:50
  • If you are targeting jailbroken iOS devices, you should take your question as "Jailbreak" so people don't misunderstand. If you aren't targeting jailbroken iOS devices then give up on this madness because it will never be allowed. – borrrden Jul 29 '13 at 02:51
  • @borrrden, I have edited and pointed out the jailbroken environment, could you give some advices?Thank you. – Suge Jul 29 '13 at 05:11
  • Nope, I don't do that sort of stuff. – borrrden Jul 29 '13 at 05:15
  • I want to simulate the click on home screen, not only open the other app, is there any way? – Suge Jul 30 '13 at 02:00
  • @Bob, I rolled back your last edit to the question. Please don't add additional questions to a question after it's been answered. If you need to ask for clarification on an answer, please put that below the answer in a *comment* (as you did). If you have a new question about how to simulate a swipe on the home screen, please post that as a **new** question. Thanks. – Nate Jul 31 '13 at 17:01

1 Answers1

3

Yes, I think your getFrontMostAppPort() method is fine, if you got it from here.

I'm trying to understand what you want:

  1. If you simply want to open up a particular app (by bundleId), then I would recommend using the command-line open utility available on Cydia. You can call this programmatically with system(), or an exec call. Or, if you want to build this "open" capability into your own app, see my answer here.

  2. Now, maybe you are writing code for an app or tweak that's in the background, not the foreground app. And, maybe you really do need to touch a specific {x,y} coordinate, not open an app by its bundleId. If you really want that, this code works for me (based on this answer ... with corrections):

static void sendTouchEvent(GSHandInfoType handInfoType, CGPoint point) {

   uint8_t gsTouchEvent[sizeof(GSEventRecord) + sizeof(GSHandInfo) + sizeof(GSPathInfo)];

   // structure of touch GSEvent
   struct GSTouchEvent {
      GSEventRecord record;
      GSHandInfo    handInfo;
   } * touchEvent = (struct GSTouchEvent*) &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);
   touchEvent->record.timestamp = GSCurrentEventTimestamp();
   //touchEvent->record.window = winRef;
   //touchEvent->record.senderPID = 919;  
   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 = (handInfoType == kGSHandInfoTypeTouchDown) ? 2 : 1;
   touchEvent->handInfo.deltaX = 1;
   touchEvent->handInfo.deltaY = 1;
   touchEvent->handInfo.pathInfosCount = 0;
   touchEvent->handInfo.pathInfos[0].pathIndex = 1;
   touchEvent->handInfo.pathInfos[0].pathIdentity = 2;
   touchEvent->handInfo.pathInfos[0].pathProximity = (handInfoType == kGSHandInfoTypeTouchDown || handInfoType == kGSHandInfoTypeTouchDragged || handInfoType == kGSHandInfoTypeTouchMoved) ? 0x03: 0x00;
   touchEvent->handInfo.x52 = 1;  // iOS 5+, I believe
   touchEvent->handInfo.pathInfos[0].pathLocation = point;
   //touchEvent->handInfo.pathInfos[0].pathWindow = winRef;

   GSEventRecord* record = (GSEventRecord*) touchEvent;
   record->timestamp = GSCurrentEventTimestamp();

   GSSendEvent(record, getFrontMostAppPort());
}

- (void) simulateHomeScreenTouch {
   CGPoint location = CGPointMake(50, 50);
   sendTouchEvent(kGSHandInfoTypeTouchDown, location);

   double delayInSeconds = 0.1;
   dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
   dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
      sendTouchEvent(kGSHandInfoTypeTouchUp, location);
   });
}

This will send a touch down/up event pair to SpringBoard, as long as SpringBoard is the frontmost app (no other app open). Also, you can see where the handInfoType value is mapped to 2 or 1 for touch down and up events. The code above assumes that those are the only two types of events you're generating.


Note: I first tried with your coordinates of x=100, y=200, and nothing happened. I think that coordinate is between two home screen icons. Using other coordinates (e.g. x=50, y=50) works fine.


Note II: I don't believe this solution actually requires jailbreaking. It uses Private APIs, so it can't be submitted to the App Store, but this should work for jailed phones in an enterprise, or hobbyist deployment.

Community
  • 1
  • 1
Nate
  • 31,017
  • 13
  • 83
  • 207
  • Hi @Nate, would you see my update above, why does handInfo.type is 2 when handInfoType == kGSHandInfoTypeTouchDown, thank you very much. – Suge Jul 31 '13 at 13:48
  • And in fact, I'm trying to simulate all the touch events, including touchDown,touchMove,touchUp and touchCancel, but have no clear ideas. – Suge Jul 31 '13 at 14:15
  • @Bob, these are all undocumented APIs, so Apple can change them any time. It's possible that GSEvent.h has changed recently (iOS 6?), and that the numeric values of `GSHandInfoType` are different. 2 and 1 are the values that work for me, and the person online who suggested I use them. You can experiment for yourself what the proper values are for "move" and "cancel". That was not part of your original question, though, and aren't part of a normal click event. – Nate Jul 31 '13 at 16:59
  • @Nate did I put the method simulateHomeScreenTouch in the viewdidload and I click the home screen button to simulate this scenario if not plz give how to do thx – Dhekra Zaied Oct 17 '14 at 11:14
  • @HDNZ, sorry, I can't quite understand what you're trying to ask. Anyway, I don't think this technique works since the release of iOS 7, if I remember correctly. The APIs have changed since then. – Nate Oct 18 '14 at 04:53
  • Hi Nate thx for ur answer I want to simulate a touchor simulate the home button anything to begin the simulation topic on iOS7 ... how can I do it ...what steps can follow to begin this task ...please if u have any tutoriols...I googled for é days and I didn't get anything ... thx in advance. – Dhekra Zaied Oct 19 '14 at 15:14
  • @HDNZ, Stack Overflow isn't a comment forum. If you have a question about how to do this with the newer APIs on iOS 7/8, you should post a **new** question. If we simply talk about it down here, nobody will ever find it. Unfortunately, though, I haven't tried to find a new solution that works on iOS 7. – Nate Oct 19 '14 at 20:38
  • this my new question can u help me http://stackoverflow.com/questions/26460614/simulate-touch-on-ios7-8 – Dhekra Zaied Oct 20 '14 at 09:33