iPhone類比觸屏實現事件教程是本文呀介紹的內容,不多說,我們先來看內容。目前又有了一個想在iPhone上做協助調試的設想,當然控制權什麼的是別說了,就是做一些協助方在自己螢幕上點點劃劃,被協助方也要有同樣的操作,因為被偵錯工具的不確定性,那隻能做成發送各種針對螢幕的類比事件了。
因為apple沒有放出直接發送觸屏事件等的API,所以用的都是越獄的iPhone加上PrivateFramework,根本沒指望上市,反正就是為了內部調試。
首先在kennytm的網站拔下私人framework的標頭檔,就本應用而言,只需要GrapicsServices檔案夾以及Availability2.h即可。然後匯入Xcode目錄下Platforms下對應的GraphicsService.framework,準備工作就OK了。
發送事件訊息,主要是構造GSEventRecord,簡單的事件可能只需要填充GSEventRecord裡面的type型別參數,再複雜一些的就需要在結構的後面繼續填充,填充大小必須在infoSize參數裡指定
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;
標頭檔裡沒有提供一些便捷方法構造複雜的資訊結構,這和public API真是雲泥之別。不過一些非常簡單的訊息還是可以直接調用的,如void GSEventLockDevice();就相當與構造了一個type為kGSEventLockDevice的GSEventRecord結構再將其發送出去。
用一個稍微複雜的例子,我們向螢幕的{50,50}座標處發送一個“按下”的指令
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);
- }
裡面需要注意的是向某應用發送事件,必須獲得該應用的連接埠,也就是第一行代碼。而發送複雜的資訊必須要將若干資訊體拼接到一起,自己定義一寫需要的結構體比較合適,並正確填寫資訊體的大小,這些技巧彷彿回到了蠻荒時代。我本身看到0長數組,順手就在堆上構造結構了,但這些訊息的處理是非同步,我也不清楚何時可以安全地回收記憶體,所以建議還是使用結構體拼湊的方法。
除了觸屏之外,另一個非常重要的就是鍵盤輸入了,但是iPhone的輸入的特殊性,不太好說是鍵盤輸入,反正就是那個意思。
具體編碼過程其實和觸屏事件沒什麼兩樣,不過如果把GSHardwareKeyInfo或者GSKeyInfo這種似乎是鍵盤事件的結構名放google上搜尋,一個結果都沒有,一開始我還想湊,花了兩三天實在湊不出來了發現其實可以逆向來嘛,用GSEventCreateKeyEvent創造一個鍵盤事件,然後解析它就是,於是這樣才搞定,而且可悲的發現其實我想得太多了,裡面絕大多數成員填0就行了,沒必要為編碼區這些東西煩惱。
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());
這樣就可以輸入一個a了,前提是游標必須在輸入框內。
當然後續問題還有很多,這實際上不過是自己的程式向自己的發送事件而已,後面需要做的是程式運行到後台時向前景程式甚至是主介面發事件,能否做到,我也不敢肯定。
小結:iPhone類比觸屏實現事件教程的內容介紹完了,希望本文對你有所協助!更多相關內容請參考編輯精選。