Created
December 20, 2015 12:12
-
-
Save jadkik/91b4074593c9496ef411 to your computer and use it in GitHub Desktop.
A small tool to manipulate your phone without a working touchscreen. Install [TouchControl](https://github.com/ternes3/TouchControl-for-Android) to see what happens on your screen as it's happening.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import sys | |
import readline | |
import atexit | |
from collections import defaultdict | |
def completer(funcs): | |
completionhelper = dict() | |
def thecompleter(text, state): | |
a = completionhelper.get(text, None) | |
if a is not None: | |
return a[state] if state < len(a) else None | |
a = [f for f in funcs if f.startswith(text)] | |
completionhelper[text] = a | |
return a[0] if len(a) > 0 else None | |
return thecompleter | |
histfile = os.path.join(os.path.expanduser("~"), ".android_broken_screen_history") | |
def with_history(funcs): | |
global histfile | |
try: | |
readline.read_history_file(histfile) | |
except IOError: | |
pass | |
atexit.register(readline.write_history_file, histfile) | |
readline.parse_and_bind("tab: complete") | |
readline.set_completer(completer(funcs)) | |
def shell(*args): | |
a = 'adb shell input ' + ' '.join(map(str, args)) | |
print(a, file=sys.stderr) | |
os.system(a) | |
def run(*args): | |
a = 'adb shell ' + ' '.join(map(str, args)) | |
print(a, file=sys.stderr) | |
os.system(a) | |
DEFAULT_DURATION = 300 | |
tab = lambda: shell('keyevent', 61) | |
enter = lambda: shell('keyevent', 66) | |
back = lambda: shell('keyevent', 4) | |
power = lambda: shell('keyevent', 26) | |
home = lambda: shell('keyevent', 3) | |
volumeup = lambda: shell('keyevent', 24) | |
volumedown = lambda: shell('keyevent', 25) | |
up = lambda: shell('keyevent', 19) | |
down = lambda: shell('keyevent', 20) | |
left = lambda: shell('keyevent', 21) | |
right = lambda: shell('keyevent', 22) | |
swipe = lambda x1, y1, x2, y2, duration=DEFAULT_DURATION: shell('swipe', x1, y1, x2, y2, duration) | |
hswipe = lambda y, x1, x2, duration=DEFAULT_DURATION: swipe(x1, y, x2, y, duration) | |
vswipe = lambda x, y1, y2, duration=DEFAULT_DURATION: swipe(x, y1, x, y2, duration) | |
tap = lambda x, y: shell('tap', x, y) | |
longpress = lambda x, y, duration=DEFAULT_DURATION: swipe(x, y, x, y, duration) | |
notification = lambda midx, maxy, duration=DEFAULT_DURATION: vswipe(midx, 0, maxy, duration) | |
def write(s): | |
ss = s.split() | |
for p in ss[:-1]: | |
shell('text', p) # one word | |
shell('keyevent', 62) # one space | |
if len(ss) >= 1: | |
shell('text', ss[-1]) # last word | |
allowed_funcs = frozenset(( | |
'shell', 'run', | |
'write', 'notification', | |
'hswipe', 'vswipe', 'swipe', 'tap', 'longpress', | |
'tab', 'enter', 'back', 'power', 'home', 'volumeup', 'volumedown', | |
'up', 'down', 'left', 'right' | |
)) | |
if __name__ == '__main__': | |
try: | |
try: | |
resolution = tuple(map(int, input('Resolution (e.g. 1920x1080): ').split('x', 1))) | |
except (KeyboardInterrupt, EOFError) as e: | |
raise | |
except: | |
resolution = (1920, 1080) | |
print('Using default resolution', resolution) | |
else: | |
print('Using custom resolution', resolution) | |
print('WARNING: be careful what you write. You may execute arbitrary code on your PC or your Android device if you are not careful (or are malicious).') | |
input('Press enter if you know what you are doing. Ctrl-C otherwise.') | |
print('Checking adb devices') | |
try: | |
os.system('adb devices') | |
except: | |
print('Nope.') | |
raise | |
with_history(allowed_funcs) | |
while True: | |
cmd = input('> ') | |
func, *params = cmd.split(None, 1) | |
params = params[0] if params else '' | |
if func not in allowed_funcs: | |
print('Unknown command', func) | |
continue | |
elif func == 'help': | |
print(' '.join(allowed_funcs)) | |
continue | |
if func == 'write': | |
write(params) | |
elif func == 'notification': | |
try: | |
midx, maxy = map(int, params.split(None, 1)) | |
except: | |
midx, maxy = int(resolution[1]/2), int(resolution[0] - 100) | |
notification(midx, maxy) | |
elif func in ('tab', 'enter', 'back', 'power', 'home', 'volumeup', 'volumedown', 'up', 'down', 'left', 'right'): | |
globals()[func]() | |
elif func in ('swipe', 'hswipe', 'vswipe', 'tap', 'longpress'): | |
try: | |
args = map(int, params.split()) | |
globals()[func](*args) | |
except Exception as e: | |
print('Could not call', repr(func), 'with params', repr(params)) | |
print(e) | |
elif func == 'shell': | |
shell(params) | |
elif func == 'run': | |
run(params) | |
else: | |
print('This should not happen. Sorry. Try "shell', params, '" instead.') | |
except (KeyboardInterrupt, EOFError) as e: | |
print() | |
print('Exiting...') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment