示例#1
0
文件: OSXUI.py 项目: adolli/Poco
    def __init__(self, addr=DEFAULT_ADDR):
        self.reactor = StdRpcReactor()
        self.reactor.register('Dump', self.Dump)
        self.reactor.register('GetSDKVersion', self.GetSDKVersion)
        self.reactor.register('GetDebugProfilingData',
                              self.GetDebugProfilingData)
        self.reactor.register('GetScreenSize', self.GetScreenSize)
        self.reactor.register('Screenshot', self.Screenshot)
        self.reactor.register('Click', self.Click)
        self.reactor.register('Swipe', self.Swipe)
        self.reactor.register('LongClick', self.LongClick)
        self.reactor.register('SetForeground', self.SetForeground)
        self.reactor.register('ConnectWindow', self.ConnectWindow)

        transport = TcpSocket()
        transport.bind(addr)
        self.rpc = StdRpcEndpointController(transport, self.reactor)

        self.running = False
        self.root = None
示例#2
0
文件: OSXUI.py 项目: zjd2626/Poco
 def run(self):
     self.reactor = StdRpcReactor()
     self.reactor.register('Dump', self.Dump)
     self.reactor.register('GetSDKVersion', self.GetSDKVersion)
     self.reactor.register('GetDebugProfilingData',
                           self.GetDebugProfilingData)
     self.reactor.register('GetScreenSize', self.GetScreenSize)
     self.reactor.register('Screenshot', self.Screenshot)
     self.reactor.register('Click', self.Click)
     self.reactor.register('Swipe', self.Swipe)
     self.reactor.register('LongClick', self.LongClick)
     self.reactor.register('SetForeground', self.SetForeground)
     self.reactor.register('ConnectWindow', self.ConnectWindow)
     self.reactor.register('Scroll', self.Scroll)
     self.reactor.register('RClick', self.RClick)
     self.reactor.register('DoubleClick', self.DoubleClick)
     self.reactor.register('KeyEvent', self.KeyEvent)
     transport = TcpSocket()
     transport.bind(self.addr)
     self.rpc = StdRpcEndpointController(transport, self.reactor)
     if self.running is False:
         self.running = True
         self.rpc.serve_forever()
