2011-07-01 04:34:49 +08:00
|
|
|
from subprocess import Popen, PIPE
|
2013-06-23 07:32:08 +08:00
|
|
|
import PIL.Image # python-imaging
|
|
|
|
import PIL.ImageStat # python-imaging
|
|
|
|
import Xlib.display # python-xlib
|
|
|
|
import re
|
|
|
|
import tesserocr
|
2011-07-01 04:34:49 +08:00
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
class Window:
|
|
|
|
def __init__(self, wid):
|
|
|
|
assert type(wid) == int
|
|
|
|
self.wid = wid
|
2013-06-23 07:32:08 +08:00
|
|
|
self.geometry = self.get_geometry()
|
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def get_wid(self):
|
|
|
|
return self.wid
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def get_pid(self):
|
|
|
|
c = "getwindowpid %d" % self.wid
|
|
|
|
return int(run_command(c))
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def get_name(self):
|
|
|
|
c = "getwindowname %d" % self.wid
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def get_geometry(self):
|
|
|
|
# TODO: should be parsed into Python objects
|
|
|
|
c = "getwindowgeometry %d" % self.wid
|
2013-06-23 07:32:08 +08:00
|
|
|
result = run_command(c)
|
|
|
|
ret = re.findall(
|
|
|
|
r"Position: (\d+?),(\d+).+\n.+Geometry: (\d+?)x(\d+)",
|
|
|
|
result.decode('utf-8'))
|
|
|
|
return dict(x=int(ret[0][0]), y=int(ret[0][1]),
|
|
|
|
w=int(ret[0][2]), h=int(ret[0][3]))
|
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def set_size(self, width, height):
|
|
|
|
c = "windowsize %d %d %d" % (self.wid, width, height)
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def move(self, x, y):
|
|
|
|
c = "windowmove %d %d %d" % (self.wid, x, y)
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def activate(self):
|
|
|
|
c = "windowactivate %d" % self.wid
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def focus(self):
|
|
|
|
c = "windowfocus %d" % self.wid
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def screen_map(self):
|
|
|
|
c = "windowmap %d" % self.wid
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def minimize(self):
|
|
|
|
c = "windowminimize %d" % self.wid
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def kill(self):
|
|
|
|
c = "windowkill %d" % self.wid
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
def key(self, keyname):
|
|
|
|
c = "key --window %d %s" % (self.wid, keyname)
|
|
|
|
return run_command(c)
|
|
|
|
|
|
|
|
# Lifted from http://rosettacode.org/wiki/Color_of_a_screen_pixel
|
|
|
|
def get_pixel_color(self, i_x, i_y):
|
|
|
|
self.geometry = self.get_geometry()
|
|
|
|
i_x = self.geometry['x'] + i_x
|
|
|
|
i_y = self.geometry['y'] + i_y
|
|
|
|
o_x_root = Xlib.display.Display().screen().root
|
|
|
|
o_x_image = o_x_root.get_image(
|
|
|
|
i_x, i_y, 1, 1, Xlib.X.ZPixmap, 0xffffffff)
|
|
|
|
o_pil_image_rgb = PIL.Image.frombytes(
|
|
|
|
"RGB", (1, 1), o_x_image.data, "raw", "BGRX")
|
|
|
|
lf_colour = PIL.ImageStat.Stat(o_pil_image_rgb).mean
|
|
|
|
return tuple(map(int, lf_colour))
|
|
|
|
|
|
|
|
def get_window_image(self):
|
|
|
|
self.geometry = self.get_geometry()
|
|
|
|
o_x_root = Xlib.display.Display().screen().root
|
|
|
|
o_x_image = o_x_root.get_image(
|
|
|
|
self.geometry['x'], self.geometry['y'],
|
|
|
|
self.geometry['w'], self.geometry['h'],
|
|
|
|
Xlib.X.ZPixmap, 0xffffffff)
|
|
|
|
return o_x_image
|
|
|
|
|
|
|
|
def get_window_area_image(self, area):
|
|
|
|
self.geometry = self.get_geometry()
|
|
|
|
o_x_root = Xlib.display.Display().screen().root
|
|
|
|
o_x_image = o_x_root.get_image(
|
|
|
|
self.geometry['x'] + area['x'], self.geometry['y'] + area['y'],
|
|
|
|
area['w'], area['h'],
|
|
|
|
Xlib.X.ZPixmap, 0xffffffff)
|
|
|
|
return o_x_image
|
|
|
|
|
|
|
|
def check_multi_color(self, point_list, color_list, delta):
|
|
|
|
image = self.get_window_image()
|
|
|
|
return check_multi_color_of_image(image, point_list, color_list,
|
|
|
|
(0, 0), delta)
|
|
|
|
|
|
|
|
def find_multi_color(self, point_list, color_list, offset, delta):
|
|
|
|
image = self.get_window_image()
|
|
|
|
for x_offset in range(0, offset):
|
|
|
|
for y_offset in range(0, offset):
|
|
|
|
if check_multi_color_of_image(image, point_list, color_list,
|
|
|
|
(x_offset, y_offset), delta):
|
|
|
|
return True
|
|
|
|
for x_offset in range(-1, -offset, -1):
|
|
|
|
for y_offset in range(-1, -offset, -1):
|
|
|
|
if check_multi_color_of_image(image, point_list, color_list,
|
|
|
|
(x_offset, y_offset), delta):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def find_area_text(self, area):
|
|
|
|
image = self.get_window_area_image(area)
|
|
|
|
o_pil_image_rgb = PIL.Image.frombytes(
|
|
|
|
"RGB", (area['w'], area['h']), image.data, "raw", "BGRX")
|
|
|
|
text = tesserocr.image_to_text(o_pil_image_rgb)
|
|
|
|
return text.strip()
|
|
|
|
|
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
# Lifted from http://rosettacode.org/wiki/Color_of_a_screen_pixel
|
|
|
|
def get_pixel_color(i_x, i_y):
|
2013-06-23 07:32:08 +08:00
|
|
|
o_x_root = Xlib.display.Display().screen().root
|
|
|
|
o_x_image = o_x_root.get_image(i_x, i_y, 1, 1, Xlib.X.ZPixmap, 0xffffffff)
|
|
|
|
o_pil_image_rgb = PIL.Image.frombytes(
|
2020-07-14 17:04:12 +08:00
|
|
|
"RGB", (1, 1), o_x_image.data, "raw", "BGRX")
|
|
|
|
return o_pil_image_rgb.getpixel((0, 0))
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
def get_pixel_color_of_image(o_x_image, i_x, i_y):
|
|
|
|
if i_x < 0:
|
|
|
|
return (-1000, -1000, -1000)
|
|
|
|
if i_y < 0:
|
|
|
|
return (-1000, -1000, -1000)
|
|
|
|
o_pil_image_rgb = PIL.Image.frombytes(
|
|
|
|
"RGB", (i_x + 1, i_y + 1), o_x_image.data, "raw", "BGRX")
|
2020-07-14 17:04:12 +08:00
|
|
|
return o_pil_image_rgb.getpixel((i_x, i_y))
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
|
|
|
|
def check_multi_color_of_image(image, point_list, color_list, offset, delta):
|
|
|
|
for i, p in enumerate(point_list):
|
|
|
|
c = get_pixel_color_of_image(image, p[0] + offset[0], p[1] + offset[1])
|
|
|
|
if(abs(c[0] - color_list[i][0]) > delta
|
|
|
|
or abs(c[1] - color_list[i][1]) > delta
|
|
|
|
or abs(c[2] - color_list[i][2]) > delta):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
|
|
|
|
def get_focused_window():
|
|
|
|
c = "getactivewindow"
|
|
|
|
wid = int(run_command(c))
|
|
|
|
return Window(wid)
|
2011-07-01 05:30:36 +08:00
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def get_active_window():
|
2011-07-01 05:30:36 +08:00
|
|
|
c = "getactivewindow"
|
|
|
|
wid = int(run_command(c))
|
|
|
|
return Window(wid)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def get_windows(wids):
|
|
|
|
windows = []
|
|
|
|
for wid in wids:
|
|
|
|
windows.append(Window(wid))
|
|
|
|
return windows
|
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 05:30:36 +08:00
|
|
|
def search(**kwargs):
|
|
|
|
c = "search"
|
|
|
|
noargs = ["onlyvisible", "class", "classname", "all", "any", "sync"]
|
|
|
|
for arg in noargs:
|
|
|
|
if arg in kwargs:
|
|
|
|
if kwargs[arg]:
|
|
|
|
c += " --%s" % arg
|
|
|
|
if "name" in kwargs:
|
|
|
|
c += ' --name "%s"' % kwargs['name']
|
|
|
|
if "pid" in kwargs:
|
|
|
|
c += " --pid %s" % kwargs['pid']
|
|
|
|
str_wids = run_command(c).split()
|
|
|
|
wids = []
|
|
|
|
for str_wid in str_wids:
|
|
|
|
wids.append(int(str_wid))
|
|
|
|
return get_windows(wids)
|
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-01 12:27:00 +08:00
|
|
|
def mouse_move(x, y):
|
2011-07-01 04:34:49 +08:00
|
|
|
c = "mousemove %d %d" % (x, y)
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
def type_string(string):
|
|
|
|
c = "type '%s'" % string
|
|
|
|
return run_command(c)
|
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
def key(keyname):
|
|
|
|
c = "key %s" % keyname
|
|
|
|
return run_command(c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
|
2011-07-01 04:34:49 +08:00
|
|
|
def click(btn):
|
|
|
|
c = "click %d" % btn
|
|
|
|
return run_command(c)
|
|
|
|
|
2013-06-23 07:32:08 +08:00
|
|
|
|
2011-07-02 05:14:38 +08:00
|
|
|
def click_at(x, y, btn=1):
|
2011-07-01 12:27:00 +08:00
|
|
|
mouse_move(x, y)
|
2011-07-01 04:34:49 +08:00
|
|
|
return click(btn)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
|
2011-07-01 04:34:49 +08:00
|
|
|
def run_command(c):
|
2011-07-02 05:14:38 +08:00
|
|
|
return run_command_raw("xdotool " + c)
|
2013-06-23 07:32:08 +08:00
|
|
|
|
|
|
|
|
2011-07-02 05:14:38 +08:00
|
|
|
def run_command_raw(c):
|
|
|
|
return Popen(c, stdout=PIPE, shell=True).stdout.read()
|