I want to inject touch event in iPhone. I get the coordinates of touch event via network socket. GSSendEvent seems to be good choice. However, it needs GSEventRecord as one of the inputs.
Does anyone know how to prepare GSEventRecord? I prepared it based on some examples but the app crashes after GSSendEvent call.
Appreciate any help.
-(void) handleMouseEventAtPoint:(CGPoint) point
{
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));
// set up GSEvent
touchEvent->record.type = kGSEventHand;
touchEvent->record.windowLocation = point;
touchEvent->record.timestamp = GSCurrentEventTimestamp();
touchEvent->record.infoSize = sizeof(GSHandInfo) + sizeof(GSPathInfo);
touchEvent->handInfo.type = getHandInfoType(0, 1);
touchEvent->handInfo.pathInfosCount = 1;
bzero(&touchEvent->handInfo.pathInfos[0], sizeof(GSPathInfo));
touchEvent->handInfo.pathInfos[0].pathIndex = 1;
touchEvent->handInfo.pathInfos[0].pathIdentity = 2;
touchEvent->handInfo.pathInfos[0].pathProximity = 1 ? 0x03 : 0x00;
touchEvent->handInfo.pathInfos[0].pathLocation = point;
port_ = GSGetPurpleSystemEventPort();
GSSendEvent((GSEventRecord*)touchEvent ,port_);
}
static GSHandInfoType getHandInfoType(int touch_before, int touch_now){
if (!touch_before) {
return (GSHandInfoType) kGSHandInfoType2TouchDown;
}
if (touch_now) {
return (GSHandInfoType) kGSHandInfoType2TouchChange;
}
return (GSHandInfoType) kGSHandInfoType2TouchFinal;
}
Only tested on iOS 6
You are actually on the right track. The problem is you have to figure out what values you should assign to these variables.
First of all, you need to import GraphicsServices.h. Then, you can try the following code with the port which you can get from How to find the purple port for the front most application in IOS 5 and above?.
I am not an iOS expert and Apple doesn't provide any documentation so I can't explain much what's going on here. (It happens to work fine for me.)
Anyway, you can play with it using xcode debug mode to see what happens under the hood.
struct GSTouchEvent * 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;
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;
touchEvent->handInfo.pathInfos[0].pathLocation = point;
touchEvent->handInfo.pathInfos[0].pathWindow = winRef;
GSEventRecord* record = (GSEventRecord*) touchEvent;
record->timestamp = GSCurrentEventTimestamp();
GSSendEvent(record, port);
To use this code, you have to call it multiple times. For one tap, there are touch-down, touch-drag and then touch-up.
Also note that pathProximity is 0 when touch is up.
As far as I remember, the winRef doesn't matter.
Hope this helps.
Edit: From Bugivore's comment, the problem is:
The way I allocated touchEvent via malloc was wrong. It should be done as EntryLevelDev showed - "static uint8_t handJob[sizeof(GSEventRecord) + sizeof(GSHandInfo) + sizeof(GSPathInfo)];"
Answer from EntryLevelDev is correct, but some of the value is not so important. I got the below codes from somewhere else and have done some try and errors, here is my codes(worked for till latested ios6).
And is anyone working on this for IOS7 now? I could not get it to work. see my post here:With GSCopyPurpleNamedPort(appId) in GraphicsServices deprecated in IOS7, what is the alternative approach?
static int prev_click = 0;
if (!click && !prev_click)
{
//which should never enter
NSLog(@"***error, postHandEvent cancel");
return;
}
CGPoint location = CGPointMake(x, y);
struct GSTouchEvent {
GSEventRecord record;
GSHandInfo handInfo;
} * event = (struct GSTouchEvent*) &touchEvent;
bzero(touchEvent, sizeof(touchEvent));
event->record.type = kGSEventHand;
event->record.windowLocation = location;
event->record.timestamp = GSCurrentEventTimestamp();
//NSLog(@"Timestamp GSCurrentEventTimestamp: %llu",GSCurrentEventTimestamp());
event->record.infoSize = sizeof(GSHandInfo) + sizeof(GSPathInfo);
event->handInfo.type = getHandInfoType(prev_click, click);
//must have the following line
event->handInfo.x52 = 1;
//below line is for ios4
//event->handInfo.pathInfosCount = 1;
bzero(&event->handInfo.pathInfos[0], sizeof(GSPathInfo));
event->handInfo.pathInfos[0].pathIndex = 2;
//following 2 lines, they are by default
event->handInfo.pathInfos[0].pathMajorRadius = 1.0;
event->handInfo.pathInfos[0].pathPressure = 1.0;
//event->handInfo.pathInfos[0].pathIdentity = 2;
event->handInfo.pathInfos[0].pathProximity = click ? 0x03 : 0x00;
//event->handInfo.pathInfos[0].pathProximity = action;
event->handInfo.pathInfos[0].pathLocation = location;
// send GSEvent
GSEventRecord *event1 = (GSEventRecord*) event;
sendGSEvent(event1);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With