示例#3
0
文件: OSXUI.py 项目: adolli/Poco
class PocoSDKOSX(object):
    def __init__(self, addr=DEFAULT_ADDR):
        self.reactor = StdRpcReactor()
        self.reactor.register('Dump', self.Dump)
        self.reactor.register('GetSDKVersion', self.GetSDKVersion)
        self.reactor.register('GetDebugProfilingData',
                              self.GetDebugProfilingData)
        self.reactor.register('GetScreenSize', self.GetScreenSize)
        self.reactor.register('Screenshot', self.Screenshot)
        self.reactor.register('Click', self.Click)
        self.reactor.register('Swipe', self.Swipe)
        self.reactor.register('LongClick', self.LongClick)
        self.reactor.register('SetForeground', self.SetForeground)
        self.reactor.register('ConnectWindow', self.ConnectWindow)

        transport = TcpSocket()
        transport.bind(addr)
        self.rpc = StdRpcEndpointController(transport, self.reactor)

        self.running = False
        self.root = None

    def Dump(self, _):
        res = OSXUIDumper(self.root).dumpHierarchy()
        return res

    def SetForeground(self):
        self.root.AXMinimized = False
        self.app.AXFrontmost = True

    def GetSDKVersion(self):
        return '0.0.1'

    def GetDebugProfilingData(self):
        return {}

    def GetScreenSize(self):
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        return [Width, Height]

    def Screenshot(self, width):
        self.SetForeground()
        size = self.root.AXSize
        pos = self.root.AXPosition
        pyautogui.screenshot(
            'Screenshot.png',
            (pos[0], pos[1], size[0], size[1])).save('Screenshot.png')
        f = open(r'Screenshot.png', 'rb')
        deflated = zlib.compress(f.read())
        ls_f = base64.b64encode(deflated)
        f.close()
        return [ls_f, "png.deflate"]

        # self.root.ToBitmap().ToFile('Screenshot.bmp')
        # f = open(r'Screenshot.bmp', 'rb')
        # ls_f = base64.b64encode(f.read())
        # f.close()
        # return [ls_f, "bmp"]

    def Click(self, x, y):
        self.SetForeground()
        size = self.root.AXSize
        pos = self.root.AXPosition
        pyautogui.moveTo(pos[0] + size[0] * x, pos[1] + size[1] * y)
        pyautogui.click(pos[0] + size[0] * x, pos[1] + size[1] * y)
        return True

    def Swipe(self, x1, y1, x2, y2, duration):
        self.SetForeground()
        Left = self.root.AXPosition[0]
        Top = self.root.AXPosition[1]
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        x1 = Left + Width * x1
        y1 = Top + Height * y1
        x2 = Left + Width * x2
        y2 = Top + Height * y2
        pyautogui.moveTo(x1, y1)
        pyautogui.dragTo(x2, y2, duration)
        return True

    def LongClick(self, x, y, duration):
        self.SetForeground()
        Left = self.root.AXPosition[0]
        Top = self.root.AXPosition[1]
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        x = Left + Width * x
        y = Top + Height * y
        pyautogui.moveTo(x, y)
        pyautogui.dragTo(x, y, duration)
        return True

    def EnumWindows(self, selector):
        names = []
        if 'bundleid' in selector:
            self.app = atomac.getAppRefByBundleId(selector['bundleid'])
            windows = self.app.windows()
            for i, w in enumerate(windows):
                names.append((w.AXTitle, i))
            return names

        if 'appname' in selector:
            self.app = atomac.getAppRefByLocalizedName(selector['appname'])
            windows = self.app.windows()
            for i, w in enumerate(windows):
                names.append((w.AXTitle, i))
            return names

        if 'appname_re' in selector:  # 此方法由于MacOS API,问题较多
            apps = atomac.NativeUIElement._getRunningApps()  # 获取当前运行的所有应用程序
            appset = set()  # 应用程序集合
            appnameset = set()  # 应用程序标题集合
            for t in apps:
                tempapp = atomac.getAppRefByPid(t.processIdentifier())
                if str(tempapp) == str(atomac.AXClasses.NativeUIElement()
                                       ):  # 通过trick判断应用程序是都否为空
                    continue
                attrs = tempapp.getAttributes()
                if 'AXTitle' in attrs:
                    tit = tempapp.AXTitle
                    if re.match(selector['appname_re'], tit):
                        appset.add(tempapp)
                        appnameset.add(
                            tit)  # 这里有Bug,可能会获取到进程的不同副本,所以要通过名字去判断是否唯一

            if len(appnameset) is 0:
                raise InvalidSurfaceException(
                    selector,
                    "Can't find any applications by the given parameter")
            if len(appnameset) != 1:
                raise NonuniqueSurfaceException(selector)
            while len(names) is 0:  # 有可能有多个副本,但只有一个真的应用程序有窗口,所以要枚举去找
                if len(appset) is 0:
                    return names
                self.app = appset.pop()
                windows = self.app.windows()  # 获取当前应用程序的所有窗口
                for i, w in enumerate(windows):
                    names.append((w.AXTitle, i))
            return names
        return names

    def ConnectWindowsByWindowTitle(self, selector, wlist):
        hn = set()
        for n in wlist:
            if selector['windowtitle'] == n[0]:
                hn.add(n[1])
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByWindowTitleRe(self, selector, wlist):
        hn = set()
        for n in wlist:
            if re.match(selector['windowtitle_re'], n[0]):
                hn.add(n[1])
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindow(self, selector):

        # 目前来说,如下处理,以后添加更多的参数后需修改代码逻辑
        argunums = 0
        if 'bundleid' in selector:
            argunums += 1
        if 'appname' in selector:
            argunums += 1
        if 'appname_re' in selector:
            argunums += 1
        if argunums == 0:
            raise ValueError("Expect bundleid or appname, got none")
        elif argunums != 1:
            raise ValueError(
                "Too many arguments, only need bundleid or appname or appname_re"
            )

        winlist = self.EnumWindows(selector)

        handleSetList = []
        if 'windowtitle' in selector:
            handleSetList.append(
                self.ConnectWindowsByWindowTitle(selector, winlist))
        if 'windowindex' in selector:
            handleSetList.append(set([selector['windowindex']]))
        if "windowtitle_re" in selector:
            handleSetList.append(
                self.ConnectWindowsByWindowTitleRe(selector, winlist))

        while -1 in handleSetList:
            handleSetList.remove(-1)

        if len(handleSetList) == 0:  # 三种方法都找不到窗口
            raise InvalidSurfaceException(
                selector, "Can't find any applications by the given parameter")

        handleSet = reduce(operator.__and__, handleSetList)

        if len(handleSet) == 0:
            raise InvalidSurfaceException(
                selector, "Can't find any applications by the given parameter")
        elif len(handleSet) != 1:
            raise NonuniqueSurfaceException(selector)
        else:
            hn = handleSet.pop()
            w = self.app.windows()
            if len(w) <= hn:
                raise IndexError(
                    "Unable to find the specified window through the index, you may have closed the specified window during the run"
                )
            self.root = self.app.windows()[hn]
            self.SetForeground()

    def run(self):
        if self.running is False:
            self.running = True
            self.rpc.serve_forever()
