Yes, I think your getFrontMostAppPort()
method is fine, if you got it from here.
I'm trying to understand what you want:
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 withsystem()
, or anexec
call. Or, if you want to build this "open" capability into your own app, see my answer here.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.