本工具为原创,涉及知识:

- Python编程

- Tkinter GUI编程

- ADB通信机制

代码已经开源:

https://code.csdn.net/codehat/andev/tree/master/src/arobot.py

代码全文:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------------
# Android Robot 3.1
# This is a free software under GPL.
#
# Author: DiaoXuesong
# Bug report: wishcom@163.com
# ---------------------------------------------------------------------------
#
# Function:
# Screen cast via adb daemon, without java env.
# Usage:
# arobot.py [-option]
# Example:
# arobot.py
# arobot.py -lcd
# arobot.py -keypad import subprocess,os
import threading
import socket,sys
import time try:
import Tkinter as tk
import ttk
from PIL import Image,ImageTk,ImageDraw
except:
print 'Following module is needed:'
print '- Tkinter: sudo apt-get install python-tk'
print '- PIL: sudo apt-get install python-imaging-tk'
sys.exit() # Set DEBUG to True if you need know more running message
DEBUG = False # Set USE_TTK to False if you need classic Tk/Tcl GUI-style
USE_TTK = True '''
Key value definition refer from KeyEvent.java
public class KeyEvent extends InputEvent implements Parcelable {
/** Key code constant: Unknown key code. */
public static final int KEYCODE_UNKNOWN = 0;
public static final int KEYCODE_SOFT_LEFT = 1;
public static final int KEYCODE_SOFT_RIGHT = 2;
public static final int KEYCODE_HOME = 3;
public static final int KEYCODE_BACK = 4;
public static final int KEYCODE_CALL = 5;
public static final int KEYCODE_ENDCALL = 6;
public static final int KEYCODE_0 = 7;
public static final int KEYCODE_1 = 8;
public static final int KEYCODE_2 = 9;
public static final int KEYCODE_3 = 10;
public static final int KEYCODE_4 = 11;
public static final int KEYCODE_5 = 12;
public static final int KEYCODE_6 = 13;
public static final int KEYCODE_7 = 14;
public static final int KEYCODE_8 = 15;
public static final int KEYCODE_9 = 16;
public static final int KEYCODE_STAR = 17;
public static final int KEYCODE_POUND = 18;
public static final int KEYCODE_DPAD_UP = 19;
public static final int KEYCODE_DPAD_DOWN = 20;
public static final int KEYCODE_DPAD_LEFT = 21;
public static final int KEYCODE_DPAD_RIGHT = 22;
public static final int KEYCODE_DPAD_CENTER = 23;
public static final int KEYCODE_VOLUME_UP = 24;
public static final int KEYCODE_VOLUME_DOWN = 25;
public static final int KEYCODE_POWER = 26;
public static final int KEYCODE_CAMERA = 27;
public static final int KEYCODE_CLEAR = 28;
public static final int KEYCODE_A = 29;
public static final int KEYCODE_B = 30;
public static final int KEYCODE_C = 31;
public static final int KEYCODE_D = 32;
public static final int KEYCODE_E = 33;
public static final int KEYCODE_F = 34;
public static final int KEYCODE_G = 35;
public static final int KEYCODE_H = 36;
public static final int KEYCODE_I = 37;
public static final int KEYCODE_J = 38;
public static final int KEYCODE_K = 39;
public static final int KEYCODE_L = 40;
public static final int KEYCODE_M = 41;
public static final int KEYCODE_N = 42;
public static final int KEYCODE_O = 43;
public static final int KEYCODE_P = 44;
public static final int KEYCODE_Q = 45;
public static final int KEYCODE_R = 46;
public static final int KEYCODE_S = 47;
public static final int KEYCODE_T = 48;
public static final int KEYCODE_U = 49;
public static final int KEYCODE_V = 50;
public static final int KEYCODE_W = 51;
public static final int KEYCODE_X = 52;
public static final int KEYCODE_Y = 53;
public static final int KEYCODE_Z = 54;
public static final int KEYCODE_COMMA = 55;
public static final int KEYCODE_PERIOD = 56;
public static final int KEYCODE_ALT_LEFT = 57;
public static final int KEYCODE_ALT_RIGHT = 58;
public static final int KEYCODE_SHIFT_LEFT = 59;
public static final int KEYCODE_SHIFT_RIGHT = 60;
public static final int KEYCODE_TAB = 61;
public static final int KEYCODE_SPACE = 62;
public static final int KEYCODE_SYM = 63;
public static final int KEYCODE_EXPLORER = 64;
public static final int KEYCODE_ENVELOPE = 65;
public static final int KEYCODE_ENTER = 66;
public static final int KEYCODE_DEL = 67;
public static final int KEYCODE_GRAVE = 68;
public static final int KEYCODE_MINUS = 69;
public static final int KEYCODE_EQUALS = 70;
public static final int KEYCODE_LEFT_BRACKET = 71;
public static final int KEYCODE_RIGHT_BRACKET = 72;
public static final int KEYCODE_BACKSLASH = 73;
public static final int KEYCODE_SEMICOLON = 74;
public static final int KEYCODE_APOSTROPHE = 75;
public static final int KEYCODE_SLASH = 76;
public static final int KEYCODE_AT = 77;
public static final int KEYCODE_NUM = 78;
public static final int KEYCODE_HEADSETHOOK = 79;
public static final int KEYCODE_FOCUS = 80;
public static final int KEYCODE_PLUS = 81;
public static final int KEYCODE_MENU = 82;
public static final int KEYCODE_NOTIFICATION = 83;
public static final int KEYCODE_SEARCH = 84;
public static final int KEYCODE_MEDIA_PLAY_PAUSE= 85;
public static final int KEYCODE_MEDIA_STOP = 86;
public static final int KEYCODE_MEDIA_NEXT = 87;
public static final int KEYCODE_MEDIA_PREVIOUS = 88;
public static final int KEYCODE_MEDIA_REWIND = 89;
public static final int KEYCODE_MEDIA_FAST_FORWARD = 90;
public static final int KEYCODE_MUTE = 91;
public static final int KEYCODE_PAGE_UP = 92;
public static final int KEYCODE_PAGE_DOWN = 93;
public static final int KEYCODE_PICTSYMBOLS = 94;
public static final int KEYCODE_SWITCH_CHARSET = 95;
public static final int KEYCODE_BUTTON_A = 96;
public static final int KEYCODE_BUTTON_B = 97;
public static final int KEYCODE_BUTTON_C = 98;
public static final int KEYCODE_BUTTON_X = 99;
public static final int KEYCODE_BUTTON_Y = 100;
public static final int KEYCODE_BUTTON_Z = 101;
public static final int KEYCODE_BUTTON_L1 = 102;
public static final int KEYCODE_BUTTON_R1 = 103;
public static final int KEYCODE_BUTTON_L2 = 104;
public static final int KEYCODE_BUTTON_R2 = 105;
public static final int KEYCODE_BUTTON_THUMBL = 106;
public static final int KEYCODE_BUTTON_THUMBR = 107;
public static final int KEYCODE_BUTTON_START = 108;
public static final int KEYCODE_BUTTON_SELECT = 109;
public static final int KEYCODE_BUTTON_MODE = 110;
public static final int KEYCODE_ESCAPE = 111;
public static final int KEYCODE_FORWARD_DEL = 112;
public static final int KEYCODE_CTRL_LEFT = 113;
public static final int KEYCODE_CTRL_RIGHT = 114;
public static final int KEYCODE_CAPS_LOCK = 115;
public static final int KEYCODE_SCROLL_LOCK = 116;
public static final int KEYCODE_META_LEFT = 117;
public static final int KEYCODE_META_RIGHT = 118;
public static final int KEYCODE_FUNCTION = 119;
public static final int KEYCODE_SYSRQ = 120;
public static final int KEYCODE_BREAK = 121;
public static final int KEYCODE_MOVE_HOME = 122;
public static final int KEYCODE_MOVE_END = 123;
public static final int KEYCODE_INSERT = 124;
public static final int KEYCODE_FORWARD = 125;
public static final int KEYCODE_MEDIA_PLAY = 126;
public static final int KEYCODE_MEDIA_PAUSE = 127;
public static final int KEYCODE_MEDIA_CLOSE = 128;
public static final int KEYCODE_MEDIA_EJECT = 129;
public static final int KEYCODE_MEDIA_RECORD = 130;
public static final int KEYCODE_F1 = 131;
public static final int KEYCODE_F2 = 132;
public static final int KEYCODE_F3 = 133;
public static final int KEYCODE_F4 = 134;
public static final int KEYCODE_F5 = 135;
public static final int KEYCODE_F6 = 136;
public static final int KEYCODE_F7 = 137;
public static final int KEYCODE_F8 = 138;
public static final int KEYCODE_F9 = 139;
public static final int KEYCODE_F10 = 140;
public static final int KEYCODE_F11 = 141;
public static final int KEYCODE_F12 = 142;
public static final int KEYCODE_NUM_LOCK = 143;
public static final int KEYCODE_NUMPAD_0 = 144;
public static final int KEYCODE_NUMPAD_1 = 145;
public static final int KEYCODE_NUMPAD_2 = 146;
public static final int KEYCODE_NUMPAD_3 = 147;
public static final int KEYCODE_NUMPAD_4 = 148;
public static final int KEYCODE_NUMPAD_5 = 149;
public static final int KEYCODE_NUMPAD_6 = 150;
public static final int KEYCODE_NUMPAD_7 = 151;
public static final int KEYCODE_NUMPAD_8 = 152;
public static final int KEYCODE_NUMPAD_9 = 153;
public static final int KEYCODE_NUMPAD_DIVIDE = 154;
public static final int KEYCODE_NUMPAD_MULTIPLY = 155;
public static final int KEYCODE_NUMPAD_SUBTRACT = 156;
public static final int KEYCODE_NUMPAD_ADD = 157;
public static final int KEYCODE_NUMPAD_DOT = 158;
public static final int KEYCODE_NUMPAD_COMMA = 159;
public static final int KEYCODE_NUMPAD_ENTER = 160;
public static final int KEYCODE_NUMPAD_EQUALS = 161;
public static final int KEYCODE_NUMPAD_LEFT_PAREN = 162;
public static final int KEYCODE_NUMPAD_RIGHT_PAREN = 163;
public static final int KEYCODE_VOLUME_MUTE = 164;
public static final int KEYCODE_INFO = 165;
public static final int KEYCODE_CHANNEL_UP = 166;
public static final int KEYCODE_CHANNEL_DOWN = 167;
public static final int KEYCODE_ZOOM_IN = 168;
public static final int KEYCODE_ZOOM_OUT = 169;
public static final int KEYCODE_TV = 170;
public static final int KEYCODE_WINDOW = 171;
public static final int KEYCODE_GUIDE = 172;
public static final int KEYCODE_DVR = 173;
public static final int KEYCODE_BOOKMARK = 174;
public static final int KEYCODE_CAPTIONS = 175;
public static final int KEYCODE_SETTINGS = 176;
public static final int KEYCODE_TV_POWER = 177;
public static final int KEYCODE_TV_INPUT = 178;
public static final int KEYCODE_STB_POWER = 179;
public static final int KEYCODE_STB_INPUT = 180;
public static final int KEYCODE_AVR_POWER = 181;
public static final int KEYCODE_AVR_INPUT = 182;
public static final int KEYCODE_PROG_RED = 183;
public static final int KEYCODE_PROG_GREEN = 184;
public static final int KEYCODE_PROG_YELLOW = 185;
public static final int KEYCODE_PROG_BLUE = 186;
public static final int KEYCODE_APP_SWITCH = 187;
public static final int KEYCODE_BUTTON_1 = 188;
public static final int KEYCODE_BUTTON_2 = 189;
public static final int KEYCODE_BUTTON_3 = 190;
public static final int KEYCODE_BUTTON_4 = 191;
public static final int KEYCODE_BUTTON_5 = 192;
public static final int KEYCODE_BUTTON_6 = 193;
public static final int KEYCODE_BUTTON_7 = 194;
public static final int KEYCODE_BUTTON_8 = 195;
public static final int KEYCODE_BUTTON_9 = 196;
public static final int KEYCODE_BUTTON_10 = 197;
public static final int KEYCODE_BUTTON_11 = 198;
public static final int KEYCODE_BUTTON_12 = 199;
public static final int KEYCODE_BUTTON_13 = 200;
public static final int KEYCODE_BUTTON_14 = 201;
public static final int KEYCODE_BUTTON_15 = 202;
public static final int KEYCODE_BUTTON_16 = 203;
public static final int KEYCODE_LANGUAGE_SWITCH = 204;
public static final int KEYCODE_MANNER_MODE = 205;
public static final int KEYCODE_3D_MODE = 206;
public static final int KEYCODE_CONTACTS = 207;
public static final int KEYCODE_CALENDAR = 208;
public static final int KEYCODE_MUSIC = 209;
public static final int KEYCODE_CALCULATOR = 210;
public static final int KEYCODE_ZENKAKU_HANKAKU = 211;
public static final int KEYCODE_EISU = 212;
public static final int KEYCODE_MUHENKAN = 213;
public static final int KEYCODE_HENKAN = 214;
public static final int KEYCODE_KATAKANA_HIRAGANA = 215;
public static final int KEYCODE_YEN = 216;
public static final int KEYCODE_RO = 217;
public static final int KEYCODE_KANA = 218;
public static final int KEYCODE_ASSIST = 219;
private static final int LAST_KEYCODE = KEYCODE_ASSIST; private static final int KEYCODE_TEST_BASE = 220;
public static final int KEYCODE_POWER_TEST = KEYCODE_TEST_BASE + 1;
public static final int KEYCODE_HOME_TEST = KEYCODE_TEST_BASE + 2;
public static final int KEYCODE_BACK_TEST = KEYCODE_TEST_BASE + 3;
public static final int KEYCODE_MENU_TEST = KEYCODE_TEST_BASE + 4;
public static final int KEYCODE_SEARCH_TEST = KEYCODE_TEST_BASE + 5;
public static final int KEYCODE_CALL_TEST = KEYCODE_TEST_BASE + 6;
public static final int KEYCODE_ENDCALL_TEST = KEYCODE_TEST_BASE + 7;
public static final int KEYCODE_VOLUME_UP_TEST = KEYCODE_TEST_BASE + 8;
public static final int KEYCODE_VOLUME_DOWN_TEST = KEYCODE_TEST_BASE + 9;
public static final int KEYCODE_CAMERA_TEST = KEYCODE_TEST_BASE + 10;
public static final int KEYCODE_SPACE_TEST = KEYCODE_TEST_BASE + 11;
public static final int KEYCODE_FUNCTION_TEST = KEYCODE_TEST_BASE + 12;
''' # keynames is the key name list
# 'none': no keys in this grid
keynames = ['home', 'menu', 'back', 'srch',
'call', '^', 'end', 'none',
'<', 'ok', '>', 'vol+',
'none', 'v', 'none', 'vol-',
'1', '2', '3', 'none',
'4', '5', '6', 'cam',
'7', '8', '9', 'enter',
'*', '0', '#'
] # keyvalues is the key value list map with the keynames
# 0: no keys here
keyvalues = [ 3, 82, 4, 84,
5, 19, 6, 0,
21,23,22, 24,
0, 20, 0, 25,
8, 9,10, 0,
11,12,13, 27,
14,15,16, 66,
17, 7,18
] # Print Hex Buffer
def hexdump(buf = None):
if buf != None:
pstr = ''
cnt = 0
for x in buf:
if (cnt + 1) % 8 == 0:
pstr = '%s%02X\n' % (pstr, x)
else:
pstr = '%s%02X ' % (pstr, x)
cnt = cnt + 1
print pstr # Read adb response, if 'OKAY' turn true
def readAdbResponse(s):
if s != None:
resp = s.recv(4)
if DEBUG:
print 'resp: %s' % repr(resp) if len(resp) != 4:
print 'protocol fault (no status)'
return False if resp == 'OKAY':
return True
elif resp == 'FAIL':
resp = s.recv(4)
if len(resp) < 4:
print 'protocol fault (status len)'
return False
else:
length = int(resp, 16)
resp = s.recv(length)
if len(resp) != length:
print 'protocol fault (status read)'
return False
else:
print resp
return False
else:
print "protocol fault (status %02x %02x %02x %02x?!)", (resp[0], resp[1], resp[2], resp[3])
return False return False # Send adb shell command
def adbshellcommand(cmd):
reply = None
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # waiting adb server start
while True:
try:
s.connect(('127.0.0.1', 5037))
except:
os.system('adb start-server')
time.sleep(2)
continue
else:
break req_msg = 'host:transport-any'
s.sendall('%04x' % len(req_msg))
s.sendall(req_msg)
if not readAdbResponse(s):
return None req_msg = 'shell:%s' % cmd
if DEBUG:
print '%s' % req_msg
s.sendall('%04x' % len(req_msg))
s.sendall(req_msg)
if readAdbResponse(s):
reply = s.recv(4096)
if DEBUG:
hexdump(bytearray(reply))
s.close() return reply # Convert buffer to Int
def getInt(tbuf = None):
if (tbuf != None):
if DEBUG:
hexdump(bytearray(tbuf))
if len(tbuf) < 4:
print 'buff len < 4'
return 0
else:
if DEBUG:
print 'parse: %02x %02x %02x %02x' % (tbuf[0],tbuf[1],tbuf[2],tbuf[3])
intnum = tbuf[0]
intnum = intnum + tbuf[1]*0x100
intnum = intnum + tbuf[2]*0x10000
intnum = intnum + tbuf[3]*0x1000000
if DEBUG:
print 'INT: %08x' % intnum
return intnum
else:
return 0 # Parse fb header from buffer
def readHeader(tfb, ver, buf):
if DEBUG:
print 'readHeader: ver = %d' % ver
if ver == 16:
tfb.fb_bpp = 16
tfb.fb_size = getInt(buf[0:4])
tfb.fb_width = getInt(buf[4:8])
tfb.fb_height = getInt(buf[8:12])
tfb.red_offset = 11
tfb.red_length = 5
tfb.blue_offset = 5
tfb.blue_length = 6
tfb.green_offset = 0
tfb.green_length = 5
tfb.alpha_offset = 0
tfb.alpha_length = 0
elif ver == 1:
tfb.fb_bpp = getInt(bytearray(buf[0:4]))
tfb.fb_size = getInt(bytearray(buf[4:8]))
tfb.fb_width = getInt(bytearray(buf[8:12]))
tfb.fb_height = getInt(bytearray(buf[12:16]))
tfb.red_offset = getInt(bytearray(buf[16:20]))
tfb.red_length = getInt(bytearray(buf[20:24]))
tfb.blue_offset = getInt(bytearray(buf[24:28]))
tfb.blue_length = getInt(bytearray(buf[28:32]))
tfb.green_offset = getInt(bytearray(buf[32:36]))
tfb.green_length = getInt(bytearray(buf[36:40]))
tfb.alpha_offset = getInt(bytearray(buf[40:44]))
tfb.alpha_length = getInt(bytearray(buf[44:48]))
else:
return False
return True # Find the Touch input device and event
def get_touch_event():
tp_names = ['ft5x06', 'gt818']
output = adbshellcommand('getevent -S')
if output == None:
return None if DEBUG:
print output
dev = ''
name = ''
for line in output.splitlines():
if '/dev/input/event' in line:
line = line.split(':')
if len(line) == 2:
line = line[1]
line = line.strip(' ')
line = line.strip('"')
dev = line
elif 'name:' in line:
line = line.split(':')
if len(line) == 2:
line = line[1]
line = line.strip(' ')
line = line.strip('"')
name = line if (dev != '') and (name in tp_names):
break if DEBUG:
print '%s : %s' % (name, dev) if name in tp_names:
return (name, dev)
else:
return None # Do the touch action
def send_touch_event(action, x0, y0, x1 = None, y1 = None):
# Note: input support tap & swipe after 4.1
# so we need emulate TP via sendevent if tap or swipe fail
if action == 'tap':
resp = adbshellcommand('input tap %d %d' % (x0, y0))
if 'Error' in resp:
print 'Not support tap command' # get tp device
tp = get_touch_event() if tp == None:
return # down
cmd_str = ''
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 53, x0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 54, y0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 57, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 48, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 2, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 1, 330, 1)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 0, 0) # up
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 1, 330, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 2, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 0, 0) if DEBUG:
print cmd_str
adbshellcommand(cmd_str)
elif action == 'swipe':
resp = adbshellcommand('input swipe %d %d %d %d' % (x0, y0, x1, y1))
if 'Error' in resp:
print 'Not support tap command' # get tp device
tp = get_touch_event() if tp == None:
return step = 3
stepx = abs(x1 - x0) / step
stepy = abs(y1 - y0) / step
x = x0
y = y0 for i in range(0, step + 1):
if x0 < x1:
x = x0 + i * stepx
else:
x = x0 - i * stepx if y0 < y1:
y = y0 + i * stepy
else:
y = y0 - i * stepy cmd_str = ''
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 53, x)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 54, y)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 57, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 3, 48, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 2, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 1, 330, 1)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 0, 0)
adbshellcommand(cmd_str) # up
cmd_str = ''
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 1, 330, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d;' % (tp[1], 0, 2, 0)
cmd_str = cmd_str + 'sendevent %s %d %d %d' % (tp[1], 0, 0, 0)
if DEBUG:
print cmd_str
adbshellcommand(cmd_str) # Framebuffer Class
# Only record framebuffer attributs
class fb:
fb_bpp = 0
fb_size = 0
fb_width = 0
fb_height = 0
red_offset = 0
red_length = 0
blue_offset = 0
blue_length = 0
green_offset = 0
green_length = 0
alpha_offset = 0
alpha_length = 0
fb_data = None def __init__(self):
fb_bpp = 0
fb_size = 0
fb_width = 0
fb_height = 0
red_offset = 0
red_length = 0
blue_offset = 0
blue_length = 0
green_offset = 0
green_length = 0
alpha_offset = 0
alpha_length = 0
fb_data = None # send key thread
class send_key_thread(threading.Thread):
__tkapp = None
__root = None
__key = None def __init__(self, key):
if DEBUG:
print 'send_key_thread init'
threading.Thread.__init__(self)
self.thread_stop = False
self.__key = key def devexist(self):
p = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
p.wait()
devList = p.communicate()
devList = devList[0].splitlines()
if 'device' in devList[1]:
if DEBUG:
print devList[1]
return True
else:
if DEBUG:
print 'No adb device found'
return False def sendKey(self):
if DEBUG:
print 'send_key: %s' % self.__key
if self.__key in keynames:
if self.devexist():
if self.__key != 'none':
adbshellcommand('input keyevent %s' % str(keyvalues[keynames.index(self.__key)])) def run(self):
if DEBUG:
print 'send_key_thread run'
self.sendKey() def stop(self):
if DEBUG:
print 'stop send_key_thread'
self.thread_stop = True # Kaypad Tkinter-Based GUI application
class KeypadApplication(tk.Frame):
def __init__(self, master=None):
if master == None:
master = tk.Tk()
tk.Frame.__init__(self, master, class_='KeypadApplication')
self.createkeypad()
self.grid() def createkeypad(self):
# creat buttons from keymap with 4 buttons each row
for btn_name in keynames:
row_id = keynames.index(btn_name) / 4
col_id = keynames.index(btn_name) % 4 if btn_name != 'none':
self.tbutton = tk.Button(self, name = btn_name, text=btn_name)
self.tbutton['activebackground'] = '#BBBBBB'
#self.tbutton['highlightcolor'] = '#BBBB00'
else:
self.tbutton = tk.Button(self, name = btn_name, text='') self.tbutton['width'] = 10
if btn_name != 'none':
self.tbutton.bind('<ButtonRelease-1>', self.sendKey)
self.tbutton.grid(padx = 5, pady = 1, column = col_id, row = row_id) def devexist(self):
p = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
p.wait()
devList = p.communicate()
devList = devList[0].splitlines()
if 'device' in devList[1]:
if DEBUG:
print devList[1]
return True
else:
if DEBUG:
print 'No adb device found'
return False def sendKey(self, event=None):
if DEBUG:
print event.widget.winfo_name()
keyname = event.widget.winfo_name()
if keyname in keynames:
sender = send_key_thread(keyname)
sender.start() # Kaypad Tkinter-Based GUI application
class ttkKeypadApplication(ttk.Frame):
def __init__(self, master=None):
if master == None:
master = ttk.Tk()
ttk.Frame.__init__(self, master, class_='ttkKeypadApplication')
self.createkeypad()
self.grid() def createkeypad(self):
# creat buttons from keymap with 4 buttons each row
for btn_name in keynames:
row_id = keynames.index(btn_name) / 4
col_id = keynames.index(btn_name) % 4 if btn_name != 'none':
self.tbutton = ttk.Button(self, name = btn_name, text=btn_name)
else:
self.tbutton = ttk.Button(self, name = btn_name, text='') self.tbutton['width'] = 10
if btn_name != 'none':
self.tbutton.bind('<ButtonRelease-1>', self.sendKey)
self.tbutton.grid(padx = 5, pady = 1, column = col_id, row = row_id) def devexist(self):
p = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
p.wait()
devList = p.communicate()
devList = devList[0].splitlines()
if 'device' in devList[1]:
if DEBUG:
print devList[1]
return True
else:
if DEBUG:
print 'No adb device found'
return False def sendKey(self, event=None):
if DEBUG:
print event.widget.winfo_name()
keyname = event.widget.winfo_name()
if keyname in keynames:
sender = send_key_thread(keyname)
sender.start() # LCD Tkinter-Based GUI application
class LcdApplication(tk.Frame):
__img_factor = 1.00 # image resize rate
__lcd = None # the label widget
__keepupdate = True
__im = None
__rotate = 0 # record mouse start & end point location
__start = [0, 0]
__end = [0, 0] def __init__(self, master=None):
if DEBUG:
print 'LcdApplication: __init__'
if master == None:
master = tk.Tk()
tk.Frame.__init__(self, master, class_='LcdApplication')
self.__rotate = 0
self.createlcd()
self.grid() def createlcd(self):
# creat label as lcd
if DEBUG:
print 'LcdApplication: createlcd' # make default image display on label
image = Image.new(mode = 'RGB', size = (240, 320), color = '#000000')
draw = ImageDraw.Draw(image)
draw.text((80, 100), 'Connecting...')
self.__im = ImageTk.PhotoImage(image) # create label with image option
self.__lcd = tk.Label(self, image=self.__im)
self.__lcd.bind('<Button-1>', self.click_label)
self.__lcd.bind('<ButtonRelease-1>', self.click_label)
self.__lcd.bind('<ButtonRelease-3>', self.rightclick_label) # disply label on frame
self.__lcd.grid() # To serve right click on label widget
def rightclick_label(self, event=None):
if DEBUG:
print 'Type: %s' % event.type
self.__rotate = (self.__rotate + 90) % 360
print "rotate: %d" % self.__rotate # To serve left click on label widget
def click_label(self, event=None):
if DEBUG:
print 'Type: %s' % event.type
if event.type == '4':
# record mouse left button down
if DEBUG:
print 'Click at: (%d, %d)' % (event.x, event.y)
self.__start[0] = int(float(event.x) / float(self.__img_factor))
self.__start[1] = int(float(event.y) / float(self.__img_factor))
self.__end = None
elif event.type == '5':
# record mouse left button up
if DEBUG:
print 'Release at: (%d, %d)' % (event.x, event.y)
self.__end = [0, 0]
self.__end[0] = int(float(event.x) / float(self.__img_factor))
self.__end[1] = int(float(event.y) / float(self.__img_factor)) # Do not report touch event during mouse down
if self.__end == None:
return if abs(self.__start[0] - self.__end[0]) < 2 and \
abs(self.__start[1] - self.__end[1]) < 2 :
# mouse action: tap
send_touch_event('tap', self.__start[0], self.__start[1])
else:
# mouse action: swipe
send_touch_event('swipe', self.__start[0], self.__start[1], self.__end[0], self.__end[1]) def stop(self):
if DEBUG:
print 'LcdApplication: stop'
self.__keepupdate = False # screen capture via socket from adb server
def updatelcd_sock(self):
if DEBUG:
print 'LcdApplication: updatelcd_sock'
# Max display area size on label widget
#max_lcd_w = 1024
#max_lcd_h = 600
max_lcd_w = 1440
max_lcd_h = 720 dev_sn = ''
hdrsize = 0
myfb = fb()
refresh_count = 0 # record refresh count while self.__keepupdate:
# Get device SerialNumber from ADB server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect(('127.0.0.1', 5037))
except:
os.system('adb start-server')
time.sleep(2)
continue req_msg = 'host:devices'
s.sendall('%04x' % len(req_msg))
s.sendall(req_msg)
if readAdbResponse(s):
len_str = s.recv(4)
if len(len_str) < 4:
continue
length = int(len_str, 16)
dev_info = s.recv(length)
if '\t' in dev_info:
dev_sn = dev_info[0:dev_info.index('\t')]
else:
dev_sn = ''
if DEBUG:
print 'dev serial: %s' % dev_sn
s.recv(1024) # receive all rest data
s.close() if dev_sn == '':
continue # Get framebuffer from ADB server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 5037))
req_msg = 'host:transport:%s' % dev_sn
s.sendall('%04x' % len(req_msg))
s.sendall(req_msg)
if not readAdbResponse(s):
s.close()
else:
if DEBUG:
print 'ready to transport'
req_msg = 'framebuffer:'
s.sendall('%04x' % len(req_msg))
s.sendall(req_msg)
if not readAdbResponse(s):
s.close()
else:
reply = s.recv(4)
if len(reply) < 4:
continue fbver = ord(reply[0]) + \
ord(reply[1]) * 0x100 + \
ord(reply[2]) * 0x10000 + \
ord(reply[3]) * 0x1000000
if DEBUG:
print 'fbver: %08x' % fbver # Get fb header size
if fbver == 16:
hdrsize = 3
elif fbver == 1:
hdrsize = 12
else:
hdrsize = 0;
if DEBUG:
print 'fb header size: %d' % hdrsize # read the header
header = s.recv(hdrsize * 4)
if len(header) < (hdrsize * 4):
continue if DEBUG:
hexdump(bytearray(header))
readHeader(myfb, fbver, header)
if DEBUG:
print 'bpp: %d' % myfb.fb_bpp
print 'size: %d' % myfb.fb_size
print 'width: %d' % myfb.fb_width
print 'height: %d' % myfb.fb_height
print 'red_offset: %d' % myfb.red_offset
print 'red_length: %d' % myfb.red_length
print 'blue_offset: %d' % myfb.blue_offset
print 'blue_length: %d' % myfb.blue_length
print 'green_offset: %d' % myfb.green_offset
print 'green_length: %d' % myfb.green_length
print 'alpha_offset: %d' % myfb.alpha_offset
print 'alpha_length: %d' % myfb.alpha_length # read fb buffer
rcvcnt = 0
readbyte = 0
imagebuff = []
while True:
if (rcvcnt < myfb.fb_size):
readbyte = myfb.fb_size - rcvcnt
else:
break
resp = s.recv(readbyte)
if DEBUG:
print 'read byte: %d' % len(resp)
rcvcnt = rcvcnt + len(resp);
imagebuff.extend(resp)
if len(resp) == 0:
break if DEBUG:
print 'total rcv byte: %d' % rcvcnt
reply = s.recv(10)
s.close()
myfb.fb_data = bytearray(imagebuff) if len(imagebuff) < myfb.fb_size:
continue # convert raw-rgb to image
image = Image.frombuffer('RGBA',
(myfb.fb_width, myfb.fb_height),
myfb.fb_data,
'raw',
'RGBA',
0,
1) lcd_w = image.size[0]
lcd_h = image.size[1]
if DEBUG:
print 'LCD size: %d x %d' % (lcd_w,lcd_h)
factor_w = 1.00
factor_h = 1.00
if lcd_w > max_lcd_w:
img_w = max_lcd_w
factor_w = float(img_w)/float(lcd_w)
if lcd_h > max_lcd_h:
img_h = max_lcd_h
factor_h = float(img_h)/float(lcd_h)
factor = min([factor_w, factor_h])
self.__img_factor = factor # Keep the rate of w:h
img_w = int(lcd_w * factor)
img_h = int(lcd_h * factor)
if DEBUG:
print 'Image size: %d x %d' % (img_w, img_h) # resize image
if (factor < 1.00):
image = image.resize((img_w, img_h)) # rotate image
if self.__rotate != 0:
image = image.rotate(self.__rotate) if self.__lcd != None:
try:
# save image to local path
if DEBUG:
refresh_count = refresh_count + 1
image_name = 'image_%d.png' % refresh_count
image.save(image_name, format='PNG')
new_image = ImageTk.PhotoImage(image)
self.__im = new_image
self.__lcd['image'] = self.__im
except:
continue # keypad window thread
class arobot_keys(threading.Thread):
__tkapp = None
__root = None def __init__(self):
threading.Thread.__init__(self)
self.thread_stop = False def run(self):
if DEBUG:
print 'run arobot_keys'
self.__root = tk.Tk()
if USE_TTK:
self.__tkapp = ttkKeypadApplication(master=self.__root)
else:
self.__tkapp = KeypadApplication(master=self.__root)
self.__tkapp.master.title('ARobot3.0-Keypad')
self.__tkapp.grid()
self.__tkapp.mainloop()
if DEBUG:
print 'exit arobot_keys mainloop' def stop(self):
if DEBUG:
print 'stop arobot_keys'
if self.__tkapp != None:
self.__tkapp.quit()
self.thread_stop = True # screen windows thread
class arobot_lcd(threading.Thread):
__tkapp = None
__root = None def __init__(self):
threading.Thread.__init__(self)
self.thread_stop = False def run(self):
if DEBUG:
print 'run arobot_lcd'
self.__root = tk.Tk()
self.__tkapp = LcdApplication(master=self.__root)
self.__tkapp.master.title('ARobot3.0-Lcd')
t = threading.Timer(1, self.__tkapp.updatelcd_sock)
t.start()
self.__tkapp.grid()
self.__tkapp.mainloop()
if DEBUG:
print 'exit arobot_lcd mainloop'
self.__tkapp.stop() def stop(self):
if DEBUG:
print 'stop arobot_lcd'
self.thread_stop = True
if self.__tkapp != None:
self.__tkapp.stop()
self.__tkapp.quit() def arobot_main(prog):
if prog == None:
return if prog == 'lcd':
lcd_thread = arobot_lcd()
lcd_thread.start() if prog == 'keypad':
keypad_thread = arobot_keys()
keypad_thread.start() def usage():
print '--------------------------------------------'
print 'Arobot 3.1'
print 'This is a tool to control Android device via ADB'
print 'usage: python %s [option]' % sys.argv[0]
print 'option:'
print ' -keypad run keypad'
print ' -lcd run lcd'
print '--------------------------------------------' if __name__ == '__main__':
prog_name = sys.argv[0]
if '--debug' in sys.argv:
DEBUG = True if DEBUG:
if len(sys.argv) == 2:
cmd_str = 'python %s -keypad --debug' % prog_name
p1 = subprocess.Popen(cmd_str, shell=True)
cmd_str = 'python %s -lcd --debug' % prog_name
p2 = subprocess.Popen(cmd_str, shell=True)
elif len(sys.argv) == 3:
if sys.argv[1] == '-keypad':
arobot_main('keypad')
elif sys.argv[1] == '-lcd':
arobot_main('lcd')
else:
usage()
else:
if len(sys.argv) == 1:
# Do not wast your time on threading, it is disaster working with tk!
# I have tried many ways to open multi-windows via Tk and Threading
# but fail! or linux ok but windows fail, so, just use the subprocess!
cmd_str = 'python %s -keypad' % prog_name
p1 = subprocess.Popen(cmd_str, shell=True)
cmd_str = 'python %s -lcd' % prog_name
p2 = subprocess.Popen(cmd_str, shell=True)
elif len(sys.argv) == 2:
if sys.argv[1] == '-keypad':
arobot_main('keypad')
elif sys.argv[1] == '-lcd':
arobot_main('lcd')
else:
usage()
else:
usage()