示例#4
0
class PocoSDKWindows(object):

    def __init__(self, addr=DEFAULT_ADDR):
        self.reactor = StdRpcReactor()
        self.reactor.register('Dump', self.Dump)
        self.reactor.register('SetText', self.SetText)
        self.reactor.register('GetSDKVersion', self.GetSDKVersion)
        self.reactor.register('GetDebugProfilingData', self.GetDebugProfilingData)
        self.reactor.register('GetScreenSize', self.GetScreenSize)
        self.reactor.register('Screenshot', self.Screenshot)
        self.reactor.register('Click', self.Click)
        self.reactor.register('Swipe', self.Swipe)
        self.reactor.register('LongClick', self.LongClick)
        self.reactor.register('KeyEvent', self.KeyEvent)
        self.reactor.register('SetForeground', self.SetForeground)
        self.reactor.register('ConnectWindow', self.ConnectWindow)

        transport = TcpSocket()
        transport.bind(addr)
        self.rpc = StdRpcEndpointController(transport, self.reactor)

        self.running = False
        UIAuto.OPERATION_WAIT_TIME = 0.1  # make operation faster
        self.root = None

    def Dump(self, _):
        res = WindowsUIDumper(self.root).dumpHierarchy()
        return res

    def SetText(self, id, val2):
        control = UIAuto.ControlFromHandle(id)
        if not control or not isinstance(val2, string_types):
            raise UnableToSetAttributeException("text", control)
        else:
            control.SetValue(val2)

    def GetSDKVersion(self):
        return '0.0.1'

    def GetDebugProfilingData(self):
        return {}

    def GetScreenSize(self):
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        return [Width, Height]

    def JudgeSize(self):
        size = self.GetScreenSize()
        if size[0] == 0 or size[1] == 0:
            raise InvalidSurfaceException(self, "You may have minimized your window or the window is too small!")

    def Screenshot(self, width):
        self.JudgeSize()
        self.root.ToBitmap().ToFile('Screenshot.bmp')
        f = open(r'Screenshot.bmp', 'rb')
        deflated = zlib.compress(f.read())
        ls_f = base64.b64encode(deflated)
        f.close()
        return [ls_f, "bmp.deflate"]

        # self.root.ToBitmap().ToFile('Screenshot.bmp')
        # f = open(r'Screenshot.bmp', 'rb')
        # ls_f = base64.b64encode(f.read())
        # f.close()
        # return [ls_f, "bmp"]

    def Click(self, x, y):
        self.JudgeSize()
        self.root.Click(x, y)
        return True

    def Swipe(self, x1, y1, x2, y2, duration):
        self.JudgeSize()
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x1 = Left + Width * x1
        y1 = Top + Height * y1
        x2 = Left + Width * x2
        y2 = Top + Height * y2
        UIAuto.MAX_MOVE_SECOND = duration * 10
        UIAuto.DragDrop(int(x1), int(y1), int(x2), int(y2))
        return True

    def LongClick(self, x, y, duration):
        self.JudgeSize()
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x = Left + Width * x
        y = Top + Height * y
        UIAuto.MAX_MOVE_SECOND = duration * 10
        UIAuto.DragDrop(int(x), int(y), int(x), int(y))
        return True

    def KeyEvent(self, keycode):
        UIAuto.SendKeys(keycode)
        return True

    def SetForeground(self):
        win32gui.ShowWindow(self.root.Handle, win32con.SW_SHOWNORMAL)
        UIAuto.Win32API.SetForegroundWindow(self.root.Handle)
        return True

    def EnumWindows(self):
        hWndList = []

        def foo(hwnd, mouse):
            if win32gui.IsWindow(hwnd):
                hWndList.append(hwnd)
        win32gui.EnumWindows(foo, 0)
        return hWndList

    def ConnectWindowsByTitle(self, title):
        hn = set()
        hWndList = self.EnumWindows()
        for handle in hWndList:
            title_temp = win32gui.GetWindowText(handle)
            if PY2:
                title_temp = title_temp.decode("gbk")
            if title == title_temp:
                hn.add(handle)
        if len(hn) == 0:
            print
        return hn

    def ConnectWindowsByTitleRe(self, title_re):
        hn = set()
        hWndList = self.EnumWindows()
        for handle in hWndList:
            title = win32gui.GetWindowText(handle)
            if PY2:
                title = title.decode("gbk")
            if re.match(title_re, title):
                hn.add(handle)
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByHandle(self, handle):
        hn = set()
        hWndList = self.EnumWindows()
        for handle_temp in hWndList:
            if int(handle_temp) == int(handle):
                hn.add(handle)
                break
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindow(self, selector, foreground=False):
        if foreground:
            time.sleep(1)
            self.root = UIAuto.GetForegroundControl()
            return True

        handleSetList = []
        if 'title' in selector:
            handleSetList.append(self.ConnectWindowsByTitle(selector['title']))
        if 'handle' in selector:
            handleSetList.append(self.ConnectWindowsByHandle(selector['handle']))
        if "title_re" in selector:
            handleSetList.append(self.ConnectWindowsByTitleRe(selector['title_re']))

        while -1 in handleSetList:
            handleSetList.remove(-1)

        if len(handleSetList) == 0:
            return False

        handleSet = handleSetList[0]
        for s in handleSetList:
            handleSet = s & handleSet

        if len(handleSet) == 0:
            return False
        elif len(handleSet) != 1:
            raise NonuniqueSurfaceException(selector)
        else:
            hn = handleSet.pop()
            if hn:
                self.root = UIAuto.ControlFromHandle(hn)
                return True
            else:
                return False

    def run(self, use_foregrond_window=False):
        if self.running is False:
            self.running = True
            if use_foregrond_window:
                self.ConnectWindow(set(), True)
            self.rpc.serve_forever()
示例#5
0
import threading

from poco.sdk.std.rpc.controller import StdRpcEndpointController
from poco.sdk.std.rpc.reactor import StdRpcReactor
from poco.utils.net.transport.tcp import TcpSocket
from poco.utils.net.stdbroker import StdBroker


def Dump(arg):
    return 'this is Dump ' + arg


if __name__ == '__main__':
    # broker = StdBroker('tcp://*:15003', 'tcp://*:15004')

    reactor = StdRpcReactor()
    reactor.register('Dump', Dump)

    responser = TcpSocket()
    responser.connect(('localhost', 15003))

    rpc_responser = StdRpcEndpointController(responser, reactor)
    t = threading.Thread(target=rpc_responser.serve_forever)
    t.daemon = True
    t.start()

    requester = TcpSocket()
    requester.connect(('localhost', 15004))
    rpc_requester = StdRpcEndpointController(requester, StdRpcReactor())
    t = threading.Thread(target=rpc_requester.serve_forever)
    t.daemon = True
