zoukankan      html  css  js  c++  java
  • Python实现的基于ADB的Android远程工具

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

    - 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
    ' % (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 ' %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()


  • 相关阅读:
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 695 岛屿的最大面积(DFS)
    Java实现 LeetCode 695 岛屿的最大面积(DFS)
    PHP serialize() 函数
    PHP print_r() 函数
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6978611.html
Copyright © 2011-2022 走看看