iPhone模擬觸屏實(shí)現(xiàn)事件教程
iPhone模擬觸屏實(shí)現(xiàn)事件教程是本文呀介紹的內(nèi)容,不多說(shuō),我們先來(lái)看內(nèi)容。目前又有了一個(gè)想在iPhone上做協(xié)助調(diào)試的設(shè)想,當(dāng)然控制權(quán)什么的是別說(shuō)了,就是做一些協(xié)助方在自己屏幕上點(diǎn)點(diǎn)劃劃,被協(xié)助方也要有同樣的操作,因?yàn)楸徽{(diào)試程序的不確定性,那只能做成發(fā)送各種針對(duì)屏幕的模擬事件了。
因?yàn)閍pple沒(méi)有放出直接發(fā)送觸屏事件等的API,所以用的都是越獄的iPhone加上PrivateFramework,根本沒(méi)指望上市,反正就是為了內(nèi)部調(diào)試。
首先在kennytm的網(wǎng)站拔下私有framework的頭文件,就本應(yīng)用而言,只需要GrapicsServices文件夾以及Availability2.h即可。然后導(dǎo)入Xcode目錄下Platforms下對(duì)應(yīng)的GraphicsService.framework,準(zhǔn)備工作就OK了。
發(fā)送事件消息,主要是構(gòu)造GSEventRecord,簡(jiǎn)單的事件可能只需要填充GSEventRecord里面的type類型參數(shù),再?gòu)?fù)雜一些的就需要在結(jié)構(gòu)的后面繼續(xù)填充,填充大小必須在infoSize參數(shù)里指定
C代碼
- typedef struct GSEventRecord {
- GSEventType type; // 0x8
- GSEventSubType subtype; // 0xC
- CGPoint location; // 0x10
- CGPoint windowLocation; // 0x18
- int windowContextId; // 0x20
- uint64_t timestamp; // 0x24, from mach_absolute_time
- GSWindowRef window; // 0x2C
- GSEventFlags flags; // 0x30
- unsigned senderPID; // 0x34
- CFIndex infoSize; // 0x38
- } GSEventRecord;
- typedef struct GSEventRecord {
- GSEventType type; // 0x8
- GSEventSubType subtype; // 0xC
- CGPoint location; // 0x10
- CGPoint windowLocation; // 0x18
- int windowContextId; // 0x20
- uint64_t timestamp; // 0x24, from mach_absolute_time
- GSWindowRef window; // 0x2C
- GSEventFlags flags; // 0x30
- unsigned senderPID; // 0x34
- CFIndex infoSize; // 0x38
- } GSEventRecord;
頭文件里沒(méi)有提供一些便捷方法構(gòu)造復(fù)雜的信息結(jié)構(gòu),這和public API真是云泥之別。不過(guò)一些非常簡(jiǎn)單的消息還是可以直接調(diào)用的,如void GSEventLockDevice();就相當(dāng)與構(gòu)造了一個(gè)type為kGSEventLockDevice的GSEventRecord結(jié)構(gòu)再將其發(fā)送出去。
用一個(gè)稍微復(fù)雜的例子,我們向屏幕的{50,50}坐標(biāo)處發(fā)送一個(gè)“按下”的指令
C代碼
- #import "GSEvent.h"
- #include <mach/mach_time.h>
- void sendclickevent(){
- mach_port_t thePortOfApp = GSCopyPurpleNamedPort("com.fuckyou.fuck");
- GSEventRecord header;
- GSHandInfo click;
- GSPathInfo pathInfo = {2,2,2,1,1,{50,50}, NULL};
- bzero(&header, sizeof(header));
- bzero(&click, sizeof(click));
- header.type = kGSEventHand;
- header.subtype = kGSEventSubTypeUnknown;
- header.location.x = 50;
- header.location.y = 50;
- header.windowLocation.x = 50;
- header.windowLocation.y = 50;
- header.infoSize = sizeof(GSHandInfo)+sizeof(GSPathInfo);
- header.timestamp = mach_absolute_time();
- click.type = kGSHandInfoTypeTouchDown;
- click.deltaX = 1;
- click.deltaY = 1;
- click.pathInfosCount = 1;
- struct
- {
- GSEventRecord record;
- GSHandInfo hand;
- GSPathInfo path;
- } record = {header, click, pathInfo};
- GSSendEvent(&record, thePortOfApp);
- }
- #import "GSEvent.h"
- #include <mach/mach_time.h>
- void sendclickevent(){
- mach_port_t thePortOfApp = GSCopyPurpleNamedPort("com.fuckyou.fuck");
- GSEventRecord header;
- GSHandInfo click;
- GSPathInfo pathInfo = {2,2,2,1,1,{50,50}, NULL};
- bzero(&header, sizeof(header));
- bzero(&click, sizeof(click));
- header.type = kGSEventHand;
- header.subtype = kGSEventSubTypeUnknown;
- header.location.x = 50;
- header.location.y = 50;
- header.windowLocation.x = 50;
- header.windowLocation.y = 50;
- header.infoSize = sizeof(GSHandInfo)+sizeof(GSPathInfo);
- header.timestamp = mach_absolute_time();
- click.type = kGSHandInfoTypeTouchDown;
- click.deltaX = 1;
- click.deltaY = 1;
- click.pathInfosCount = 1;
- struct
- {
- GSEventRecord record;
- GSHandInfo hand;
- GSPathInfo path;
- } record = {header, click, pathInfo};
- GSSendEvent(&record, thePortOfApp);
- }
里面需要注意的是向某應(yīng)用發(fā)送事件,必須獲得該應(yīng)用的端口,也就是第一行代碼。而發(fā)送復(fù)雜的信息必須要將若干信息體拼接到一起,自己定義一寫(xiě)需要的結(jié)構(gòu)體比較合適,并正確填寫(xiě)信息體的大小,這些技巧仿佛回到了蠻荒時(shí)代。我本身看到0長(zhǎng)數(shù)組,順手就在堆上構(gòu)造結(jié)構(gòu)了,但這些消息的處理是異步的,我也不清楚何時(shí)可以安全地回收內(nèi)存,所以建議還是使用結(jié)構(gòu)體拼湊的方法。
除了觸屏之外,另一個(gè)非常重要的就是鍵盤(pán)輸入了,但是iPhone的輸入的特殊性,不太好說(shuō)是鍵盤(pán)輸入,反正就是那個(gè)意思。
具體編碼過(guò)程其實(shí)和觸屏事件沒(méi)什么兩樣,不過(guò)如果把GSHardwareKeyInfo或者GSKeyInfo這種似乎是鍵盤(pán)事件的結(jié)構(gòu)名放google上搜索,一個(gè)結(jié)果都沒(méi)有,一開(kāi)始我還想湊,花了兩三天實(shí)在湊不出來(lái)了發(fā)現(xiàn)其實(shí)可以逆向來(lái)嘛,用GSEventCreateKeyEvent創(chuàng)造一個(gè)鍵盤(pán)事件,然后解析它就是,于是這樣才搞定,而且可悲的發(fā)現(xiàn)其實(shí)我想得太多了,里面絕大多數(shù)成員填0就行了,沒(méi)必要為編碼區(qū)這些東西煩惱。
Objective-c代碼
- GSEventRecord header;
- GSHardwareKeyInfo key = {0,0,0,0,1,{'a'},1,{'a'},0,0,0,0};
- memset(&header, 0, sizeof(header));
- header.type = kGSEventKeyDown;
- header.infoSize = sizeof(GSHardwareKeyInfo);
- header.timestamp = mach_absolute_time();
- struct
- {
- GSEventRecord header1;
- GSHardwareKeyInfo key1;
- }fuck = {header, key};
- GSSendEvent(&fuck, GSGetPurpleApplicationPort());
- GSEventRecord header;
- GSHardwareKeyInfo key = {0,0,0,0,1,{'a'},1,{'a'},0,0,0,0};
- memset(&header, 0, sizeof(header));
- header.type = kGSEventKeyDown;
- header.infoSize = sizeof(GSHardwareKeyInfo);
- header.timestamp = mach_absolute_time();
- struct
- {
- GSEventRecord header1;
- GSHardwareKeyInfo key1;
- }fuck = {header, key};
- GSSendEvent(&fuck, GSGetPurpleApplicationPort());
這樣就可以輸入一個(gè)a了,前提是光標(biāo)必須在輸入框內(nèi)。
當(dāng)然后續(xù)問(wèn)題還有很多,這實(shí)際上不過(guò)是自己的程序向自己的發(fā)送事件而已,后面需要做的是程序運(yùn)行到后臺(tái)時(shí)向前臺(tái)程序甚至是主界面發(fā)事件,能否做到,我也不敢肯定。
小結(jié):iPhone模擬觸屏實(shí)現(xiàn)事件教程的內(nèi)容介紹完了,希望本文對(duì)你有所幫助!更多相關(guān)內(nèi)容請(qǐng)參考編輯推薦。