{"id":13620372,"url":"https://github.com/yinkaisheng/Python-UIAutomation-for-Windows","last_synced_at":"2025-04-14T19:31:57.452Z","repository":{"id":34088668,"uuid":"37912001","full_name":"yinkaisheng/Python-UIAutomation-for-Windows","owner":"yinkaisheng","description":"🐍Python 3 wrapper of Microsoft UIAutomation. Support UIAutomation for MFC, WindowsForm, WPF, Modern UI(Metro UI), Qt, IE, Firefox, Chrome ...","archived":false,"fork":false,"pushed_at":"2025-04-08T07:08:48.000Z","size":12435,"stargazers_count":2808,"open_issues_count":150,"forks_count":516,"subscribers_count":89,"default_branch":"master","last_synced_at":"2025-04-09T02:11:11.178Z","etag":null,"topics":["automation","gui","python","uiautomation","windows"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yinkaisheng.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-06-23T10:17:30.000Z","updated_at":"2025-04-08T22:41:51.000Z","dependencies_parsed_at":"2022-07-12T12:04:26.643Z","dependency_job_id":"d63831dc-71ef-4bba-acd5-7ecfde41775d","html_url":"https://github.com/yinkaisheng/Python-UIAutomation-for-Windows","commit_stats":{"total_commits":411,"total_committers":17,"mean_commits":"24.176470588235293","dds":"0.22384428223844277","last_synced_commit":"bb93e0046bbc822f49bc3e544e171be4dfbb232a"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yinkaisheng%2FPython-UIAutomation-for-Windows","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yinkaisheng%2FPython-UIAutomation-for-Windows/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yinkaisheng%2FPython-UIAutomation-for-Windows/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yinkaisheng%2FPython-UIAutomation-for-Windows/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yinkaisheng","download_url":"https://codeload.github.com/yinkaisheng/Python-UIAutomation-for-Windows/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248945980,"owners_count":21187421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","gui","python","uiautomation","windows"],"created_at":"2024-08-01T21:00:55.083Z","updated_at":"2025-04-14T19:31:57.445Z","avatar_url":"https://github.com/yinkaisheng.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# The uiautomation module\n\n:cn:[中文版介绍](https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/blob/master/readme_cn.md)\n\nDo not use 3.7.6 and 3.8.1, comtypes doesn't work in these two versions. Install an earlier version or the latest version.\nhttps://github.com/enthought/comtypes/issues/202\n\n\nThis module is for [UIAutomation](https://docs.microsoft.com/en-us/windows/win32/winauto/ui-automation-specification) on Windows(Windows XP with SP3, Windows Vista, Windows 7 and Windows 8/8.1/10).\nIt supports UIAutomation for the applications which implmented UIAutomation Provider, such as MFC, Windows Form, WPF, Modern UI(Metro UI), Qt(Partly), Firefox(**version\u003c=56 or \u003e=60**), Chrome and Electron based apps(require **--force-renderer-accessibility** command line parameter).\n\nI developed it in my spare time and for my personal use.\n\nuiautomation is shared under the Apache Licence 2.0.  \nThis means that the code can be freely copied and distributed, and costs nothing to use.\n\nuiautomation1.x supports py2, py3 and doesn't depend on any third package.\n\nuiautomation2.0+ only supports py3 and depends on comtypes and typing(Python3.5+ built-in).  \nuiautomation2.0+ is not backward compatible with early versions. See [API changes](https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/blob/master/API%20changes.txt).\n\nYou can install uiautomation by \"pip install uiautomation\". After installation, a automation.py that calls uiautomation will be in 'C:\\PythonXX\\Scripts\\'.\nYou use this script to traverse UI controls.\n\nRun 'C:\\PythonXX\\Scripts\\automation.py -h' for help.  \nRun demos\\automation_calculator.py to see a simple demo.\n\nOn Windows 8/8.1, to automate a Metro App, the app must be in foreground. If a Metro App was switched to background, uiautomation can't fetch its controls' information.\n\nBy the way, You should run python as **administrator**. Otherwise uiautomation may fail to enumerate controls or get controls' information on Windows 7 or higher.\n\n[Requirements:](https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/nn-uiautomationclient-iuiautomation)\n\nMicrosoft UIAutomation Minimum supported client:\nWindows 7, Windows Vista with SP2 and Platform Update for Windows Vista, Windows XP with SP3 and Platform Update for Windows Vista [desktop apps only]\n\nMicrosoft UIAutomation Minimum supported server:\nWindows Server 2008 R2, Windows Server 2008 with SP2 and Platform Update for Windows Server 2008, Windows Server 2003 with SP2 and Platform Update for Windows Server 2008 [desktop apps only]\n\nC++ dll source code: [UIAutomationClient](https://github.com/yinkaisheng/UIAutomationClient)\n\n---\n\nHow to use uiautomation?\nrun '**automation.py -h**'\n![help](images/uiautomation-h.png)\n\nUnderstand the arguments of automation.py, and try the following examples:  \n**automation.py -t 0 -n**, print current active window's controls, show fullname  \n**automation.py -r -d 1 -t 0**, print desktop(the root of control tree) and it's children(top level windows)  \n\n![top level windows](images/automation_toplevels.png)\n\nautomation.py prints the properties of controls and the patterns they support. \nYou use controls and patterns to get controls' information and operate them.\n\nA control should support some patterns or conditionally supports some patterns according to its control type.\n\n![patterns](images/control_pattern.png)\n\nRefer [Control Pattern Mapping for UI Automation Clients](https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-controlpatternmapping) for the complete control pattern table.\n\n\nuiautomation searches controls from the control tree based on the controls' properties you supply.\n\nSuppose the control tree is  \n\nroot(Name='Desktop', Depth=0)  \n　　window1(Depth=1)  \n　　　　control1-001(Depth=2)  \n　　　　control1-...(Depth=2)  \n　　　　...  \n　　　　control1-100(Depth=2)  \n　　window2(Name='window2', Depth=1)  \n　　　　control2-1(Depth=2)  \n　　　　　　control2-1-001(Depth=3)  \n　　　　　　control2-1-...(Depth=3)  \n　　　　　　...  \n　　　　　　control2-1-100(Depth=3)  \n　　　　control2-2(Depth=2)  \n　　　　control2-3(Depth=2)  \n　　　　control2-4(Name='2-4', Depth=2)  \n　　　　　　editcontrol(Name='myedit1', Depth=3)  \n　　　　　　**editcontrol(Name='myedit2', Depth=3)**  \n\nIf you want to find the EditControl whose name is 'myedit2' and type 'hi',  \nyou can write the following code:\n\n```python\nuiautomation.EditControl(searchDepth=3, Name='myedit2').SendKeys('hi')\n```\n\nBut this code run slowly because there are more than 200 controls before myedit2 in the control tree.  \nuiautomation has to traverse more than 200 controls before finding myedit2 if search from root in 3 search depth.  \nThe better is:\n\n```python\nwindow2 = uiautomation.WindowControl(searchDepth=1, Name='window2') # search 2 times\nsub = window2.Control(searchDepth=1, Name='2-4')    # search 4 times\nedit = sub.EditControl(searchDepth=1, Name='myedit2')   # search 2 times\nedit.SendKeys('hi')\n```\n\nThis code run faster than the former.  \nYou can also combine the four lines code into one line.  \n\n```python\nuiautomation.WindowControl(searchDepth=1, Name='window2').Control(searchDepth=1, Name='2-4').EditControl(searchDepth=1, Name='myedit2').SendKeys('hi')\n```\n\nNow let's take notepad.exe for an example.  \nLuanch notepad.exe and run automation.py -t 3, then swith to Notepad and wait for 5 seconds  \n\nautomation.py will print the controls of Notepad and save them to @AutomationLog.txt:  \n\nControlType: PaneControl    ClassName: #32769    Name: 桌面    Depth: 0    **(Desktop window, the root control)**  \n　　ControlType: WindowControl    ClassName: Notepad    Depth: 1    **(Top level window)**  \n　　　　ControlType: EditControl    ClassName: Edit    Depth: 2  \n　　　　　　ControlType: ScrollBarControl    ClassName:     Depth: 3  \n　　　　　　　　ControlType: ButtonControl    ClassName:     Depth: 4  \n　　　　　　　　ControlType: ButtonControl    ClassName:     Depth: 4  \n　　　　　　ControlType: ThumbControl    ClassName:     Depth: 3  \n　　　　ControlType: TitleBarControl    ClassName:     Depth: 2  \n　　　　　　ControlType: MenuBarControl    ClassName:     Depth: 3  \n　　　　　　　　ControlType: MenuItemControl    ClassName:     Depth: 4  \n　　　　　　ControlType: ButtonControl    ClassName:     Name: 最小化    Depth: 3    **(Minimize Button)**  \n　　　　　　ControlType: ButtonControl    ClassName:     Name: 最大化    Depth: 3    **(Maximize Button)**  \n　　　　　　ControlType: ButtonControl    ClassName:     Name: 关闭    Depth: 3    **(Close Button)**  \n...  \n\nRun the following code\n\n```python\n# -*- coding: utf-8 -*-\n# this script only works with Win32 notepad.exe\n# if you notepad.exe is the Windows Store version in Windows 11, you need to uninstall it.\nimport subprocess\nimport uiautomation as auto\n\ndef test():\n    print(auto.GetRootControl())\n    subprocess.Popen('notepad.exe', shell=True)\n    # you should find the top level window first, then find children from the top level window\n    notepadWindow = auto.WindowControl(searchDepth=1, ClassName='Notepad')\n    if not notepadWindow.Exists(3, 1):\n        print('Can not find Notepad window')\n        exit(0)\n    print(notepadWindow)\n    notepadWindow.SetTopmost(True)\n    # find the first EditControl in notepadWindow\n    edit = notepadWindow.EditControl()\n    # usually you don't need to catch exceptions\n    # but if you meet a COMError exception, put it in a try block\n    try:\n        # use value pattern to get or set value\n        edit.GetValuePattern().SetValue('Hello')# or edit.GetPattern(auto.PatternId.ValuePattern)\n    except auto.comtypes.COMError as ex:\n        # maybe you don't run python as administrator\n        # or the control doesn't have a implementation for the pattern method(I have no solution for this)\n        pass\n    edit.Click() # this step is optional, but some edits need it\n    edit.SendKeys('{Ctrl}{End}{Enter}World')\n    print('current text:', edit.GetValuePattern().Value)\n    # find the first TitleBarControl in notepadWindow,\n    # then find the second ButtonControl in TitleBarControl, which is the Maximize button\n    maximizeButton = notepadWindow.TitleBarControl().ButtonControl(foundIndex=2)\n    maximizeButton.Click(waitTime=2)\n    maximizeButton.Click()\n    # find the first button in notepadWindow whose Name is '关闭' or 'Close', the close button\n    # the relative depth from Close button to Notepad window is 2\n    notepadWindow.ButtonControl(searchDepth=2, Compare=lambda c, d: c.Name in ['Close', '关闭']).Click()\n    # then notepad will popup a window askes you to save or not, press hotkey alt+n not to save\n    auto.SendKeys('{Alt}n')\n\nif __name__ == '__main__':\n    test()\n```\n\nauto.GetRootControl() returns the root control(the Desktop window)  \nauto.WindowControl(searchDepth=1, ClassName='Notepad') creates a WindowControl, the parameters specify how to search the control  \nthe following parameters can be used  \nsearchFromControl = None,   \nsearchDepth = 0xFFFFFFFF,   \nsearchInterval = SEARCH_INTERVAL,   \nfoundIndex = 1  \nName  \nSubName  \nRegexName  \nClassName  \nAutomationId  \nControlType  \nDepth  \nCompare  \n\nSee Control.\\_\\_init\\_\\_ for the comments of the parameters.  \nSee scripts in folder **demos** for more examples.  \n\nControl.Element returns the low level COM object [IUIAutomationElement](https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/nn-uiautomationclient-iuiautomationelement),\nAlmost all methods and properties of Control are implemented via IUIAutomationElement COM API and Win32 API.\nwhen calling a control's method or property that indirectly calls Control.Element and Control.Element is None, \nuiautomation starts to search the control by the properties you supply.\nuiautomation will raise a LookupError exception if it can't find the control in uiautomation.TIME_OUT_SECOND(default 10 seconds).\nControl.Element will has a valid value if uiautomation finds the control successfully.\nYou can use Control.Exists(maxSearchSeconds, searchIntervalSeconds) to check whether a control Exists, this function doesn't raise any exception.\nCall Control.Refind or Control.Exists to make Control.Element invalid again and uiautomation will starts a new search.  \n\nFor example:  \n```python\n#!python3\n# -*- coding:utf-8 -*-\n# this script only works with Win32 notepad.exe\n# if you notepad.exe is the Windows Store version in Windows 11, you need to uninstall it.\nimport subprocess\nimport uiautomation as auto\nauto.uiautomation.SetGlobalSearchTimeout(15)  # set new timeout 15\n\n\ndef main():\n    subprocess.Popen('notepad.exe', shell=True)\n    window = auto.WindowControl(searchDepth=1, ClassName='Notepad')\n    # or use Compare for custom search\n    # window = auto.WindowControl(searchDepth=1, ClassName='Notepad', Compare=lambda control,depth:control.ProcessId==100)\n    edit = window.EditControl()\n    # when calling SendKeys, uiautomation starts to search window and edit in 15 seconds\n    # because SendKeys indirectly calls Control.Element and Control.Element is None\n    # if window and edit don't exist in 15 seconds, a LookupError exception will be raised\n    try:\n        edit.SendKeys('first notepad')\n    except LookupError as ex:\n        print(\"The first notepad doesn't exist in 15 seconds\")\n        return\n    # the second call to SendKeys doesn't trigger a search, the previous call makes sure that Control.Element is valid\n    edit.SendKeys('{Ctrl}a{Del}')\n    window.GetWindowPattern().Close()  # close the first Notepad, window and edit become invalid even though their Elements have a value\n\n    subprocess.Popen('notepad.exe')  # run second Notepad\n    window.Refind()  # need to refind window, trigger a new search\n    edit.Refind()  # need to refind edit, trigger a new search\n    edit.SendKeys('second notepad')\n    edit.SendKeys('{Ctrl}a{Del}')\n    window.GetWindowPattern().Close()  # close the second Notepad, window and edit become invalid again\n\n    subprocess.Popen('notepad.exe')  # run third Notepad\n    if window.Exists(3, 1): # trigger a new search\n        if edit.Exists(3):  # trigger a new search\n            edit.SendKeys('third notepad')  # edit.Exists makes sure that edit.Element has a valid value now\n            edit.SendKeys('{Ctrl}a{Del}')\n        window.GetWindowPattern().Close()\n    else:\n        print(\"The third notepad doesn't exist in 3 seconds\")\n\n\nif __name__ == '__main__':\n    main()\n```\n---\n\n**If automation.py can't print the controls you see.\nMaybe the controls were built by DirectUI(or CustomControl), not UI Frameworks supplied by Microsoft.\nIn order to support UIAutomation, an UI Framework must implement [UI Automation Provider](https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-providersoverview).**\n\nA Microsoft UI Automation provider is a software object that exposes an element of an application's UI so that accessibility client applications can retrieve information about the element and invoke its functionality. In general, each control or other distinct element in a UI has a provider.\n\nMicrosoft includes a provider for each of the standard controls that are supplied with Microsoft Win32, Windows Forms, and Windows Presentation Foundation (WPF). This means that the standard controls are automatically exposed to UI Automation clients; you do not need to implement any accessibility interfaces for the standard controls.\n\nIf your application includes any custom controls, you need to implement UI Automation providers for those controls to make them accessible to accessibility client applications. You also need to implement providers for any third party controls that do not include a provider. You implement a provider by implementing UI Automation provider interfaces and control pattern interfaces.\n\n---\n\nAnother UI tool [Inspect.exe](https://docs.microsoft.com/en-us/windows/win32/winauto/inspect-objects) supplied by Microsoft can also be used to traverse the UI elements. It has an UI interface while my script shows UI elements in terminal.\nBut I found that my script is more convenient sometimes.\n\n![Inspect](https://docs.microsoft.com/en-us/windows/desktop/WinAuto/images/inspect.png)\n\n---\n\nSome screenshots:\n\nBatch rename pdf bookmark\n![bookmark](images/rename_pdf_bookmark.gif)\n\n\nMicrosoft Word        \n![Word](images/word.png)\n\n\nWireshark 3.0 (Qt 5.12)\n![Wireshark](images/wireshark3.0.gif)\n\n\nGitHub Desktop (Electron App)\n![GitHubDesktop](images/github_desktop.png)\n\n\nPretty print dir        \n![PrettyPrint](images/pretty_print_dir.png)\n\n\nDonate：                                \n![微信](images/yks-wx.png) ![支付宝](images/yks-zfb.png)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyinkaisheng%2FPython-UIAutomation-for-Windows","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyinkaisheng%2FPython-UIAutomation-for-Windows","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyinkaisheng%2FPython-UIAutomation-for-Windows/lists"}