示例#6
0
class PocoSDKWindows(object):
    def __init__(self, addr=DEFAULT_ADDR):
        self.reactor = None
        self.addr = addr
        self.running = False
        UIAuto.OPERATION_WAIT_TIME = 0.05  # make operation faster
        self.root = None

    def Dump(self, _):
        res = WindowsUIDumper(self.root).dumpHierarchy()
        return res

    def SetText(self, id, val2):
        control = UIAuto.ControlFromHandle(id)
        if not control or not isinstance(val2, string_types):
            raise UnableToSetAttributeException("text", control)
        else:
            control.SetValue(val2)

    def GetSDKVersion(self):
        return '0.0.1'

    def GetDebugProfilingData(self):
        return {}

    def GetScreenSize(self):
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        return [Width, Height]

    def GetWindowRect(self):
        return self.root.BoundingRectangle

    def JudgeSize(self):
        self.SetForeground()  # 先打开窗口再获取大小,否则最小化的窗口获取到的大小会为0
        size = self.GetScreenSize()
        if size[0] == 0 or size[1] == 0:
            raise InvalidSurfaceException(
                self,
                "You may have minimized or closed your window or the window is too small!"
            )

    def Screenshot(self, width):
        self.JudgeSize()
        self.root.ToBitmap().ToFile('Screenshot.bmp')
        f = open(r'Screenshot.bmp', 'rb')
        deflated = zlib.compress(f.read())  # 压缩图片
        ls_f = base64.b64encode(deflated)
        f.close()
        return [ls_f, "bmp.deflate"]

        # self.root.ToBitmap().ToFile('Screenshot.bmp')
        # f = open(r'Screenshot.bmp', 'rb')
        # ls_f = base64.b64encode(f.read())
        # f.close()
        # return [ls_f, "bmp"]

    def Click(self, x, y):
        self.JudgeSize()
        self.root.Click(x, y)
        return True

    def RClick(self, x, y):
        self.JudgeSize()
        self.root.RightClick(x, y)
        return True

    def DoubleClick(self, x, y):
        self.JudgeSize()
        self.root.DoubleClick(x, y)
        return True

    def Swipe(self, x1, y1, x2, y2, duration, **kwargs):
        self.JudgeSize()
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x1 = int(Left + Width * x1)  # 比例换算
        y1 = int(Top + Height * y1)
        x2 = int(Left + Width * x2)
        y2 = int(Top + Height * y2)

        UIAuto.MAX_MOVE_SECOND = duration * 10  # 同步到跟UIAutomation库的时间设定一样
        UIAuto.DragDrop(int(x1), int(y1), int(x2), int(y2))
        return True

    def LongClick(self, x, y, duration, **kwargs):
        self.JudgeSize()
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x = Left + Width * x
        y = Top + Height * y

        UIAuto.MAX_MOVE_SECOND = duration * 10
        UIAuto.DragDrop(int(x), int(y), int(x), int(y))
        return True

    def Scroll(self, direction, percent, duration):
        if direction not in ('vertical', 'horizontal'):
            return False

        if direction == 'horizontal':
            return False

        self.JudgeSize()
        x = 0.5  # 先把鼠标移到窗口中间,这样才能保证滚动的是这个窗口。
        y = 0.5
        steps = percent
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x = Left + Width * x
        y = Top + Height * y
        x = int(x)
        y = int(y)
        UIAuto.MoveTo(x, y)
        interval = float(duration - 0.3 * steps) / (abs(steps) + 1)  # 实现滚动时间
        if interval <= 0:
            interval = 0.1
        if steps < 0:
            for i in range(0, abs(steps)):
                time.sleep(interval)
                UIAuto.WheelUp(1)
        else:
            for i in range(0, abs(steps)):
                time.sleep(interval)
                UIAuto.WheelDown(1)
        return True

    def KeyEvent(self, keycode):
        self.JudgeSize()
        UIAuto.SendKeys(keycode)
        return True

    def SetForeground(self):
        win32gui.ShowWindow(self.root.Handle,
                            win32con.SW_SHOWNORMAL)  # 先把窗口取消最小化
        UIAuto.Win32API.SetForegroundWindow(
            self.root.Handle)  # 再把窗口设为前台,方便点击和截图
        return True

    def EnumWindows(self):
        hWndList = []  # 枚举所有窗口,并把有效窗口handle保存在hwndlist里

        def foo(hwnd, mouse):
            if win32gui.IsWindow(hwnd):
                hWndList.append(hwnd)

        win32gui.EnumWindows(foo, 0)
        return hWndList

    def ConnectWindowsByTitle(self, title):
        hn = set()  # 匹配窗口的集合,把所有标题匹配上的窗口handle都保存在这个集合里
        hWndList = self.EnumWindows()
        for handle in hWndList:
            title_temp = win32gui.GetWindowText(handle)
            if PY2:
                title_temp = title_temp.decode(
                    "gbk")  # py2要解码成GBK,WindowsAPI中文返回的一般都是GBK
            if title == title_temp:
                hn.add(handle)
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByTitleRe(self, title_re):
        hn = set()  # 匹配窗口的集合,把所有标题(正则表达式)匹配上的窗口handle都保存在这个集合里
        hWndList = self.EnumWindows()
        for handle in hWndList:
            title = win32gui.GetWindowText(handle)
            if PY2:
                title = title.decode("gbk")
            if re.match(title_re, title):
                hn.add(handle)
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByHandle(self, handle):
        hn = set()  # 匹配窗口的集合,把所有handle匹配上的窗口handle都保存在这个集合里
        hWndList = self.EnumWindows()
        for handle_temp in hWndList:
            if int(handle_temp) == int(handle):
                hn.add(handle)
                break
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindow(self, selector):

        # 目前来说,如下处理,以后添加更多的参数后需修改代码逻辑
        argunums = 0
        if 'handle' in selector:
            argunums += 1
        if 'title' in selector:
            argunums += 1
        if 'title_re' in selector:
            argunums += 1

        if argunums == 0:
            raise ValueError("Expect handle or title, got none")
        elif argunums != 1:
            raise ValueError(
                "Too many arguments, only need handle or title or title_re")

        handleSetList = []
        if 'title' in selector:
            handleSetList.append(self.ConnectWindowsByTitle(selector['title']))
        if 'handle' in selector:
            handleSetList.append(
                self.ConnectWindowsByHandle(selector['handle']))
        if "title_re" in selector:
            handleSetList.append(
                self.ConnectWindowsByTitleRe(selector['title_re']))

        while -1 in handleSetList:
            handleSetList.remove(-1)  # 有些参数没有提供会返回-1.把所有的-1去掉

        if len(handleSetList) is 0:
            raise InvalidSurfaceException(
                selector, "Can't find any windows by the given parameter")

        handleSet = reduce(operator.__and__,
                           handleSetList)  # 提供了多个参数来确定唯一一个窗口,所以要做交集,取得唯一匹配的窗口

        if len(handleSet) == 0:
            raise InvalidSurfaceException(
                selector, "Can't find any windows by the given parameter")
        elif len(handleSet) != 1:
            raise NonuniqueSurfaceException(selector)
        else:
            hn = handleSet.pop()  # 取得那个唯一的窗口
            self.root = UIAuto.ControlFromHandle(hn)
            if self.root is None:
                raise InvalidSurfaceException(
                    selector, "Can't find any windows by the given parameter")
            self.SetForeground()

    def run(self):
        self.reactor = StdRpcReactor()
        self.reactor.register('Dump', self.Dump)  # 注册各种函数
        self.reactor.register('SetText', self.SetText)
        self.reactor.register('GetSDKVersion', self.GetSDKVersion)
        self.reactor.register('GetDebugProfilingData',
                              self.GetDebugProfilingData)
        self.reactor.register('GetScreenSize', self.GetScreenSize)
        self.reactor.register('Screenshot', self.Screenshot)
        self.reactor.register('Click', self.Click)
        self.reactor.register('Swipe', self.Swipe)
        self.reactor.register('LongClick', self.LongClick)
        self.reactor.register('KeyEvent', self.KeyEvent)
        self.reactor.register('SetForeground', self.SetForeground)
        self.reactor.register('ConnectWindow', self.ConnectWindow)
        self.reactor.register('Scroll', self.Scroll)
        self.reactor.register('RClick', self.RClick)
        self.reactor.register('DoubleClick', self.DoubleClick)
        transport = TcpSocket()
        transport.bind(self.addr)
        self.rpc = StdRpcEndpointController(transport, self.reactor)
        if self.running is False:
            self.running = True
            self.rpc.serve_forever()
