├── .gitignore ├── README.md ├── auto_bot.py ├── common ├── KeyCode.py ├── __init__.py ├── colormatch.py ├── config.py ├── debug.py └── screenshot.py ├── config └── config.json ├── example.py ├── requirements.txt └── test.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyMacro 2 | 3 | Python版模拟按键精灵库,无需ROOT 4 | 5 | 功能包括:**模拟按键、模拟屏幕触摸、模拟文字输入、获取指定位置屏幕颜色、指定区域查找相似颜色等** 6 | 7 | ## 原理 8 | 手机连接电脑,并开启USB调试模式,使用ADB工具获取屏幕截图,分析并模拟各种操作。(需要自己写代码) 9 | 10 | ## 运行环境要求 11 | 12 | 1. Android4.4+ 13 | 2. Python 3 14 | 3. [ADB](https://developer.android.com/studio/releases/platform-tools.html)驱动([下载](https://adb.clockworkmod.com/)) 15 | 4. Python 依赖库 16 | 17 | pip install -r requirements.txt 18 | 19 | 20 | ## 示例 21 | 新建python文件,导入 auto_bot 22 | 23 | import auto_bot 24 | 25 | 26 | # 模拟按键 27 | auto_bot.key(KeyCode.KEYCODE_HOME.value) 28 | 29 | # 模拟文字输入 30 | auto_bot.text("&*test#@? 'c") 31 | 32 | # 模拟点击 33 | auto_bot.tap(887, 1664) 34 | 35 | # 模拟滑动 36 | auto_bot.swipe_time(887, 1664, 200, 1664, 200) 37 | 38 | 其他操作参考:[example.py](https://github.com/Using1174/PyMacro/blob/master/example.py) -------------------------------------------------------------------------------- /auto_bot.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | 通过 adb shell 操作,截取手机屏幕,并根据界面模拟点击。 5 | 可以无需Root权限,实现按键精灵/触摸精灵/触动精灵等的脚本效果。 6 | """ 7 | from __future__ import print_function, division 8 | import os 9 | import time 10 | from PIL import Image 11 | import traceback 12 | 13 | try: 14 | from common import debug, config, screenshot, colormatch 15 | except Exception as ex: 16 | traceback.print_exc() 17 | print('请将脚本放在项目根目录中运行') 18 | print('请检查项目根目录中的 common 文件夹是否存在') 19 | exit(-1) 20 | 21 | VERSION = "1.0.0" 22 | 23 | # DEBUG 开关,需要调试的时候请改为 True,不需要调试的时候为 False 24 | DEBUG_SWITCH = False 25 | 26 | # 读取配置文件 27 | config = config.get_dic() 28 | 29 | screen_height = config['screen_height'] 30 | screen_width = config['screen_width'] 31 | img_path = config['img_path'] 32 | # 是否使用缓存图片,False 每次都更新截取新的图 33 | keep_capture = False 34 | # 缓存的图片 35 | im = None 36 | # 缓存的图片像素 37 | im_pixels = None 38 | 39 | 40 | def keep_cap(): 41 | global keep_capture 42 | keep_capture = True 43 | 44 | 45 | def release_cap(): 46 | global keep_capture 47 | keep_capture = False 48 | 49 | 50 | def _pull_screenshot(): 51 | if not keep_capture: 52 | screenshot.check_screenshot(img_path) 53 | 54 | 55 | def update_img(): 56 | _pull_screenshot() 57 | global im, im_pixels 58 | im = Image.open(img_path) 59 | im_pixels = im.load() 60 | if DEBUG_SWITCH: 61 | ts = int(time.time()) 62 | debug.save_debug_screenshot(ts, im, screen_width, screen_height) 63 | debug.backup_screenshot(ts) 64 | 65 | 66 | # 返回 tuple: (r,g,b,a) 67 | def get_pixels(x, y): 68 | return colormatch.get_pixels(im_pixels, x, y) 69 | 70 | 71 | def find_color(hex_val, same_rate): 72 | return colormatch.find_color(im, im_pixels, hex_val, same_rate) 73 | 74 | 75 | def find_color_hsv(hex_val, same_rate): 76 | return colormatch.find_color_hsv(im, im_pixels, hex_val, same_rate) 77 | 78 | 79 | def find_color_area(x1, y1, x2, y2, hex_val, same_rate): 80 | return colormatch.find_color_area(im_pixels, x1, y1, x2, y2, hex_val, False, same_rate) 81 | 82 | 83 | # 多点比色 84 | # match_list [(x,y,(r,g,b))] 85 | def multi_color_match(match_list, same_rate): 86 | return colormatch.multi_color_match(im_pixels, match_list, same_rate) 87 | 88 | 89 | # 模拟滑动,默认持续时间 90 | def swipe(x1, y1, x2, y2): 91 | swipe_time(x1, y1, x2, y2, 1) 92 | 93 | 94 | # 模拟滑动,并指定持续时间 95 | def swipe_time(x1, y1, x2, y2, press_time): 96 | cmd = 'adb shell input swipe {x1} {y1} {x2} {y2} {duration}'.format( 97 | x1=x1, 98 | y1=y1, 99 | x2=x2, 100 | y2=y2, 101 | duration=press_time 102 | ) 103 | adb_shell(cmd) 104 | 105 | 106 | # 模拟轻触 107 | def tap(x, y): 108 | cmd = 'adb shell input tap {} {}'.format(x, y) 109 | adb_shell(cmd) 110 | 111 | 112 | # 按键事件 113 | # Key Code ref: https://developer.android.com/reference/android/view/KeyEvent.html 114 | def key(key_code): 115 | cmd = 'adb shell input keyevent {}'.format(key_code) 116 | adb_shell(cmd) 117 | 118 | 119 | # 模拟输入文本, 不支持双引号"和unicode字符 120 | # 若机器安装了ADB输入法:https://github.com/senzhk/ADBKeyBoard,则可使用unicode字符 121 | def text(text): 122 | cmd = 'adb shell input text "{}"'.format(text) 123 | adb_shell(cmd) 124 | 125 | 126 | # 模拟原理是对驱动发送消息,就是linux里面的input子系统。 127 | # 命令格式: sendevent /dev/input/eventX [type] [key] [value] 128 | # 其中/dev/input/eventX 对应的是设备,可以用getevent查看可用设备。 129 | # ref: http://www.cnblogs.com/AsionTang/p/6211895.html 130 | def send_event(idx, type, key, value): 131 | cmd = 'adb shell sendevent /dev/input/event{idx} {type} {key} {value}'.format( 132 | idx=idx, 133 | type=type, 134 | key=key, 135 | value=value 136 | ) 137 | adb_shell(cmd) 138 | 139 | 140 | def adb_shell(cmd): 141 | print(cmd) 142 | os.system(cmd) 143 | 144 | 145 | def init(): 146 | print('Bot Version:{}'.format(VERSION)) 147 | debug.dump_device_info() 148 | screenshot.check_screenshot(img_path) 149 | global im, im_pixels 150 | im = Image.open(img_path) 151 | im_pixels = im.load() 152 | -------------------------------------------------------------------------------- /common/KeyCode.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, IntEnum, unique 2 | 3 | try: 4 | @unique 5 | class KeyCode(Enum): 6 | # ACTION_DOWN = 0 # the key has been pressed down. 7 | # ACTION_UP = 1 # the key has been released. 8 | # ACTION_MULTIPLE = 2 # 9 | # FLAG_KEEP_TOUCH_MODE = 4 # This mask is set if we don't want the key event to cause us to leave touch mode. 10 | # FLAG_FROM_SYSTEM = 8 # 11 | # FLAG_EDITOR_ACTION = 16 # 12 | # FLAG_CANCELED = 32 # 13 | # FLAG_VIRTUAL_HARD_KEY = 64 # 14 | # FLAG_LONG_PRESS = 128 # This flag is set for the first key repeat that occurs after the long press timeout. 15 | # FLAG_CANCELED_LONG_PRESS = 256 # 16 | # FLAG_TRACKING = 512 # 17 | # FLAG_FALLBACK = 1024 # 18 | 19 | # FLAG_WOKE_HERE = 1 # 20 | # FLAG_SOFT_KEYBOARD = 2 # This mask is set if the key event was generated by a software keyboard. 21 | 22 | KEYCODE_0 = 7 # '0' key. 23 | KEYCODE_1 = 8 # '1' key. 24 | KEYCODE_11 = 227 # '11' key. 25 | KEYCODE_12 = 228 # '12' key. 26 | KEYCODE_2 = 9 # '2' key. 27 | KEYCODE_3 = 10 # '3' key. 28 | KEYCODE_3D_MODE = 206 # 3D Mode key. 29 | KEYCODE_4 = 11 # '4' key. 30 | KEYCODE_5 = 12 # '5' key. 31 | KEYCODE_6 = 13 # '6' key. 32 | KEYCODE_7 = 14 # '7' key. 33 | KEYCODE_8 = 15 # '8' key. 34 | KEYCODE_9 = 16 # '9' key. 35 | KEYCODE_A = 29 # 'A' key. 36 | KEYCODE_ALT_LEFT = 57 # Left Alt modifier key. 37 | KEYCODE_ALT_RIGHT = 58 # Right Alt modifier key. 38 | KEYCODE_APOSTROPHE = 75 # ''' (apostrophe) key. 39 | KEYCODE_APP_SWITCH = 187 # App switch key. 40 | KEYCODE_ASSIST = 219 # Assist key. 41 | KEYCODE_AT = 77 # '@' key. 42 | KEYCODE_AVR_INPUT = 182 # A/V Receiver input key. 43 | KEYCODE_AVR_POWER = 181 # A/V Receiver power key. 44 | KEYCODE_B = 30 # 'B' key. 45 | KEYCODE_BACK = 4 # Back key. 46 | KEYCODE_BACKSLASH = 73 # '\' key. 47 | KEYCODE_BOOKMARK = 174 # Bookmark key. 48 | KEYCODE_BREAK = 121 # Break / Pause key. 49 | KEYCODE_BRIGHTNESS_DOWN = 220 # Brightness Down key. 50 | KEYCODE_BRIGHTNESS_UP = 221 # Brightness Up key. 51 | KEYCODE_BUTTON_1 = 188 # Generic Game Pad Button #1. 52 | KEYCODE_BUTTON_10 = 197 # Generic Game Pad Button #10. 53 | KEYCODE_BUTTON_11 = 198 # Generic Game Pad Button #11. 54 | KEYCODE_BUTTON_12 = 199 # Generic Game Pad Button #12. 55 | KEYCODE_BUTTON_13 = 200 # Generic Game Pad Button #13. 56 | KEYCODE_BUTTON_14 = 201 # Generic Game Pad Button #14. 57 | KEYCODE_BUTTON_15 = 202 # Generic Game Pad Button #15. 58 | KEYCODE_BUTTON_16 = 203 # Generic Game Pad Button #16. 59 | KEYCODE_BUTTON_2 = 189 # Generic Game Pad Button #2. 60 | KEYCODE_BUTTON_3 = 190 # Generic Game Pad Button #3. 61 | KEYCODE_BUTTON_4 = 191 # Generic Game Pad Button #4. 62 | KEYCODE_BUTTON_5 = 192 # Generic Game Pad Button #5. 63 | KEYCODE_BUTTON_6 = 193 # Generic Game Pad Button #6. 64 | KEYCODE_BUTTON_7 = 194 # Generic Game Pad Button #7. 65 | KEYCODE_BUTTON_8 = 195 # Generic Game Pad Button #8. 66 | KEYCODE_BUTTON_9 = 196 # Generic Game Pad Button #9. 67 | KEYCODE_BUTTON_A = 96 # A Button key. 68 | KEYCODE_BUTTON_B = 97 # B Button key. 69 | KEYCODE_BUTTON_C = 98 # C Button key. 70 | KEYCODE_BUTTON_L1 = 102 # L1 Button key. 71 | KEYCODE_BUTTON_L2 = 104 # L2 Button key. 72 | KEYCODE_BUTTON_MODE = 110 # Mode Button key. 73 | KEYCODE_BUTTON_R1 = 103 # R1 Button key. 74 | KEYCODE_BUTTON_R2 = 105 # R2 Button key. 75 | KEYCODE_BUTTON_SELECT = 109 # Select Button key. 76 | KEYCODE_BUTTON_START = 108 # Start Button key. 77 | KEYCODE_BUTTON_THUMBL = 106 # Left Thumb Button key. 78 | KEYCODE_BUTTON_THUMBR = 107 # Right Thumb Button key. 79 | KEYCODE_BUTTON_X = 99 # X Button key. 80 | KEYCODE_BUTTON_Y = 100 # Y Button key. 81 | KEYCODE_BUTTON_Z = 101 # Z Button key. 82 | KEYCODE_C = 31 # 'C' key. 83 | KEYCODE_CALCULATOR = 210 # Calculator special function key. 84 | KEYCODE_CALENDAR = 208 # Calendar special function key. 85 | KEYCODE_CALL = 5 # Call key. 86 | KEYCODE_CAMERA = 27 # Camera key. 87 | KEYCODE_CAPS_LOCK = 115 # Caps Lock key. 88 | KEYCODE_CAPTIONS = 175 # Toggle captions key. 89 | KEYCODE_CHANNEL_DOWN = 167 # Channel down key. 90 | KEYCODE_CHANNEL_UP = 166 # Channel up key. 91 | KEYCODE_CLEAR = 28 # Clear key. 92 | KEYCODE_COMMA = 55 # ',' key. 93 | KEYCODE_CONTACTS = 207 # Contacts special function key. 94 | KEYCODE_COPY = 278 # Copy key. 95 | KEYCODE_CTRL_LEFT = 113 # Left Control modifier key. 96 | KEYCODE_CTRL_RIGHT = 114 # Right Control modifier key. 97 | KEYCODE_CUT = 277 # Cut key. 98 | KEYCODE_D = 32 # 'D' key. 99 | KEYCODE_DEL = 67 # Backspace key. 100 | KEYCODE_DPAD_CENTER = 23 # Directional Pad Center key. 101 | KEYCODE_DPAD_DOWN = 20 # Directional Pad Down key. 102 | KEYCODE_DPAD_DOWN_LEFT = 269 # Directional Pad Down-Left 103 | KEYCODE_DPAD_DOWN_RIGHT = 271 # Directional Pad Down-Right 104 | KEYCODE_DPAD_LEFT = 21 # Directional Pad Left key. 105 | KEYCODE_DPAD_RIGHT = 22 # Directional Pad Right key. 106 | KEYCODE_DPAD_UP = 19 # Directional Pad Up key. 107 | KEYCODE_DPAD_UP_LEFT = 268 # Directional Pad Up-Left 108 | KEYCODE_DPAD_UP_RIGHT = 270 # Directional Pad Up-Right 109 | KEYCODE_DVR = 173 # DVR key. 110 | KEYCODE_E = 33 # 'E' key. 111 | KEYCODE_EISU = 212 # Japanese alphanumeric key. 112 | KEYCODE_ENDCALL = 6 # End Call key. 113 | KEYCODE_ENTER = 66 # Enter key. 114 | KEYCODE_ENVELOPE = 65 # Envelope special function key. 115 | KEYCODE_EQUALS = 70 # '=' key. 116 | KEYCODE_ESCAPE = 111 # Escape key. 117 | KEYCODE_EXPLORER = 64 # Explorer special function key. 118 | KEYCODE_F = 34 # 'F' key. 119 | KEYCODE_F1 = 131 # F1 key. 120 | KEYCODE_F10 = 140 # F10 key. 121 | KEYCODE_F11 = 141 # F11 key. 122 | KEYCODE_F12 = 142 # F12 key. 123 | KEYCODE_F2 = 132 # F2 key. 124 | KEYCODE_F3 = 133 # F3 key. 125 | KEYCODE_F4 = 134 # F4 key. 126 | KEYCODE_F5 = 135 # F5 key. 127 | KEYCODE_F6 = 136 # F6 key. 128 | KEYCODE_F7 = 137 # F7 key. 129 | KEYCODE_F8 = 138 # F8 key. 130 | KEYCODE_F9 = 139 # F9 key. 131 | KEYCODE_FOCUS = 80 # Camera Focus key. 132 | KEYCODE_FORWARD = 125 # Forward key. 133 | KEYCODE_FORWARD_DEL = 112 # Forward Delete key. 134 | KEYCODE_FUNCTION = 119 # Function modifier key. 135 | KEYCODE_G = 35 # 'G' key. 136 | KEYCODE_GRAVE = 68 # '`' (backtick) key. 137 | KEYCODE_GUIDE = 172 # Guide key. 138 | KEYCODE_H = 36 # 'H' key. 139 | KEYCODE_HEADSETHOOK = 79 # Headset Hook key. 140 | KEYCODE_HELP = 259 # Help key. 141 | KEYCODE_HENKAN = 214 # Japanese conversion key. 142 | KEYCODE_HOME = 3 # Home key. 143 | KEYCODE_I = 37 # 'I' key. 144 | KEYCODE_INFO = 165 # Info key. 145 | KEYCODE_INSERT = 124 # Insert key. 146 | KEYCODE_J = 38 # 'J' key. 147 | KEYCODE_K = 39 # 'K' key. 148 | KEYCODE_KANA = 218 # Japanese kana key. 149 | KEYCODE_KATAKANA_HIRAGANA = 215 # Japanese katakana / hiragana key. 150 | KEYCODE_L = 40 # 'L' key. 151 | KEYCODE_LANGUAGE_SWITCH = 204 # Language Switch key. 152 | KEYCODE_LAST_CHANNEL = 229 # Last Channel key. 153 | KEYCODE_LEFT_BRACKET = 71 # '[' key. 154 | KEYCODE_M = 41 # 'M' key. 155 | KEYCODE_MANNER_MODE = 205 # Manner Mode key. 156 | KEYCODE_MEDIA_AUDIO_TRACK = 222 # Audio Track key. 157 | KEYCODE_MEDIA_CLOSE = 128 # Close media key. 158 | KEYCODE_MEDIA_EJECT = 129 # Eject media key. 159 | KEYCODE_MEDIA_FAST_FORWARD = 90 # Fast Forward media key. 160 | KEYCODE_MEDIA_NEXT = 87 # Play Next media key. 161 | KEYCODE_MEDIA_PAUSE = 127 # Pause media key. 162 | KEYCODE_MEDIA_PLAY = 126 # Play media key. 163 | KEYCODE_MEDIA_PLAY_PAUSE = 85 # Play/Pause media key. 164 | KEYCODE_MEDIA_PREVIOUS = 88 # Play Previous media key. 165 | KEYCODE_MEDIA_RECORD = 130 # Record media key. 166 | KEYCODE_MEDIA_REWIND = 89 # Rewind media key. 167 | KEYCODE_MEDIA_SKIP_BACKWARD = 273 # Skip backward media key. 168 | KEYCODE_MEDIA_SKIP_FORWARD = 272 # Skip forward media key. 169 | KEYCODE_MEDIA_STEP_BACKWARD = 275 # Step backward media key. 170 | KEYCODE_MEDIA_STEP_FORWARD = 274 # Step forward media key. 171 | KEYCODE_MEDIA_STOP = 86 # Stop media key. 172 | KEYCODE_MEDIA_TOP_MENU = 226 # Media Top Menu key. 173 | KEYCODE_MENU = 82 # Menu key. 174 | KEYCODE_META_LEFT = 117 # Left Meta modifier key. 175 | KEYCODE_META_RIGHT = 118 # Right Meta modifier key. 176 | KEYCODE_MINUS = 69 # '-'. 177 | KEYCODE_MOVE_END = 123 # End Movement key. 178 | KEYCODE_MOVE_HOME = 122 # Home Movement key. 179 | KEYCODE_MUHENKAN = 213 # Japanese non-conversion key. 180 | KEYCODE_MUSIC = 209 # Music special function key. 181 | KEYCODE_MUTE = 91 # Mute key. 182 | KEYCODE_N = 42 # 'N' key. 183 | KEYCODE_NAVIGATE_IN = 262 # Navigate in key. 184 | KEYCODE_NAVIGATE_NEXT = 261 # Navigate to next key. 185 | KEYCODE_NAVIGATE_OUT = 263 # Navigate out key. 186 | KEYCODE_NAVIGATE_PREVIOUS = 260 # Navigate to previous key. 187 | KEYCODE_NOTIFICATION = 83 # Notification key. 188 | KEYCODE_NUM = 78 # Number modifier key. 189 | KEYCODE_NUMPAD_0 = 144 # Numeric keypad '0' key. 190 | KEYCODE_NUMPAD_1 = 145 # Numeric keypad '1' key. 191 | KEYCODE_NUMPAD_2 = 146 # Numeric keypad '2' key. 192 | KEYCODE_NUMPAD_3 = 147 # Numeric keypad '3' key. 193 | KEYCODE_NUMPAD_4 = 148 # Numeric keypad '4' key. 194 | KEYCODE_NUMPAD_5 = 149 # Numeric keypad '5' key. 195 | KEYCODE_NUMPAD_6 = 150 # Numeric keypad '6' key. 196 | KEYCODE_NUMPAD_7 = 151 # Numeric keypad '7' key. 197 | KEYCODE_NUMPAD_8 = 152 # Numeric keypad '8' key. 198 | KEYCODE_NUMPAD_9 = 153 # Numeric keypad '9' key. 199 | KEYCODE_NUMPAD_ADD = 157 # Numeric keypad '+' key (for addition). 200 | KEYCODE_NUMPAD_COMMA = 159 # Numeric keypad ',' key (for decimals or digit grouping). 201 | KEYCODE_NUMPAD_DIVIDE = 154 # Numeric keypad '/' key (for division). 202 | KEYCODE_NUMPAD_DOT = 158 # Numeric keypad '.' key (for decimals or digit grouping). 203 | KEYCODE_NUMPAD_ENTER = 160 # Numeric keypad Enter key. 204 | KEYCODE_NUMPAD_EQUALS = 161 # Numeric keypad '=' key. 205 | KEYCODE_NUMPAD_LEFT_PAREN = 162 # Numeric keypad '(' key. 206 | KEYCODE_NUMPAD_MULTIPLY = 155 # Numeric keypad '*' key (for multiplication). 207 | KEYCODE_NUMPAD_RIGHT_PAREN = 163 # Numeric keypad ')' key. 208 | KEYCODE_NUMPAD_SUBTRACT = 156 # Numeric keypad '-' key (for subtraction). 209 | KEYCODE_NUM_LOCK = 143 # Num Lock key. 210 | KEYCODE_O = 43 # 'O' key. 211 | KEYCODE_P = 44 # 'P' key. 212 | KEYCODE_PAGE_DOWN = 93 # Page Down key. 213 | KEYCODE_PAGE_UP = 92 # Page Up key. 214 | KEYCODE_PAIRING = 225 # Pairing key. 215 | KEYCODE_PASTE = 279 # Paste key. 216 | KEYCODE_PERIOD = 56 # '.' key. 217 | KEYCODE_PICTSYMBOLS = 94 # Picture Symbols modifier key. 218 | KEYCODE_PLUS = 81 # '+' key. 219 | KEYCODE_POUND = 18 # '#' key. 220 | KEYCODE_POWER = 26 # Power key. 221 | KEYCODE_PROG_BLUE = 186 # Blue "programmable" key. 222 | KEYCODE_PROG_GREEN = 184 # Green "programmable" key. 223 | KEYCODE_PROG_RED = 183 # Red "programmable" key. 224 | KEYCODE_PROG_YELLOW = 185 # Yellow "programmable" key. 225 | KEYCODE_Q = 45 # 'Q' key. 226 | KEYCODE_R = 46 # 'R' key. 227 | KEYCODE_RIGHT_BRACKET = 72 # ']' key. 228 | KEYCODE_RO = 217 # Japanese Ro key. 229 | KEYCODE_S = 47 # 'S' key. 230 | KEYCODE_SCROLL_LOCK = 116 # Scroll Lock key. 231 | KEYCODE_SEARCH = 84 # Search key. 232 | KEYCODE_SEMICOLON = 74 # ';' key. 233 | KEYCODE_SETTINGS = 176 # Settings key. 234 | KEYCODE_SHIFT_LEFT = 59 # Left Shift modifier key. 235 | KEYCODE_SHIFT_RIGHT = 60 # Right Shift modifier key. 236 | KEYCODE_SLASH = 76 # '/' key. 237 | KEYCODE_SLEEP = 223 # Sleep key. 238 | KEYCODE_SOFT_LEFT = 1 # Soft Left key. 239 | KEYCODE_SOFT_RIGHT = 2 # Soft Right key. 240 | KEYCODE_SOFT_SLEEP = 276 # put device to sleep unless a wakelock is held. 241 | KEYCODE_SPACE = 62 # Space key. 242 | KEYCODE_STAR = 17 # '*' key. 243 | KEYCODE_STB_INPUT = 180 # Set-top-box input key. 244 | KEYCODE_STB_POWER = 179 # Set-top-box power key. 245 | KEYCODE_STEM_1 = 265 # Generic stem key 1 for Wear 246 | KEYCODE_STEM_2 = 266 # Generic stem key 2 for Wear 247 | KEYCODE_STEM_3 = 267 # Generic stem key 3 for Wear 248 | KEYCODE_STEM_PRIMARY = 264 # Primary stem key for Wear 249 | KEYCODE_SWITCH_CHARSET = 95 # Switch Charset modifier key. 250 | KEYCODE_SYM = 63 # Symbol modifier key. 251 | KEYCODE_SYSRQ = 120 # System Request / Print Screen key. 252 | KEYCODE_SYSTEM_NAVIGATION_DOWN = 281 # Consumed by the system for navigation down 253 | KEYCODE_SYSTEM_NAVIGATION_LEFT = 282 # Consumed by the system for navigation left 254 | KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283 # Consumed by the system for navigation right 255 | KEYCODE_SYSTEM_NAVIGATION_UP = 280 # Consumed by the system for navigation up 256 | KEYCODE_T = 48 # 'T' key. 257 | KEYCODE_TAB = 61 # Tab key. 258 | KEYCODE_TV = 170 # TV key. 259 | KEYCODE_TV_ANTENNA_CABLE = 242 # Antenna/Cable key. 260 | KEYCODE_TV_AUDIO_DESCRIPTION = 252 # Audio description key. 261 | KEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254 # Audio description mixing volume down key. 262 | KEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253 # Audio description mixing volume up key. 263 | KEYCODE_TV_CONTENTS_MENU = 256 # Contents menu key. 264 | KEYCODE_TV_DATA_SERVICE = 230 # TV data service key. 265 | KEYCODE_TV_INPUT = 178 # TV input key. 266 | KEYCODE_TV_INPUT_COMPONENT_1 = 249 # Component #1 key. 267 | KEYCODE_TV_INPUT_COMPONENT_2 = 250 # Component #2 key. 268 | KEYCODE_TV_INPUT_COMPOSITE_1 = 247 # Composite #1 key. 269 | KEYCODE_TV_INPUT_COMPOSITE_2 = 248 # Composite #2 key. 270 | KEYCODE_TV_INPUT_HDMI_1 = 243 # HDMI #1 key. 271 | KEYCODE_TV_INPUT_HDMI_2 = 244 # HDMI #2 key. 272 | KEYCODE_TV_INPUT_HDMI_3 = 245 # HDMI #3 key. 273 | KEYCODE_TV_INPUT_HDMI_4 = 246 # HDMI #4 key. 274 | KEYCODE_TV_INPUT_VGA_1 = 251 # VGA #1 key. 275 | KEYCODE_TV_MEDIA_CONTEXT_MENU = 257 # Media context menu key. 276 | KEYCODE_TV_NETWORK = 241 # Toggle Network key. 277 | KEYCODE_TV_NUMBER_ENTRY = 234 # Number entry key. 278 | KEYCODE_TV_POWER = 177 # TV power key. 279 | KEYCODE_TV_RADIO_SERVICE = 232 # Radio key. 280 | KEYCODE_TV_SATELLITE = 237 # Satellite key. 281 | KEYCODE_TV_SATELLITE_BS = 238 # BS key. 282 | KEYCODE_TV_SATELLITE_CS = 239 # CS key. 283 | KEYCODE_TV_SATELLITE_SERVICE = 240 # BS/CS key. 284 | KEYCODE_TV_TELETEXT = 233 # Teletext key. 285 | KEYCODE_TV_TERRESTRIAL_ANALOG = 235 # Analog Terrestrial key. 286 | KEYCODE_TV_TERRESTRIAL_DIGITAL = 236 # Digital Terrestrial key. 287 | KEYCODE_TV_TIMER_PROGRAMMING = 258 # Timer programming key. 288 | KEYCODE_TV_ZOOM_MODE = 255 # Zoom mode key. 289 | KEYCODE_U = 49 # 'U' key. 290 | KEYCODE_UNKNOWN = 0 # Unknown key code. 291 | KEYCODE_V = 50 # 'V' key. 292 | KEYCODE_VOICE_ASSIST = 231 # Voice Assist key. 293 | KEYCODE_VOLUME_DOWN = 25 # Volume Down key. 294 | KEYCODE_VOLUME_MUTE = 164 # Volume Mute key. 295 | KEYCODE_VOLUME_UP = 24 # Volume Up key. 296 | KEYCODE_W = 51 # 'W' key. 297 | KEYCODE_WAKEUP = 224 # Wakeup key. 298 | KEYCODE_WINDOW = 171 # Window key. 299 | KEYCODE_X = 52 # 'X' key. 300 | KEYCODE_Y = 53 # 'Y' key. 301 | KEYCODE_YEN = 216 # Japanese Yen key. 302 | KEYCODE_Z = 54 # 'Z' key. 303 | KEYCODE_ZENKAKU_HANKAKU = 211 # Japanese full-width / half-width key. 304 | KEYCODE_ZOOM_IN = 168 # Zoom in key. 305 | KEYCODE_ZOOM_OUT = 169 # Zoom out key. 306 | 307 | 308 | except ValueError as e: 309 | print(e) 310 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /common/colormatch.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import struct 3 | import colorsys 4 | import math 5 | 6 | 7 | # 返回 tuple: (r,g,b,a) 8 | def get_pixels(pixels, x, y): 9 | return pixels[x, y] 10 | 11 | 12 | # 使用RGB色彩全屏找色, 接收字符 #FFFFFF, 返回查找的结果x,y 13 | # 若x==-1 && y==-1, 表示找不到 14 | def find_color(im, pixels, hex_val, same_rate): 15 | w, h = im.size 16 | return find_color_area(pixels, 0, 0, w, h, hex_val, False, same_rate) 17 | 18 | 19 | # 使用HSV色彩全屏找色, 接收字符 #FFFFFF, 返回查找的结果x,y 20 | # 若x==-1 && y==-1, 表示找不到 21 | def find_color_hsv(im, pixels, hex_val, same_rate): 22 | w, h = im.size 23 | return find_color_area(pixels, 0, 0, w, h, hex_val, True, same_rate) 24 | 25 | 26 | # 在指定范围内查找 27 | # 若x==-1&&y==-1,表示找不到 28 | # same_rate 颜色相似率(0-1) 29 | def find_color_area(pixels, x1, y1, x2, y2, hex_val, use_hsv, same_rate): 30 | hex_str = hex_val[1:] 31 | # rgb (0-255) 32 | rgb = hex2rgb(hex_str) 33 | 34 | if use_hsv: 35 | for i in range(x1, x2): 36 | for j in range(y1, y2): 37 | pixel = pixels[i, j] 38 | if match_color_hsv(rgb, pixel, same_rate): 39 | return (i, j) 40 | else: 41 | for i in range(x1, x2): 42 | for j in range(y1, y2): 43 | pixel = pixels[i, j] 44 | if match_color(rgb, pixel, same_rate): 45 | return (i, j) 46 | 47 | return (-1, -1) 48 | 49 | 50 | # same_rate为颜色的相似程度 51 | def match_color_hsv(rgb1, rgb2, same_rate): 52 | # hsv h:0-1, s:0-1, v:0-1 53 | hsv1 = colorsys.rgb_to_hsv(rgb1[0] / 255, rgb1[1] / 255, rgb1[2] / 255) 54 | hsv2 = colorsys.rgb_to_hsv(rgb2[0] / 255, rgb2[1] / 255, rgb2[2] / 255) 55 | 56 | if color_distance_hsv(hsv1, hsv2) <= 1.0 - same_rate: 57 | return True 58 | else: 59 | return False 60 | 61 | 62 | # 多点比色 63 | # match_list [(x,y,(r,g,b))] 64 | def multi_color_match(pixels, match_list, same_rate): 65 | for tp in match_list: 66 | pixel = pixels[tp[0], tp[1]] 67 | rgb = tp[2] 68 | if not (match_color(rgb, pixel) <= 1.0 - same_rate): 69 | return False 70 | # 所有点都满足条件 71 | return True 72 | 73 | 74 | def match_color(rgb1, rgb2, same_rate): 75 | if color_distance_rgb(rgb1, rgb2) <= 1.0 - same_rate: 76 | return True 77 | else: 78 | return False 79 | 80 | 81 | # RGB色彩空间,计算差值在0.1 以内时,基本可以判定为相似颜色 82 | # 值越小,说明颜色越相近(0.0-1.0) 83 | def color_distance_rgb(rgb1, rgb2): 84 | tp = tuple(((a - b) / 255) ** 2 for a, b in zip(rgb1, rgb2)) 85 | return math.sqrt(sum(tp)) 86 | 87 | 88 | # HSV色彩空间,计算差值在0.1 以内时,基本可以判定为相似颜色 89 | # 值越小,说明颜色越相近(0.0-1.0) 90 | def color_distance_hsv(hsv1, hsv2): 91 | # 灰度值是个循环,需取最小值判定 92 | h_dis = min((hsv1[0] - hsv2[0]) ** 2, (hsv1[0] + hsv2[0] - 1.0) ** 2) 93 | s_dis = (hsv1[1] - hsv2[1]) ** 2 94 | v_dis = (hsv1[2] - hsv2[2]) ** 2 95 | 96 | return math.sqrt(h_dis + v_dis + s_dis) 97 | 98 | 99 | # RGB元素范围(0-255) 100 | def hex2rgb(hex_str): 101 | int_tuple = struct.unpack('BBB', bytes.fromhex(hex_str)) 102 | return tuple([val for val in int_tuple]) 103 | 104 | 105 | # RGB元素范围(0-1) 106 | def hex_to_rgb(hex_str): 107 | int_tuple = struct.unpack('BBB', bytes.fromhex(hex_str)) 108 | return tuple([val / 255 for val in int_tuple]) 109 | 110 | 111 | def rgb_to_hex(rgb): 112 | return '#%02x%02x%02x' % rgb 113 | -------------------------------------------------------------------------------- /common/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 调取配置文件和屏幕分辨率的代码 4 | """ 5 | import os 6 | import sys 7 | import json 8 | import re 9 | 10 | inited = False 11 | _global_dict = {} 12 | 13 | 14 | def _init(): 15 | """ 16 | 调用配置文件 17 | """ 18 | global _global_dict 19 | # screen_size = get_screen_size() 20 | config_file = "{path}/config/config.json".format( 21 | path=sys.path[0] 22 | ) 23 | if os.path.exists(config_file): 24 | with open(config_file, 'r') as f: 25 | print("Load config file from {}".format(config_file)) 26 | _global_dict = json.load(f) 27 | global inited 28 | inited = True 29 | return _global_dict 30 | else: 31 | print("Load default config fail") 32 | return _global_dict 33 | 34 | 35 | def get_dic(): 36 | global inited 37 | if inited: 38 | return _global_dict 39 | else: 40 | return _init() 41 | 42 | 43 | def get_screen_size(): 44 | """ 45 | 获取手机屏幕大小 46 | """ 47 | size_str = os.popen('adb shell wm size').read() 48 | if not size_str: 49 | print('请安装 ADB 及驱动并配置环境变量') 50 | sys.exit() 51 | m = re.search(r'(\d+)x(\d+)', size_str) 52 | if m: 53 | return "{height}x{width}".format(height=m.group(2), width=m.group(1)) 54 | return "1920x1080" 55 | -------------------------------------------------------------------------------- /common/debug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 这儿是debug的代码,当DEBUG_SWITCH开关开启的时候,会将各种信息存在本地,方便检查故障 4 | """ 5 | import os 6 | import sys 7 | import shutil 8 | from PIL import ImageDraw 9 | from common import config 10 | 11 | config = config.get_dic() 12 | screenshot_backup_dir = 'screenshot_backups/' 13 | img_path = config['img_path'] 14 | 15 | 16 | def make_debug_dir(screenshot_backup_dir): 17 | """ 18 | 创建备份文件夹 19 | """ 20 | if not os.path.isdir(screenshot_backup_dir): 21 | os.mkdir(screenshot_backup_dir) 22 | 23 | 24 | def backup_screenshot(ts): 25 | """ 26 | 为了方便失败的时候 debug 27 | """ 28 | make_debug_dir(screenshot_backup_dir) 29 | shutil.copy(img_path, '{}{}.png'.format(screenshot_backup_dir, ts)) 30 | 31 | 32 | def save_debug_screenshot(ts, im, screen_width, screen_height): 33 | """ 34 | 对 debug 图片加上详细的注释 35 | """ 36 | make_debug_dir(screenshot_backup_dir) 37 | draw = ImageDraw.Draw(im) 38 | # draw something in picture 39 | del draw 40 | im.save('{}{}_d.png'.format(screenshot_backup_dir, ts)) 41 | 42 | 43 | def dump_device_info(): 44 | """ 45 | 显示设备信息 46 | """ 47 | size_str = os.popen('adb shell wm size').read() 48 | device_str = os.popen('adb shell getprop ro.product.device').read() 49 | phone_os_str = os.popen('adb shell getprop ro.build.version.release').read() 50 | density_str = os.popen('adb shell wm density').read() 51 | print("""********** 52 | Screen: {size} 53 | Density: {dpi} 54 | Device: {device} 55 | Phone OS: {phone_os} 56 | Host OS: {host_os} 57 | Python: {python} 58 | **********""".format( 59 | size=size_str.strip(), 60 | dpi=density_str.strip(), 61 | device=device_str.strip(), 62 | phone_os=phone_os_str.strip(), 63 | host_os=sys.platform, 64 | python=sys.version 65 | )) 66 | -------------------------------------------------------------------------------- /common/screenshot.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 手机屏幕截图的代码 4 | """ 5 | import subprocess 6 | import os 7 | import sys 8 | from PIL import Image 9 | 10 | # SCREENSHOT_WAY 是截图方法,经过 check_screenshot 后,会自动递减,不需手动修改 11 | SCREENSHOT_WAY = 3 12 | 13 | 14 | def pull_screenshot(img_path): 15 | """ 16 | 获取屏幕截图,目前有 0 1 2 3 四种方法,未来添加新的平台监测方法时, 17 | 可根据效率及适用性由高到低排序 18 | """ 19 | global SCREENSHOT_WAY 20 | if 1 <= SCREENSHOT_WAY <= 3: 21 | process = subprocess.Popen( 22 | 'adb shell screencap -p', 23 | shell=True, stdout=subprocess.PIPE) 24 | binary_screenshot = process.stdout.read() 25 | if SCREENSHOT_WAY == 2: 26 | binary_screenshot = binary_screenshot.replace(b'\r\n', b'\n') 27 | elif SCREENSHOT_WAY == 1: 28 | binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n') 29 | lenb = len(binary_screenshot) 30 | if lenb > 0: 31 | f = open(img_path, 'wb') 32 | f.write(binary_screenshot) 33 | f.close() 34 | else: 35 | print("error! no screenshot data!") 36 | elif SCREENSHOT_WAY == 0: 37 | screenshot_name = "screenshot.png" 38 | os.system('adb shell screencap -p /sdcard/{}'.format(screenshot_name)) 39 | os.system('adb pull /sdcard/{} {}'.format(screenshot_name, img_path)) 40 | 41 | 42 | def check_screenshot(img_path): 43 | """ 44 | 检查获取截图的方式 45 | """ 46 | global SCREENSHOT_WAY 47 | # 每次提交不删除旧的文件 48 | # if os.path.isfile(img_path): 49 | # try: 50 | # os.remove(img_path) 51 | # except Exception: 52 | # pass 53 | if SCREENSHOT_WAY < 0: 54 | print('暂不支持当前设备截屏') 55 | return 56 | # sys.exit() 57 | # upload image 58 | pull_screenshot(img_path) 59 | try: 60 | # Image.open(img_path).load() 61 | Image.open(img_path) 62 | print('采用方式 {} 获取截图:{}'.format(SCREENSHOT_WAY, img_path)) 63 | except Exception: 64 | SCREENSHOT_WAY -= 1 65 | check_screenshot(img_path) 66 | -------------------------------------------------------------------------------- /config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "screen_height": 1920, 3 | "screen_width": 1080, 4 | "img_path": "./yys_auto_bot.jpg" 5 | } 6 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import auto_bot 3 | import time 4 | import random 5 | from common.KeyCode import KeyCode 6 | 7 | 8 | def touch_example(): 9 | # 轻触 10 | auto_bot.tap(887, 1664) 11 | # 滑动 12 | auto_bot.swipe_time(887, 1664, 200, 1664, 200) 13 | auto_bot.swipe_time(543, 1536, 543, 1536, 710) 14 | 15 | 16 | def key_press_example(): 17 | # 按键模拟 18 | auto_bot.key(KeyCode.KEYCODE_HOME.value) 19 | 20 | 21 | def text_example(): 22 | # 文字输入 23 | auto_bot.text("&*test#@? 'c") 24 | 25 | 26 | def main(): 27 | ltc = time.localtime() 28 | 29 | auto_bot.init() 30 | while True: 31 | start = time.time() 32 | 33 | # 调用后台截取屏幕,更新缓存图片 34 | auto_bot.update_img() 35 | 36 | mid = time.time() 37 | print("updateimg cost: {}ms".format(mid - start)) 38 | 39 | # 屏幕颜色获取 40 | x, y = 100, 200 41 | pixel = auto_bot.get_pixels(x, y) 42 | print('screen ({},{}) color_rgba:{}'.format(x, y, pixel)) 43 | 44 | # 全屏查找相似颜色 45 | x, y = auto_bot.find_color("#FFFFFF", 0.9) 46 | print(x, y) 47 | 48 | # 指定区域查找相似颜色 49 | x, y = auto_bot.find_color_area(50, 100, 100, 200, "#FFFFFF", 0.9) 50 | print(x, y) 51 | 52 | # 按键示例 53 | key_press_example() 54 | 55 | # 屏幕点击示例 56 | touch_example() 57 | 58 | # 文字输入需激活输入框 59 | # text_example() 60 | 61 | end = time.time() 62 | print("cost time: {}ms".format(end - start)) 63 | 64 | 65 | # 暂停一会儿 66 | # time.sleep(random.uniform(3, 5)) 67 | 68 | 69 | if __name__ == '__main__': 70 | main() 71 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Pillow==8.1.1 -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import auto_bot 3 | import colorsys 4 | from common import colormatch 5 | from common import KeyCode 6 | 7 | 8 | def rgb_test(): 9 | col1 = "FF0000" 10 | col2 = "ff000f" 11 | rgb1 = colormatch.hex_to_rgb(col1) 12 | rgb2 = colormatch.hex_to_rgb(col2) 13 | hsv1 = colorsys.rgb_to_hsv(rgb1[0], rgb1[1], rgb1[2]) 14 | hsv2 = colorsys.rgb_to_hsv(rgb2[0], rgb2[1], rgb2[2]) 15 | dis_hsv = colormatch.color_distance_hsv(hsv1, hsv2) 16 | rgb255_1 = colormatch.hex2rgb(col1) 17 | rgb255_2 = colormatch.hex2rgb(col2) 18 | dis_rgb = colormatch.color_distance_rgb(rgb255_1, rgb255_2) 19 | print(rgb1, rgb2, hsv1, hsv2) 20 | print(dis_hsv, dis_rgb) 21 | 22 | 23 | def main(): 24 | rgb_test() 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | --------------------------------------------------------------------------------