Python实现的基于ADB的Android远程工具的更多相关文章

  1. Android远程桌面助手

    很早之前,做过一个<WinCE远程桌面助手>,在没有屏幕或者在调试LCD驱动时,发挥了很大作用,平日开发也是必备.后来还被网友用于处理一些疑难问题,如无法输入开机密码时可通过该工具远程输入 ...

  2. Android配置----小米手机通过wifi连接ADB调试Android应用

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  3. Android远程桌面助手(B1371)

    Android远程桌面助手(B1371),下载:https://files.cnblogs.com/files/we-hjb/ARDC%28B1371%29.7z 1.增加了对超大分辨率4320*21 ...

  4. Android远程桌面助手(B1309)

    修改了窗口缩放的处理,支持Android Car等非常规分辨率的Android设备: 修改了获取Android端软件版本的方法,优化了APK的升级逻辑: 优化了远程输入法功能,支持利用PC端输入法快速 ...

  5. Android远程桌面助手扩展之微信跳一跳辅助

    微信跳一跳的外挂辅助已是五花八门,万能的TB上也有了各种明码标价的代练.微信小程序游戏的火爆甚至带火了手游外挂产业.另一方面,跳一跳游戏也在不断更新,防止使用外挂刷高分.Android远程桌面助手支持 ...

  6. Android远程桌面助手之系统兼容篇

    Android远程桌面助手理论上兼容Android4.4至Android8.1之间所有的原生安卓系统,其他第三方ROM,如MIUI.Flyme.EMUI和Smartisan OS等也都陆续测试过,目前 ...

  7. ARDC Android 远程桌面助手 录屏 演示 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  8. adb(Android Debug Bridge)(一)

    上一篇介绍的am,pm命令都是基于adb shell下的命令.这节来详细介绍下adb命令. Android Debug Bridge(adb)是一个让你跟模拟器或者android设备通信的多功能命令. ...

  9. 转:Android 调试桥(adb)是多种用途的工具

    转自:http://my.oschina.net/xuwa/blog/1574 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态. 可以通过下列几种方法加入 ...