示例#7
0
文件: OSXUI.py 项目: zjd2626/Poco
class PocoSDKOSX(object):
    def __init__(self, addr=DEFAULT_ADDR):
        self.reactor = None
        self.addr = addr
        self.running = False
        self.root = None
        self.keyboard = Controller()

    def Dump(self, _):
        res = OSXUIDumper(self.root).dumpHierarchy()
        return res

    def SetForeground(self):
        self.root.AXMinimized = False
        self.app.AXFrontmost = True

    def GetSDKVersion(self):
        return '0.0.1'

    def GetDebugProfilingData(self):
        return {}

    def GetScreenSize(self):
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        return [Width, Height]

    def GetWindowRect(self):
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        return [
            self.root.AXPosition[0], self.root.AXPosition[1],
            self.root.AXPosition[0] + Width, self.root.AXPosition[1] + Height
        ]

    def KeyEvent(self, keycode):
        waittime = 0.05
        for c in keycode:
            self.keyboard.press(key=c)
            self.keyboard.release(key=c)
            time.sleep(waittime)
        return True

    def Screenshot(self, width):
        self.SetForeground()
        size = self.root.AXSize
        pos = self.root.AXPosition
        pyautogui.screenshot(
            'Screenshot.png',
            (pos[0], pos[1], size[0], size[1])).save('Screenshot.png')
        f = open(r'Screenshot.png', 'rb')
        deflated = zlib.compress(f.read())
        ls_f = base64.b64encode(deflated)
        f.close()
        return [ls_f, "png.deflate"]

        # self.root.ToBitmap().ToFile('Screenshot.bmp')
        # f = open(r'Screenshot.bmp', 'rb')
        # ls_f = base64.b64encode(f.read())
        # f.close()
        # return [ls_f, "bmp"]

    def Click(self, x, y):
        self.SetForeground()
        size = self.root.AXSize
        pos = self.root.AXPosition
        OSXFunc.click(pos[0] + size[0] * x, pos[1] + size[1] * y)
        return True

    def RClick(self, x, y):
        self.SetForeground()
        size = self.root.AXSize
        pos = self.root.AXPosition
        OSXFunc.rclick(pos[0] + size[0] * x, pos[1] + size[1] * y)
        return True

    def DoubleClick(self, x, y):
        self.SetForeground()
        size = self.root.AXSize
        pos = self.root.AXPosition
        OSXFunc.doubleclick(pos[0] + size[0] * x, pos[1] + size[1] * y)
        return True

    def Swipe(self, x1, y1, x2, y2, duration):
        self.SetForeground()
        Left = self.root.AXPosition[0]
        Top = self.root.AXPosition[1]
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        x1 = Left + Width * x1
        y1 = Top + Height * y1
        x2 = Left + Width * x2
        y2 = Top + Height * y2
        sx = abs(x1 - x2)
        sy = abs(y1 - y2)
        stepx = sx / (duration * 10.0)  # 将滑动距离分割,实现平滑的拖动
        stepy = sy / (duration * 10.0)
        OSXFunc.move(x1, y1)
        OSXFunc.press(x1, y1)
        duration = int(duration * 10.0)
        for i in range(duration + 1):
            OSXFunc.drag(x1 + stepx * i, y1 + stepy * i)
            time.sleep(0.1)
        OSXFunc.release(x2, y2)
        return True

    def LongClick(self, x, y, duration, **kwargs):
        self.SetForeground()

        # poco std暂不支持选择鼠标按键
        button = kwargs.get("button", "left")
        if button not in ("left", "right"):
            raise ValueError("Unknow button: " + button)
        if button is "left":
            button = 1
        else:
            button = 2

        Left = self.root.AXPosition[0]
        Top = self.root.AXPosition[1]
        Width = self.root.AXSize[0]
        Height = self.root.AXSize[1]
        x = Left + Width * x
        y = Top + Height * y
        OSXFunc.move(x, y)
        OSXFunc.press(x, y, button=button)
        time.sleep(duration)
        OSXFunc.release(x, y, button=button)
        return True

    def Scroll(self, direction, percent, duration):
        if direction not in ('vertical', 'horizontal'):
            raise ValueError(
                'Argument `direction` should be one of "vertical" or "horizontal". Got {}'
                .format(repr(direction)))

        x = 0.5  # 先把鼠标移到窗口中间,这样才能保证滚动的是这个窗口。
        y = 0.5
        steps = percent
        Left = self.GetWindowRect()[0]
        Top = self.GetWindowRect()[1]
        Width = self.GetScreenSize()[0]
        Height = self.GetScreenSize()[1]
        x = Left + Width * x
        y = Top + Height * y
        x = int(x)
        y = int(y)
        OSXFunc.move(x, y)

        if direction == 'horizontal':
            interval = float(duration) / (abs(steps) + 1)
            if steps < 0:
                for i in range(0, abs(steps)):
                    time.sleep(interval)
                    OSXFunc.scroll(None, 1)
            else:
                for i in range(0, abs(steps)):
                    time.sleep(interval)
                    OSXFunc.scroll(None, -1)
        else:
            interval = float(duration) / (abs(steps) + 1)
            if steps < 0:
                for i in range(0, abs(steps)):
                    time.sleep(interval)
                    OSXFunc.scroll(1)
            else:
                for i in range(0, abs(steps)):
                    time.sleep(interval)
                    OSXFunc.scroll(-1)
        return True

    def EnumWindows(self, selector):
        names = []  # 一个应用程序会有多个窗口,因此我们要先枚举一个应用程序里的所有窗口
        if 'bundleid' in selector:
            self.app = OSXFunc.getAppRefByBundleId(selector['bundleid'])
            windows = self.app.windows()
            for i, w in enumerate(windows):
                names.append((w.AXTitle, i))
            return names

        if 'appname' in selector:
            self.app = OSXFunc.getAppRefByLocalizedName(selector['appname'])
            windows = self.app.windows()
            for i, w in enumerate(windows):
                names.append((w.AXTitle, i))
            return names

        if 'appname_re' in selector:  # 此方法由于MacOS API,问题较多
            apps = OSXFunc.getRunningApps()  # 获取当前运行的所有应用程序
            appset = []  # 应用程序集合
            appnameset = set()  # 应用程序标题集合
            for t in apps:
                tempapp = OSXFunc.getAppRefByPid(t.processIdentifier())
                if str(tempapp) == str(atomac.AXClasses.NativeUIElement()
                                       ):  # 通过trick判断应用程序是都否为空
                    continue
                attrs = tempapp.getAttributes()
                if 'AXTitle' in attrs:
                    tit = tempapp.AXTitle
                    if re.match(selector['appname_re'], tit):
                        appset.append(tempapp)
                        appnameset.add(
                            tit)  # 这里有Bug,可能会获取到进程的不同副本,所以要通过名字去判断是否唯一

            if len(appnameset) is 0:
                raise InvalidSurfaceException(
                    selector,
                    "Can't find any applications by the given parameter")
            if len(appnameset) != 1:
                raise NonuniqueSurfaceException(selector)
            while len(names) is 0:  # 有可能有多个副本,但只有一个真的应用程序有窗口,所以要枚举去找
                if len(appset) is 0:
                    return names
                self.app = appset.pop()
                windows = self.app.windows()  # 获取当前应用程序的所有窗口
                for i, w in enumerate(windows):
                    names.append((w.AXTitle, i))
            return names
        return names

    def ConnectWindowsByWindowTitle(self, selector, wlist):
        hn = set()
        for n in wlist:
            if selector['windowtitle'] == n[0]:
                hn.add(n[1])  # 添加窗口索引到集合里
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByWindowTitleRe(self, selector, wlist):
        hn = set()
        for n in wlist:
            if re.match(selector['windowtitle_re'], n[0]):
                hn.add(n[1])  # 添加窗口索引到集合里
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindow(self, selector):

        # 目前来说,如下处理,以后添加更多的参数后需修改代码逻辑
        argunums = 0
        if 'bundleid' in selector:
            argunums += 1
        if 'appname' in selector:
            argunums += 1
        if 'appname_re' in selector:
            argunums += 1
        if argunums == 0:
            raise ValueError("Expect bundleid or appname, got none")
        elif argunums != 1:
            raise ValueError(
                "Too many arguments, only need bundleid or appname or appname_re"
            )

        winlist = self.EnumWindows(selector)

        handleSetList = []
        if 'windowtitle' in selector:
            handleSetList.append(
                self.ConnectWindowsByWindowTitle(selector, winlist))
        if 'windowindex' in selector:
            handleSetList.append(set([selector['windowindex']]))
        if "windowtitle_re" in selector:
            handleSetList.append(
                self.ConnectWindowsByWindowTitleRe(selector, winlist))

        while -1 in handleSetList:
            handleSetList.remove(-1)  # 有些参数没有提供会返回-1.把所有的-1去掉

        if len(handleSetList) == 0:  # 三种方法都找不到窗口
            raise InvalidSurfaceException(
                selector, "Can't find any applications by the given parameter")

        handleSet = reduce(operator.__and__,
                           handleSetList)  # 提供了多个参数来确定唯一一个窗口,所以要做交集,取得唯一匹配的窗口

        if len(handleSet) == 0:
            raise InvalidSurfaceException(
                selector, "Can't find any applications by the given parameter")
        elif len(handleSet) != 1:
            raise NonuniqueSurfaceException(selector)
        else:
            hn = handleSet.pop()  # 取得该窗口的索引
            w = self.app.windows()
            if len(w) <= hn:
                raise IndexError(
                    "Unable to find the specified window through the index, you may have closed the specified window during the run"
                )
            self.root = self.app.windows()[hn]
            self.SetForeground()
            return True

    def run(self):
        self.reactor = StdRpcReactor()
        self.reactor.register('Dump', self.Dump)
        self.reactor.register('GetSDKVersion', self.GetSDKVersion)
        self.reactor.register('GetDebugProfilingData',
                              self.GetDebugProfilingData)
        self.reactor.register('GetScreenSize', self.GetScreenSize)
        self.reactor.register('Screenshot', self.Screenshot)
        self.reactor.register('Click', self.Click)
        self.reactor.register('Swipe', self.Swipe)
        self.reactor.register('LongClick', self.LongClick)
        self.reactor.register('SetForeground', self.SetForeground)
        self.reactor.register('ConnectWindow', self.ConnectWindow)
        self.reactor.register('Scroll', self.Scroll)
        self.reactor.register('RClick', self.RClick)
        self.reactor.register('DoubleClick', self.DoubleClick)
        self.reactor.register('KeyEvent', self.KeyEvent)
        transport = TcpSocket()
        transport.bind(self.addr)
        self.rpc = StdRpcEndpointController(transport, self.reactor)
        if self.running is False:
            self.running = True
            self.rpc.serve_forever()
