Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / Python实现的基于ADB的Android远程工具

Python实现的基于ADB的Android远程工具,本工具为原创,涉及知识:- Python编程
- Tkinter GUI编程
- ADB通信机制代码全文:#!/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 -keypadimport subprocess,os
import threading
import socket,sys
import timetry:
    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 " % (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 " " in dev_info:
                    dev_sn = dev_info[0:dev_info.index(" ")]
                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
                  &nbs