随机推荐

  1. Python解析Socket数据流异常bytes问题

    Python解析Socket数据流异常bytes问题 -- 2019-03-12 python在通过socket发送数据时,英文字符转义后为原来本身的字符,占一个字节(如:s转移后为s),而中文字符在 ...

  2. CSU 1364 Interview RMQ

    题意: 瑶瑶有一家有一家公司,最近他想招m个人.因为他的公司是如此的出名,所以有n个人来参加面试.然而,瑶瑶是如此忙,以至于没有时间来亲自面试他们.所以他准备选择m场面试来测试他们. 瑶瑶决定这样来安 ...

  3. Oracle运行set autotrace on报错SP2-0618、SP2-0611

    SQL> set autotrace on SP2-0618: 无法找到会话标识符.启用检查 PLUSTRACE 角色 SP2-0611: 启用 STATISTICS 报告时出错 原因: PLU ...

  4. [Poi] Build and Analyze Your JavaScript Bundles with Poi

    Ever wonder where those extra KB in your bundle are coming from? This lesson walks you through runni ...

  5. Iocomp控件之数字显示【图文】

    Iocomp关于数字显示有自己的一套方案.并且效果非常棒哦 效果图: 插入控件: 默认效果: 随意改动属性后: 加入变量 调用函数: ); 效果图:

  6. IDEA中如何设置自动导包

    IDEA跟eclipse还是有一些差别,一些东西要自己去设置,但同时也还是有快捷键的方式来帮助我们 1.如何设置自动导包:如下图所示 点击FIle--->settings 其次还可以通过按快捷键 ...

  7. ajax --- 解决ajax跨域请求导致session失效的问题

    起因:http是无状态的,因此我们通常需要用到cookie以及session来保存状态,session是在服务器端存储的,会和cookie一起使用,设置了session之后,会发送给浏览器一个cook ...

  8. Ftp的上传和下载

    百度知道的那个在“ 绑定和SSL设置”模块,选择的是允许 如果一直找不到网页的话,就是这里错了:反正就是牵扯到一堆防火墙的设置(最后我也没搞成) 选择成无就OK了:一切迎刃而解............ ...

  9. boost::asio与ACE的对比

    http://blog.163.com/miky_sun/blog/static/3369405201041753652505/

  10. codeforces 543 C Remembering Strings

    题意:若一个字符串集合里的每一个字符串都至少有一个字符满足在i位上,仅仅有它有,那么这个就是合法的,给出全部串的每一个字符修改的花费,求变成合法的最小代价. 做法:dp[i][j].前i个串的状态为j ...