示例#8
0
class PocoSDKWindows(object):
    def __init__(self, addr=DEFAULT_ADDR):
        self.reactor = StdRpcReactor()
        self.reactor.register('Dump', self.Dump)
        self.reactor.register('SetText', self.SetText)
        self.reactor.register('GetSDKVersion', self.GetSDKVersion)
        self.reactor.register('GetDebugProfilingData',
                              self.GetDebugProfilingData)
        self.reactor.register('GetScreenSize', self.GetScreenSize)
        self.reactor.register('Screenshot', self.Screenshot)
        self.reactor.register('Click', self.Click)
        self.reactor.register('Swipe', self.Swipe)
        self.reactor.register('LongClick', self.LongClick)
        self.reactor.register('KeyEvent', self.KeyEvent)
        self.reactor.register('SetForeground', self.SetForeground)
        self.reactor.register('ConnectWindow', self.ConnectWindow)

        transport = TcpSocket()
        transport.bind(addr)
        self.rpc = StdRpcEndpointController(transport, self.reactor)

        self.running = False
        UIAuto.OPERATION_WAIT_TIME = 0.1  # make operation faster
        self.root = None

    def Dump(self, _):
        res = WindowsUIDumper(self.root).dumpHierarchy()
        return res

    def SetText(self, id, val2):
        control = UIAuto.ControlFromHandle(id)
        if not control or not isinstance(val2, string_types):
            raise UnableToSetAttributeException("text", control)
        else:
            control.SetValue(val2)

    def GetSDKVersion(self):
        return '0.0.1'

    def GetDebugProfilingData(self):
        return {}

    def GetScreenSize(self):
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        return [Width, Height]

    def JudgeSize(self):
        self.SetForeground()  # 先打开窗口再获取大小,否则最小化的窗口获取到的大小会为0
        size = self.GetScreenSize()
        if size[0] == 0 or size[1] == 0:
            raise InvalidSurfaceException(
                self,
                "You may have minimized your window or the window is too small!"
            )

    def Screenshot(self, width):
        self.JudgeSize()
        self.root.ToBitmap().ToFile('Screenshot.bmp')
        f = open(r'Screenshot.bmp', 'rb')
        deflated = zlib.compress(f.read())
        ls_f = base64.b64encode(deflated)
        f.close()
        return [ls_f, "bmp.deflate"]

        # self.root.ToBitmap().ToFile('Screenshot.bmp')
        # f = open(r'Screenshot.bmp', 'rb')
        # ls_f = base64.b64encode(f.read())
        # f.close()
        # return [ls_f, "bmp"]

    def Click(self, x, y):
        self.JudgeSize()
        self.root.Click(x, y)
        return True

    def Swipe(self, x1, y1, x2, y2, duration):
        self.JudgeSize()
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x1 = Left + Width * x1
        y1 = Top + Height * y1
        x2 = Left + Width * x2
        y2 = Top + Height * y2
        UIAuto.MAX_MOVE_SECOND = duration * 10  # 同步到跟UIAutomation库的时间设定一样
        UIAuto.DragDrop(int(x1), int(y1), int(x2), int(y2))
        return True

    def LongClick(self, x, y, duration):
        self.JudgeSize()
        Left = self.root.BoundingRectangle[0]
        Top = self.root.BoundingRectangle[1]
        Width = self.root.BoundingRectangle[2] - self.root.BoundingRectangle[0]
        Height = self.root.BoundingRectangle[3] - self.root.BoundingRectangle[1]
        x = Left + Width * x
        y = Top + Height * y
        UIAuto.MAX_MOVE_SECOND = duration * 10
        UIAuto.DragDrop(int(x), int(y), int(x), int(y))
        return True

    def KeyEvent(self, keycode):
        self.JudgeSize()
        UIAuto.SendKeys(keycode)
        return True

    def SetForeground(self):
        win32gui.ShowWindow(self.root.Handle,
                            win32con.SW_SHOWNORMAL)  # 先把窗口取消最小化
        UIAuto.Win32API.SetForegroundWindow(
            self.root.Handle)  # 再把窗口设为前台,方便点击和截图
        return True

    def EnumWindows(self):
        hWndList = []

        def foo(hwnd, mouse):
            if win32gui.IsWindow(hwnd):
                hWndList.append(hwnd)

        win32gui.EnumWindows(foo, 0)
        return hWndList

    def ConnectWindowsByTitle(self, title):
        hn = set()
        hWndList = self.EnumWindows()
        for handle in hWndList:
            title_temp = win32gui.GetWindowText(handle)
            if PY2:
                title_temp = title_temp.decode(
                    "gbk")  # py2要解码成GBK,WindowsAPI中文返回的一般都是GBK
            if title == title_temp:
                hn.add(handle)
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByTitleRe(self, title_re):
        hn = set()
        hWndList = self.EnumWindows()
        for handle in hWndList:
            title = win32gui.GetWindowText(handle)
            if PY2:
                title = title.decode("gbk")
            if re.match(title_re, title):
                hn.add(handle)
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindowsByHandle(self, handle):
        hn = set()
        hWndList = self.EnumWindows()
        for handle_temp in hWndList:
            if int(handle_temp) == int(handle):
                hn.add(handle)
                break
        if len(hn) == 0:
            return -1
        return hn

    def ConnectWindow(self, selector):

        # 目前来说,如下处理,以后添加更多的参数后需修改代码逻辑
        argunums = 0
        if 'handle' in selector:
            argunums += 1
        if 'title' in selector:
            argunums += 1
        if 'title_re' in selector:
            argunums += 1

        if argunums == 0:
            raise ValueError("Expect handle or title, got none")
        elif argunums != 1:
            raise ValueError(
                "Too many arguments, only need handle or title or title_re")

        handleSetList = []
        if 'title' in selector:
            handleSetList.append(self.ConnectWindowsByTitle(selector['title']))
        if 'handle' in selector:
            handleSetList.append(
                self.ConnectWindowsByHandle(selector['handle']))
        if "title_re" in selector:
            handleSetList.append(
                self.ConnectWindowsByTitleRe(selector['title_re']))

        while -1 in handleSetList:
            handleSetList.remove(-1)

        if len(handleSetList) is 0:
            raise InvalidSurfaceException(
                selector, "Can't find any windows by the given parameter")

        handleSet = reduce(operator.__and__, handleSetList)

        if len(handleSet) == 0:
            raise InvalidSurfaceException(
                selector, "Can't find any windows by the given parameter")
        elif len(handleSet) != 1:
            raise NonuniqueSurfaceException(selector)
        else:
            hn = handleSet.pop()
            self.root = UIAuto.ControlFromHandle(hn)
            if self.root is None:
                raise InvalidSurfaceException(
                    selector, "Can't find any windows by the given parameter")

    def run(self):
        if self.running is False:
            self.running = True
            self.rpc.serve_forever()