Android天天飞车游戏辅助系统
Android天天飛車游戲輔助系統
聲明:單純的輔助模擬人操作,非修改游戲內存,非修改游戲運行文件,非修改調用庫……
(避免使用外掛這個詞,畢竟離外掛還有好遠的距離~)
玩了好久的騰訊天天飛車,每天的20局任務相當蛋疼,遂頭腦一熱想開發個Android應用,來模擬手動操作。
花了幾天時間,把Android開發環境搭建了,搞了個簡單的能識別當前游戲處在哪個界面,并模擬操作點擊左右轉向按鍵,馬馬虎虎算是可以完成每日20局任務了~
摸索新領域總是充滿未知和驚喜的,遂記之如下。
整體思路
通過屏幕像素點的顏色信息,判斷當前處于哪個界面(弱爆了的感覺~~~~~)
然后模擬按鍵操作~~~
手機:移動M701 ROOT
一、如何搭建Android開發環境
度娘之~
二、如何創建浮動窗口
因為考慮到不能影響到正常使用其他應用,需要將控制按鈕放在浮動于所有應用之上的窗口上。
先要在OnCreate()函數里初始化如下變量:
private static WindowManager wm =(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE); private static WindowManager.LayoutParamsparams = new WindowManager.LayoutParams(); public ViewGroup controlViewGroup =(ViewGroup) View.inflate(getApplicationContext(), R.layout.floating, null);?
創建懸浮窗的代碼:
?
/*** 創建可移動的懸浮窗,在所有應用最頂層顯示*/ private void createFloatView() {Log.i(TAG,TAG+"createFloatView()");btn_floatView= new Button(getApplicationContext());btn_floatView.setBackgroundResource(R.drawable.img_float);//設置window typeparams.type= WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;params.format= PixelFormat.RGBA_8888; // 設置圖片格式,效果為背景透明//設置Window flagparams.flags= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE ;params.flags&= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; // 屏幕常亮僅在控制板可見時有效params.alpha= CONTROL_VIEW_ALPHA; // 設置懸浮窗的透明度 //設置懸浮窗的長得寬params.width= FLOATING_VIEW_SIZE;params.height= FLOATING_VIEW_SIZE;//設置懸浮窗的Touch監聽 //可以實現按住拖放的功能,單擊后,彈出控制窗口btn_floatView.setOnTouchListener(newOnTouchListener(){intlastX, lastY;intparamX, paramY;intupX,upY;publicboolean onTouch(View v, MotionEvent event){switch(event.getAction()){caseMotionEvent.ACTION_DOWN:lastX= (int) event.getRawX();lastY= (int) event.getRawY();paramX= params.x;paramY= params.y;break;caseMotionEvent.ACTION_MOVE:intdx = (int) event.getRawX() - lastX;intdy = (int) event.getRawY() - lastY;params.x= paramX + dx;params.y= paramY + dy;//更新懸浮窗位置wm.updateViewLayout(btn_floatView,params);break;caseMotionEvent.ACTION_UP:upX= (int) event.getRawX();upY= (int) event.getRawY();if(Math.abs(lastX-upX) < 5 && Math.abs(lastY-upY) < 5){//單擊后,彈出控制面板createControlView();}break;}returntrue;}}); wm.addView(btn_floatView,params); }控制窗口的顯示代碼如下:
/*** 創建控制面板* 啟動/暫停按鈕、 最小化按鈕、 退出按鈕*/ private void createControlView() { //設置Window flag//params.flags&= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;params.flags&= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 接受焦點輸入params.flags|= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; // 屏幕常亮//wm.updateViewLayout(gView,params); //設置懸浮窗的長得寬params.width= CONTROL_VIEW_WIDTH;params.height= CONTROL_VIEW_HEIGHT;//params.x= 200;//params.y= 400;wm.removeView(btn_floatView);wm.addView(controlViewGroup,params); }?
?
三、如何模擬控制按鍵操作
有很多種方法,這里我采用的方法是直接往linux底層/dev/input/event*寫事件,當然是需要手機root權限的。
先說下android界面捕獲事件的流程吧:
用戶點擊-(硬件驅動部分)硬件產生一個中斷,往/dev/input/event*寫入一個相應的信號,android循環讀取/dev/input/event*的事件,再分發給WindowManagerServer,最后再發到相應的ViewGroup和View。因此這里可以通過往/dev/input/event*寫信號的方式,來達到模擬按鍵的目的。
類似分析可參見這里:
http://zuoshu.iteye.com/blog/1775606
http://blog.csdn.net/learnrose/article/details/6236890
總而言之,步驟如下:
1、查看設備屬性
查看當前手機的輸入設備:
>adb shell getevent
可以看到觸摸屏name=mtk-tpd, 是event3,如果不放心,可以隨意觸摸屏幕,會發現收到很多event3的數據
2、確定按鍵命令格式信息
>adb shell getevent | grep event3這個命令可以使得命令窗口只顯示event3的數據信息,快速點擊下屏幕發現有很多數據,如下圖左側部分:
但這些數據都是16進制數字,我們可沒法看,別急,輸入下面命令:
>adb shell getevent -d -l/dev/input/event3通過給getevent加上-d -l參數來查看:
-d: show HID descriptor, if available
-l: label event types and names in plain text
這樣就得到上圖右邊紅色框里的數據了。
這樣我們就得到了一次按鍵的數據命令格式如下:
EV_KEY BTN_TOUCH DOWN 0001 014a 00000001EV_ABS ABS_MT_TOUCH_MAJOR 00000001 EV_ABS ABS_MT_POSITION_X 0000003e EV_ABS ABS_MT_POSITION_Y 000000ef EV_ABS ABS_MT_TRACKING_ID 00000001 0003 0030 00000001 0003 0035 00000028 0003 0036 00000112 0003 0039 00000001EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 0000 0002 00000000 0000 0000 00000000EV_ABS ABS_MT_TOUCH_MAJOR 00000001 EV_ABS ABS_MT_POSITION_X 0000003e EV_ABS ABS_MT_POSITION_Y 000000ef EV_ABS ABS_MT_TRACKING_ID 00000001 0003 0030 00000001 0003 0035 00000028 0003 0036 00000112 0003 0039 00000001EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 0000 0002 00000000 0000 0000 00000000EV_KEY BTN_TOUCH UP 0001 014a 00000000EV_SYN SYN_MT_REPORT 00000000 EV_SYN SYN_REPORT 00000000 0000 0002 00000000 0000 0000 00000000根據手指的抖動情況,xy坐標可能會發送多次。
3、代碼模擬按鍵
現在我們通過向event3發送數據來模擬按鍵。
這里,我們通過app操作手機的超級終端來發送命令。
代碼如下:
?
// 命令定義 切記不要忘記最后的換行符 public static final String CMD_DOWN = "sendevent/dev/input/event3 1 330 1 \n"; public static final String CMD_TOUCH_MAJOR= "sendevent /dev/input/event3 3 4820 \n"; public static final String CMD_X = "sendevent/dev/input/event3 3 53 "; public static final String CMD_Y = "sendevent/dev/input/event3 3 54 "; public static final String CMD_TRACK_ID = "sendevent /dev/input/event3 357 0 \n"; public static final StringCMD_SYN_MT_REPORT = "sendevent/dev/input/event3 0 2 0 \n"; public static final String CMD_SYN_REPORT = "sendevent /dev/input/event3 00 0 \n"; public static final String CMD_UP = "sendevent/dev/input/event3 1 330 0 \n";Process proc; // 先獲取root,運行shell // 因為su需要花一定時間,所以os放在最后才初始化 try { proc= Runtime.getRuntime().exec("su"); // 以root運行超級終端,設備需要擁有su權限 }catch (IOException e) { e.printStackTrace(); } DataOutputStream os = newDataOutputStream(proc.getOutputStream());// 模擬按鍵 os.writeBytes(CMD_DOWN); os.flush(); for (int i=0; i<1; i++) {os.writeBytes(CMD_TOUCH_MAJOR);os.flush();os.writeBytes(CMD_X+ x +" \n");os.flush();os.writeBytes(CMD_Y+ y +" \n");os.flush();os.writeBytes(CMD_TRACK_ID);os.flush();os.writeBytes(CMD_SYN_MT_REPORT);os.flush();os.writeBytes(CMD_SYN_REPORT);os.flush(); } os.writeBytes(CMD_UP); os.flush(); os.writeBytes(CMD_SYN_MT_REPORT); os.flush(); os.writeBytes(CMD_SYN_REPORT); os.flush();實際可能還需要根據屏幕的坐標系,確定xy的方向。
我的手機是右上角為原點,自上向下為x正方向,自右向左為y正方向。
四、如何感知當前屏幕像素點顏色信息?
其實這有點類似于“Android屏幕截圖”這個問題。
我們知道,DDMS可以很容易的獲取Android 手機的屏幕截圖,那么它是怎么做到的呢??
其實,android手機上有一個叫做FrameBuffer的設備,圖像信息都是通過FrameBuffer寫到手機屏幕上去的。因此可以通過讀取此設備中的數據來獲取當前正在顯示的圖像。當然DDMS也是這么做到的。
FrameBuffer 對應的設備文件就是/dev/graphics/fb0。因此我們可以通過讀取這個設備文件的內容來獲取屏幕的圖像數據。這個文件的信息如下:
使用這種方法第一個難題是獲取FrameBuffer,因為默認的配置中FrameBuffer的讀取權限是“root”,而Apk的權限最高只能提升到“system”,framework工作的權限也是“system”,所以需要手機root。
1、修改設備文件/dev/graphics/fb0的屬性
為了能夠讀取內容,我們可以修改下fb0的設備權限為一般用戶可讀:
chmod 444 /dev/graphics/fb02、讀取設備文件/dev/graphics/fb0內的數據
好了,接下來就是將fb0內的數據讀入到我們自己的數組里:
?
// 獲取屏幕大小: DisplayMetrics metrics = new DisplayMetrics(); WindowManager WM = (WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE); Display display = WM.getDefaultDisplay(); display.getMetrics(metrics); int height = metrics.heightPixels; //屏幕高 int width = metrics.widthPixels; //屏幕的寬 // 獲取顯示方式 int pixelformat = display.getPixelFormat(); // 1 RGBA_8888 實際讀取到的fb0的數據格式為BGRA PixelFormat localPixelFormat1 = new PixelFormat(); PixelFormat.getPixelFormatInfo(pixelformat,localPixelFormat1); int deepth = localPixelFormat1.bytesPerPixel;//位深 // 4 // // 讀取buffer myFrameBuffer = new byte[height * width * deepth * 2];// 雙緩沖,實際我們也只需要用一個就夠了try {os.writeBytes("chmod666 /dev/graphics/fb0 \n");os.flush();FileInputStreamstream = new FileInputStream(newFile("/dev/graphics/fb0"));myFrameBufferStream= new DataInputStream(stream);myFrameBufferStream.readFully(myFrameBuffer);myFrameBufferStream.close();stream.close(); } catch (FileNotFoundException e) {// TODOAuto-generated catch blocke.printStackTrace(); } catch (IOException e) {// TODOAuto-generated catch blocke.printStackTrace(); }?
接下來就是將讀取到的數據顯示在我的控件之上:
?
readFrameBuffer(); int w = 720; int h = 1280; Bitmap bitmap =Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); for (int i=0; i<h; i++) {int line_length = 2944; // 實際一行數據字節數for (int j=0; j<w; j++){int pos = i*line_length + j*4;int a = 255;// rgba - bgraint r = (int)(myFrameBuffer[pos + 2 ] &0x0FF);int g = (int)(myFrameBuffer[pos + 1 ] &0x0FF);int b = (int)(myFrameBuffer[pos + 0 ] &0x0FF);//System.out.println("FCQD " + "i: "+i +" j: "+j +" "+ r +" "+ g +""+ b +" "+ a );bitmap.setPixel(j, i, Color.rgb(r, g, b));} } ImageView image =(ImageView) controlViewGroup.findViewById(R.id.imageView1); image.setImageBitmap(bitmap);3、正確解析FrameBuffer內的數據
這里還需要強調一點,就是變量line_length,因為在adb shell里查看fb0的信息如下:
我們可以看到fb0的大小為7536640,我的手機是720*1280的,根據代碼里的PixelFormat可以看到位深4,即一個像素4字節數據(BGRA),這樣算下來應該是 720*1280*4=3686400,考慮雙緩沖有3686400*2=7372800,咦,怎么比fb0的實際大小略小?我一直以為類似于bmp的數據格式,按行存儲的,通過winhex查看fb0 cat出來的文件數據也沒發現什么問題,但是顯示的始終就是花屏,類似于這樣:
折騰了好幾天,度娘了好久,最后還是google到一個牛逼國外網友:
http://stackoverflow.com/questions/15468542/how-to-discover-framebuffer-width-on-android
The right padding is called"stride" (stride = (line_length in pixel) - width). Many device hadthis stride in the framebuffer if the display resolution is not multiply of 8.
So the formula is:
fileSize = line_length * yres * numberOfFrames
Don't multiply it with bpp/8, because the line_length is memory size (not pixelsize).
To retrive the?line_length?Youshould used?FBIOGET_FSCREENINFO?(0x4602 -17922) rather thanFBIOGET_VSCREENINFO?(0x4600 -17922) like this:
>adb shell ioctl -rl 50 /dev/graphics/fb0 17922
My Galaxy Nexus return like this:
return buf: 6f 6d 61706662 00 00000000 00 00000000 00 00 a0 ac000000
01 00 00 00000000 00 00020000 00 01000100 00 00000080 0b 00000000
My Galaxy Nexus have line_length: 2944(0xb80).
意思就是說,內存里的一行字節數是line_length,而不是width*4!
查了好久,貌似基本都會提到ioctl,沒想到強大的adb竟然也提供了這個命令,可以查看屏幕的參數信息:
>adbshell ioctl -rl 28 /dev/graphics/fb0 17920
屏幕寬度:0x000002d0 = 720
屏幕高度:0x00000500 = 1280
每像素bit:0x00000020 = 32
為了查看line_length,根據這位牛逼國外網友的提示:
>adbshell ioctl -rl 50 /dev/graphics/fb0 17922
也即我的line_length:0x00000b80 = 2944
這樣,7536640 = 1280行 * 2944 * 2屏, 這回就可以正確解析FrameBuffer里的圖像數據了。
?
五、?? 最終效果圖
很粗糙,期待后續改進,現在是隨機控制左右轉向,要是能識別車輛就好了~(這個貌似單純的通過像素點來判斷恐怕不現實,不知是不是可以從游戲使用的引擎入手,不過那么高的高度也是后話了~~~)
?
?
?
總結
以上是生活随笔為你收集整理的Android天天飞车游戏辅助系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机自动安装程序,如何阻止电脑自动安装
- 下一篇: Android图片色彩变幻