GSSendEvent - Inject Touch Event для iOS
Я хочу добавить сенсорное событие в iPhone. Я получаю координаты события касания через сетевой сокет. GSSendEvent, кажется, хороший выбор. Тем не менее, он нуждается в GSEventRecord в качестве одного из входных данных.
Кто-нибудь знает, как подготовить GSEventRecord? Я подготовил его на основе некоторых примеров, но приложение вылетает после вызова GSSendEvent.
Ценю любую помощь.
-(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;
}
2 ответа
Проверено только на iOS 6
Вы на самом деле на правильном пути. Проблема в том, что вы должны выяснить, какие значения вы должны присвоить этим переменным.
Прежде всего, вам необходимо импортировать GraphicsServices.h. Затем вы можете попробовать следующий код с портом, который вы можете получить из Как найти фиолетовый порт для самого переднего приложения в IOS 5 и выше?,
Я не эксперт по iOS, и Apple не предоставляет никакой документации, поэтому я не могу объяснить, что здесь происходит. (Это работает нормально для меня.)
В любом случае, вы можете поиграть с ним, используя режим отладки xcode, чтобы увидеть, что происходит под капотом.
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);
Чтобы использовать этот код, вы должны вызывать его несколько раз. Для одного касания есть касание, перетаскивание и затем касание.
Также обратите внимание, что pathProximity равна 0, когда касание вверх.
Насколько я помню, winRef не имеет значения.
Надеюсь это поможет.
Изменить: Из комментария Bugivore проблема заключается в:
Способ, которым я выделил touchEvent через malloc, был неправильным. Это должно быть сделано, как показал EntryLevelDev: "статический uint8_t handJob[sizeof(GSEventRecord) + sizeof(GSHandInfo) + sizeof(GSPathInfo)];"
Ответ от EntryLevelDev является правильным, но некоторые значения не так важны. Я получил приведенные ниже коды откуда-то еще и сделал несколько попыток и ошибок, вот мои коды (работал до последней версии ios6).
И кто-нибудь сейчас работает над этим для IOS7? Я не мог заставить его работать. см. мой пост здесь: Каков альтернативный подход с GSCopyPurpleNamedPort(appId) в GraphicsServices, который устарел в IOS7?
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);