#!python3
# -*- coding: utf-8 -*-
"""
uiautomation for Python 3.
Author: yinkaisheng@live.com
Source: https://github.com/yinkaisheng/Python-UIAutomation-for-Windows
This module is for UIAutomation on Windows(Windows XP with SP3, Windows Vista and Windows 7/8/8.1/10).
It supports UIAutomation for the applications which implmented IUIAutomation, such as MFC, Windows Form, WPF, Modern UI(Metro UI), Qt, Firefox and Chrome.
Run 'automation.py -h' for help.
uiautomation is shared under the Apache Licene 2.0.
This means that the code can be freely copied and distributed, and costs nothing to use.
"""
import os
import sys
import time
import datetime
import re
import threading
import ctypes
import ctypes.wintypes
import comtypes #need pip install comtypes
import comtypes.client
from typing import (Any, Callable, Dict, List, Iterable, Tuple) # need pip install typing for Python3.4 or lower
TreeNode = Any
# print('uia done')
AUTHOR_MAIL = 'yinkaisheng@live.com'
METRO_WINDOW_CLASS_NAME = 'Windows.UI.Core.CoreWindow' # for Windows 8 and 8.1
SEARCH_INTERVAL = 0.5 # search control interval seconds
MAX_MOVE_SECOND = 1 # simulate mouse move or drag max seconds
TIME_OUT_SECOND = 10
OPERATION_WAIT_TIME = 0.1
MAX_PATH = 260
DEBUG_SEARCH_TIME = False
DEBUG_EXIST_DISAPPEAR = False
S_OK = 0
IsNT6orHigher = os.sys.getwindowsversion().major >= 6
ProcessTime = time.perf_counter #this returns nearly 0 when first call it if python version <= 3.6
ProcessTime() # need to call it once if python version <= 3.6
class _AutomationClient:
_instance = None
@classmethod
def instance(cls) -> '_AutomationClient':
"""Singleton instance (this prevents com creation on import)."""
if cls._instance is None:
cls._instance = cls()
return cls._instance
def __init__(self):
tryCount = 3
for retry in range(tryCount):
try:
self.UIAutomationCore = comtypes.client.GetModule("UIAutomationCore.dll")
self.IUIAutomation = comtypes.client.CreateObject("{ff48dba4-60ef-4201-aa87-54103eef594e}", interface=self.UIAutomationCore.IUIAutomation)
self.ViewWalker = self.IUIAutomation.RawViewWalker
#self.ViewWalker = self.IUIAutomation.ControlViewWalker
break
except Exception as ex:
if retry + 1 == tryCount:
Logger.WriteLine('Can not load UIAutomationCore.dll.\nYou may need to install Windows Update KB971513.\nhttps://github.com/yinkaisheng/WindowsUpdateKB971513ForIUIAutomation', ConsoleColor.Yellow)
raise ex
#Windows dll
ctypes.windll.user32.GetClipboardData.restype = ctypes.c_void_p
ctypes.windll.user32.GetWindowDC.restype = ctypes.c_void_p
ctypes.windll.user32.OpenDesktopW.restype = ctypes.c_void_p
ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_p
ctypes.windll.user32.SendMessageW.restype = ctypes.wintypes.LONG
ctypes.windll.user32.GetForegroundWindow.restype = ctypes.c_void_p
ctypes.windll.user32.GetWindowLongW.restype = ctypes.wintypes.LONG
ctypes.windll.kernel32.GlobalLock.restype = ctypes.c_void_p
ctypes.windll.kernel32.GlobalAlloc.restype = ctypes.c_void_p
ctypes.windll.kernel32.GetStdHandle.restype = ctypes.c_void_p
ctypes.windll.kernel32.OpenProcess.restype = ctypes.c_void_p
ctypes.windll.kernel32.CreateToolhelp32Snapshot.restype = ctypes.c_void_p
SetDpiAwareness(dpiAwarenessPerMonitor=True)
class _DllClient:
_instance = None
@classmethod
def instance(cls) -> '_DllClient':
"""Singleton instance (this prevents com creation on import)."""
if cls._instance is None:
cls._instance = cls()
return cls._instance
def __init__(self):
binPath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
os.environ["PATH"] = binPath + os.pathsep + os.environ["PATH"]
load = False
if sys.version >= '3.8':
os.add_dll_directory(binPath)
if sys.maxsize > 0xFFFFFFFF:
try:
self.dll = ctypes.cdll.UIAutomationClient_VC140_X64
load = True
except Exception as ex:
print(ex)
else:
try:
self.dll = ctypes.cdll.UIAutomationClient_VC140_X86
load = True
except Exception as ex:
print(ex)
if load:
self.dll.BitmapCreate.restype = ctypes.c_size_t
self.dll.BitmapFromWindow.argtypes = (ctypes.c_size_t, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int)
self.dll.BitmapFromWindow.restype = ctypes.c_size_t
self.dll.BitmapFromFile.argtypes = (ctypes.c_wchar_p, )
self.dll.BitmapFromFile.restype = ctypes.c_size_t
self.dll.BitmapToFile.argtypes = (ctypes.c_size_t, ctypes.c_wchar_p, ctypes.c_wchar_p)
self.dll.BitmapRelease.argtypes = (ctypes.c_size_t, )
self.dll.BitmapGetWidthAndHeight.argtypes = (ctypes.c_size_t, )
self.dll.BitmapGetPixel.argtypes = (ctypes.c_size_t, ctypes.c_int, ctypes.c_int)
self.dll.BitmapSetPixel.argtypes = (ctypes.c_size_t, ctypes.c_int, ctypes.c_int, ctypes.c_uint)
self.dll.Initialize()
else:
self.dll = None
Logger.WriteLine('Can not load dll.\nFunctionalities related to Bitmap are not available.\nYou may need to install Microsoft Visual C++ 2015 Redistributable Package.', ConsoleColor.Yellow)
def __del__(self):
if self.dll:
self.dll.Uninitialize()
class ControlType:
"""
ControlType from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/WinAuto/uiauto-controltype-ids
"""
AppBarControl = 50040
ButtonControl = 50000
CalendarControl = 50001
CheckBoxControl = 50002
ComboBoxControl = 50003
CustomControl = 50025
DataGridControl = 50028
DataItemControl = 50029
DocumentControl = 50030
EditControl = 50004
GroupControl = 50026
HeaderControl = 50034
HeaderItemControl = 50035
HyperlinkControl = 50005
ImageControl = 50006
ListControl = 50008
ListItemControl = 50007
MenuBarControl = 50010
MenuControl = 50009
MenuItemControl = 50011
PaneControl = 50033
ProgressBarControl = 50012
RadioButtonControl = 50013
ScrollBarControl = 50014
SemanticZoomControl = 50039
SeparatorControl = 50038
SliderControl = 50015
SpinnerControl = 50016
SplitButtonControl = 50031
StatusBarControl = 50017
TabControl = 50018
TabItemControl = 50019
TableControl = 50036
TextControl = 50020
ThumbControl = 50027
TitleBarControl = 50037
ToolBarControl = 50021
ToolTipControl = 50022
TreeControl = 50023
TreeItemControl = 50024
WindowControl = 50032
ControlTypeNames = {
ControlType.AppBarControl: 'AppBarControl',
ControlType.ButtonControl: 'ButtonControl',
ControlType.CalendarControl: 'CalendarControl',
ControlType.CheckBoxControl: 'CheckBoxControl',
ControlType.ComboBoxControl: 'ComboBoxControl',
ControlType.CustomControl: 'CustomControl',
ControlType.DataGridControl: 'DataGridControl',
ControlType.DataItemControl: 'DataItemControl',
ControlType.DocumentControl: 'DocumentControl',
ControlType.EditControl: 'EditControl',
ControlType.GroupControl: 'GroupControl',
ControlType.HeaderControl: 'HeaderControl',
ControlType.HeaderItemControl: 'HeaderItemControl',
ControlType.HyperlinkControl: 'HyperlinkControl',
ControlType.ImageControl: 'ImageControl',
ControlType.ListControl: 'ListControl',
ControlType.ListItemControl: 'ListItemControl',
ControlType.MenuBarControl: 'MenuBarControl',
ControlType.MenuControl: 'MenuControl',
ControlType.MenuItemControl: 'MenuItemControl',
ControlType.PaneControl: 'PaneControl',
ControlType.ProgressBarControl: 'ProgressBarControl',
ControlType.RadioButtonControl: 'RadioButtonControl',
ControlType.ScrollBarControl: 'ScrollBarControl',
ControlType.SemanticZoomControl: 'SemanticZoomControl',
ControlType.SeparatorControl: 'SeparatorControl',
ControlType.SliderControl: 'SliderControl',
ControlType.SpinnerControl: 'SpinnerControl',
ControlType.SplitButtonControl: 'SplitButtonControl',
ControlType.StatusBarControl: 'StatusBarControl',
ControlType.TabControl: 'TabControl',
ControlType.TabItemControl: 'TabItemControl',
ControlType.TableControl: 'TableControl',
ControlType.TextControl: 'TextControl',
ControlType.ThumbControl: 'ThumbControl',
ControlType.TitleBarControl: 'TitleBarControl',
ControlType.ToolBarControl: 'ToolBarControl',
ControlType.ToolTipControl: 'ToolTipControl',
ControlType.TreeControl: 'TreeControl',
ControlType.TreeItemControl: 'TreeItemControl',
ControlType.WindowControl: 'WindowControl',
}
class PatternId:
"""
PatternId from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/WinAuto/uiauto-controlpattern-ids
"""
AnnotationPattern = 10023
CustomNavigationPattern = 10033
DockPattern = 10011
DragPattern = 10030
DropTargetPattern = 10031
ExpandCollapsePattern = 10005
GridItemPattern = 10007
GridPattern = 10006
InvokePattern = 10000
ItemContainerPattern = 10019
LegacyIAccessiblePattern = 10018
MultipleViewPattern = 10008
ObjectModelPattern = 10022
RangeValuePattern = 10003
ScrollItemPattern = 10017
ScrollPattern = 10004
SelectionItemPattern = 10010
SelectionPattern = 10001
SpreadsheetItemPattern = 10027
SpreadsheetPattern = 10026
StylesPattern = 10025
SynchronizedInputPattern = 10021
TableItemPattern = 10013
TablePattern = 10012
TextChildPattern = 10029
TextEditPattern = 10032
TextPattern = 10014
TextPattern2 = 10024
TogglePattern = 10015
TransformPattern = 10016
TransformPattern2 = 10028
ValuePattern = 10002
VirtualizedItemPattern = 10020
WindowPattern = 10009
PatternIdNames = {
PatternId.AnnotationPattern: 'AnnotationPattern',
PatternId.CustomNavigationPattern: 'CustomNavigationPattern',
PatternId.DockPattern: 'DockPattern',
PatternId.DragPattern: 'DragPattern',
PatternId.DropTargetPattern: 'DropTargetPattern',
PatternId.ExpandCollapsePattern: 'ExpandCollapsePattern',
PatternId.GridItemPattern: 'GridItemPattern',
PatternId.GridPattern: 'GridPattern',
PatternId.InvokePattern: 'InvokePattern',
PatternId.ItemContainerPattern: 'ItemContainerPattern',
PatternId.LegacyIAccessiblePattern: 'LegacyIAccessiblePattern',
PatternId.MultipleViewPattern: 'MultipleViewPattern',
PatternId.ObjectModelPattern: 'ObjectModelPattern',
PatternId.RangeValuePattern: 'RangeValuePattern',
PatternId.ScrollItemPattern: 'ScrollItemPattern',
PatternId.ScrollPattern: 'ScrollPattern',
PatternId.SelectionItemPattern: 'SelectionItemPattern',
PatternId.SelectionPattern: 'SelectionPattern',
PatternId.SpreadsheetItemPattern: 'SpreadsheetItemPattern',
PatternId.SpreadsheetPattern: 'SpreadsheetPattern',
PatternId.StylesPattern: 'StylesPattern',
PatternId.SynchronizedInputPattern: 'SynchronizedInputPattern',
PatternId.TableItemPattern: 'TableItemPattern',
PatternId.TablePattern: 'TablePattern',
PatternId.TextChildPattern: 'TextChildPattern',
PatternId.TextEditPattern: 'TextEditPattern',
PatternId.TextPattern: 'TextPattern',
PatternId.TextPattern2: 'TextPattern2',
PatternId.TogglePattern: 'TogglePattern',
PatternId.TransformPattern: 'TransformPattern',
PatternId.TransformPattern2: 'TransformPattern2',
PatternId.ValuePattern: 'ValuePattern',
PatternId.VirtualizedItemPattern: 'VirtualizedItemPattern',
PatternId.WindowPattern: 'WindowPattern',
}
class PropertyId:
"""
PropertyId from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/WinAuto/uiauto-automation-element-propids
Refer https://docs.microsoft.com/en-us/windows/desktop/WinAuto/uiauto-control-pattern-propids
"""
AcceleratorKeyProperty = 30006
AccessKeyProperty = 30007
AnnotationAnnotationTypeIdProperty = 30113
AnnotationAnnotationTypeNameProperty = 30114
AnnotationAuthorProperty = 30115
AnnotationDateTimeProperty = 30116
AnnotationObjectsProperty = 30156
AnnotationTargetProperty = 30117
AnnotationTypesProperty = 30155
AriaPropertiesProperty = 30102
AriaRoleProperty = 30101
AutomationIdProperty = 30011
BoundingRectangleProperty = 30001
CenterPointProperty = 30165
ClassNameProperty = 30012
ClickablePointProperty = 30014
ControlTypeProperty = 30003
ControllerForProperty = 30104
CultureProperty = 30015
DescribedByProperty = 30105
DockDockPositionProperty = 30069
DragDropEffectProperty = 30139
DragDropEffectsProperty = 30140
DragGrabbedItemsProperty = 30144
DragIsGrabbedProperty = 30138
DropTargetDropTargetEffectProperty = 30142
DropTargetDropTargetEffectsProperty = 30143
ExpandCollapseExpandCollapseStateProperty = 30070
FillColorProperty = 30160
FillTypeProperty = 30162
FlowsFromProperty = 30148
FlowsToProperty = 30106
FrameworkIdProperty = 30024
FullDescriptionProperty = 30159
GridColumnCountProperty = 30063
GridItemColumnProperty = 30065
GridItemColumnSpanProperty = 30067
GridItemContainingGridProperty = 30068
GridItemRowProperty = 30064
GridItemRowSpanProperty = 30066
GridRowCountProperty = 30062
HasKeyboardFocusProperty = 30008
HelpTextProperty = 30013
IsAnnotationPatternAvailableProperty = 30118
IsContentElementProperty = 30017
IsControlElementProperty = 30016
IsCustomNavigationPatternAvailableProperty = 30151
IsDataValidForFormProperty = 30103
IsDockPatternAvailableProperty = 30027
IsDragPatternAvailableProperty = 30137
IsDropTargetPatternAvailableProperty = 30141
IsEnabledProperty = 30010
IsExpandCollapsePatternAvailableProperty = 30028
IsGridItemPatternAvailableProperty = 30029
IsGridPatternAvailableProperty = 30030
IsInvokePatternAvailableProperty = 30031
IsItemContainerPatternAvailableProperty = 30108
IsKeyboardFocusableProperty = 30009
IsLegacyIAccessiblePatternAvailableProperty = 30090
IsMultipleViewPatternAvailableProperty = 30032
IsObjectModelPatternAvailableProperty = 30112
IsOffscreenProperty = 30022
IsPasswordProperty = 30019
IsPeripheralProperty = 30150
IsRangeValuePatternAvailableProperty = 30033
IsRequiredForFormProperty = 30025
IsScrollItemPatternAvailableProperty = 30035
IsScrollPatternAvailableProperty = 30034
IsSelectionItemPatternAvailableProperty = 30036
IsSelectionPattern2AvailableProperty = 30168
IsSelectionPatternAvailableProperty = 30037
IsSpreadsheetItemPatternAvailableProperty = 30132
IsSpreadsheetPatternAvailableProperty = 30128
IsStylesPatternAvailableProperty = 30127
IsSynchronizedInputPatternAvailableProperty = 30110
IsTableItemPatternAvailableProperty = 30039
IsTablePatternAvailableProperty = 30038
IsTextChildPatternAvailableProperty = 30136
IsTextEditPatternAvailableProperty = 30149
IsTextPattern2AvailableProperty = 30119
IsTextPatternAvailableProperty = 30040
IsTogglePatternAvailableProperty = 30041
IsTransformPattern2AvailableProperty = 30134
IsTransformPatternAvailableProperty = 30042
IsValuePatternAvailableProperty = 30043
IsVirtualizedItemPatternAvailableProperty = 30109
IsWindowPatternAvailableProperty = 30044
ItemStatusProperty = 30026
ItemTypeProperty = 30021
LabeledByProperty = 30018
LandmarkTypeProperty = 30157
LegacyIAccessibleChildIdProperty = 30091
LegacyIAccessibleDefaultActionProperty = 30100
LegacyIAccessibleDescriptionProperty = 30094
LegacyIAccessibleHelpProperty = 30097
LegacyIAccessibleKeyboardShortcutProperty = 30098
LegacyIAccessibleNameProperty = 30092
LegacyIAccessibleRoleProperty = 30095
LegacyIAccessibleSelectionProperty = 30099
LegacyIAccessibleStateProperty = 30096
LegacyIAccessibleValueProperty = 30093
LevelProperty = 30154
LiveSettingProperty = 30135
LocalizedControlTypeProperty = 30004
LocalizedLandmarkTypeProperty = 30158
MultipleViewCurrentViewProperty = 30071
MultipleViewSupportedViewsProperty = 30072
NameProperty = 30005
NativeWindowHandleProperty = 30020
OptimizeForVisualContentProperty = 30111
OrientationProperty = 30023
OutlineColorProperty = 30161
OutlineThicknessProperty = 30164
PositionInSetProperty = 30152
ProcessIdProperty = 30002
ProviderDescriptionProperty = 30107
RangeValueIsReadOnlyProperty = 30048
RangeValueLargeChangeProperty = 30051
RangeValueMaximumProperty = 30050
RangeValueMinimumProperty = 30049
RangeValueSmallChangeProperty = 30052
RangeValueValueProperty = 30047
RotationProperty = 30166
RuntimeIdProperty = 30000
ScrollHorizontalScrollPercentProperty = 30053
ScrollHorizontalViewSizeProperty = 30054
ScrollHorizontallyScrollableProperty = 30057
ScrollVerticalScrollPercentProperty = 30055
ScrollVerticalViewSizeProperty = 30056
ScrollVerticallyScrollableProperty = 30058
Selection2CurrentSelectedItemProperty = 30171
Selection2FirstSelectedItemProperty = 30169
Selection2ItemCountProperty = 30172
Selection2LastSelectedItemProperty = 30170
SelectionCanSelectMultipleProperty = 30060
SelectionIsSelectionRequiredProperty = 30061
SelectionItemIsSelectedProperty = 30079
SelectionItemSelectionContainerProperty = 30080
SelectionSelectionProperty = 30059
SizeOfSetProperty = 30153
SizeProperty = 30167
SpreadsheetItemAnnotationObjectsProperty = 30130
SpreadsheetItemAnnotationTypesProperty = 30131
SpreadsheetItemFormulaProperty = 30129
StylesExtendedPropertiesProperty = 30126
StylesFillColorProperty = 30122
StylesFillPatternColorProperty = 30125
StylesFillPatternStyleProperty = 30123
StylesShapeProperty = 30124
StylesStyleIdProperty = 30120
StylesStyleNameProperty = 30121
TableColumnHeadersProperty = 30082
TableItemColumnHeaderItemsProperty = 30085
TableItemRowHeaderItemsProperty = 30084
TableRowHeadersProperty = 30081
TableRowOrColumnMajorProperty = 30083
ToggleToggleStateProperty = 30086
Transform2CanZoomProperty = 30133
Transform2ZoomLevelProperty = 30145
Transform2ZoomMaximumProperty = 30147
Transform2ZoomMinimumProperty = 30146
TransformCanMoveProperty = 30087
TransformCanResizeProperty = 30088
TransformCanRotateProperty = 30089
ValueIsReadOnlyProperty = 30046
ValueValueProperty = 30045
VisualEffectsProperty = 30163
WindowCanMaximizeProperty = 30073
WindowCanMinimizeProperty = 30074
WindowIsModalProperty = 30077
WindowIsTopmostProperty = 30078
WindowWindowInteractionStateProperty = 30076
WindowWindowVisualStateProperty = 30075
PropertyIdNames = {
PropertyId.AcceleratorKeyProperty: 'AcceleratorKeyProperty',
PropertyId.AccessKeyProperty: 'AccessKeyProperty',
PropertyId.AnnotationAnnotationTypeIdProperty: 'AnnotationAnnotationTypeIdProperty',
PropertyId.AnnotationAnnotationTypeNameProperty: 'AnnotationAnnotationTypeNameProperty',
PropertyId.AnnotationAuthorProperty: 'AnnotationAuthorProperty',
PropertyId.AnnotationDateTimeProperty: 'AnnotationDateTimeProperty',
PropertyId.AnnotationObjectsProperty: 'AnnotationObjectsProperty',
PropertyId.AnnotationTargetProperty: 'AnnotationTargetProperty',
PropertyId.AnnotationTypesProperty: 'AnnotationTypesProperty',
PropertyId.AriaPropertiesProperty: 'AriaPropertiesProperty',
PropertyId.AriaRoleProperty: 'AriaRoleProperty',
PropertyId.AutomationIdProperty: 'AutomationIdProperty',
PropertyId.BoundingRectangleProperty: 'BoundingRectangleProperty',
PropertyId.CenterPointProperty: 'CenterPointProperty',
PropertyId.ClassNameProperty: 'ClassNameProperty',
PropertyId.ClickablePointProperty: 'ClickablePointProperty',
PropertyId.ControlTypeProperty: 'ControlTypeProperty',
PropertyId.ControllerForProperty: 'ControllerForProperty',
PropertyId.CultureProperty: 'CultureProperty',
PropertyId.DescribedByProperty: 'DescribedByProperty',
PropertyId.DockDockPositionProperty: 'DockDockPositionProperty',
PropertyId.DragDropEffectProperty: 'DragDropEffectProperty',
PropertyId.DragDropEffectsProperty: 'DragDropEffectsProperty',
PropertyId.DragGrabbedItemsProperty: 'DragGrabbedItemsProperty',
PropertyId.DragIsGrabbedProperty: 'DragIsGrabbedProperty',
PropertyId.DropTargetDropTargetEffectProperty: 'DropTargetDropTargetEffectProperty',
PropertyId.DropTargetDropTargetEffectsProperty: 'DropTargetDropTargetEffectsProperty',
PropertyId.ExpandCollapseExpandCollapseStateProperty: 'ExpandCollapseExpandCollapseStateProperty',
PropertyId.FillColorProperty: 'FillColorProperty',
PropertyId.FillTypeProperty: 'FillTypeProperty',
PropertyId.FlowsFromProperty: 'FlowsFromProperty',
PropertyId.FlowsToProperty: 'FlowsToProperty',
PropertyId.FrameworkIdProperty: 'FrameworkIdProperty',
PropertyId.FullDescriptionProperty: 'FullDescriptionProperty',
PropertyId.GridColumnCountProperty: 'GridColumnCountProperty',
PropertyId.GridItemColumnProperty: 'GridItemColumnProperty',
PropertyId.GridItemColumnSpanProperty: 'GridItemColumnSpanProperty',
PropertyId.GridItemContainingGridProperty: 'GridItemContainingGridProperty',
PropertyId.GridItemRowProperty: 'GridItemRowProperty',
PropertyId.GridItemRowSpanProperty: 'GridItemRowSpanProperty',
PropertyId.GridRowCountProperty: 'GridRowCountProperty',
PropertyId.HasKeyboardFocusProperty: 'HasKeyboardFocusProperty',
PropertyId.HelpTextProperty: 'HelpTextProperty',
PropertyId.IsAnnotationPatternAvailableProperty: 'IsAnnotationPatternAvailableProperty',
PropertyId.IsContentElementProperty: 'IsContentElementProperty',
PropertyId.IsControlElementProperty: 'IsControlElementProperty',
PropertyId.IsCustomNavigationPatternAvailableProperty: 'IsCustomNavigationPatternAvailableProperty',
PropertyId.IsDataValidForFormProperty: 'IsDataValidForFormProperty',
PropertyId.IsDockPatternAvailableProperty: 'IsDockPatternAvailableProperty',
PropertyId.IsDragPatternAvailableProperty: 'IsDragPatternAvailableProperty',
PropertyId.IsDropTargetPatternAvailableProperty: 'IsDropTargetPatternAvailableProperty',
PropertyId.IsEnabledProperty: 'IsEnabledProperty',
PropertyId.IsExpandCollapsePatternAvailableProperty: 'IsExpandCollapsePatternAvailableProperty',
PropertyId.IsGridItemPatternAvailableProperty: 'IsGridItemPatternAvailableProperty',
PropertyId.IsGridPatternAvailableProperty: 'IsGridPatternAvailableProperty',
PropertyId.IsInvokePatternAvailableProperty: 'IsInvokePatternAvailableProperty',
PropertyId.IsItemContainerPatternAvailableProperty: 'IsItemContainerPatternAvailableProperty',
PropertyId.IsKeyboardFocusableProperty: 'IsKeyboardFocusableProperty',
PropertyId.IsLegacyIAccessiblePatternAvailableProperty: 'IsLegacyIAccessiblePatternAvailableProperty',
PropertyId.IsMultipleViewPatternAvailableProperty: 'IsMultipleViewPatternAvailableProperty',
PropertyId.IsObjectModelPatternAvailableProperty: 'IsObjectModelPatternAvailableProperty',
PropertyId.IsOffscreenProperty: 'IsOffscreenProperty',
PropertyId.IsPasswordProperty: 'IsPasswordProperty',
PropertyId.IsPeripheralProperty: 'IsPeripheralProperty',
PropertyId.IsRangeValuePatternAvailableProperty: 'IsRangeValuePatternAvailableProperty',
PropertyId.IsRequiredForFormProperty: 'IsRequiredForFormProperty',
PropertyId.IsScrollItemPatternAvailableProperty: 'IsScrollItemPatternAvailableProperty',
PropertyId.IsScrollPatternAvailableProperty: 'IsScrollPatternAvailableProperty',
PropertyId.IsSelectionItemPatternAvailableProperty: 'IsSelectionItemPatternAvailableProperty',
PropertyId.IsSelectionPattern2AvailableProperty: 'IsSelectionPattern2AvailableProperty',
PropertyId.IsSelectionPatternAvailableProperty: 'IsSelectionPatternAvailableProperty',
PropertyId.IsSpreadsheetItemPatternAvailableProperty: 'IsSpreadsheetItemPatternAvailableProperty',
PropertyId.IsSpreadsheetPatternAvailableProperty: 'IsSpreadsheetPatternAvailableProperty',
PropertyId.IsStylesPatternAvailableProperty: 'IsStylesPatternAvailableProperty',
PropertyId.IsSynchronizedInputPatternAvailableProperty: 'IsSynchronizedInputPatternAvailableProperty',
PropertyId.IsTableItemPatternAvailableProperty: 'IsTableItemPatternAvailableProperty',
PropertyId.IsTablePatternAvailableProperty: 'IsTablePatternAvailableProperty',
PropertyId.IsTextChildPatternAvailableProperty: 'IsTextChildPatternAvailableProperty',
PropertyId.IsTextEditPatternAvailableProperty: 'IsTextEditPatternAvailableProperty',
PropertyId.IsTextPattern2AvailableProperty: 'IsTextPattern2AvailableProperty',
PropertyId.IsTextPatternAvailableProperty: 'IsTextPatternAvailableProperty',
PropertyId.IsTogglePatternAvailableProperty: 'IsTogglePatternAvailableProperty',
PropertyId.IsTransformPattern2AvailableProperty: 'IsTransformPattern2AvailableProperty',
PropertyId.IsTransformPatternAvailableProperty: 'IsTransformPatternAvailableProperty',
PropertyId.IsValuePatternAvailableProperty: 'IsValuePatternAvailableProperty',
PropertyId.IsVirtualizedItemPatternAvailableProperty: 'IsVirtualizedItemPatternAvailableProperty',
PropertyId.IsWindowPatternAvailableProperty: 'IsWindowPatternAvailableProperty',
PropertyId.ItemStatusProperty: 'ItemStatusProperty',
PropertyId.ItemTypeProperty: 'ItemTypeProperty',
PropertyId.LabeledByProperty: 'LabeledByProperty',
PropertyId.LandmarkTypeProperty: 'LandmarkTypeProperty',
PropertyId.LegacyIAccessibleChildIdProperty: 'LegacyIAccessibleChildIdProperty',
PropertyId.LegacyIAccessibleDefaultActionProperty: 'LegacyIAccessibleDefaultActionProperty',
PropertyId.LegacyIAccessibleDescriptionProperty: 'LegacyIAccessibleDescriptionProperty',
PropertyId.LegacyIAccessibleHelpProperty: 'LegacyIAccessibleHelpProperty',
PropertyId.LegacyIAccessibleKeyboardShortcutProperty: 'LegacyIAccessibleKeyboardShortcutProperty',
PropertyId.LegacyIAccessibleNameProperty: 'LegacyIAccessibleNameProperty',
PropertyId.LegacyIAccessibleRoleProperty: 'LegacyIAccessibleRoleProperty',
PropertyId.LegacyIAccessibleSelectionProperty: 'LegacyIAccessibleSelectionProperty',
PropertyId.LegacyIAccessibleStateProperty: 'LegacyIAccessibleStateProperty',
PropertyId.LegacyIAccessibleValueProperty: 'LegacyIAccessibleValueProperty',
PropertyId.LevelProperty: 'LevelProperty',
PropertyId.LiveSettingProperty: 'LiveSettingProperty',
PropertyId.LocalizedControlTypeProperty: 'LocalizedControlTypeProperty',
PropertyId.LocalizedLandmarkTypeProperty: 'LocalizedLandmarkTypeProperty',
PropertyId.MultipleViewCurrentViewProperty: 'MultipleViewCurrentViewProperty',
PropertyId.MultipleViewSupportedViewsProperty: 'MultipleViewSupportedViewsProperty',
PropertyId.NameProperty: 'NameProperty',
PropertyId.NativeWindowHandleProperty: 'NativeWindowHandleProperty',
PropertyId.OptimizeForVisualContentProperty: 'OptimizeForVisualContentProperty',
PropertyId.OrientationProperty: 'OrientationProperty',
PropertyId.OutlineColorProperty: 'OutlineColorProperty',
PropertyId.OutlineThicknessProperty: 'OutlineThicknessProperty',
PropertyId.PositionInSetProperty: 'PositionInSetProperty',
PropertyId.ProcessIdProperty: 'ProcessIdProperty',
PropertyId.ProviderDescriptionProperty: 'ProviderDescriptionProperty',
PropertyId.RangeValueIsReadOnlyProperty: 'RangeValueIsReadOnlyProperty',
PropertyId.RangeValueLargeChangeProperty: 'RangeValueLargeChangeProperty',
PropertyId.RangeValueMaximumProperty: 'RangeValueMaximumProperty',
PropertyId.RangeValueMinimumProperty: 'RangeValueMinimumProperty',
PropertyId.RangeValueSmallChangeProperty: 'RangeValueSmallChangeProperty',
PropertyId.RangeValueValueProperty: 'RangeValueValueProperty',
PropertyId.RotationProperty: 'RotationProperty',
PropertyId.RuntimeIdProperty: 'RuntimeIdProperty',
PropertyId.ScrollHorizontalScrollPercentProperty: 'ScrollHorizontalScrollPercentProperty',
PropertyId.ScrollHorizontalViewSizeProperty: 'ScrollHorizontalViewSizeProperty',
PropertyId.ScrollHorizontallyScrollableProperty: 'ScrollHorizontallyScrollableProperty',
PropertyId.ScrollVerticalScrollPercentProperty: 'ScrollVerticalScrollPercentProperty',
PropertyId.ScrollVerticalViewSizeProperty: 'ScrollVerticalViewSizeProperty',
PropertyId.ScrollVerticallyScrollableProperty: 'ScrollVerticallyScrollableProperty',
PropertyId.Selection2CurrentSelectedItemProperty: 'Selection2CurrentSelectedItemProperty',
PropertyId.Selection2FirstSelectedItemProperty: 'Selection2FirstSelectedItemProperty',
PropertyId.Selection2ItemCountProperty: 'Selection2ItemCountProperty',
PropertyId.Selection2LastSelectedItemProperty: 'Selection2LastSelectedItemProperty',
PropertyId.SelectionCanSelectMultipleProperty: 'SelectionCanSelectMultipleProperty',
PropertyId.SelectionIsSelectionRequiredProperty: 'SelectionIsSelectionRequiredProperty',
PropertyId.SelectionItemIsSelectedProperty: 'SelectionItemIsSelectedProperty',
PropertyId.SelectionItemSelectionContainerProperty: 'SelectionItemSelectionContainerProperty',
PropertyId.SelectionSelectionProperty: 'SelectionSelectionProperty',
PropertyId.SizeOfSetProperty: 'SizeOfSetProperty',
PropertyId.SizeProperty: 'SizeProperty',
PropertyId.SpreadsheetItemAnnotationObjectsProperty: 'SpreadsheetItemAnnotationObjectsProperty',
PropertyId.SpreadsheetItemAnnotationTypesProperty: 'SpreadsheetItemAnnotationTypesProperty',
PropertyId.SpreadsheetItemFormulaProperty: 'SpreadsheetItemFormulaProperty',
PropertyId.StylesExtendedPropertiesProperty: 'StylesExtendedPropertiesProperty',
PropertyId.StylesFillColorProperty: 'StylesFillColorProperty',
PropertyId.StylesFillPatternColorProperty: 'StylesFillPatternColorProperty',
PropertyId.StylesFillPatternStyleProperty: 'StylesFillPatternStyleProperty',
PropertyId.StylesShapeProperty: 'StylesShapeProperty',
PropertyId.StylesStyleIdProperty: 'StylesStyleIdProperty',
PropertyId.StylesStyleNameProperty: 'StylesStyleNameProperty',
PropertyId.TableColumnHeadersProperty: 'TableColumnHeadersProperty',
PropertyId.TableItemColumnHeaderItemsProperty: 'TableItemColumnHeaderItemsProperty',
PropertyId.TableItemRowHeaderItemsProperty: 'TableItemRowHeaderItemsProperty',
PropertyId.TableRowHeadersProperty: 'TableRowHeadersProperty',
PropertyId.TableRowOrColumnMajorProperty: 'TableRowOrColumnMajorProperty',
PropertyId.ToggleToggleStateProperty: 'ToggleToggleStateProperty',
PropertyId.Transform2CanZoomProperty: 'Transform2CanZoomProperty',
PropertyId.Transform2ZoomLevelProperty: 'Transform2ZoomLevelProperty',
PropertyId.Transform2ZoomMaximumProperty: 'Transform2ZoomMaximumProperty',
PropertyId.Transform2ZoomMinimumProperty: 'Transform2ZoomMinimumProperty',
PropertyId.TransformCanMoveProperty: 'TransformCanMoveProperty',
PropertyId.TransformCanResizeProperty: 'TransformCanResizeProperty',
PropertyId.TransformCanRotateProperty: 'TransformCanRotateProperty',
PropertyId.ValueIsReadOnlyProperty: 'ValueIsReadOnlyProperty',
PropertyId.ValueValueProperty: 'ValueValueProperty',
PropertyId.VisualEffectsProperty: 'VisualEffectsProperty',
PropertyId.WindowCanMaximizeProperty: 'WindowCanMaximizeProperty',
PropertyId.WindowCanMinimizeProperty: 'WindowCanMinimizeProperty',
PropertyId.WindowIsModalProperty: 'WindowIsModalProperty',
PropertyId.WindowIsTopmostProperty: 'WindowIsTopmostProperty',
PropertyId.WindowWindowInteractionStateProperty: 'WindowWindowInteractionStateProperty',
PropertyId.WindowWindowVisualStateProperty: 'WindowWindowVisualStateProperty',
}
class AccessibleRole:
"""
AccessibleRole from IUIAutomation.
Refer https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.accessiblerole?view=netframework-4.8
"""
TitleBar = 0x1
MenuBar = 0x2
ScrollBar = 0x3
Grip = 0x4
Sound = 0x5
Cursor = 0x6
Caret = 0x7
Alert = 0x8
Window = 0x9
Client = 0xa
MenuPopup = 0xb
MenuItem = 0xc
ToolTip = 0xd
Application = 0xe
Document = 0xf
Pane = 0x10
Chart = 0x11
Dialog = 0x12
Border = 0x13
Grouping = 0x14
Separator = 0x15
Toolbar = 0x16
StatusBar = 0x17
Table = 0x18
ColumnHeader = 0x19
RowHeader = 0x1a
Column = 0x1b
Row = 0x1c
Cell = 0x1d
Link = 0x1e
HelpBalloon = 0x1f
Character = 0x20
List = 0x21
ListItem = 0x22
Outline = 0x23
OutlineItem = 0x24
PageTab = 0x25
PropertyPage = 0x26
Indicator = 0x27
Graphic = 0x28
StaticText = 0x29
Text = 0x2a
PushButton = 0x2b
CheckButton = 0x2c
RadioButton = 0x2d
ComboBox = 0x2e
DropList = 0x2f
ProgressBar = 0x30
Dial = 0x31
HotkeyField = 0x32
Slider = 0x33
SpinButton = 0x34
Diagram = 0x35
Animation = 0x36
Equation = 0x37
ButtonDropDown = 0x38
ButtonMenu = 0x39
ButtonDropDownGrid = 0x3a
WhiteSpace = 0x3b
PageTabList = 0x3c
Clock = 0x3d
SplitButton = 0x3e
IpAddress = 0x3f
OutlineButton = 0x40
class AccessibleState():
"""
AccessibleState from IUIAutomation.
Refer https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.accessiblestates?view=netframework-4.8
"""
Normal = 0
Unavailable = 0x1
Selected = 0x2
Focused = 0x4
Pressed = 0x8
Checked = 0x10
Mixed = 0x20
Indeterminate = 0x20
ReadOnly = 0x40
HotTracked = 0x80
Default = 0x100
Expanded = 0x200
Collapsed = 0x400
Busy = 0x800
Floating = 0x1000
Marqueed = 0x2000
Animated = 0x4000
Invisible = 0x8000
Offscreen = 0x10000
Sizeable = 0x20000
Moveable = 0x40000
SelfVoicing = 0x80000
Focusable = 0x100000
Selectable = 0x200000
Linked = 0x400000
Traversed = 0x800000
MultiSelectable = 0x1000000
ExtSelectable = 0x2000000
AlertLow = 0x4000000
AlertMedium = 0x8000000
AlertHigh = 0x10000000
Protected = 0x20000000
Valid = 0x7fffffff
HasPopup = 0x40000000
class AccessibleSelection:
"""
AccessibleSelection from IUIAutomation.
Refer https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.accessibleselection?view=netframework-4.8
"""
None_ = 0
TakeFocus = 0x1
TakeSelection = 0x2
ExtendSelection = 0x4
AddSelection = 0x8
RemoveSelection = 0x10
class AnnotationType:
"""
AnnotationType from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/WinAuto/uiauto-annotation-type-identifiers
"""
AdvancedProofingIssue = 60020
Author = 60019
CircularReferenceError = 60022
Comment = 60003
ConflictingChange = 60018
DataValidationError = 60021
DeletionChange = 60012
EditingLockedChange = 60016
Endnote = 60009
ExternalChange = 60017
Footer = 60007
Footnote = 60010
FormatChange = 60014
FormulaError = 60004
GrammarError = 60002
Header = 60006
Highlighted = 60008
InsertionChange = 60011
Mathematics = 60023
MoveChange = 60013
SpellingError = 60001
TrackChanges = 60005
Unknown = 60000
UnsyncedChange = 60015
class NavigateDirection:
"""
NavigateDirection from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-navigatedirection
"""
Parent = 0
NextSibling = 1
PreviousSibling = 2
FirstChild = 3
LastChild = 4
class DockPosition:
"""
DockPosition from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-dockposition
"""
Top = 0
Left = 1
Bottom = 2
Right = 3
Fill = 4
None_ = 5
class ScrollAmount:
"""
ScrollAmount from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-scrollamount
"""
LargeDecrement = 0
SmallDecrement = 1
NoAmount = 2
LargeIncrement = 3
SmallIncrement = 4
class StyleId:
"""
StyleId from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/WinAuto/uiauto-style-identifiers
"""
Custom = 70000
Heading1 = 70001
Heading2 = 70002
Heading3 = 70003
Heading4 = 70004
Heading5 = 70005
Heading6 = 70006
Heading7 = 70007
Heading8 = 70008
Heading9 = 70009
Title = 70010
Subtitle = 70011
Normal = 70012
Emphasis = 70013
Quote = 70014
BulletedList = 70015
NumberedList = 70016
class RowOrColumnMajor:
"""
RowOrColumnMajor from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-roworcolumnmajor
"""
RowMajor = 0
ColumnMajor = 1
Indeterminate = 2
class ExpandCollapseState:
"""
ExpandCollapseState from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-expandcollapsestate
"""
Collapsed = 0
Expanded = 1
PartiallyExpanded = 2
LeafNode = 3
class OrientationType:
"""
OrientationType from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-orientationtype
"""
None_ = 0
Horizontal = 1
Vertical = 2
class ToggleState:
"""
ToggleState from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-togglestate
"""
Off = 0
On = 1
Indeterminate = 2
class TextPatternRangeEndpoint:
"""
TextPatternRangeEndpoint from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-textpatternrangeendpoint
"""
Start = 0
End = 1
class TextAttributeId:
"""
TextAttributeId from IUIAutomation.
Refer https://docs.microsoft.com/zh-cn/windows/desktop/WinAuto/uiauto-textattribute-ids
"""
AfterParagraphSpacingAttribute = 40042
AnimationStyleAttribute = 40000
AnnotationObjectsAttribute = 40032
AnnotationTypesAttribute = 40031
BackgroundColorAttribute = 40001
BeforeParagraphSpacingAttribute = 40041
BulletStyleAttribute = 40002
CapStyleAttribute = 40003
CaretBidiModeAttribute = 40039
CaretPositionAttribute = 40038
CultureAttribute = 40004
FontNameAttribute = 40005
FontSizeAttribute = 40006
FontWeightAttribute = 40007
ForegroundColorAttribute = 40008
HorizontalTextAlignmentAttribute = 40009
IndentationFirstLineAttribute = 40010
IndentationLeadingAttribute = 40011
IndentationTrailingAttribute = 40012
IsActiveAttribute = 40036
IsHiddenAttribute = 40013
IsItalicAttribute = 40014
IsReadOnlyAttribute = 40015
IsSubscriptAttribute = 40016
IsSuperscriptAttribute = 40017
LineSpacingAttribute = 40040
LinkAttribute = 40035
MarginBottomAttribute = 40018
MarginLeadingAttribute = 40019
MarginTopAttribute = 40020
MarginTrailingAttribute = 40021
OutlineStylesAttribute = 40022
OverlineColorAttribute = 40023
OverlineStyleAttribute = 40024
SayAsInterpretAsAttribute = 40043
SelectionActiveEndAttribute = 40037
StrikethroughColorAttribute = 40025
StrikethroughStyleAttribute = 40026
StyleIdAttribute = 40034
StyleNameAttribute = 40033
TabsAttribute = 40027
TextFlowDirectionsAttribute = 40028
UnderlineColorAttribute = 40029
UnderlineStyleAttribute = 40030
class TextUnit:
"""
TextUnit from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-textunit
"""
Character = 0
Format = 1
Word = 2
Line = 3
Paragraph = 4
Page = 5
Document = 6
class ZoomUnit:
"""
ZoomUnit from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-zoomunit
"""
NoAmount = 0
LargeDecrement = 1
SmallDecrement = 2
LargeIncrement = 3
SmallIncrement = 4
class WindowInteractionState:
"""
WindowInteractionState from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-windowinteractionstate
"""
Running = 0
Closing = 1
ReadyForUserInteraction = 2
BlockedByModalWindow = 3
NotResponding = 4
class WindowVisualState:
"""
WindowVisualState from IUIAutomation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationcore/ne-uiautomationcore-windowvisualstate
"""
Normal = 0
Maximized = 1
Minimized = 2
class ConsoleColor:
"""ConsoleColor from Win32."""
Default = -1
Black = 0
DarkBlue = 1
DarkGreen = 2
DarkCyan = 3
DarkRed = 4
DarkMagenta = 5
DarkYellow = 6
Gray = 7
DarkGray = 8
Blue = 9
Green = 10
Cyan = 11
Red = 12
Magenta = 13
Yellow = 14
White = 15
class GAFlag:
"""GAFlag from Win32."""
Parent = 1
Root = 2
RootOwner = 3
class MouseEventFlag:
"""MouseEventFlag from Win32."""
Move = 0x0001
LeftDown = 0x0002
LeftUp = 0x0004
RightDown = 0x0008
RightUp = 0x0010
MiddleDown = 0x0020
MiddleUp = 0x0040
XDown = 0x0080
XUp = 0x0100
Wheel = 0x0800
HWheel = 0x1000
MoveNoCoalesce = 0x2000
VirtualDesk = 0x4000
Absolute = 0x8000
class KeyboardEventFlag:
"""KeyboardEventFlag from Win32."""
KeyDown = 0x0000
ExtendedKey = 0x0001
KeyUp = 0x0002
KeyUnicode = 0x0004
KeyScanCode = 0x0008
class InputType:
"""InputType from Win32"""
Mouse = 0
Keyboard = 1
Hardware = 2
class ModifierKey:
"""ModifierKey from Win32."""
Alt = 0x0001
Control = 0x0002
Shift = 0x0004
Win = 0x0008
NoRepeat = 0x4000
class SW:
"""ShowWindow params from Win32."""
Hide = 0
ShowNormal = 1
Normal = 1
ShowMinimized = 2
ShowMaximized = 3
Maximize = 3
ShowNoActivate = 4
Show = 5
Minimize = 6
ShowMinNoActive = 7
ShowNA = 8
Restore = 9
ShowDefault = 10
ForceMinimize = 11
Max = 11
class SWP:
"""SetWindowPos params from Win32."""
HWND_Top = 0
HWND_Bottom = 1
HWND_Topmost = -1
HWND_NoTopmost = -2
SWP_NoSize = 0x0001
SWP_NoMove = 0x0002
SWP_NoZOrder = 0x0004
SWP_NoRedraw = 0x0008
SWP_NoActivate = 0x0010
SWP_FrameChanged = 0x0020 # The frame changed: send WM_NCCALCSIZE
SWP_ShowWindow = 0x0040
SWP_HideWindow = 0x0080
SWP_NoCopyBits = 0x0100
SWP_NoOwnerZOrder = 0x0200 # Don't do owner Z ordering
SWP_NoSendChanging = 0x0400 # Don't send WM_WINDOWPOSCHANGING
SWP_DrawFrame = SWP_FrameChanged
SWP_NoReposition = SWP_NoOwnerZOrder
SWP_DeferErase = 0x2000
SWP_AsyncWindowPos = 0x4000
class MB:
"""MessageBox flags from Win32."""
Ok = 0x00000000
OkCancel = 0x00000001
AbortRetryIgnore = 0x00000002
YesNoCancel = 0x00000003
YesNo = 0x00000004
RetryCancel = 0x00000005
CancelTryContinue = 0x00000006
IconHand = 0x00000010
IconQuestion = 0x00000020
IconExclamation = 0x00000030
IconAsterisk = 0x00000040
UserIcon = 0x00000080
IconWarning = 0x00000030
IconError = 0x00000010
IconInformation = 0x00000040
IconStop = 0x00000010
DefButton1 = 0x00000000
DefButton2 = 0x00000100
DefButton3 = 0x00000200
DefButton4 = 0x00000300
ApplModal = 0x00000000
SystemModal = 0x00001000
TaskModal = 0x00002000
Help = 0x00004000 # help button
NoFocus = 0x00008000
SetForeground = 0x00010000
DefaultDesktopOnly = 0x00020000
Topmost = 0x00040000
Right = 0x00080000
RtlReading = 0x00100000
ServiceNotification = 0x00200000
ServiceNotificationNT3X = 0x00040000
TypeMask = 0x0000000f
IconMask = 0x000000f0
DefMask = 0x00000f00
ModeMask = 0x00003000
MiscMask = 0x0000c000
IdOk = 1
IdCancel = 2
IdAbort = 3
IdRetry = 4
IdIgnore = 5
IdYes = 6
IdNo = 7
IdClose = 8
IdHelp = 9
IdTryAgain = 10
IdContinue = 11
IdTimeout = 32000
class GWL:
ExStyle = -20
HInstance = -6
HwndParent = -8
ID = -12
Style = -16
UserData = -21
WndProc = -4
class ProcessDpiAwareness:
ProcessDpiUnaware = 0
ProcessSystemDpiAware = 1
ProcessPerMonitorDpiAware = 2
class DpiAwarenessContext:
DpiAwarenessContextUnaware = -1
DpiAwarenessContextSystemAware = -2
DpiAwarenessContextPerMonitorAware = -3
DpiAwarenessContextPerMonitorAwareV2 = -4
DpiAwarenessContextUnawareGdiScaled = -5
class Keys:
"""Key codes from Win32."""
VK_LBUTTON = 0x01 #Left mouse button
VK_RBUTTON = 0x02 #Right mouse button
VK_CANCEL = 0x03 #Control-break processing
VK_MBUTTON = 0x04 #Middle mouse button (three-button mouse)
VK_XBUTTON1 = 0x05 #X1 mouse button
VK_XBUTTON2 = 0x06 #X2 mouse button
VK_BACK = 0x08 #BACKSPACE key
VK_TAB = 0x09 #TAB key
VK_CLEAR = 0x0C #CLEAR key
VK_RETURN = 0x0D #ENTER key
VK_ENTER = 0x0D
VK_SHIFT = 0x10 #SHIFT key
VK_CONTROL = 0x11 #CTRL key
VK_MENU = 0x12 #ALT key
VK_PAUSE = 0x13 #PAUSE key
VK_CAPITAL = 0x14 #CAPS LOCK key
VK_KANA = 0x15 #IME Kana mode
VK_HANGUEL = 0x15 #IME Hanguel mode (maintained for compatibility; use VK_HANGUL)
VK_HANGUL = 0x15 #IME Hangul mode
VK_JUNJA = 0x17 #IME Junja mode
VK_FINAL = 0x18 #IME final mode
VK_HANJA = 0x19 #IME Hanja mode
VK_KANJI = 0x19 #IME Kanji mode
VK_ESCAPE = 0x1B #ESC key
VK_CONVERT = 0x1C #IME convert
VK_NONCONVERT = 0x1D #IME nonconvert
VK_ACCEPT = 0x1E #IME accept
VK_MODECHANGE = 0x1F #IME mode change request
VK_SPACE = 0x20 #SPACEBAR
VK_PRIOR = 0x21 #PAGE UP key
VK_PAGEUP = 0x21
VK_NEXT = 0x22 #PAGE DOWN key
VK_PAGEDOWN = 0x22
VK_END = 0x23 #END key
VK_HOME = 0x24 #HOME key
VK_LEFT = 0x25 #LEFT ARROW key
VK_UP = 0x26 #UP ARROW key
VK_RIGHT = 0x27 #RIGHT ARROW key
VK_DOWN = 0x28 #DOWN ARROW key
VK_SELECT = 0x29 #SELECT key
VK_PRINT = 0x2A #PRINT key
VK_EXECUTE = 0x2B #EXECUTE key
VK_SNAPSHOT = 0x2C #PRINT SCREEN key
VK_INSERT = 0x2D #INS key
VK_DELETE = 0x2E #DEL key
VK_HELP = 0x2F #HELP key
VK_0 = 0x30 #0 key
VK_1 = 0x31 #1 key
VK_2 = 0x32 #2 key
VK_3 = 0x33 #3 key
VK_4 = 0x34 #4 key
VK_5 = 0x35 #5 key
VK_6 = 0x36 #6 key
VK_7 = 0x37 #7 key
VK_8 = 0x38 #8 key
VK_9 = 0x39 #9 key
VK_A = 0x41 #A key
VK_B = 0x42 #B key
VK_C = 0x43 #C key
VK_D = 0x44 #D key
VK_E = 0x45 #E key
VK_F = 0x46 #F key
VK_G = 0x47 #G key
VK_H = 0x48 #H key
VK_I = 0x49 #I key
VK_J = 0x4A #J key
VK_K = 0x4B #K key
VK_L = 0x4C #L key
VK_M = 0x4D #M key
VK_N = 0x4E #N key
VK_O = 0x4F #O key
VK_P = 0x50 #P key
VK_Q = 0x51 #Q key
VK_R = 0x52 #R key
VK_S = 0x53 #S key
VK_T = 0x54 #T key
VK_U = 0x55 #U key
VK_V = 0x56 #V key
VK_W = 0x57 #W key
VK_X = 0x58 #X key
VK_Y = 0x59 #Y key
VK_Z = 0x5A #Z key
VK_LWIN = 0x5B #Left Windows key (Natural keyboard)
VK_RWIN = 0x5C #Right Windows key (Natural keyboard)
VK_APPS = 0x5D #Applications key (Natural keyboard)
VK_SLEEP = 0x5F #Computer Sleep key
VK_NUMPAD0 = 0x60 #Numeric keypad 0 key
VK_NUMPAD1 = 0x61 #Numeric keypad 1 key
VK_NUMPAD2 = 0x62 #Numeric keypad 2 key
VK_NUMPAD3 = 0x63 #Numeric keypad 3 key
VK_NUMPAD4 = 0x64 #Numeric keypad 4 key
VK_NUMPAD5 = 0x65 #Numeric keypad 5 key
VK_NUMPAD6 = 0x66 #Numeric keypad 6 key
VK_NUMPAD7 = 0x67 #Numeric keypad 7 key
VK_NUMPAD8 = 0x68 #Numeric keypad 8 key
VK_NUMPAD9 = 0x69 #Numeric keypad 9 key
VK_MULTIPLY = 0x6A #Multiply key
VK_ADD = 0x6B #Add key
VK_SEPARATOR = 0x6C #Separator key
VK_SUBTRACT = 0x6D #Subtract key
VK_DECIMAL = 0x6E #Decimal key
VK_DIVIDE = 0x6F #Divide key
VK_F1 = 0x70 #F1 key
VK_F2 = 0x71 #F2 key
VK_F3 = 0x72 #F3 key
VK_F4 = 0x73 #F4 key
VK_F5 = 0x74 #F5 key
VK_F6 = 0x75 #F6 key
VK_F7 = 0x76 #F7 key
VK_F8 = 0x77 #F8 key
VK_F9 = 0x78 #F9 key
VK_F10 = 0x79 #F10 key
VK_F11 = 0x7A #F11 key
VK_F12 = 0x7B #F12 key
VK_F13 = 0x7C #F13 key
VK_F14 = 0x7D #F14 key
VK_F15 = 0x7E #F15 key
VK_F16 = 0x7F #F16 key
VK_F17 = 0x80 #F17 key
VK_F18 = 0x81 #F18 key
VK_F19 = 0x82 #F19 key
VK_F20 = 0x83 #F20 key
VK_F21 = 0x84 #F21 key
VK_F22 = 0x85 #F22 key
VK_F23 = 0x86 #F23 key
VK_F24 = 0x87 #F24 key
VK_NUMLOCK = 0x90 #NUM LOCK key
VK_SCROLL = 0x91 #SCROLL LOCK key
VK_LSHIFT = 0xA0 #Left SHIFT key
VK_RSHIFT = 0xA1 #Right SHIFT key
VK_LCONTROL = 0xA2 #Left CONTROL key
VK_RCONTROL = 0xA3 #Right CONTROL key
VK_LMENU = 0xA4 #Left MENU key
VK_RMENU = 0xA5 #Right MENU key
VK_BROWSER_BACK = 0xA6 #Browser Back key
VK_BROWSER_FORWARD = 0xA7 #Browser Forward key
VK_BROWSER_REFRESH = 0xA8 #Browser Refresh key
VK_BROWSER_STOP = 0xA9 #Browser Stop key
VK_BROWSER_SEARCH = 0xAA #Browser Search key
VK_BROWSER_FAVORITES = 0xAB #Browser Favorites key
VK_BROWSER_HOME = 0xAC #Browser Start and Home key
VK_VOLUME_MUTE = 0xAD #Volume Mute key
VK_VOLUME_DOWN = 0xAE #Volume Down key
VK_VOLUME_UP = 0xAF #Volume Up key
VK_MEDIA_NEXT_TRACK = 0xB0 #Next Track key
VK_MEDIA_PREV_TRACK = 0xB1 #Previous Track key
VK_MEDIA_STOP = 0xB2 #Stop Media key
VK_MEDIA_PLAY_PAUSE = 0xB3 #Play/Pause Media key
VK_LAUNCH_MAIL = 0xB4 #Start Mail key
VK_LAUNCH_MEDIA_SELECT = 0xB5 #Select Media key
VK_LAUNCH_APP1 = 0xB6 #Start Application 1 key
VK_LAUNCH_APP2 = 0xB7 #Start Application 2 key
VK_OEM_1 = 0xBA #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the ';:' key
VK_OEM_PLUS = 0xBB #For any country/region, the '+' key
VK_OEM_COMMA = 0xBC #For any country/region, the ',' key
VK_OEM_MINUS = 0xBD #For any country/region, the '-' key
VK_OEM_PERIOD = 0xBE #For any country/region, the '.' key
VK_OEM_2 = 0xBF #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '/?' key
VK_OEM_3 = 0xC0 #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '`~' key
VK_OEM_4 = 0xDB #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '[{' key
VK_OEM_5 = 0xDC #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '\|' key
VK_OEM_6 = 0xDD #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the ']}' key
VK_OEM_7 = 0xDE #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the 'single-quote/double-quote' key
VK_OEM_8 = 0xDF #Used for miscellaneous characters; it can vary by keyboard.
VK_OEM_102 = 0xE2 #Either the angle bracket key or the backslash key on the RT 102-key keyboard
VK_PROCESSKEY = 0xE5 #IME PROCESS key
VK_PACKET = 0xE7 #Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KeyUp
VK_ATTN = 0xF6 #Attn key
VK_CRSEL = 0xF7 #CrSel key
VK_EXSEL = 0xF8 #ExSel key
VK_EREOF = 0xF9 #Erase EOF key
VK_PLAY = 0xFA #Play key
VK_ZOOM = 0xFB #Zoom key
VK_NONAME = 0xFC #Reserved
VK_PA1 = 0xFD #PA1 key
VK_OEM_CLEAR = 0xFE #Clear key
SpecialKeyNames = {
'LBUTTON': Keys.VK_LBUTTON, #Left mouse button
'RBUTTON': Keys.VK_RBUTTON, #Right mouse button
'CANCEL': Keys.VK_CANCEL, #Control-break processing
'MBUTTON': Keys.VK_MBUTTON, #Middle mouse button (three-button mouse)
'XBUTTON1': Keys.VK_XBUTTON1, #X1 mouse button
'XBUTTON2': Keys.VK_XBUTTON2, #X2 mouse button
'BACK': Keys.VK_BACK, #BACKSPACE key
'TAB': Keys.VK_TAB, #TAB key
'CLEAR': Keys.VK_CLEAR, #CLEAR key
'RETURN': Keys.VK_RETURN, #ENTER key
'ENTER': Keys.VK_RETURN, #ENTER key
'SHIFT': Keys.VK_SHIFT, #SHIFT key
'CTRL': Keys.VK_CONTROL, #CTRL key
'CONTROL': Keys.VK_CONTROL, #CTRL key
'ALT': Keys.VK_MENU, #ALT key
'PAUSE': Keys.VK_PAUSE, #PAUSE key
'CAPITAL': Keys.VK_CAPITAL, #CAPS LOCK key
'KANA': Keys.VK_KANA, #IME Kana mode
'HANGUEL': Keys.VK_HANGUEL, #IME Hanguel mode (maintained for compatibility; use VK_HANGUL)
'HANGUL': Keys.VK_HANGUL, #IME Hangul mode
'JUNJA': Keys.VK_JUNJA, #IME Junja mode
'FINAL': Keys.VK_FINAL, #IME final mode
'HANJA': Keys.VK_HANJA, #IME Hanja mode
'KANJI': Keys.VK_KANJI, #IME Kanji mode
'ESC': Keys.VK_ESCAPE, #ESC key
'ESCAPE': Keys.VK_ESCAPE, #ESC key
'CONVERT': Keys.VK_CONVERT, #IME convert
'NONCONVERT': Keys.VK_NONCONVERT, #IME nonconvert
'ACCEPT': Keys.VK_ACCEPT, #IME accept
'MODECHANGE': Keys.VK_MODECHANGE, #IME mode change request
'SPACE': Keys.VK_SPACE, #SPACEBAR
'PRIOR': Keys.VK_PRIOR, #PAGE UP key
'PAGEUP': Keys.VK_PRIOR, #PAGE UP key
'NEXT': Keys.VK_NEXT, #PAGE DOWN key
'PAGEDOWN': Keys.VK_NEXT, #PAGE DOWN key
'END': Keys.VK_END, #END key
'HOME': Keys.VK_HOME, #HOME key
'LEFT': Keys.VK_LEFT, #LEFT ARROW key
'UP': Keys.VK_UP, #UP ARROW key
'RIGHT': Keys.VK_RIGHT, #RIGHT ARROW key
'DOWN': Keys.VK_DOWN, #DOWN ARROW key
'SELECT': Keys.VK_SELECT, #SELECT key
'PRINT': Keys.VK_PRINT, #PRINT key
'EXECUTE': Keys.VK_EXECUTE, #EXECUTE key
'SNAPSHOT': Keys.VK_SNAPSHOT, #PRINT SCREEN key
'PRINTSCREEN': Keys.VK_SNAPSHOT, #PRINT SCREEN key
'INSERT': Keys.VK_INSERT, #INS key
'INS': Keys.VK_INSERT, #INS key
'DELETE': Keys.VK_DELETE, #DEL key
'DEL': Keys.VK_DELETE, #DEL key
'HELP': Keys.VK_HELP, #HELP key
'WIN': Keys.VK_LWIN, #Left Windows key (Natural keyboard)
'LWIN': Keys.VK_LWIN, #Left Windows key (Natural keyboard)
'RWIN': Keys.VK_RWIN, #Right Windows key (Natural keyboard)
'APPS': Keys.VK_APPS, #Applications key (Natural keyboard)
'SLEEP': Keys.VK_SLEEP, #Computer Sleep key
'NUMPAD0': Keys.VK_NUMPAD0, #Numeric keypad 0 key
'NUMPAD1': Keys.VK_NUMPAD1, #Numeric keypad 1 key
'NUMPAD2': Keys.VK_NUMPAD2, #Numeric keypad 2 key
'NUMPAD3': Keys.VK_NUMPAD3, #Numeric keypad 3 key
'NUMPAD4': Keys.VK_NUMPAD4, #Numeric keypad 4 key
'NUMPAD5': Keys.VK_NUMPAD5, #Numeric keypad 5 key
'NUMPAD6': Keys.VK_NUMPAD6, #Numeric keypad 6 key
'NUMPAD7': Keys.VK_NUMPAD7, #Numeric keypad 7 key
'NUMPAD8': Keys.VK_NUMPAD8, #Numeric keypad 8 key
'NUMPAD9': Keys.VK_NUMPAD9, #Numeric keypad 9 key
'MULTIPLY': Keys.VK_MULTIPLY, #Multiply key
'ADD': Keys.VK_ADD, #Add key
'SEPARATOR': Keys.VK_SEPARATOR, #Separator key
'SUBTRACT': Keys.VK_SUBTRACT, #Subtract key
'DECIMAL': Keys.VK_DECIMAL, #Decimal key
'DIVIDE': Keys.VK_DIVIDE, #Divide key
'F1': Keys.VK_F1, #F1 key
'F2': Keys.VK_F2, #F2 key
'F3': Keys.VK_F3, #F3 key
'F4': Keys.VK_F4, #F4 key
'F5': Keys.VK_F5, #F5 key
'F6': Keys.VK_F6, #F6 key
'F7': Keys.VK_F7, #F7 key
'F8': Keys.VK_F8, #F8 key
'F9': Keys.VK_F9, #F9 key
'F10': Keys.VK_F10, #F10 key
'F11': Keys.VK_F11, #F11 key
'F12': Keys.VK_F12, #F12 key
'F13': Keys.VK_F13, #F13 key
'F14': Keys.VK_F14, #F14 key
'F15': Keys.VK_F15, #F15 key
'F16': Keys.VK_F16, #F16 key
'F17': Keys.VK_F17, #F17 key
'F18': Keys.VK_F18, #F18 key
'F19': Keys.VK_F19, #F19 key
'F20': Keys.VK_F20, #F20 key
'F21': Keys.VK_F21, #F21 key
'F22': Keys.VK_F22, #F22 key
'F23': Keys.VK_F23, #F23 key
'F24': Keys.VK_F24, #F24 key
'NUMLOCK': Keys.VK_NUMLOCK, #NUM LOCK key
'SCROLL': Keys.VK_SCROLL, #SCROLL LOCK key
'LSHIFT': Keys.VK_LSHIFT, #Left SHIFT key
'RSHIFT': Keys.VK_RSHIFT, #Right SHIFT key
'LCONTROL': Keys.VK_LCONTROL, #Left CONTROL key
'LCTRL': Keys.VK_LCONTROL, #Left CONTROL key
'RCONTROL': Keys.VK_RCONTROL, #Right CONTROL key
'RCTRL': Keys.VK_RCONTROL, #Right CONTROL key
'LALT': Keys.VK_LMENU, #Left MENU key
'RALT': Keys.VK_RMENU, #Right MENU key
'BROWSER_BACK': Keys.VK_BROWSER_BACK, #Browser Back key
'BROWSER_FORWARD': Keys.VK_BROWSER_FORWARD, #Browser Forward key
'BROWSER_REFRESH': Keys.VK_BROWSER_REFRESH, #Browser Refresh key
'BROWSER_STOP': Keys.VK_BROWSER_STOP, #Browser Stop key
'BROWSER_SEARCH': Keys.VK_BROWSER_SEARCH, #Browser Search key
'BROWSER_FAVORITES': Keys.VK_BROWSER_FAVORITES, #Browser Favorites key
'BROWSER_HOME': Keys.VK_BROWSER_HOME, #Browser Start and Home key
'VOLUME_MUTE': Keys.VK_VOLUME_MUTE, #Volume Mute key
'VOLUME_DOWN': Keys.VK_VOLUME_DOWN, #Volume Down key
'VOLUME_UP': Keys.VK_VOLUME_UP, #Volume Up key
'MEDIA_NEXT_TRACK': Keys.VK_MEDIA_NEXT_TRACK, #Next Track key
'MEDIA_PREV_TRACK': Keys.VK_MEDIA_PREV_TRACK, #Previous Track key
'MEDIA_STOP': Keys.VK_MEDIA_STOP, #Stop Media key
'MEDIA_PLAY_PAUSE': Keys.VK_MEDIA_PLAY_PAUSE, #Play/Pause Media key
'LAUNCH_MAIL': Keys.VK_LAUNCH_MAIL, #Start Mail key
'LAUNCH_MEDIA_SELECT': Keys.VK_LAUNCH_MEDIA_SELECT,#Select Media key
'LAUNCH_APP1': Keys.VK_LAUNCH_APP1, #Start Application 1 key
'LAUNCH_APP2': Keys.VK_LAUNCH_APP2, #Start Application 2 key
'OEM_1': Keys.VK_OEM_1, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the ';:' key
'OEM_PLUS': Keys.VK_OEM_PLUS, #For any country/region, the '+' key
'OEM_COMMA': Keys.VK_OEM_COMMA, #For any country/region, the ',' key
'OEM_MINUS': Keys.VK_OEM_MINUS, #For any country/region, the '-' key
'OEM_PERIOD': Keys.VK_OEM_PERIOD, #For any country/region, the '.' key
'OEM_2': Keys.VK_OEM_2, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '/?' key
'OEM_3': Keys.VK_OEM_3, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '`~' key
'OEM_4': Keys.VK_OEM_4, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '[{' key
'OEM_5': Keys.VK_OEM_5, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the '\|' key
'OEM_6': Keys.VK_OEM_6, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the ']}' key
'OEM_7': Keys.VK_OEM_7, #Used for miscellaneous characters; it can vary by keyboard.For the US standard keyboard, the 'single-quote/double-quote' key
'OEM_8': Keys.VK_OEM_8, #Used for miscellaneous characters; it can vary by keyboard.
'OEM_102': Keys.VK_OEM_102, #Either the angle bracket key or the backslash key on the RT 102-key keyboard
'PROCESSKEY': Keys.VK_PROCESSKEY, #IME PROCESS key
'PACKET': Keys.VK_PACKET, #Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KeyUp
'ATTN': Keys.VK_ATTN, #Attn key
'CRSEL': Keys.VK_CRSEL, #CrSel key
'EXSEL': Keys.VK_EXSEL, #ExSel key
'EREOF': Keys.VK_EREOF, #Erase EOF key
'PLAY': Keys.VK_PLAY, #Play key
'ZOOM': Keys.VK_ZOOM, #Zoom key
'NONAME': Keys.VK_NONAME, #Reserved
'PA1': Keys.VK_PA1, #PA1 key
'OEM_CLEAR': Keys.VK_OEM_CLEAR, #Clear key
}
CharacterCodes = {
'0': Keys.VK_0, #0 key
'1': Keys.VK_1, #1 key
'2': Keys.VK_2, #2 key
'3': Keys.VK_3, #3 key
'4': Keys.VK_4, #4 key
'5': Keys.VK_5, #5 key
'6': Keys.VK_6, #6 key
'7': Keys.VK_7, #7 key
'8': Keys.VK_8, #8 key
'9': Keys.VK_9, #9 key
'a': Keys.VK_A, #A key
'A': Keys.VK_A, #A key
'b': Keys.VK_B, #B key
'B': Keys.VK_B, #B key
'c': Keys.VK_C, #C key
'C': Keys.VK_C, #C key
'd': Keys.VK_D, #D key
'D': Keys.VK_D, #D key
'e': Keys.VK_E, #E key
'E': Keys.VK_E, #E key
'f': Keys.VK_F, #F key
'F': Keys.VK_F, #F key
'g': Keys.VK_G, #G key
'G': Keys.VK_G, #G key
'h': Keys.VK_H, #H key
'H': Keys.VK_H, #H key
'i': Keys.VK_I, #I key
'I': Keys.VK_I, #I key
'j': Keys.VK_J, #J key
'J': Keys.VK_J, #J key
'k': Keys.VK_K, #K key
'K': Keys.VK_K, #K key
'l': Keys.VK_L, #L key
'L': Keys.VK_L, #L key
'm': Keys.VK_M, #M key
'M': Keys.VK_M, #M key
'n': Keys.VK_N, #N key
'N': Keys.VK_N, #N key
'o': Keys.VK_O, #O key
'O': Keys.VK_O, #O key
'p': Keys.VK_P, #P key
'P': Keys.VK_P, #P key
'q': Keys.VK_Q, #Q key
'Q': Keys.VK_Q, #Q key
'r': Keys.VK_R, #R key
'R': Keys.VK_R, #R key
's': Keys.VK_S, #S key
'S': Keys.VK_S, #S key
't': Keys.VK_T, #T key
'T': Keys.VK_T, #T key
'u': Keys.VK_U, #U key
'U': Keys.VK_U, #U key
'v': Keys.VK_V, #V key
'V': Keys.VK_V, #V key
'w': Keys.VK_W, #W key
'W': Keys.VK_W, #W key
'x': Keys.VK_X, #X key
'X': Keys.VK_X, #X key
'y': Keys.VK_Y, #Y key
'Y': Keys.VK_Y, #Y key
'z': Keys.VK_Z, #Z key
'Z': Keys.VK_Z, #Z key
' ': Keys.VK_SPACE, #Space key
'`': Keys.VK_OEM_3, #` key
#'~' : Keys.VK_OEM_3, #~ key
'-': Keys.VK_OEM_MINUS, #- key
#'_' : Keys.VK_OEM_MINUS, #_ key
'=': Keys.VK_OEM_PLUS, #= key
#'+' : Keys.VK_OEM_PLUS, #+ key
'[': Keys.VK_OEM_4, #[ key
#'{' : Keys.VK_OEM_4, #{ key
']': Keys.VK_OEM_6, #] key
#'}' : Keys.VK_OEM_6, #} key
'\\': Keys.VK_OEM_5, #\ key
#'|' : Keys.VK_OEM_5, #| key
';': Keys.VK_OEM_1, #; key
#':' : Keys.VK_OEM_1, #: key
'\'': Keys.VK_OEM_7, #' key
#'"' : Keys.VK_OEM_7, #" key
',': Keys.VK_OEM_COMMA, #, key
#'<' : Keys.VK_OEM_COMMA, #< key
'.': Keys.VK_OEM_PERIOD, #. key
#'>' : Keys.VK_OEM_PERIOD, #> key
'/': Keys.VK_OEM_2, #/ key
#'?' : Keys.VK_OEM_2, #? key
}
class ConsoleScreenBufferInfo(ctypes.Structure):
_fields_ = [
('dwSize', ctypes.wintypes._COORD),
('dwCursorPosition', ctypes.wintypes._COORD),
('wAttributes', ctypes.c_uint),
('srWindow', ctypes.wintypes.SMALL_RECT),
('dwMaximumWindowSize', ctypes.wintypes._COORD),
]
class MOUSEINPUT(ctypes.Structure):
_fields_ = (('dx', ctypes.wintypes.LONG),
('dy', ctypes.wintypes.LONG),
('mouseData', ctypes.wintypes.DWORD),
('dwFlags', ctypes.wintypes.DWORD),
('time', ctypes.wintypes.DWORD),
('dwExtraInfo', ctypes.wintypes.PULONG))
class KEYBDINPUT(ctypes.Structure):
_fields_ = (('wVk', ctypes.wintypes.WORD),
('wScan', ctypes.wintypes.WORD),
('dwFlags', ctypes.wintypes.DWORD),
('time', ctypes.wintypes.DWORD),
('dwExtraInfo', ctypes.wintypes.PULONG))
class HARDWAREINPUT(ctypes.Structure):
_fields_ = (('uMsg', ctypes.wintypes.DWORD),
('wParamL', ctypes.wintypes.WORD),
('wParamH', ctypes.wintypes.WORD))
class _INPUTUnion(ctypes.Union):
_fields_ = (('mi', MOUSEINPUT),
('ki', KEYBDINPUT),
('hi', HARDWAREINPUT))
class INPUT(ctypes.Structure):
_fields_ = (('type', ctypes.wintypes.DWORD),
('union', _INPUTUnion))
class Rect():
"""
class Rect, like `ctypes.wintypes.RECT`.
"""
def __init__(self, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0):
self.left = left
self.top = top
self.right = right
self.bottom = bottom
def width(self) -> int:
return self.right - self.left
def height(self) -> int:
return self.bottom - self.top
def xcenter(self) -> int:
return self.left + self.width() // 2
def ycenter(self) -> int:
return self.top + self.height() // 2
def contains(self, x: int, y: int) -> bool:
return self.left <= x < self.right and self.top <= y < self.bottom
def __eq__(self, rect):
return self.left == rect.left and self.top == rect.top and self.right == rect.right and self.bottom == rect.bottom
def __str__(self) -> str:
return '({},{},{},{})[{}x{}]'.format(self.left, self.top, self.right, self.bottom, self.width(), self.height())
def __repr__(self) -> str:
return '{}({},{},{},{})[{}x{}]'.format(self.__class__.__name__, self.left, self.top, self.right, self.bottom, self.width(), self.height())
_StdOutputHandle = -11
_ConsoleOutputHandle = ctypes.c_void_p(0)
_DefaultConsoleColor = None
def GetClipboardText() -> str:
if ctypes.windll.user32.OpenClipboard(0):
if ctypes.windll.user32.IsClipboardFormatAvailable(13): # CF_TEXT=1, CF_UNICODETEXT=13
hClipboardData = ctypes.windll.user32.GetClipboardData(13)
hText = ctypes.windll.kernel32.GlobalLock(ctypes.c_void_p(hClipboardData))
text = ctypes.c_wchar_p(hText).value[:]
ctypes.windll.kernel32.GlobalUnlock(ctypes.c_void_p(hClipboardData))
ctypes.windll.user32.CloseClipboard()
return text
return ''
def SetClipboardText(text: str) -> bool:
"""
Return bool, True if succeed otherwise False.
"""
if ctypes.windll.user32.OpenClipboard(0):
ctypes.windll.user32.EmptyClipboard()
textByteLen = (len(text) + 1) * 2
hClipboardData = ctypes.windll.kernel32.GlobalAlloc(0, textByteLen) # GMEM_FIXED=0
hDestText = ctypes.windll.kernel32.GlobalLock(ctypes.c_void_p(hClipboardData))
ctypes.cdll.msvcrt.wcsncpy(ctypes.c_wchar_p(hDestText), ctypes.c_wchar_p(text), ctypes.c_size_t(textByteLen // 2))
ctypes.windll.kernel32.GlobalUnlock(ctypes.c_void_p(hClipboardData))
# system owns hClipboardData after calling SetClipboardData,
# application can not write to or free the data once ownership has been transferred to the system
ctypes.windll.user32.SetClipboardData(ctypes.c_uint(13), ctypes.c_void_p(hClipboardData)) # CF_TEXT=1, CF_UNICODETEXT=13
ctypes.windll.user32.CloseClipboard()
return True
return False
def SetConsoleColor(color: int) -> bool:
"""
Change the text color on console window.
color: int, a value in class `ConsoleColor`.
Return bool, True if succeed otherwise False.
"""
global _ConsoleOutputHandle
global _DefaultConsoleColor
if not _DefaultConsoleColor:
if not _ConsoleOutputHandle:
_ConsoleOutputHandle = ctypes.c_void_p(ctypes.windll.kernel32.GetStdHandle(_StdOutputHandle))
bufferInfo = ConsoleScreenBufferInfo()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(_ConsoleOutputHandle, ctypes.byref(bufferInfo))
_DefaultConsoleColor = int(bufferInfo.wAttributes & 0xFF)
if sys.stdout:
sys.stdout.flush()
return bool(ctypes.windll.kernel32.SetConsoleTextAttribute(_ConsoleOutputHandle, ctypes.c_ushort(color)))
def ResetConsoleColor() -> bool:
"""
Reset to the default text color on console window.
Return bool, True if succeed otherwise False.
"""
if sys.stdout:
sys.stdout.flush()
return bool(ctypes.windll.kernel32.SetConsoleTextAttribute(_ConsoleOutputHandle, ctypes.c_ushort(_DefaultConsoleColor)))
def WindowFromPoint(x: int, y: int) -> int:
"""
WindowFromPoint from Win32.
Return int, a native window handle.
"""
return ctypes.windll.user32.WindowFromPoint(ctypes.wintypes.POINT(x, y)) # or ctypes.windll.user32.WindowFromPoint(x, y)
def GetCursorPos() -> Tuple[int, int]:
"""
GetCursorPos from Win32.
Get current mouse cursor positon.
Return Tuple[int, int], two ints tuple (x, y).
"""
point = ctypes.wintypes.POINT(0, 0)
ctypes.windll.user32.GetCursorPos(ctypes.byref(point))
return point.x, point.y
def SetCursorPos(x: int, y: int) -> bool:
"""
SetCursorPos from Win32.
Set mouse cursor to point x, y.
x: int.
y: int.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.user32.SetCursorPos(x, y))
def GetDoubleClickTime() -> int:
"""
GetDoubleClickTime from Win32.
Return int, in milliseconds.
"""
return ctypes.windll.user32.GetDoubleClickTime()
def mouse_event(dwFlags: int, dx: int, dy: int, dwData: int, dwExtraInfo: int) -> None:
"""mouse_event from Win32."""
ctypes.windll.user32.mouse_event(dwFlags, dx, dy, dwData, dwExtraInfo)
def keybd_event(bVk: int, bScan: int, dwFlags: int, dwExtraInfo: int) -> None:
"""keybd_event from Win32."""
ctypes.windll.user32.keybd_event(bVk, bScan, dwFlags, dwExtraInfo)
def PostMessage(handle: int, msg: int, wParam: int, lParam: int) -> bool:
"""
PostMessage from Win32.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.user32.PostMessageW(ctypes.c_void_p(handle), ctypes.c_uint(msg), ctypes.wintypes.WPARAM(wParam), ctypes.wintypes.LPARAM(lParam)))
def SendMessage(handle: int, msg: int, wParam: int, lParam: int) -> int:
"""
SendMessage from Win32.
Return int, the return value specifies the result of the message processing;
it depends on the message sent.
"""
return ctypes.windll.user32.SendMessageW(ctypes.c_void_p(handle), ctypes.c_uint(msg), ctypes.wintypes.WPARAM(wParam), ctypes.wintypes.LPARAM(lParam))
def Click(x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse click at point x, y.
x: int.
y: int.
waitTime: float.
"""
SetCursorPos(x, y)
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.LeftDown | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(0.05)
mouse_event(MouseEventFlag.LeftUp | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def MiddleClick(x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse middle click at point x, y.
x: int.
y: int.
waitTime: float.
"""
SetCursorPos(x, y)
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.MiddleDown | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(0.05)
mouse_event(MouseEventFlag.MiddleUp | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def RightClick(x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse right click at point x, y.
x: int.
y: int.
waitTime: float.
"""
SetCursorPos(x, y)
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.RightDown | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(0.05)
mouse_event(MouseEventFlag.RightUp | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def PressMouse(x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Press left mouse.
x: int.
y: int.
waitTime: float.
"""
SetCursorPos(x, y)
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.LeftDown | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def ReleaseMouse(waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Release left mouse.
waitTime: float.
"""
x, y = GetCursorPos()
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.LeftUp | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def RightPressMouse(x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Press right mouse.
x: int.
y: int.
waitTime: float.
"""
SetCursorPos(x, y)
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.RightDown | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def RightReleaseMouse(waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Release right mouse.
waitTime: float.
"""
x, y = GetCursorPos()
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.RightUp | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def MiddlePressMouse(x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Press middle mouse.
x: int.
y: int.
waitTime: float.
"""
SetCursorPos(x, y)
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.MiddleDown | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def MiddleReleaseMouse(waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Release middle mouse.
waitTime: float.
"""
x, y = GetCursorPos()
screenWidth, screenHeight = GetScreenSize()
mouse_event(MouseEventFlag.MiddleUp | MouseEventFlag.Absolute, x * 65535 // screenWidth, y * 65535 // screenHeight, 0, 0)
time.sleep(waitTime)
def MoveTo(x: int, y: int, moveSpeed: float = 1, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse move to point x, y from current cursor.
x: int.
y: int.
moveSpeed: float, 1 normal speed, < 1 move slower, > 1 move faster.
waitTime: float.
"""
if moveSpeed <= 0:
moveTime = 0
else:
moveTime = MAX_MOVE_SECOND / moveSpeed
curX, curY = GetCursorPos()
xCount = abs(x - curX)
yCount = abs(y - curY)
maxPoint = max(xCount, yCount)
screenWidth, screenHeight = GetScreenSize()
maxSide = max(screenWidth, screenHeight)
minSide = min(screenWidth, screenHeight)
if maxPoint > minSide:
maxPoint = minSide
if maxPoint < maxSide:
maxPoint = 100 + int((maxSide - 100) / maxSide * maxPoint)
moveTime = moveTime * maxPoint * 1.0 / maxSide
stepCount = maxPoint // 20
if stepCount > 1:
xStep = (x - curX) * 1.0 / stepCount
yStep = (y - curY) * 1.0 / stepCount
interval = moveTime / stepCount
for i in range(stepCount):
cx = curX + int(xStep * i)
cy = curY + int(yStep * i)
# upper-left(0,0), lower-right(65536,65536)
# mouse_event(MouseEventFlag.Move | MouseEventFlag.Absolute, cx*65536//screenWidth, cy*65536//screenHeight, 0, 0)
SetCursorPos(cx, cy)
time.sleep(interval)
SetCursorPos(x, y)
time.sleep(waitTime)
def DragDrop(x1: int, y1: int, x2: int, y2: int, moveSpeed: float = 1, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse left button drag from point x1, y1 drop to point x2, y2.
x1: int.
y1: int.
x2: int.
y2: int.
moveSpeed: float, 1 normal speed, < 1 move slower, > 1 move faster.
waitTime: float.
"""
PressMouse(x1, y1, 0.05)
MoveTo(x2, y2, moveSpeed, 0.05)
ReleaseMouse(waitTime)
def RightDragDrop(x1: int, y1: int, x2: int, y2: int, moveSpeed: float = 1, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse right button drag from point x1, y1 drop to point x2, y2.
x1: int.
y1: int.
x2: int.
y2: int.
moveSpeed: float, 1 normal speed, < 1 move slower, > 1 move faster.
waitTime: float.
"""
RightPressMouse(x1, y1, 0.05)
MoveTo(x2, y2, moveSpeed, 0.05)
RightReleaseMouse(waitTime)
def MiddleDragDrop(x1: int, y1: int, x2: int, y2: int, moveSpeed: float = 1, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse middle button drag from point x1, y1 drop to point x2, y2.
x1: int.
y1: int.
x2: int.
y2: int.
moveSpeed: float, 1 normal speed, < 1 move slower, > 1 move faster.
waitTime: float.
"""
MiddlePressMouse(x1, y1, 0.05)
MoveTo(x2, y2, moveSpeed, 0.05)
MiddleReleaseMouse(waitTime)
def WheelDown(wheelTimes: int = 1, interval: float = 0.05, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse wheel down.
wheelTimes: int.
interval: float.
waitTime: float.
"""
for i in range(wheelTimes):
mouse_event(MouseEventFlag.Wheel, 0, 0, -120, 0) #WHEEL_DELTA=120
time.sleep(interval)
time.sleep(waitTime)
def WheelUp(wheelTimes: int = 1, interval: float = 0.05, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate mouse wheel up.
wheelTimes: int.
interval: float.
waitTime: float.
"""
for i in range(wheelTimes):
mouse_event(MouseEventFlag.Wheel, 0, 0, 120, 0) #WHEEL_DELTA=120
time.sleep(interval)
time.sleep(waitTime)
def SetDpiAwareness(dpiAwarenessPerMonitor: bool = True) -> int:
'''
Call SetThreadDpiAwarenessContext(Windows 10 version 1607+) or SetProcessDpiAwareness(Windows 8.1+).
You should call this function with True if you enable DPI scaling. uiautomation calls this function when it initializes.
dpiAwarenessPerMonitor: bool.
Return int.
'''
try:
# https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddpiawarenesscontext
# Windows 10 1607+
ctypes.windll.user32.SetThreadDpiAwarenessContext.restype = ctypes.c_void_p
context = DpiAwarenessContext.DpiAwarenessContextPerMonitorAware if dpiAwarenessPerMonitor else DpiAwarenessContext.DpiAwarenessContextUnaware
oldContext = ctypes.windll.user32.SetThreadDpiAwarenessContext(ctypes.c_void_p(context))
return oldContext
except Exception as ex:
try:
# https://docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
# Once SetProcessDpiAwareness is set for an app, any future calls to SetProcessDpiAwareness will fail.
# Windows 8.1+
if dpiAwarenessPerMonitor:
return ctypes.windll.shcore.SetProcessDpiAwareness(ProcessDpiAwareness.ProcessPerMonitorDpiAware)
except Exception as ex2:
pass
def GetScreenSize(dpiAwarenessPerMonitor: bool = True) -> Tuple[int, int]:
"""
dpiAwarenessPerMonitor: bool.
Return Tuple[int, int], two ints tuple (width, height).
"""
SetDpiAwareness(dpiAwarenessPerMonitor)
SM_CXSCREEN = 0
SM_CYSCREEN = 1
w = ctypes.windll.user32.GetSystemMetrics(SM_CXSCREEN)
h = ctypes.windll.user32.GetSystemMetrics(SM_CYSCREEN)
return w, h
def GetVirtualScreenSize(dpiAwarenessPerMonitor: bool = True) -> Tuple[int, int]:
"""
dpiAwarenessPerMonitor: bool.
Return Tuple[int, int], two ints tuple (width, height).
"""
SetDpiAwareness(dpiAwarenessPerMonitor)
SM_CXVIRTUALSCREEN = 78
SM_CYVIRTUALSCREEN = 79
w = ctypes.windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN)
h = ctypes.windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN)
return w, h
def GetMonitorsRect(dpiAwarenessPerMonitor: bool = False) -> List[Rect]:
"""
Get monitors' rect.
dpiAwarenessPerMonitor: bool.
Return List[Rect].
"""
SetDpiAwareness(dpiAwarenessPerMonitor)
MonitorEnumProc = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_size_t, ctypes.c_size_t, ctypes.POINTER(ctypes.wintypes.RECT), ctypes.c_size_t)
rects = []
def MonitorCallback(hMonitor: int, hdcMonitor: int, lprcMonitor: ctypes.POINTER(ctypes.wintypes.RECT), dwData: int):
rect = Rect(lprcMonitor.contents.left, lprcMonitor.contents.top, lprcMonitor.contents.right, lprcMonitor.contents.bottom)
rects.append(rect)
return 1
ret = ctypes.windll.user32.EnumDisplayMonitors(ctypes.c_void_p(0), ctypes.c_void_p(0), MonitorEnumProc(MonitorCallback), 0)
return rects
def GetPixelColor(x: int, y: int, handle: int = 0) -> int:
"""
Get pixel color of a native window.
x: int.
y: int.
handle: int, the handle of a native window.
Return int, the bgr value of point (x,y).
r = bgr & 0x0000FF
g = (bgr & 0x00FF00) >> 8
b = (bgr & 0xFF0000) >> 16
If handle is 0, get pixel from Desktop window(root control).
Note:
Not all devices support GetPixel.
An application should call GetDeviceCaps to determine whether a specified device supports this function.
For example, console window doesn't support.
"""
hdc = ctypes.windll.user32.GetWindowDC(ctypes.c_void_p(handle))
bgr = ctypes.windll.gdi32.GetPixel(hdc, x, y)
ctypes.windll.user32.ReleaseDC(ctypes.c_void_p(handle), ctypes.c_void_p(hdc))
return bgr
def MessageBox(content: str, title: str, flags: int = MB.Ok) -> int:
"""
MessageBox from Win32.
content: str.
title: str.
flags: int, a value or some combined values in class `MB`.
Return int, a value in MB whose name starts with Id, such as MB.IdOk
"""
return ctypes.windll.user32.MessageBoxW(ctypes.c_void_p(0), ctypes.c_wchar_p(content), ctypes.c_wchar_p(title), ctypes.c_uint(flags))
def SetForegroundWindow(handle: int) -> bool:
"""
SetForegroundWindow from Win32.
handle: int, the handle of a native window.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.user32.SetForegroundWindow(ctypes.c_void_p(handle)))
def BringWindowToTop(handle: int) -> bool:
"""
BringWindowToTop from Win32.
handle: int, the handle of a native window.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.user32.BringWindowToTop(ctypes.c_void_p(handle)))
def SwitchToThisWindow(handle: int) -> None:
"""
SwitchToThisWindow from Win32.
handle: int, the handle of a native window.
"""
ctypes.windll.user32.SwitchToThisWindow(ctypes.c_void_p(handle), ctypes.c_int(1)) #void function, no return
def GetAncestor(handle: int, flag: int) -> int:
"""
GetAncestor from Win32.
handle: int, the handle of a native window.
index: int, a value in class `GAFlag`.
Return int, a native window handle.
"""
return ctypes.windll.user32.GetAncestor(ctypes.c_void_p(handle), ctypes.c_int(flag))
def IsTopLevelWindow(handle: int) -> bool:
"""
IsTopLevelWindow from Win32.
handle: int, the handle of a native window.
Return bool.
Only available on Windows 7 or Higher.
"""
return bool(ctypes.windll.user32.IsTopLevelWindow(ctypes.c_void_p(handle)))
def GetWindowLong(handle: int, index: int) -> int:
"""
GetWindowLong from Win32.
handle: int, the handle of a native window.
index: int.
"""
return ctypes.windll.user32.GetWindowLongW(ctypes.c_void_p(handle), ctypes.c_int(index))
def SetWindowLong(handle: int, index: int, value: int) -> int:
"""
SetWindowLong from Win32.
handle: int, the handle of a native window.
index: int.
value: int.
Return int, the previous value before set.
"""
return ctypes.windll.user32.SetWindowLongW(ctypes.c_void_p(handle), index, value)
def IsIconic(handle: int) -> bool:
"""
IsIconic from Win32.
Determine whether a native window is minimized.
handle: int, the handle of a native window.
Return bool.
"""
return bool(ctypes.windll.user32.IsIconic(ctypes.c_void_p(handle)))
def IsZoomed(handle: int) -> bool:
"""
IsZoomed from Win32.
Determine whether a native window is maximized.
handle: int, the handle of a native window.
Return bool.
"""
return bool(ctypes.windll.user32.IsZoomed(ctypes.c_void_p(handle)))
def IsWindowVisible(handle: int) -> bool:
"""
IsWindowVisible from Win32.
handle: int, the handle of a native window.
Return bool.
"""
return bool(ctypes.windll.user32.IsWindowVisible(ctypes.c_void_p(handle)))
def ShowWindow(handle: int, cmdShow: int) -> bool:
"""
ShowWindow from Win32.
handle: int, the handle of a native window.
cmdShow: int, a value in clas `SW`.
Return bool, True if succeed otherwise False.
"""
return ctypes.windll.user32.ShowWindow(ctypes.c_void_p(handle), ctypes.c_int(cmdShow))
def MoveWindow(handle: int, x: int, y: int, width: int, height: int, repaint: int = 1) -> bool:
"""
MoveWindow from Win32.
handle: int, the handle of a native window.
x: int.
y: int.
width: int.
height: int.
repaint: int, use 1 or 0.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.user32.MoveWindow(ctypes.c_void_p(handle), ctypes.c_int(x), ctypes.c_int(y), ctypes.c_int(width), ctypes.c_int(height), ctypes.c_int(repaint)))
def SetWindowPos(handle: int, hWndInsertAfter: int, x: int, y: int, width: int, height: int, flags: int) -> bool:
"""
SetWindowPos from Win32.
handle: int, the handle of a native window.
hWndInsertAfter: int, a value whose name starts with 'HWND' in class SWP.
x: int.
y: int.
width: int.
height: int.
flags: int, values whose name starts with 'SWP' in class `SWP`.
Return bool, True if succeed otherwise False.
"""
return ctypes.windll.user32.SetWindowPos(ctypes.c_void_p(handle), ctypes.c_void_p(hWndInsertAfter), ctypes.c_int(x), ctypes.c_int(y), ctypes.c_int(width), ctypes.c_int(height), ctypes.c_uint(flags))
def SetWindowTopmost(handle: int, isTopmost: bool) -> bool:
"""
handle: int, the handle of a native window.
isTopmost: bool
Return bool, True if succeed otherwise False.
"""
topValue = SWP.HWND_Topmost if isTopmost else SWP.HWND_NoTopmost
return bool(SetWindowPos(handle, topValue, 0, 0, 0, 0, SWP.SWP_NoSize | SWP.SWP_NoMove))
def GetWindowText(handle: int) -> str:
"""
GetWindowText from Win32.
handle: int, the handle of a native window.
Return str.
"""
arrayType = ctypes.c_wchar * MAX_PATH
values = arrayType()
ctypes.windll.user32.GetWindowTextW(ctypes.c_void_p(handle), values, ctypes.c_int(MAX_PATH))
return values.value
def SetWindowText(handle: int, text: str) -> bool:
"""
SetWindowText from Win32.
handle: int, the handle of a native window.
text: str.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.user32.SetWindowTextW(ctypes.c_void_p(handle), ctypes.c_wchar_p(text)))
def GetEditText(handle: int) -> str:
"""
Get text of a native Win32 Edit.
handle: int, the handle of a native window.
Return str.
"""
textLen = SendMessage(handle, 0x000E, 0, 0) + 1 #WM_GETTEXTLENGTH
arrayType = ctypes.c_wchar * textLen
values = arrayType()
SendMessage(handle, 0x000D, textLen, values) #WM_GETTEXT
return values.value
def GetConsoleOriginalTitle() -> str:
"""
GetConsoleOriginalTitle from Win32.
Return str.
Only available on Windows Vista or higher.
"""
if IsNT6orHigher:
arrayType = ctypes.c_wchar * MAX_PATH
values = arrayType()
ctypes.windll.kernel32.GetConsoleOriginalTitleW(values, ctypes.c_uint(MAX_PATH))
return values.value
else:
raise RuntimeError('GetConsoleOriginalTitle is not supported on Windows XP or lower.')
def GetConsoleTitle() -> str:
"""
GetConsoleTitle from Win32.
Return str.
"""
arrayType = ctypes.c_wchar * MAX_PATH
values = arrayType()
ctypes.windll.kernel32.GetConsoleTitleW(values, ctypes.c_uint(MAX_PATH))
return values.value
def SetConsoleTitle(text: str) -> bool:
"""
SetConsoleTitle from Win32.
text: str.
Return bool, True if succeed otherwise False.
"""
return bool(ctypes.windll.kernel32.SetConsoleTitleW(ctypes.c_wchar_p(text)))
def GetForegroundWindow() -> int:
"""
GetForegroundWindow from Win32.
Return int, the native handle of the foreground window.
"""
return ctypes.windll.user32.GetForegroundWindow()
def IsDesktopLocked() -> bool:
"""
Check if desktop is locked.
Return bool.
Desktop is locked if press Win+L, Ctrl+Alt+Del or in remote desktop mode.
"""
isLocked = False
desk = ctypes.windll.user32.OpenDesktopW(ctypes.c_wchar_p('Default'), ctypes.c_uint(0), ctypes.c_int(0), ctypes.c_uint(0x0100)) # DESKTOP_SWITCHDESKTOP = 0x0100
if desk:
isLocked = not ctypes.windll.user32.SwitchDesktop(ctypes.c_void_p(desk))
ctypes.windll.user32.CloseDesktop(ctypes.c_void_p(desk))
return isLocked
def PlayWaveFile(filePath: str = r'C:\Windows\Media\notify.wav', isAsync: bool = False, isLoop: bool = False) -> bool:
"""
Call PlaySound from Win32.
filePath: str, if emtpy, stop playing the current sound.
isAsync: bool, if True, the sound is played asynchronously and returns immediately.
isLoop: bool, if True, the sound plays repeatedly until PlayWaveFile(None) is called again, must also set isAsync to True.
Return bool, True if succeed otherwise False.
"""
if filePath:
SND_ASYNC = 0x0001
SND_NODEFAULT = 0x0002
SND_LOOP = 0x0008
SND_FILENAME = 0x20000
flags = SND_NODEFAULT | SND_FILENAME
if isAsync:
flags |= SND_ASYNC
if isLoop:
flags |= SND_LOOP
flags |= SND_ASYNC
return bool(ctypes.windll.winmm.PlaySoundW(ctypes.c_wchar_p(filePath), ctypes.c_void_p(0), ctypes.c_uint(flags)))
else:
return bool(ctypes.windll.winmm.PlaySoundW(ctypes.c_wchar_p(0), ctypes.c_void_p(0), ctypes.c_uint(0)))
def IsProcess64Bit(processId: int) -> bool:
"""
Return True if process is 64 bit.
Return False if process is 32 bit.
Return None if unknown, maybe caused by having no acess right to the process.
"""
try:
func = ctypes.windll.ntdll.ZwWow64ReadVirtualMemory64 #only 64 bit OS has this function
except Exception as ex:
return False
try:
IsWow64Process = ctypes.windll.kernel32.IsWow64Process
except Exception as ex:
return False
hProcess = ctypes.windll.kernel32.OpenProcess(0x1000, 0, processId) #PROCESS_QUERY_INFORMATION=0x0400,PROCESS_QUERY_LIMITED_INFORMATION=0x1000
if hProcess:
is64Bit = ctypes.c_int32()
if IsWow64Process(ctypes.c_void_p(hProcess), ctypes.byref(is64Bit)):
ctypes.windll.kernel32.CloseHandle(ctypes.c_void_p(hProcess))
return False if is64Bit.value else True
else:
ctypes.windll.kernel32.CloseHandle(ctypes.c_void_p(hProcess))
def IsUserAnAdmin() -> bool:
"""
IsUserAnAdmin from Win32.
Return bool.
Minimum supported OS: Windows XP, Windows Server 2003
"""
return bool(ctypes.windll.shell32.IsUserAnAdmin())
def RunScriptAsAdmin(argv: List[str], workingDirectory: str = None, showFlag: int = SW.ShowNormal) -> bool:
"""
Run a python script as administrator.
System will show a popup dialog askes you whether to elevate as administrator if UAC is enabled.
argv: List[str], a str list like sys.argv, argv[0] is the script file, argv[1:] are other arguments.
workingDirectory: str, the working directory for the script file.
showFlag: int, a value in class `SW`.
Return bool, True if succeed.
"""
args = ' '.join('"{}"'.format(arg) for arg in argv)
return ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, args, workingDirectory, showFlag) > 32
def SendKey(key: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate typing a key.
key: int, a value in class `Keys`.
"""
keybd_event(key, 0, KeyboardEventFlag.KeyDown | KeyboardEventFlag.ExtendedKey, 0)
keybd_event(key, 0, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey, 0)
time.sleep(waitTime)
def PressKey(key: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate a key down for key.
key: int, a value in class `Keys`.
waitTime: float.
"""
keybd_event(key, 0, KeyboardEventFlag.KeyDown | KeyboardEventFlag.ExtendedKey, 0)
time.sleep(waitTime)
def ReleaseKey(key: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Simulate a key up for key.
key: int, a value in class `Keys`.
waitTime: float.
"""
keybd_event(key, 0, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey, 0)
time.sleep(waitTime)
def IsKeyPressed(key: int) -> bool:
"""
key: int, a value in class `Keys`.
Return bool.
"""
state = ctypes.windll.user32.GetAsyncKeyState(key)
return bool(state & 0x8000)
def _CreateInput(structure) -> INPUT:
"""
Create Win32 struct `INPUT` for `SendInput`.
Return `INPUT`.
"""
if isinstance(structure, MOUSEINPUT):
return INPUT(InputType.Mouse, _INPUTUnion(mi=structure))
if isinstance(structure, KEYBDINPUT):
return INPUT(InputType.Keyboard, _INPUTUnion(ki=structure))
if isinstance(structure, HARDWAREINPUT):
return INPUT(InputType.Hardware, _INPUTUnion(hi=structure))
raise TypeError('Cannot create INPUT structure!')
def MouseInput(dx: int, dy: int, mouseData: int = 0, dwFlags: int = MouseEventFlag.LeftDown, time_: int = 0) -> INPUT:
"""
Create Win32 struct `MOUSEINPUT` for `SendInput`.
Return `INPUT`.
"""
return _CreateInput(MOUSEINPUT(dx, dy, mouseData, dwFlags, time_, None))
def KeyboardInput(wVk: int, wScan: int, dwFlags: int = KeyboardEventFlag.KeyDown, time_: int = 0) -> INPUT:
"""Create Win32 struct `KEYBDINPUT` for `SendInput`."""
return _CreateInput(KEYBDINPUT(wVk, wScan, dwFlags, time_, None))
def HardwareInput(uMsg: int, param: int = 0) -> INPUT:
"""Create Win32 struct `HARDWAREINPUT` for `SendInput`."""
return _CreateInput(HARDWAREINPUT(uMsg, param & 0xFFFF, param >> 16 & 0xFFFF))
def SendInput(*inputs) -> int:
"""
SendInput from Win32.
input: `INPUT`.
Return int, the number of events that it successfully inserted into the keyboard or mouse input stream.
If the function returns zero, the input was already blocked by another thread.
"""
cbSize = ctypes.c_int(ctypes.sizeof(INPUT))
for ip in inputs:
ret = ctypes.windll.user32.SendInput(1, ctypes.byref(ip), cbSize)
return ret
#or one call
#nInputs = len(inputs)
#LPINPUT = INPUT * nInputs
#pInputs = LPINPUT(*inputs)
#cbSize = ctypes.c_int(ctypes.sizeof(INPUT))
#return ctypes.windll.user32.SendInput(nInputs, ctypes.byref(pInputs), cbSize)
def SendUnicodeChar(char: str, charMode: bool = True) -> int:
"""
Type a single unicode char.
char: str, len(char) must equal to 1.
charMode: bool, if False, the char typied is depend on the input method if a input method is on.
Return int, the number of events that it successfully inserted into the keyboard or mouse input stream.
If the function returns zero, the input was already blocked by another thread.
"""
if charMode:
vk = 0
scan = ord(char)
flag = KeyboardEventFlag.KeyUnicode
else:
res = ctypes.windll.user32.VkKeyScanW(ctypes.wintypes.WCHAR(char))
if (res >> 8) & 0xFF == 0:
vk = res & 0xFF
scan = 0
flag = 0
else:
vk = 0
scan = ord(char)
flag = KeyboardEventFlag.KeyUnicode
return SendInput(KeyboardInput(vk, scan, flag | KeyboardEventFlag.KeyDown),
KeyboardInput(vk, scan, flag | KeyboardEventFlag.KeyUp))
_SCKeys = {
Keys.VK_LSHIFT: 0x02A,
Keys.VK_RSHIFT: 0x136,
Keys.VK_LCONTROL: 0x01D,
Keys.VK_RCONTROL: 0x11D,
Keys.VK_LMENU: 0x038,
Keys.VK_RMENU: 0x138,
Keys.VK_LWIN: 0x15B,
Keys.VK_RWIN: 0x15C,
Keys.VK_NUMPAD0: 0x52,
Keys.VK_NUMPAD1: 0x4F,
Keys.VK_NUMPAD2: 0x50,
Keys.VK_NUMPAD3: 0x51,
Keys.VK_NUMPAD4: 0x4B,
Keys.VK_NUMPAD5: 0x4C,
Keys.VK_NUMPAD6: 0x4D,
Keys.VK_NUMPAD7: 0x47,
Keys.VK_NUMPAD8: 0x48,
Keys.VK_NUMPAD9: 0x49,
Keys.VK_DECIMAL: 0x53,
Keys.VK_NUMLOCK: 0x145,
Keys.VK_DIVIDE: 0x135,
Keys.VK_MULTIPLY: 0x037,
Keys.VK_SUBTRACT: 0x04A,
Keys.VK_ADD: 0x04E,
}
def _VKtoSC(key: int) -> int:
"""
This function is only for internal use in SendKeys.
key: int, a value in class `Keys`.
Return int.
"""
if key in _SCKeys:
return _SCKeys[key]
scanCode = ctypes.windll.user32.MapVirtualKeyA(key, 0)
if not scanCode:
return 0
keyList = [Keys.VK_APPS, Keys.VK_CANCEL, Keys.VK_SNAPSHOT, Keys.VK_DIVIDE, Keys.VK_NUMLOCK]
if key in keyList:
scanCode |= 0x0100
return scanCode
def SendKeys(text: str, interval: float = 0.01, waitTime: float = OPERATION_WAIT_TIME, charMode: bool = True, debug: bool = False) -> None:
"""
Simulate typing keys on keyboard.
text: str, keys to type.
interval: float, seconds between keys.
waitTime: float.
charMode: bool, if False, the text typied is depend on the input method if a input method is on.
debug: bool, if True, print the keys.
Examples:
{Ctrl}, {Delete} ... are special keys' name in SpecialKeyNames.
SendKeys('{Ctrl}a{Delete}{Ctrl}v{Ctrl}s{Ctrl}{Shift}s{Win}e{PageDown}') #press Ctrl+a, Delete, Ctrl+v, Ctrl+s, Ctrl+Shift+s, Win+e, PageDown
SendKeys('{Ctrl}(AB)({Shift}(123))') #press Ctrl+A+B, type (, press Shift+1+2+3, type ), if () follows a hold key, hold key won't release util )
SendKeys('{Ctrl}{a 3}') #press Ctrl+a at the same time, release Ctrl+a, then type a 2 times
SendKeys('{a 3}{B 5}') #type a 3 times, type B 5 times
SendKeys('{{}Hello{}}abc {a}{b}{c} test{} 3}{!}{a} (){(}{)}') #type: {Hello}abc abc test}}}!a ()()
SendKeys('0123456789{Enter}')
SendKeys('ABCDEFGHIJKLMNOPQRSTUVWXYZ{Enter}')
SendKeys('abcdefghijklmnopqrstuvwxyz{Enter}')
SendKeys('`~!@#$%^&*()-_=+{Enter}')
SendKeys('[]{{}{}}\\|;:\'\",<.>/?{Enter}')
"""
holdKeys = ('WIN', 'LWIN', 'RWIN', 'SHIFT', 'LSHIFT', 'RSHIFT', 'CTRL', 'CONTROL', 'LCTRL', 'RCTRL', 'LCONTROL', 'LCONTROL', 'ALT', 'LALT', 'RALT')
keys = []
printKeys = []
i = 0
insertIndex = 0
length = len(text)
hold = False
include = False
lastKeyValue = None
while True:
if text[i] == '{':
rindex = text.find('}', i)
if rindex == i + 1:#{}}
rindex = text.find('}', i + 2)
if rindex == -1:
raise ValueError('"{" or "{}" is not valid, use "{{}" for "{", use "{}}" for "}"')
key = text[i + 1:rindex]
key = [it for it in key.split(' ') if it]
if not key:
raise ValueError('"{}" is not valid, use "{{Space}}" or " " for " "'.format(text[i:rindex + 1]))
if (len(key) == 2 and not key[1].isdigit()) or len(key) > 2:
raise ValueError('"{}" is not valid'.format(text[i:rindex + 1]))
upperKey = key[0].upper()
count = 1
if len(key) > 1:
count = int(key[1])
for j in range(count):
if hold:
if upperKey in SpecialKeyNames:
keyValue = SpecialKeyNames[upperKey]
if type(lastKeyValue) == type(keyValue) and lastKeyValue == keyValue:
insertIndex += 1
printKeys.insert(insertIndex, (key[0], 'KeyDown | ExtendedKey'))
printKeys.insert(insertIndex + 1, (key[0], 'KeyUp | ExtendedKey'))
keys.insert(insertIndex, (keyValue, KeyboardEventFlag.KeyDown | KeyboardEventFlag.ExtendedKey))
keys.insert(insertIndex + 1, (keyValue, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey))
lastKeyValue = keyValue
elif key[0] in CharacterCodes:
keyValue = CharacterCodes[key[0]]
if type(lastKeyValue) == type(keyValue) and lastKeyValue == keyValue:
insertIndex += 1
printKeys.insert(insertIndex, (key[0], 'KeyDown | ExtendedKey'))
printKeys.insert(insertIndex + 1, (key[0], 'KeyUp | ExtendedKey'))
keys.insert(insertIndex, (keyValue, KeyboardEventFlag.KeyDown | KeyboardEventFlag.ExtendedKey))
keys.insert(insertIndex + 1, (keyValue, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey))
lastKeyValue = keyValue
else:
printKeys.insert(insertIndex, (key[0], 'UnicodeChar'))
keys.insert(insertIndex, (key[0], 'UnicodeChar'))
lastKeyValue = key[0]
if include:
insertIndex += 1
else:
if upperKey in holdKeys:
insertIndex += 1
else:
hold = False
else:
if upperKey in SpecialKeyNames:
keyValue = SpecialKeyNames[upperKey]
printKeys.append((key[0], 'KeyDown | ExtendedKey'))
printKeys.append((key[0], 'KeyUp | ExtendedKey'))
keys.append((keyValue, KeyboardEventFlag.KeyDown | KeyboardEventFlag.ExtendedKey))
keys.append((keyValue, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey))
lastKeyValue = keyValue
if upperKey in holdKeys:
hold = True
insertIndex = len(keys) - 1
else:
hold = False
else:
printKeys.append((key[0], 'UnicodeChar'))
keys.append((key[0], 'UnicodeChar'))
lastKeyValue = key[0]
i = rindex + 1
elif text[i] == '(':
if hold:
include = True
else:
printKeys.append((text[i], 'UnicodeChar'))
keys.append((text[i], 'UnicodeChar'))
lastKeyValue = text[i]
i += 1
elif text[i] == ')':
if hold:
include = False
hold = False
else:
printKeys.append((text[i], 'UnicodeChar'))
keys.append((text[i], 'UnicodeChar'))
lastKeyValue = text[i]
i += 1
else:
if hold:
if text[i] in CharacterCodes:
keyValue = CharacterCodes[text[i]]
if include and type(lastKeyValue) == type(keyValue) and lastKeyValue == keyValue:
insertIndex += 1
printKeys.insert(insertIndex, (text[i], 'KeyDown | ExtendedKey'))
printKeys.insert(insertIndex + 1, (text[i], 'KeyUp | ExtendedKey'))
keys.insert(insertIndex, (keyValue, KeyboardEventFlag.KeyDown | KeyboardEventFlag.ExtendedKey))
keys.insert(insertIndex + 1, (keyValue, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey))
lastKeyValue = keyValue
else:
printKeys.append((text[i], 'UnicodeChar'))
keys.append((text[i], 'UnicodeChar'))
lastKeyValue = text[i]
if include:
insertIndex += 1
else:
hold = False
else:
printKeys.append((text[i], 'UnicodeChar'))
keys.append((text[i], 'UnicodeChar'))
lastKeyValue = text[i]
i += 1
if i >= length:
break
hotkeyInterval = 0.01
for i, key in enumerate(keys):
if key[1] == 'UnicodeChar':
SendUnicodeChar(key[0], charMode)
time.sleep(interval)
if debug:
Logger.ColorfullyWrite('{}, sleep({})\n'.format(printKeys[i], interval), writeToFile=False)
else:
scanCode = _VKtoSC(key[0])
keybd_event(key[0], scanCode, key[1], 0)
if debug:
Logger.Write(printKeys[i], ConsoleColor.DarkGreen, writeToFile=False)
if i + 1 == len(keys):
time.sleep(interval)
if debug:
Logger.Write(', sleep({})\n'.format(interval), writeToFile=False)
else:
if key[1] & KeyboardEventFlag.KeyUp:
if keys[i + 1][1] == 'UnicodeChar' or keys[i + 1][1] & KeyboardEventFlag.KeyUp == 0:
time.sleep(interval)
if debug:
Logger.Write(', sleep({})\n'.format(interval), writeToFile=False)
else:
time.sleep(hotkeyInterval) #must sleep for a while, otherwise combined keys may not be caught
if debug:
Logger.Write(', sleep({})\n'.format(hotkeyInterval), writeToFile=False)
else: #KeyboardEventFlag.KeyDown
time.sleep(hotkeyInterval)
if debug:
Logger.Write(', sleep({})\n'.format(hotkeyInterval), writeToFile=False)
#make sure hold keys are not pressed
#win = ctypes.windll.user32.GetAsyncKeyState(Keys.VK_LWIN)
#ctrl = ctypes.windll.user32.GetAsyncKeyState(Keys.VK_CONTROL)
#alt = ctypes.windll.user32.GetAsyncKeyState(Keys.VK_MENU)
#shift = ctypes.windll.user32.GetAsyncKeyState(Keys.VK_SHIFT)
#if win & 0x8000:
#Logger.WriteLine('ERROR: WIN is pressed, it should not be pressed!', ConsoleColor.Red)
#keybd_event(Keys.VK_LWIN, 0, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey, 0)
#if ctrl & 0x8000:
#Logger.WriteLine('ERROR: CTRL is pressed, it should not be pressed!', ConsoleColor.Red)
#keybd_event(Keys.VK_CONTROL, 0, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey, 0)
#if alt & 0x8000:
#Logger.WriteLine('ERROR: ALT is pressed, it should not be pressed!', ConsoleColor.Red)
#keybd_event(Keys.VK_MENU, 0, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey, 0)
#if shift & 0x8000:
#Logger.WriteLine('ERROR: SHIFT is pressed, it should not be pressed!', ConsoleColor.Red)
#keybd_event(Keys.VK_SHIFT, 0, KeyboardEventFlag.KeyUp | KeyboardEventFlag.ExtendedKey, 0)
time.sleep(waitTime)
class Logger:
"""
Logger for print and log. Support for printing log with different colors on console.
"""
FileName = '@AutomationLog.txt'
_SelfFileName = os.path.split(__file__)[1]
ColorNames = {
"Black": ConsoleColor.Black,
"DarkBlue": ConsoleColor.DarkBlue,
"DarkGreen": ConsoleColor.DarkGreen,
"DarkCyan": ConsoleColor.DarkCyan,
"DarkRed": ConsoleColor.DarkRed,
"DarkMagenta": ConsoleColor.DarkMagenta,
"DarkYellow": ConsoleColor.DarkYellow,
"Gray": ConsoleColor.Gray,
"DarkGray": ConsoleColor.DarkGray,
"Blue": ConsoleColor.Blue,
"Green": ConsoleColor.Green,
"Cyan": ConsoleColor.Cyan,
"Red": ConsoleColor.Red,
"Magenta": ConsoleColor.Magenta,
"Yellow": ConsoleColor.Yellow,
"White": ConsoleColor.White,
}
@staticmethod
def SetLogFile(path: str) -> None:
Logger.FileName = path
@staticmethod
def Write(log: Any, consoleColor: int = ConsoleColor.Default, writeToFile: bool = True, printToStdout: bool = True, logFile: str = None, printTruncateLen: int = 0) -> None:
"""
log: any type.
consoleColor: int, a value in class `ConsoleColor`, such as `ConsoleColor.DarkGreen`.
writeToFile: bool.
printToStdout: bool.
logFile: str, log file path.
printTruncateLen: int, if <= 0, log is not truncated when print.
"""
if not isinstance(log, str):
log = str(log)
if printToStdout and sys.stdout:
isValidColor = (consoleColor >= ConsoleColor.Black and consoleColor <= ConsoleColor.White)
if isValidColor:
SetConsoleColor(consoleColor)
try:
if printTruncateLen > 0 and len(log) > printTruncateLen:
sys.stdout.write(log[:printTruncateLen] + '...')
else:
sys.stdout.write(log)
except Exception as ex:
SetConsoleColor(ConsoleColor.Red)
isValidColor = True
sys.stdout.write(ex.__class__.__name__ + ': can\'t print the log!')
if log.endswith('\n'):
sys.stdout.write('\n')
if isValidColor:
ResetConsoleColor()
sys.stdout.flush()
if not writeToFile:
return
fileName = logFile if logFile else Logger.FileName
fout = None
try:
fout = open(fileName, 'a+', encoding='utf-8')
fout.write(log)
except Exception as ex:
if sys.stdout:
sys.stdout.write(ex.__class__.__name__ + ': can\'t write the log!')
finally:
if fout:
fout.close()
@staticmethod
def WriteLine(log: Any, consoleColor: int = -1, writeToFile: bool = True, printToStdout: bool = True, logFile: str = None) -> None:
"""
log: any type.
consoleColor: int, a value in class `ConsoleColor`, such as `ConsoleColor.DarkGreen`.
writeToFile: bool.
printToStdout: bool.
logFile: str, log file path.
"""
Logger.Write('{}\n'.format(log), consoleColor, writeToFile, printToStdout, logFile)
@staticmethod
def ColorfullyWrite(log: str, consoleColor: int = -1, writeToFile: bool = True, printToStdout: bool = True, logFile: str = None) -> None:
"""
log: str.
consoleColor: int, a value in class `ConsoleColor`, such as `ConsoleColor.DarkGreen`.
writeToFile: bool.
printToStdout: bool.
logFile: str, log file path.
ColorfullyWrite('Hello Green !!!'), color name must be in Logger.ColorNames.
"""
text = []
start = 0
while True:
index1 = log.find('= 0:
if index1 > start:
text.append((log[start:index1], consoleColor))
index2 = log.find('>', index1)
colorName = log[index1+7:index2]
index3 = log.find('', index2 + 1)
text.append((log[index2 + 1:index3], Logger.ColorNames[colorName]))
start = index3 + 8
else:
if start < len(log):
text.append((log[start:], consoleColor))
break
for t, c in text:
Logger.Write(t, c, writeToFile, printToStdout, logFile)
@staticmethod
def ColorfullyWriteLine(log: str, consoleColor: int = -1, writeToFile: bool = True, printToStdout: bool = True, logFile: str = None) -> None:
"""
log: str.
consoleColor: int, a value in class `ConsoleColor`, such as `ConsoleColor.DarkGreen`.
writeToFile: bool.
printToStdout: bool.
logFile: str, log file path.
ColorfullyWriteLine('Hello Green !!!'), color name must be in Logger.ColorNames.
"""
Logger.ColorfullyWrite(log + '\n', consoleColor, writeToFile, printToStdout, logFile)
@staticmethod
def Log(log: Any = '', consoleColor: int = -1, writeToFile: bool = True, printToStdout: bool = True, logFile: str = None) -> None:
"""
log: any type.
consoleColor: int, a value in class `ConsoleColor`, such as `ConsoleColor.DarkGreen`.
writeToFile: bool.
printToStdout: bool.
logFile: str, log file path.
"""
frameCount = 1
while True:
frame = sys._getframe(frameCount)
_, scriptFileName = os.path.split(frame.f_code.co_filename)
if scriptFileName != Logger._SelfFileName:
break
frameCount += 1
t = datetime.datetime.now()
log = '{}-{:02}-{:02} {:02}:{:02}:{:02}.{:03} {}[{}] {} -> {}\n'.format(t.year, t.month, t.day,
t.hour, t.minute, t.second, t.microsecond // 1000, scriptFileName, frame.f_lineno, frame.f_code.co_name, log)
Logger.Write(log, consoleColor, writeToFile, printToStdout, logFile)
@staticmethod
def ColorfullyLog(log: str = '', consoleColor: int = -1, writeToFile: bool = True, printToStdout: bool = True, logFile: str = None) -> None:
"""
log: any type.
consoleColor: int, a value in class ConsoleColor, such as ConsoleColor.DarkGreen.
writeToFile: bool.
printToStdout: bool.
logFile: str, log file path.
ColorfullyLog('Hello Green !!!'), color name must be in Logger.ColorNames
"""
frameCount = 1
while True:
frame = sys._getframe(frameCount)
_, scriptFileName = os.path.split(frame.f_code.co_filename)
if scriptFileName != Logger._SelfFileName:
break
frameCount += 1
t = datetime.datetime.now()
log = '{}-{:02}-{:02} {:02}:{:02}:{:02}.{:03} {}[{}] {} -> {}\n'.format(t.year, t.month, t.day,
t.hour, t.minute, t.second, t.microsecond // 1000, scriptFileName, frame.f_lineno, frame.f_code.co_name, log)
Logger.ColorfullyWrite(log, consoleColor, writeToFile, printToStdout, logFile)
@staticmethod
def DeleteLog() -> None:
"""Delete log file."""
if os.path.exists(Logger.FileName):
os.remove(Logger.FileName)
class Bitmap:
"""
A simple Bitmap class wraps Windows GDI+ Gdiplus::Bitmap, but may not have high efficiency.
"""
def __init__(self, width: int = 0, height: int = 0):
"""
Create a black bimap of size(width, height).
"""
self._width = width
self._height = height
self._bitmap = 0
if width > 0 and height > 0:
self._bitmap = _DllClient.instance().dll.BitmapCreate(width, height)
def __del__(self):
self.Release()
def _getsize(self) -> None:
size = _DllClient.instance().dll.BitmapGetWidthAndHeight(self._bitmap)
self._width = size & 0xFFFF
self._height = size >> 16
def Release(self) -> None:
if self._bitmap:
_DllClient.instance().dll.BitmapRelease(self._bitmap)
self._bitmap = 0
self._width = 0
self._height = 0
@property
def Width(self) -> int:
"""
Property Width.
Return int.
"""
return self._width
@property
def Height(self) -> int:
"""
Property Height.
Return int.
"""
return self._height
def FromHandle(self, hwnd: int, left: int = 0, top: int = 0, right: int = 0, bottom: int = 0) -> bool:
"""
Capture a native window to Bitmap by its handle.
hwnd: int, the handle of a native window.
left: int.
top: int.
right: int.
bottom: int.
left, top, right and bottom are control's internal postion(from 0,0).
Return bool, True if succeed otherwise False.
"""
self.Release()
root = GetRootControl()
rect = ctypes.wintypes.RECT()
ctypes.windll.user32.GetWindowRect(hwnd, ctypes.byref(rect))
left, top, right, bottom = left + rect.left, top + rect.top, right + rect.left, bottom + rect.top
self._bitmap = _DllClient.instance().dll.BitmapFromWindow(root.NativeWindowHandle, left, top, right, bottom)
self._getsize()
return self._bitmap > 0
def FromControl(self, control: 'Control', x: int = 0, y: int = 0, width: int = 0, height: int = 0) -> bool:
"""
Capture a control to Bitmap.
control: `Control` or its subclass.
x: int.
y: int.
width: int.
height: int.
x, y: the point in control's internal position(from 0,0)
width, height: image's width and height from x, y, use 0 for entire area,
If width(or height) < 0, image size will be control's width(or height) - width(or height).
Return bool, True if succeed otherwise False.
"""
rect = control.BoundingRectangle
while rect.width() == 0 or rect.height() == 0:
#some controls maybe visible but their BoundingRectangle are all 0, capture its parent util valid
control = control.GetParentControl()
if not control:
return False
rect = control.BoundingRectangle
if width <= 0:
width = rect.width() + width
if height <= 0:
height = rect.height() + height
handle = control.NativeWindowHandle
if handle:
left = x
top = y
right = left + width
bottom = top + height
else:
while True:
control = control.GetParentControl()
handle = control.NativeWindowHandle
if handle:
pRect = control.BoundingRectangle
left = rect.left - pRect.left + x
top = rect.top - pRect.top + y
right = left + width
bottom = top + height
break
return self.FromHandle(handle, left, top, right, bottom)
def FromFile(self, filePath: str) -> bool:
"""
Load image from a file.
filePath: str.
Return bool, True if succeed otherwise False.
"""
self.Release()
self._bitmap = _DllClient.instance().dll.BitmapFromFile(ctypes.c_wchar_p(filePath))
self._getsize()
return self._bitmap > 0
def ToFile(self, savePath: str) -> bool:
"""
Save to a file.
savePath: str, should end with .bmp, .jpg, .jpeg, .png, .gif, .tif, .tiff.
Return bool, True if succeed otherwise False.
"""
name, ext = os.path.splitext(savePath)
extMap = {'.bmp': 'image/bmp'
, '.jpg': 'image/jpeg'
, '.jpeg': 'image/jpeg'
, '.gif': 'image/gif'
, '.tif': 'image/tiff'
, '.tiff': 'image/tiff'
, '.png': 'image/png'
}
gdiplusImageFormat = extMap.get(ext.lower(), 'image/png')
return bool(_DllClient.instance().dll.BitmapToFile(self._bitmap, ctypes.c_wchar_p(savePath), ctypes.c_wchar_p(gdiplusImageFormat)))
def GetPixelColor(self, x: int, y: int) -> int:
"""
Get color value of a pixel.
x: int.
y: int.
Return int, argb color.
b = argb & 0x0000FF
g = (argb & 0x00FF00) >> 8
r = (argb & 0xFF0000) >> 16
a = (argb & 0xFF0000) >> 24
"""
return _DllClient.instance().dll.BitmapGetPixel(self._bitmap, x, y)
def SetPixelColor(self, x: int, y: int, argb: int) -> bool:
"""
Set color value of a pixel.
x: int.
y: int.
argb: int, color value.
Return bool, True if succeed otherwise False.
"""
return _DllClient.instance().dll.BitmapSetPixel(self._bitmap, x, y, argb)
def GetPixelColorsHorizontally(self, x: int, y: int, count: int) -> ctypes.Array:
"""
x: int.
y: int.
count: int.
Return `ctypes.Array`, an iterable array of int values in argb form point x,y horizontally.
"""
arrayType = ctypes.c_uint32 * count
values = arrayType()
_DllClient.instance().dll.BitmapGetPixelsHorizontally(ctypes.c_size_t(self._bitmap), x, y, values, count)
return values
def SetPixelColorsHorizontally(self, x: int, y: int, colors: Iterable[int]) -> bool:
"""
Set pixel colors form x,y horizontally.
x: int.
y: int.
colors: Iterable[int], an iterable list of int color values in argb.
Return bool, True if succeed otherwise False.
"""
count = len(colors)
arrayType = ctypes.c_uint32 * count
values = arrayType(*colors)
return _DllClient.instance().dll.BitmapSetPixelsHorizontally(ctypes.c_size_t(self._bitmap), x, y, values, count)
def GetPixelColorsVertically(self, x: int, y: int, count: int) -> ctypes.Array:
"""
x: int.
y: int.
count: int.
Return `ctypes.Array`, an iterable array of int values in argb form point x,y vertically.
"""
arrayType = ctypes.c_uint32 * count
values = arrayType()
_DllClient.instance().dll.BitmapGetPixelsVertically(ctypes.c_size_t(self._bitmap), x, y, values, count)
return values
def SetPixelColorsVertically(self, x: int, y: int, colors: Iterable[int]) -> bool:
"""
Set pixel colors form x,y vertically.
x: int.
y: int.
colors: Iterable[int], an iterable list of int color values in argb.
Return bool, True if succeed otherwise False.
"""
count = len(colors)
arrayType = ctypes.c_uint32 * count
values = arrayType(*colors)
return _DllClient.instance().dll.BitmapSetPixelsVertically(ctypes.c_size_t(self._bitmap), x, y, values, count)
def GetPixelColorsOfRow(self, y: int) -> ctypes.Array:
"""
y: int, row index.
Return `ctypes.Array`, an iterable array of int values in argb of y row.
"""
return self.GetPixelColorsOfRect(0, y, self.Width, 1)
def GetPixelColorsOfColumn(self, x: int) -> ctypes.Array:
"""
x: int, column index.
Return `ctypes.Array`, an iterable array of int values in argb of x column.
"""
return self.GetPixelColorsOfRect(x, 0, 1, self.Height)
def GetPixelColorsOfRect(self, x: int, y: int, width: int, height: int) -> ctypes.Array:
"""
x: int.
y: int.
width: int.
height: int.
Return `ctypes.Array`, an iterable array of int values in argb of the input rect.
"""
arrayType = ctypes.c_uint32 * (width * height)
values = arrayType()
_DllClient.instance().dll.BitmapGetPixelsOfRect(ctypes.c_size_t(self._bitmap), x, y, width, height, values)
return values
def SetPixelColorsOfRect(self, x: int, y: int, width: int, height: int, colors: Iterable[int]) -> bool:
"""
x: int.
y: int.
width: int.
height: int.
colors: Iterable[int], an iterable list of int values in argb, it's length must equal to width*height.
Return bool.
"""
arrayType = ctypes.c_uint32 * (width * height)
values = arrayType(*colors)
return bool(_DllClient.instance().dll.BitmapSetPixelsOfRect(ctypes.c_size_t(self._bitmap), x, y, width, height, values))
def GetPixelColorsOfRects(self, rects: List[Tuple[int, int, int, int]]) -> List[ctypes.Array]:
"""
rects: List[Tuple[int, int, int, int]], such as [(0,0,10,10), (10,10,20,20), (x,y,width,height)].
Return List[ctypes.Array], a list whose elements are ctypes.Array which is an iterable array of int values in argb.
"""
rects2 = [(x, y, x + width, y + height) for x, y, width, height in rects]
left, top, right, bottom = zip(*rects2)
left, top, right, bottom = min(left), min(top), max(right), max(bottom)
width, height = right - left, bottom - top
allColors = self.GetPixelColorsOfRect(left, top, width, height)
colorsOfRects = []
for x, y, w, h in rects:
x -= left
y -= top
colors = []
for row in range(h):
colors.extend(allColors[(y + row) * width + x:(y + row) * width + x + w])
colorsOfRects.append(colors)
return colorsOfRects
def GetAllPixelColors(self) -> ctypes.Array:
"""
Return `ctypes.Array`, an iterable array of int values in argb.
"""
return self.GetPixelColorsOfRect(0, 0, self.Width, self.Height)
def GetSubBitmap(self, x: int, y: int, width: int, height: int) -> 'Bitmap':
"""
x: int.
y: int.
width: int.
height: int.
Return `Bitmap`, a sub bitmap of the input rect.
"""
colors = self.GetPixelColorsOfRect(x, y, width, height)
bitmap = Bitmap(width, height)
bitmap.SetPixelColorsOfRect(0, 0, width, height, colors)
return bitmap
_PatternIdInterfaces = None
def GetPatternIdInterface(patternId: int):
"""
Get pattern COM interface by pattern id.
patternId: int, a value in class `PatternId`.
Return comtypes._cominterface_meta.
"""
global _PatternIdInterfaces
if not _PatternIdInterfaces:
_PatternIdInterfaces = {
# PatternId.AnnotationPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationAnnotationPattern,
# PatternId.CustomNavigationPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationCustomNavigationPattern,
PatternId.DockPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationDockPattern,
# PatternId.DragPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationDragPattern,
# PatternId.DropTargetPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationDropTargetPattern,
PatternId.ExpandCollapsePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationExpandCollapsePattern,
PatternId.GridItemPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationGridItemPattern,
PatternId.GridPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationGridPattern,
PatternId.InvokePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationInvokePattern,
PatternId.ItemContainerPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationItemContainerPattern,
PatternId.LegacyIAccessiblePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationLegacyIAccessiblePattern,
PatternId.MultipleViewPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationMultipleViewPattern,
# PatternId.ObjectModelPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationObjectModelPattern,
PatternId.RangeValuePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationRangeValuePattern,
PatternId.ScrollItemPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationScrollItemPattern,
PatternId.ScrollPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationScrollPattern,
PatternId.SelectionItemPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationSelectionItemPattern,
PatternId.SelectionPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationSelectionPattern,
# PatternId.SpreadsheetItemPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationSpreadsheetItemPattern,
# PatternId.SpreadsheetPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationSpreadsheetPattern,
# PatternId.StylesPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationStylesPattern,
PatternId.SynchronizedInputPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationSynchronizedInputPattern,
PatternId.TableItemPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTableItemPattern,
PatternId.TablePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTablePattern,
# PatternId.TextChildPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTextChildPattern,
# PatternId.TextEditPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTextEditPattern,
PatternId.TextPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTextPattern,
# PatternId.TextPattern2: _AutomationClient.instance().UIAutomationCore.IUIAutomationTextPattern2,
PatternId.TogglePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTogglePattern,
PatternId.TransformPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationTransformPattern,
# PatternId.TransformPattern2: _AutomationClient.instance().UIAutomationCore.IUIAutomationTransformPattern2,
PatternId.ValuePattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationValuePattern,
PatternId.VirtualizedItemPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationVirtualizedItemPattern,
PatternId.WindowPattern: _AutomationClient.instance().UIAutomationCore.IUIAutomationWindowPattern,
}
debug = False
#the following patterns doesn't exist on Windows 7 or lower
try:
_PatternIdInterfaces[PatternId.AnnotationPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationAnnotationPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have AnnotationPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.CustomNavigationPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationCustomNavigationPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have CustomNavigationPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.DragPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationDragPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have DragPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.DropTargetPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationDropTargetPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have DropTargetPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.ObjectModelPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationObjectModelPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have ObjectModelPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.SpreadsheetItemPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationSpreadsheetItemPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have SpreadsheetItemPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.SpreadsheetPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationSpreadsheetPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have SpreadsheetPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.StylesPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationStylesPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have StylesPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.TextChildPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationTextChildPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have TextChildPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.TextEditPattern] = _AutomationClient.instance().UIAutomationCore.IUIAutomationTextEditPattern
except:
if debug: Logger.WriteLine('UIAutomationCore does not have TextEditPattern.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.TextPattern2] = _AutomationClient.instance().UIAutomationCore.IUIAutomationTextPattern2
except:
if debug: Logger.WriteLine('UIAutomationCore does not have TextPattern2.', ConsoleColor.Yellow)
try:
_PatternIdInterfaces[PatternId.TransformPattern2] = _AutomationClient.instance().UIAutomationCore.IUIAutomationTransformPattern2
except:
if debug: Logger.WriteLine('UIAutomationCore does not have TransformPattern2.', ConsoleColor.Yellow)
return _PatternIdInterfaces[patternId]
"""
Control Pattern Mapping for UI Automation Clients.
Refer https://docs.microsoft.com/en-us/previous-versions//dd319586(v=vs.85)
"""
class AnnotationPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationannotationpattern"""
self.pattern = pattern
@property
def AnnotationTypeId(self) -> int:
"""
Property AnnotationTypeId.
Call IUIAutomationAnnotationPattern::get_CurrentAnnotationTypeId.
Return int, a value in class `AnnotationType`.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationannotationpattern-get_currentannotationtypeid
"""
return self.pattern.CurrentAnnotationTypeId
@property
def AnnotationTypeName(self) -> str:
"""
Property AnnotationTypeName.
Call IUIAutomationAnnotationPattern::get_CurrentAnnotationTypeName.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationannotationpattern-get_currentannotationtypename
"""
return self.pattern.CurrentAnnotationTypeName
@property
def Author(self) -> str:
"""
Property Author.
Call IUIAutomationAnnotationPattern::get_CurrentAuthor.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationannotationpattern-get_currentauthor
"""
return self.pattern.CurrentAuthor
@property
def DateTime(self) -> str:
"""
Property DateTime.
Call IUIAutomationAnnotationPattern::get_CurrentDateTime.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationannotationpattern-get_currentdatetime
"""
return self.pattern.CurrentDateTime
@property
def Target(self) -> 'Control':
"""
Property Target.
Call IUIAutomationAnnotationPattern::get_CurrentTarget.
Return `Control` subclass, the element that is being annotated.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationannotationpattern-get_currenttarget
"""
ele = self.pattern.CurrentTarget
return Control.CreateControlFromElement(ele)
class CustomNavigationPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationcustomnavigationpattern"""
self.pattern = pattern
def Navigate(self, direction: int) -> 'Control':
"""
Call IUIAutomationCustomNavigationPattern::Navigate.
Get the next control in the specified direction within the logical UI tree.
direction: int, a value in class `NavigateDirection`.
Return `Control` subclass or None.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationcustomnavigationpattern-navigate
"""
ele = self.pattern.Navigate(direction)
return Control.CreateControlFromElement(ele)
class DockPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationdockpattern"""
self.pattern = pattern
@property
def DockPosition(self) -> int:
"""
Property DockPosition.
Call IUIAutomationDockPattern::get_CurrentDockPosition.
Return int, a value in class `DockPosition`.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdockpattern-get_currentdockposition
"""
return self.pattern.CurrentDockPosition
def SetDockPosition(self, dockPosition: int, waitTime: float = OPERATION_WAIT_TIME) -> int:
"""
Call IUIAutomationDockPattern::SetDockPosition.
dockPosition: int, a value in class `DockPosition`.
waitTime: float.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdockpattern-setdockposition
"""
ret = self.pattern.SetDockPosition(dockPosition)
time.sleep(waitTime)
return ret
class DragPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationdragpattern"""
self.pattern = pattern
@property
def DropEffect(self) -> str:
"""
Property DropEffect.
Call IUIAutomationDragPattern::get_CurrentDropEffect.
Return str, a localized string that indicates what happens
when the user drops this element as part of a drag-drop operation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdragpattern-get_currentdropeffect
"""
return self.pattern.CurrentDropEffect
@property
def DropEffects(self) -> List[str]:
"""
Property DropEffects.
Call IUIAutomationDragPattern::get_CurrentDropEffects, todo SAFEARRAY.
Return List[str], a list of localized strings that enumerate the full set of effects
that can happen when this element as part of a drag-and-drop operation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdragpattern-get_currentdropeffects
"""
return self.pattern.CurrentDropEffects
@property
def IsGrabbed(self) -> bool:
"""
Property IsGrabbed.
Call IUIAutomationDragPattern::get_CurrentIsGrabbed.
Return bool, indicates whether the user has grabbed this element as part of a drag-and-drop operation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdragpattern-get_currentisgrabbed
"""
return bool(self.pattern.CurrentIsGrabbed)
def GetGrabbedItems(self) -> List['Control']:
"""
Call IUIAutomationDragPattern::GetCurrentGrabbedItems.
Return List[Control], a list of `Control` subclasses that represent the full set of items
that the user is dragging as part of a drag operation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdragpattern-getcurrentgrabbeditems
"""
eleArray = self.pattern.GetCurrentGrabbedItems()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
class DropTargetPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationdroptargetpattern"""
self.pattern = pattern
@property
def DropTargetEffect(self) -> str:
"""
Property DropTargetEffect.
Call IUIAutomationDropTargetPattern::get_CurrentDropTargetEffect.
Return str, a localized string that describes what happens
when the user drops the grabbed element on this drop target.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdragpattern-get_currentdroptargeteffect
"""
return self.pattern.CurrentDropTargetEffect
@property
def DropTargetEffects(self) -> List[str]:
"""
Property DropTargetEffects.
Call IUIAutomationDropTargetPattern::get_CurrentDropTargetEffects, todo SAFEARRAY.
Return List[str], a list of localized strings that enumerate the full set of effects
that can happen when the user drops a grabbed element on this drop target
as part of a drag-and-drop operation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationdragpattern-get_currentdroptargeteffects
"""
return self.pattern.CurrentDropTargetEffects
class ExpandCollapsePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationexpandcollapsepattern"""
self.pattern = pattern
@property
def ExpandCollapseState(self) -> int:
"""
Property ExpandCollapseState.
Call IUIAutomationExpandCollapsePattern::get_CurrentExpandCollapseState.
Return int, a value in class ExpandCollapseState.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationexpandcollapsepattern-get_currentexpandcollapsestate
"""
return self.pattern.CurrentExpandCollapseState
def Collapse(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationExpandCollapsePattern::Collapse.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationexpandcollapsepattern-collapse
"""
ret = self.pattern.Collapse() == S_OK
time.sleep(waitTime)
return ret
def Expand(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationExpandCollapsePattern::Expand.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationexpandcollapsepattern-expand
"""
ret = self.pattern.Expand() == S_OK
time.sleep(waitTime)
return ret
class GridItemPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationgriditempattern"""
self.pattern = pattern
@property
def Column(self) -> int:
"""
Property Column.
Call IUIAutomationGridItemPattern::get_CurrentColumn.
Return int, the zero-based index of the column that contains the item.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgriditempattern-get_currentcolumn
"""
return self.pattern.CurrentColumn
@property
def ColumnSpan(self) -> int:
"""
Property ColumnSpan.
Call IUIAutomationGridItemPattern::get_CurrentColumnSpan.
Return int, the number of columns spanned by the grid item.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgriditempattern-get_currentcolumnspan
"""
return self.pattern.CurrentColumnSpan
@property
def ContainingGrid(self) -> 'Control':
"""
Property ContainingGrid.
Call IUIAutomationGridItemPattern::get_CurrentContainingGrid.
Return `Control` subclass, the element that contains the grid item.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgriditempattern-get_currentcontaininggrid
"""
return Control.CreateControlFromElement(self.pattern.CurrentContainingGrid)
@property
def Row(self) -> int:
"""
Property Row.
Call IUIAutomationGridItemPattern::get_CurrentRow.
Return int, the zero-based index of the row that contains the grid item.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgriditempattern-get_currentrow
"""
return self.pattern.CurrentRow
@property
def RowSpan(self) -> int:
"""
Property RowSpan.
Call IUIAutomationGridItemPattern::get_CurrentRowSpan.
Return int, the number of rows spanned by the grid item.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgriditempattern-get_currentrowspan
"""
return self.pattern.CurrentRowSpan
class GridPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationgridpattern"""
self.pattern = pattern
@property
def ColumnCount(self) -> int:
"""
Property ColumnCount.
Call IUIAutomationGridPattern::get_CurrentColumnCount.
Return int, the number of columns in the grid.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgridpattern-get_currentcolumncount
"""
return self.pattern.CurrentColumnCount
@property
def RowCount(self) -> int:
"""
Property RowCount.
Call IUIAutomationGridPattern::get_CurrentRowCount.
Return int, the number of rows in the grid.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgridpattern-get_currentrowcount
"""
return self.pattern.CurrentRowCount
def GetItem(self) -> 'Control':
"""
Call IUIAutomationGridPattern::GetItem.
Return `Control` subclass, a control representing an item in the grid.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationgridpattern-getitem
"""
return Control.CreateControlFromElement(self.pattern.GetItem())
class InvokePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationinvokepattern"""
self.pattern = pattern
def Invoke(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationInvokePattern::Invoke.
Invoke the action of a control, such as a button click.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationinvokepattern-invoke
"""
ret = self.pattern.Invoke() == S_OK
time.sleep(waitTime)
return ret
class ItemContainerPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationitemcontainerpattern"""
self.pattern = pattern
def FindItemByProperty(control: 'Control', propertyId: int, propertyValue) -> 'Control':
"""
Call IUIAutomationItemContainerPattern::FindItemByProperty.
control: `Control` or its subclass.
propertyValue: COM VARIANT according to propertyId? todo.
propertyId: int, a value in class `PropertyId`.
Return `Control` subclass, a control within a containing element, based on a specified property value.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationitemcontainerpattern-finditembyproperty
"""
ele = self.pattern.FindItemByProperty(control.Element, propertyId, propertyValue)
return Control.CreateControlFromElement(ele)
class LegacyIAccessiblePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationlegacyiaccessiblepattern"""
self.pattern = pattern
@property
def ChildId(self) -> int:
"""
Property ChildId.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentChildId.
Return int, the Microsoft Active Accessibility child identifier for the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentchildid
"""
return self.pattern.CurrentChildId
@property
def DefaultAction(self) -> str:
"""
Property DefaultAction.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentDefaultAction.
Return str, the Microsoft Active Accessibility current default action for the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentdefaultaction
"""
return self.pattern.CurrentDefaultAction
@property
def Description(self) -> str:
"""
Property Description.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentDescription.
Return str, the Microsoft Active Accessibility description of the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentdescription
"""
return self.pattern.CurrentDescription
@property
def Help(self) -> str:
"""
Property Help.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentHelp.
Return str, the Microsoft Active Accessibility help string for the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currenthelp
"""
return self.pattern.CurrentHelp
@property
def KeyboardShortcut(self) -> str:
"""
Property KeyboardShortcut.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentKeyboardShortcut.
Return str, the Microsoft Active Accessibility keyboard shortcut property for the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentkeyboardshortcut
"""
return self.pattern.CurrentKeyboardShortcut
@property
def Name(self) -> str:
"""
Property Name.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentName.
Return str, the Microsoft Active Accessibility name property of the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentname
"""
return self.pattern.CurrentName or '' # CurrentName may be None
@property
def Role(self) -> int:
"""
Property Role.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentRole.
Return int, a value in calss `AccessibleRole`, the Microsoft Active Accessibility role identifier.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentrole
"""
return self.pattern.CurrentRole
@property
def State(self) -> int:
"""
Property State.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentState.
Return int, a value in calss `AccessibleState`, the Microsoft Active Accessibility state identifier.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentstate
"""
return self.pattern.CurrentState
@property
def Value(self) -> str:
"""
Property Value.
Call IUIAutomationLegacyIAccessiblePattern::get_CurrentValue.
Return str, the Microsoft Active Accessibility value property.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-get_currentvalue
"""
return self.pattern.CurrentValue
def DoDefaultAction(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationLegacyIAccessiblePattern::DoDefaultAction.
Perform the Microsoft Active Accessibility default action for the element.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-dodefaultaction
"""
ret = self.pattern.DoDefaultAction() == S_OK
time.sleep(waitTime)
return ret
def GetSelection(self) -> List['Control']:
"""
Call IUIAutomationLegacyIAccessiblePattern::GetCurrentSelection.
Return List[Control], a list of `Control` subclasses,
the Microsoft Active Accessibility property that identifies the selected children of this element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-getcurrentselection
"""
eleArray = self.pattern.GetCurrentSelection()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
def GetIAccessible(self):
"""
Call IUIAutomationLegacyIAccessiblePattern::GetIAccessible, todo.
Return an IAccessible object that corresponds to the Microsoft UI Automation element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-getiaccessible
Refer https://docs.microsoft.com/en-us/windows/desktop/api/oleacc/nn-oleacc-iaccessible
"""
return self.pattern.GetIAccessible()
def Select(self, flagsSelect: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationLegacyIAccessiblePattern::Select.
Perform a Microsoft Active Accessibility selection.
flagsSelect: int, a value in `AccessibleSelection`.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-select
"""
ret = self.pattern.Select(flagsSelect) == S_OK
time.sleep(waitTime)
return ret
def SetValue(self, value: str, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationLegacyIAccessiblePattern::SetValue.
Set the Microsoft Active Accessibility value property for the element.
value: str.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationlegacyiaccessiblepattern-setvalue
"""
ret = self.pattern.SetValue(value) == S_OK
time.sleep(waitTime)
return ret
class MultipleViewPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationmultipleviewpattern"""
self.pattern = pattern
@property
def CurrentView(self) -> int:
"""
Property CurrentView.
Call IUIAutomationMultipleViewPattern::get_CurrentCurrentView.
Return int, the control-specific identifier of the current view of the control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationmultipleviewpattern-get_currentcurrentview
"""
return self.pattern.CurrentCurrentView
def GetSupportedViews(self) -> List[int]:
"""
Call IUIAutomationMultipleViewPattern::GetCurrentSupportedViews, todo.
Return List[int], a list of int, control-specific view identifiers.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationmultipleviewpattern-getcurrentsupportedviews
"""
return self.pattern.GetCurrentSupportedViews()
def GetViewName(self, view: int) -> str:
"""
Call IUIAutomationMultipleViewPattern::GetViewName.
view: int, the control-specific view identifier.
Return str, the name of a control-specific view.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationmultipleviewpattern-getviewname
"""
return self.pattern.GetViewName(view)
def SetView(self, view: int) -> bool:
"""
Call IUIAutomationMultipleViewPattern::SetCurrentView.
Set the view of the control.
view: int, the control-specific view identifier.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationmultipleviewpattern-setcurrentview
"""
return self.pattern.SetCurrentView(view) == S_OK
class ObjectModelPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationobjectmodelpattern"""
self.pattern = pattern
def GetUnderlyingObjectModel(self) -> ctypes.POINTER(comtypes.IUnknown):
"""
Call IUIAutomationObjectModelPattern::GetUnderlyingObjectModel, todo.
Return `ctypes.POINTER(comtypes.IUnknown)`, an interface used to access the underlying object model of the provider.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationobjectmodelpattern-getunderlyingobjectmodel
"""
return self.pattern.GetUnderlyingObjectModel()
class RangeValuePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationrangevaluepattern"""
self.pattern = pattern
@property
def IsReadOnly(self) -> bool:
"""
Property IsReadOnly.
Call IUIAutomationRangeValuePattern::get_CurrentIsReadOnly.
Return bool, indicates whether the value of the element can be changed.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-get_currentisreadonly
"""
return self.pattern.CurrentIsReadOnly
@property
def LargeChange(self) -> float:
"""
Property LargeChange.
Call IUIAutomationRangeValuePattern::get_CurrentLargeChange.
Return float, the value that is added to or subtracted from the value of the control
when a large change is made, such as when the PAGE DOWN key is pressed.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-get_currentlargechange
"""
return self.pattern.CurrentLargeChange
@property
def Maximum(self) -> float:
"""
Property Maximum.
Call IUIAutomationRangeValuePattern::get_CurrentMaximum.
Return float, the maximum value of the control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-get_currentmaximum
"""
return self.pattern.CurrentMaximum
@property
def Minimum(self) -> float:
"""
Property Minimum.
Call IUIAutomationRangeValuePattern::get_CurrentMinimum.
Return float, the minimum value of the control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-get_currentminimum
"""
return self.pattern.CurrentMinimum
@property
def SmallChange(self) -> float:
"""
Property SmallChange.
Call IUIAutomationRangeValuePattern::get_CurrentSmallChange.
Return float, the value that is added to or subtracted from the value of the control
when a small change is made, such as when an arrow key is pressed.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-get_currentsmallchange
"""
return self.pattern.CurrentSmallChange
@property
def Value(self) -> float:
"""
Property Value.
Call IUIAutomationRangeValuePattern::get_CurrentValue.
Return float, the value of the control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-get_currentvalue
"""
return self.pattern.CurrentValue
def SetValue(self, value: float, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationRangeValuePattern::SetValue.
Set the value of the control.
value: int.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationrangevaluepattern-setvalue
"""
ret = self.pattern.SetValue(value) == S_OK
time.sleep(waitTime)
return ret
class ScrollItemPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationscrollitempattern"""
self.pattern = pattern
def ScrollIntoView(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationScrollItemPattern::ScrollIntoView.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollitempattern-scrollintoview
"""
ret = self.pattern.ScrollIntoView() == S_OK
time.sleep(waitTime)
return ret
class ScrollPattern():
NoScrollValue = -1
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationscrollpattern"""
self.pattern = pattern
@property
def HorizontallyScrollable(self) -> bool:
"""
Property HorizontallyScrollable.
Call IUIAutomationScrollPattern::get_CurrentHorizontallyScrollable.
Return bool, indicates whether the element can scroll horizontally.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currenthorizontallyscrollable
"""
return bool(self.pattern.CurrentHorizontallyScrollable)
@property
def HorizontalScrollPercent(self) -> float:
"""
Property HorizontalScrollPercent.
Call IUIAutomationScrollPattern::get_CurrentHorizontalScrollPercent.
Return float, the horizontal scroll position.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currenthorizontalscrollpercent
"""
return self.pattern.CurrentHorizontalScrollPercent
@property
def HorizontalViewSize(self) -> float:
"""
Property HorizontalViewSize.
Call IUIAutomationScrollPattern::get_CurrentHorizontalViewSize.
Return float, the horizontal size of the viewable region of a scrollable element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currenthorizontalviewsize
"""
return self.pattern.CurrentHorizontalViewSize
@property
def VerticallyScrollable(self) -> bool:
"""
Property VerticallyScrollable.
Call IUIAutomationScrollPattern::get_CurrentVerticallyScrollable.
Return bool, indicates whether the element can scroll vertically.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currentverticallyscrollable
"""
return bool(self.pattern.CurrentVerticallyScrollable)
@property
def VerticalScrollPercent(self) -> float:
"""
Property VerticalScrollPercent.
Call IUIAutomationScrollPattern::get_CurrentVerticalScrollPercent.
Return float, the vertical scroll position.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currentverticalscrollpercent
"""
return self.pattern.CurrentVerticalScrollPercent
@property
def VerticalViewSize(self) -> float:
"""
Property VerticalViewSize.
Call IUIAutomationScrollPattern::get_CurrentVerticalViewSize.
Return float, the vertical size of the viewable region of a scrollable element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currentverticalviewsize
"""
return self.pattern.CurrentVerticalViewSize
def Scroll(self, horizontalAmount: int, verticalAmount: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationScrollPattern::Scroll.
Scroll the visible region of the content area horizontally and vertically.
horizontalAmount: int, a value in ScrollAmount.
verticalAmount: int, a value in ScrollAmount.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-scroll
"""
ret = self.pattern.Scroll(horizontalAmount, verticalAmount) == S_OK
time.sleep(waitTime)
return ret
def SetScrollPercent(self, horizontalPercent: float, verticalPercent: float, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationScrollPattern::SetScrollPercent.
Set the horizontal and vertical scroll positions as a percentage of the total content area within the UI Automation element.
horizontalPercent: float or int, a value in [0, 100] or ScrollPattern.NoScrollValue(-1) if no scroll.
verticalPercent: float or int, a value in [0, 100] or ScrollPattern.NoScrollValue(-1) if no scroll.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-setscrollpercent
"""
ret = self.pattern.SetScrollPercent(horizontalPercent, verticalPercent) == S_OK
time.sleep(waitTime)
return ret
class SelectionItemPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationselectionitempattern"""
self.pattern = pattern
def AddToSelection(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationSelectionItemPattern::AddToSelection.
Add the current element to the collection of selected items.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionitempattern-addtoselection
"""
ret = self.pattern.AddToSelection() == S_OK
time.sleep(waitTime)
return ret
@property
def IsSelected(self) -> bool:
"""
Property IsSelected.
Call IUIAutomationScrollPattern::get_CurrentIsSelected.
Return bool, indicates whether this item is selected.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currentisselected
"""
return bool(self.pattern.CurrentIsSelected)
@property
def SelectionContainer(self) -> 'Control':
"""
Property SelectionContainer.
Call IUIAutomationScrollPattern::get_CurrentSelectionContainer.
Return `Control` subclass, the element that supports IUIAutomationSelectionPattern and acts as the container for this item.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationscrollpattern-get_currentselectioncontainer
"""
ele = self.pattern.CurrentSelectionContainer
return Control.CreateControlFromElement(ele)
def RemoveFromSelection(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationSelectionItemPattern::RemoveFromSelection.
Remove this element from the selection.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionitempattern-removefromselection
"""
ret = self.pattern.RemoveFromSelection() == S_OK
time.sleep(waitTime)
return ret
def Select(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationSelectionItemPattern::Select.
Clear any selected items and then select the current element.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionitempattern-select
"""
ret = self.pattern.Select() == S_OK
time.sleep(waitTime)
return ret
class SelectionPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationselectionpattern"""
self.pattern = pattern
@property
def CanSelectMultiple(self) -> bool:
"""
Property CanSelectMultiple.
Call IUIAutomationSelectionPattern::get_CurrentCanSelectMultiple.
Return bool, indicates whether more than one item in the container can be selected at one time.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionpattern-get_currentcanselectmultiple
"""
return bool(self.pattern.CurrentCanSelectMultiple)
@property
def IsSelectionRequired(self) -> bool:
"""
Property IsSelectionRequired.
Call IUIAutomationSelectionPattern::get_CurrentIsSelectionRequired.
Return bool, indicates whether at least one item must be selected at all times.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionpattern-get_currentisselectionrequired
"""
return bool(self.pattern.CurrentIsSelectionRequired)
def GetSelection(self) -> List['Control']:
"""
Call IUIAutomationSelectionPattern::GetCurrentSelection.
Return List[Control], a list of `Control` subclasses, the selected elements in the container..
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionpattern-getcurrentselection
"""
eleArray = self.pattern.GetCurrentSelection()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
class SpreadsheetItemPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationspreadsheetitempattern"""
self.pattern = pattern
@property
def Formula(self) -> str:
"""
Property Formula.
Call IUIAutomationSpreadsheetItemPattern::get_CurrentFormula.
Return str, the formula for this cell.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationspreadsheetitempattern-get_currentformula
"""
return self.pattern.CurrentFormula
def GetAnnotationObjects(self) -> List['Control']:
"""
Call IUIAutomationSelectionPattern::GetCurrentAnnotationObjects.
Return List[Control], a list of `Control` subclasses representing the annotations associated with this spreadsheet cell.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationspreadsheetitempattern-getcurrentannotationobjects
"""
eleArray = self.pattern.GetCurrentAnnotationObjects()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
def GetAnnotationTypes(self) -> List[int]:
"""
Call IUIAutomationSelectionPattern::GetCurrentAnnotationTypes.
Return List[int], a list of int values in class `AnnotationType`,
indicating the types of annotations that are associated with this spreadsheet cell.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationselectionpattern-getcurrentannotationtypes
"""
return self.pattern.GetCurrentAnnotationTypes()
class SpreadsheetPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationspreadsheetpattern"""
self.pattern = pattern
def GetItemByName(self, name: str) -> 'Control':
"""
Call IUIAutomationSpreadsheetPattern::GetItemByName.
name: str.
Return `Control` subclass or None, represents the spreadsheet cell that has the specified name..
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationspreadsheetpattern-getitembyname
"""
ele = self.pattern.GetItemByName(name)
return Control.CreateControlFromElement(element=ele)
class StylesPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationstylespattern"""
self.pattern = pattern
@property
def ExtendedProperties(self) -> str:
"""
Property ExtendedProperties.
Call IUIAutomationStylesPattern::get_CurrentExtendedProperties.
Return str, a localized string that contains the list of extended properties for an element in a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationstylespattern-get_currentextendedproperties
"""
return self.pattern.CurrentExtendedProperties
@property
def FillColor(self) -> int:
"""
Property FillColor.
Call IUIAutomationStylesPattern::get_CurrentFillColor.
Return int, the fill color of an element in a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationstylespattern-get_currentfillcolor
"""
return self.pattern.CurrentFillColor
@property
def FillPatternColor(self) -> int:
"""
Property FillPatternColor.
Call IUIAutomationStylesPattern::get_CurrentFillPatternColor.
Return int, the color of the pattern used to fill an element in a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationstylespattern-get_currentfillpatterncolor
"""
return self.pattern.CurrentFillPatternColor
@property
def Shape(self) -> str:
"""
Property Shape.
Call IUIAutomationStylesPattern::get_CurrentShape.
Return str, the shape of an element in a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationstylespattern-get_currentshape
"""
return self.pattern.CurrentShape
@property
def StyleId(self) -> int:
"""
Property StyleId.
Call IUIAutomationStylesPattern::get_CurrentStyleId.
Return int, a value in class `StyleId`, the visual style associated with an element in a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationstylespattern-get_currentstyleid
"""
return self.pattern.CurrentStyleId
@property
def StyleName(self) -> str:
"""
Property StyleName.
Call IUIAutomationStylesPattern::get_CurrentStyleName.
Return str, the name of the visual style associated with an element in a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationstylespattern-get_currentstylename
"""
return self.pattern.CurrentStyleName
class SynchronizedInputPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationsynchronizedinputpattern"""
self.pattern = pattern
def Cancel(self) -> bool:
"""
Call IUIAutomationSynchronizedInputPattern::Cancel.
Cause the Microsoft UI Automation provider to stop listening for mouse or keyboard input.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationsynchronizedinputpattern-cancel
"""
return self.pattern.Cancel() == S_OK
def StartListening(self) -> bool:
"""
Call IUIAutomationSynchronizedInputPattern::StartListening.
Cause the Microsoft UI Automation provider to start listening for mouse or keyboard input.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationsynchronizedinputpattern-startlistening
"""
return self.pattern.StartListening() == S_OK
class TableItemPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtableitempattern"""
self.pattern = pattern
def GetColumnHeaderItems(self) -> List['Control']:
"""
Call IUIAutomationTableItemPattern::GetCurrentColumnHeaderItems.
Return List[Control], a list of `Control` subclasses, the column headers associated with a table item or cell.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtableitempattern-getcurrentcolumnheaderitems
"""
eleArray = self.pattern.GetCurrentColumnHeaderItems()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
def GetRowHeaderItems(self) -> List['Control']:
"""
Call IUIAutomationTableItemPattern::GetCurrentRowHeaderItems.
Return List[Control], a list of `Control` subclasses, the row headers associated with a table item or cell.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtableitempattern-getcurrentrowheaderitems
"""
eleArray = self.pattern.GetCurrentRowHeaderItems()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
class TablePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtablepattern"""
self.pattern = pattern
@property
def RowOrColumnMajor(self) -> int:
"""
Property RowOrColumnMajor.
Call IUIAutomationTablePattern::get_CurrentRowOrColumnMajor.
Return int, a value in class `RowOrColumnMajor`, the primary direction of traversal for the table.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtablepattern-get_currentroworcolumnmajor
"""
return self.pattern.CurrentRowOrColumnMajor
def GetColumnHeaders(self) -> List['Control']:
"""
Call IUIAutomationTablePattern::GetCurrentColumnHeaders.
Return List[Control], a list of `Control` subclasses, representing all the column headers in a table..
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtablepattern-getcurrentcolumnheaders
"""
eleArray = self.pattern.GetCurrentColumnHeaders()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
def GetRowHeaders(self) -> List['Control']:
"""
Call IUIAutomationTablePattern::GetCurrentRowHeaders.
Return List[Control], a list of `Control` subclasses, representing all the row headers in a table.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtablepattern-getcurrentrowheaders
"""
eleArray = self.pattern.GetCurrentRowHeaders()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
class TextRange():
def __init__(self, textRange=None):
"""
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtextrange
"""
self.textRange = textRange
def AddToSelection(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTextRange::AddToSelection.
Add the text range to the collection of selected text ranges in a control that supports multiple, disjoint spans of selected text.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-addtoselection
"""
ret = self.textRange.AddToSelection() == S_OK
time.sleep(waitTime)
return ret
def Clone(self) -> 'TextRange':
"""
Call IUIAutomationTextRange::Clone.
return `TextRange`, identical to the original and inheriting all properties of the original.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-clone
"""
return TextRange(textRange=self.textRange.Clone())
def Compare(self, textRange: 'TextRange') -> bool:
"""
Call IUIAutomationTextRange::Compare.
textRange: `TextRange`.
Return bool, specifies whether this text range has the same endpoints as another text range.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-compare
"""
return bool(self.textRange.Compare(textRange.textRange))
def CompareEndpoints(self, srcEndPoint: int, textRange: 'TextRange', targetEndPoint: int) -> int:
"""
Call IUIAutomationTextRange::CompareEndpoints.
srcEndPoint: int, a value in class `TextPatternRangeEndpoint`.
textRange: `TextRange`.
targetEndPoint: int, a value in class `TextPatternRangeEndpoint`.
Return int, a negative value if the caller's endpoint occurs earlier in the text than the target endpoint;
0 if the caller's endpoint is at the same location as the target endpoint;
or a positive value if the caller's endpoint occurs later in the text than the target endpoint.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-compareendpoints
"""
return self.textRange.CompareEndpoints(srcEndPoint, textRange, targetEndPoint)
def ExpandToEnclosingUnit(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTextRange::ExpandToEnclosingUnit.
Normalize the text range by the specified text unit.
The range is expanded if it is smaller than the specified unit,
or shortened if it is longer than the specified unit.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-expandtoenclosingunit
"""
ret = self.textRange.ExpandToEnclosingUnit() == S_OK
time.sleep(waitTime)
return ret
def FindAttribute(self, textAttributeId: int, val, backward: bool) -> 'TextRange':
"""
Call IUIAutomationTextRange::FindAttribute.
textAttributeID: int, a value in class `TextAttributeId`.
val: COM VARIANT according to textAttributeId? todo.
backward: bool, True if the last occurring text range should be returned instead of the first; otherwise False.
return `TextRange` or None, a text range subset that has the specified text attribute value.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-findattribute
"""
textRange = self.textRange.FindAttribute(textAttributeId, val, int(backward))
if textRange:
return TextRange(textRange=textRange)
def FindText(self, text: str, backward: bool, ignoreCase: bool) -> 'TextRange':
"""
Call IUIAutomationTextRange::FindText.
text: str,
backward: bool, True if the last occurring text range should be returned instead of the first; otherwise False.
ignoreCase: bool, True if case should be ignored; otherwise False.
return `TextRange` or None, a text range subset that contains the specified text.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-findtext
"""
textRange = self.textRange.FindText(text, int(backward), int(ignoreCase))
if textRange:
return TextRange(textRange=textRange)
def GetAttributeValue(self, textAttributeId: int) -> ctypes.POINTER(comtypes.IUnknown):
"""
Call IUIAutomationTextRange::GetAttributeValue.
textAttributeId: int, a value in class `TextAttributeId`.
Return `ctypes.POINTER(comtypes.IUnknown)` or None, the value of the specified text attribute across the entire text range, todo.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-getattributevalue
"""
return self.textRange.GetAttributeValue(textAttributeId)
def GetBoundingRectangles(self) -> List[Rect]:
"""
Call IUIAutomationTextRange::GetBoundingRectangles.
textAttributeId: int, a value in class `TextAttributeId`.
Return List[Rect], a list of `Rect`.
bounding rectangles for each fully or partially visible line of text in a text range..
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-getboundingrectangles
for rect in textRange.GetBoundingRectangles():
print(rect.left, rect.top, rect.right, rect.bottom, rect.width(), rect.height(), rect.xcenter(), rect.ycenter())
"""
floats = self.textRange.GetBoundingRectangles()
rects = []
for i in range(len(floats) // 4):
rect = Rect(int(floats[i * 4]), int(floats[i * 4 + 1]),
int(floats[i * 4]) + int(floats[i * 4 + 2]), int(floats[i * 4 + 1]) + int(floats[i * 4 + 3]))
rects.append(rect)
return rects
def GetChildren(self) -> List['Control']:
"""
Call IUIAutomationTextRange::GetChildren.
textAttributeId: int, a value in class `TextAttributeId`.
Return List[Control], a list of `Control` subclasses, embedded objects that fall within the text range..
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-getchildren
"""
eleArray = self.textRange.GetChildren()
if eleArray:
controls = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
con = Control.CreateControlFromElement(element=ele)
if con:
controls.append(con)
return controls
return []
def GetEnclosingControl(self) -> 'Control':
"""
Call IUIAutomationTextRange::GetEnclosingElement.
Return `Control` subclass, the innermost UI Automation element that encloses the text range.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-getenclosingelement
"""
return Control.CreateControlFromElement(self.textRange.GetEnclosingElement())
def GetText(self, maxLength: int = -1) -> str:
"""
Call IUIAutomationTextRange::GetText.
maxLength: int, the maximum length of the string to return, or -1 if no limit is required.
Return str, the plain text of the text range.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-gettext
"""
return self.textRange.GetText(maxLength)
def Move(self, unit: int, count: int, waitTime: float = OPERATION_WAIT_TIME) -> int:
"""
Call IUIAutomationTextRange::Move.
Move the text range forward or backward by the specified number of text units.
unit: int, a value in class `TextUnit`.
count: int, the number of text units to move.
A positive value moves the text range forward.
A negative value moves the text range backward. Zero has no effect.
waitTime: float.
Return: int, the number of text units actually moved.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-move
"""
ret = self.textRange.Move(unit, count)
time.sleep(waitTime)
return ret
def MoveEndpointByRange(self, srcEndPoint: int, textRange: 'TextRange', targetEndPoint: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTextRange::MoveEndpointByRange.
Move one endpoint of the current text range to the specified endpoint of a second text range.
srcEndPoint: int, a value in class `TextPatternRangeEndpoint`.
textRange: `TextRange`.
targetEndPoint: int, a value in class `TextPatternRangeEndpoint`.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-moveendpointbyrange
"""
ret = self.textRange.MoveEndpointByRange(srcEndPoint, textRange.textRange, targetEndPoint) == S_OK
time.sleep(waitTime)
return ret
def MoveEndpointByUnit(self, endPoint: int, unit: int, count: int, waitTime: float = OPERATION_WAIT_TIME) -> int:
"""
Call IUIAutomationTextRange::MoveEndpointByUnit.
Move one endpoint of the text range the specified number of text units within the document range.
endPoint: int, a value in class `TextPatternRangeEndpoint`.
unit: int, a value in class `TextUnit`.
count: int, the number of units to move.
A positive count moves the endpoint forward.
A negative count moves backward.
A count of 0 has no effect.
waitTime: float.
Return int, the count of units actually moved.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-moveendpointbyunit
"""
ret = self.textRange.MoveEndpointByUnit(endPoint, unit, count)
time.sleep(waitTime)
return ret
def RemoveFromSelection(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTextRange::RemoveFromSelection.
Remove the text range from an existing collection of selected text in a text container that supports multiple, disjoint selections.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-removefromselection
"""
ret = self.textRange.RemoveFromSelection() == S_OK
time.sleep(waitTime)
return ret
def ScrollIntoView(self, alignTop: bool = True, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTextRange::ScrollIntoView.
Cause the text control to scroll until the text range is visible in the viewport.
alignTop: bool, True if the text control should be scrolled so that the text range is flush with the top of the viewport;
False if it should be flush with the bottom of the viewport.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-scrollintoview
"""
ret = self.textRange.ScrollIntoView(int(alignTop)) == S_OK
time.sleep(waitTime)
return ret
def Select(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTextRange::Select.
Select the span of text that corresponds to this text range, and remove any previous selection.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextrange-select
"""
ret = self.textRange.Select() == S_OK
time.sleep(waitTime)
return ret
class TextChildPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtextchildpattern"""
self.pattern = pattern
@property
def TextContainer(self) -> 'Control':
"""
Property TextContainer.
Call IUIAutomationSelectionContainer::get_TextContainer.
Return `Control` subclass, the nearest ancestor element that supports the Text control pattern.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextchildpattern-get_textcontainer
"""
return Control.CreateControlFromElement(self.pattern.TextContainer)
@property
def TextRange(self) -> TextRange:
"""
Property TextRange.
Call IUIAutomationSelectionContainer::get_TextRange.
Return `TextRange`, a text range that encloses this child element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextchildpattern-get_textrange
"""
return TextRange(self.pattern.TextRange)
class TextEditPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtexteditpattern"""
self.pattern = pattern
def GetActiveComposition(self) -> TextRange:
"""
Call IUIAutomationTextEditPattern::GetActiveComposition.
Return `TextRange` or None, the active composition.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtexteditpattern-getactivecomposition
"""
textRange = self.pattern.GetActiveComposition()
if textRange:
return TextRange(textRange=textRange)
def GetConversionTarget(self) -> TextRange:
"""
Call IUIAutomationTextEditPattern::GetConversionTarget.
Return `TextRange` or None, the current conversion target range..
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtexteditpattern-getconversiontarget
"""
textRange = self.pattern.GetConversionTarget()
if textRange:
return TextRange(textRange=textRange)
class TextPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtextpattern"""
self.pattern = pattern
@property
def DocumentRange(self) -> TextRange:
"""
Property DocumentRange.
Call IUIAutomationTextPattern::get_DocumentRange.
Return `TextRange`, a text range that encloses the main text of a document.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-get_documentrange
"""
return TextRange(self.pattern.DocumentRange)
@property
def SupportedTextSelection(self) -> bool:
"""
Property SupportedTextSelection.
Call IUIAutomationTextPattern::get_SupportedTextSelection.
Return bool, specifies the type of text selection that is supported by the control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-get_supportedtextselection
"""
return bool(self.pattern.SupportedTextSelection)
def GetSelection(self) -> List[TextRange]:
"""
Call IUIAutomationTextPattern::GetSelection.
Return List[TextRange], a list of `TextRange`, represents the currently selected text in a text-based control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-getselection
"""
eleArray = self.pattern.GetSelection()
if eleArray:
textRanges = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
textRanges.append(TextRange(textRange=ele))
return textRanges
return []
def GetVisibleRanges(self) -> List[TextRange]:
"""
Call IUIAutomationTextPattern::GetVisibleRanges.
Return List[TextRange], a list of `TextRange`, disjoint text ranges from a text-based control
where each text range represents a contiguous span of visible text.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-getvisibleranges
"""
eleArray = self.pattern.GetVisibleRanges()
if eleArray:
textRanges = []
for i in range(eleArray.Length):
ele = eleArray.GetElement(i)
textRanges.append(TextRange(textRange=ele))
return textRanges
return []
def RangeFromChild(self, child) -> TextRange:
"""
Call IUIAutomationTextPattern::RangeFromChild.
child: `Control` or its subclass.
Return `TextRange` or None, a text range enclosing a child element such as an image,
hyperlink, Microsoft Excel spreadsheet, or other embedded object.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-rangefromchild
"""
textRange = self.pattern.RangeFromChild(Control.Element)
if textRange:
return TextRange(textRange=textRange)
def RangeFromPoint(self, x: int, y: int) -> TextRange:
"""
Call IUIAutomationTextPattern::RangeFromPoint.
child: `Control` or its subclass.
Return `TextRange` or None, the degenerate (empty) text range nearest to the specified screen coordinates.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-rangefrompoint
"""
textRange = self.pattern.RangeFromPoint(ctypes.wintypes.POINT(x, y))
if textRange:
return TextRange(textRange=textRange)
class TextPattern2():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtextpattern2"""
self.pattern = pattern
class TogglePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtogglepattern"""
self.pattern = pattern
@property
def ToggleState(self) -> int:
"""
Property ToggleState.
Call IUIAutomationTogglePattern::get_CurrentToggleState.
Return int, a value in class `ToggleState`, the state of the control.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtogglepattern-get_currenttogglestate
"""
return self.pattern.CurrentToggleState
def Toggle(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTogglePattern::Toggle.
Cycle through the toggle states of the control.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtogglepattern-toggle
"""
ret = self.pattern.Toggle() == S_OK
time.sleep(waitTime)
return ret
class TransformPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtransformpattern"""
self.pattern = pattern
@property
def CanMove(self) -> bool:
"""
Property CanMove.
Call IUIAutomationTransformPattern::get_CurrentCanMove.
Return bool, indicates whether the element can be moved.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern-get_currentcanmove
"""
return bool(self.pattern.CurrentCanMove)
@property
def CanResize(self) -> bool:
"""
Property CanResize.
Call IUIAutomationTransformPattern::get_CurrentCanResize.
Return bool, indicates whether the element can be resized.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern-get_currentcanresize
"""
return bool(self.pattern.CurrentCanResize)
@property
def CanRotate(self) -> bool:
"""
Property CanRotate.
Call IUIAutomationTransformPattern::get_CurrentCanRotate.
Return bool, indicates whether the element can be rotated.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern-get_currentcanrotate
"""
return bool(self.pattern.CurrentCanRotate)
def Move(self, x: int, y: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTransformPattern::Move.
Move the UI Automation element.
x: int.
y: int.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern-move
"""
ret = self.pattern.Move(x, y) == S_OK
time.sleep(waitTime)
return ret
def Resize(self, width: int, height: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTransformPattern::Resize.
Resize the UI Automation element.
width: int.
height: int.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern-resize
"""
ret = self.pattern.Resize(width, height) == S_OK
time.sleep(waitTime)
return ret
def Rotate(self, degrees: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTransformPattern::Rotate.
Rotates the UI Automation element.
degrees: int.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern-rotate
"""
ret = self.pattern.Rotate(degrees) == S_OK
time.sleep(waitTime)
return ret
class TransformPattern2():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationtransformpattern2"""
self.pattern = pattern
@property
def CanZoom(self) -> bool:
"""
Property CanZoom.
Call IUIAutomationTransformPattern2::get_CurrentCanZoom.
Return bool, indicates whether the control supports zooming of its viewport.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern2-get_CurrentCanZoom
"""
return bool(self.pattern.CurrentCanZoom)
@property
def ZoomLevel(self) -> float:
"""
Property ZoomLevel.
Call IUIAutomationTransformPattern2::get_CurrentZoomLevel.
Return float, the zoom level of the control's viewport.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern2-get_currentzoomlevel
"""
return self.pattern.CurrentZoomLevel
@property
def ZoomMaximum(self) -> float:
"""
Property ZoomMaximum.
Call IUIAutomationTransformPattern2::get_CurrentZoomMaximum.
Return float, the maximum zoom level of the control's viewport.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern2-get_currentzoommaximum
"""
return self.pattern.CurrentZoomMaximum
@property
def ZoomMinimum(self) -> float:
"""
Property ZoomMinimum.
Call IUIAutomationTransformPattern2::get_CurrentZoomMinimum.
Return float, the minimum zoom level of the control's viewport.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern2-get_currentzoomminimum
"""
return self.pattern.CurrentZoomMinimum
def Zoom(self, zoomLevel: float, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTransformPattern2::Zoom.
Zoom the viewport of the control.
zoomLevel: float for int.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern2-zoom
"""
ret = self.pattern.Zoom(zoomLevel) == S_OK
time.sleep(waitTime)
return ret
def ZoomByUnit(self, zoomUnit: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTransformPattern2::ZoomByUnit.
Zoom the viewport of the control by the specified unit.
zoomUnit: int, a value in class `ZoomUnit`.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationtransformpattern2-zoombyunit
"""
ret = self.pattern.ZoomByUnit(zoomUnit) == S_OK
time.sleep(waitTime)
return ret
class ValuePattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationvaluepattern"""
self.pattern = pattern
@property
def IsReadOnly(self) -> bool:
"""
Property IsReadOnly.
Call IUIAutomationTransformPattern2::IUIAutomationValuePattern::get_CurrentIsReadOnly.
Return bool, indicates whether the value of the element is read-only.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationvaluepattern-get_currentisreadonly
"""
return self.pattern.CurrentIsReadOnly
@property
def Value(self) -> str:
"""
Property Value.
Call IUIAutomationTransformPattern2::IUIAutomationValuePattern::get_CurrentValue.
Return str, the value of the element.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationvaluepattern-get_currentvalue
"""
return self.pattern.CurrentValue
def SetValue(self, value: str, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationTransformPattern2::IUIAutomationValuePattern::SetValue.
Set the value of the element.
value: str.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationvaluepattern-setvalue
"""
ret = self.pattern.SetValue(value) == S_OK
time.sleep(waitTime)
return ret
class VirtualizedItemPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationvirtualizeditempattern"""
self.pattern = pattern
def Realize(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationVirtualizedItemPattern::Realize.
Create a full UI Automation element for a virtualized item.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationvirtualizeditempattern-realize
"""
ret = self.pattern.Realize() == S_OK
time.sleep(waitTime)
return ret
class WindowPattern():
def __init__(self, pattern=None):
"""Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationwindowpattern"""
self.pattern = pattern
def Close(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationWindowPattern::Close.
Close the window.
waitTime: float.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-close
"""
ret = self.pattern.Close() == S_OK
time.sleep(waitTime)
return ret
@property
def CanMaximize(self) -> bool:
"""
Property CanMaximize.
Call IUIAutomationWindowPattern::get_CurrentCanMaximize.
Return bool, indicates whether the window can be maximized.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-get_currentcanmaximize
"""
return bool(self.pattern.CurrentCanMaximize)
@property
def CanMinimize(self) -> bool:
"""
Property CanMinimize.
Call IUIAutomationWindowPattern::get_CurrentCanMinimize.
Return bool, indicates whether the window can be minimized.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-get_currentcanminimize
"""
return bool(self.pattern.CurrentCanMinimize)
@property
def IsModal(self) -> bool:
"""
Property IsModal.
Call IUIAutomationWindowPattern::get_CurrentIsModal.
Return bool, indicates whether the window is modal.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-get_currentismodal
"""
return bool(self.pattern.CurrentIsModal)
@property
def IsTopmost(self) -> bool:
"""
Property IsTopmost.
Call IUIAutomationWindowPattern::get_CurrentIsTopmost.
Return bool, indicates whether the window is the topmost element in the z-order.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-get_currentistopmost
"""
return bool(self.pattern.CurrentIsTopmost)
@property
def WindowInteractionState(self) -> int:
"""
Property WindowInteractionState.
Call IUIAutomationWindowPattern::get_CurrentWindowInteractionState.
Return int, a value in class `WindowInteractionState`,
the current state of the window for the purposes of user interaction.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-get_currentwindowinteractionstate
"""
return self.pattern.CurrentWindowInteractionState
@property
def WindowVisualState(self) -> int:
"""
Property WindowVisualState.
Call IUIAutomationWindowPattern::get_CurrentWindowVisualState.
Return int, a value in class `WindowVisualState`,
the visual state of the window; that is, whether it is in the normal, maximized, or minimized state.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-get_currentwindowvisualstate
"""
return self.pattern.CurrentWindowVisualState
def SetWindowVisualState(self, state: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call IUIAutomationWindowPattern::SetWindowVisualState.
Minimize, maximize, or restore the window.
state: int, a value in class `WindowVisualState`.
waitTime: float.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-setwindowvisualstate
"""
ret = self.pattern.SetWindowVisualState(state) == S_OK
time.sleep(waitTime)
return ret
def WaitForInputIdle(self, milliseconds: int) -> bool:
'''
Call IUIAutomationWindowPattern::WaitForInputIdle.
Cause the calling code to block for the specified time or
until the associated process enters an idle state, whichever completes first.
milliseconds: int.
Return bool, True if succeed otherwise False.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationwindowpattern-waitforinputidle
'''
return self.pattern.WaitForInputIdle(milliseconds) == S_OK
PatternConstructors = {
PatternId.AnnotationPattern: AnnotationPattern,
PatternId.CustomNavigationPattern: CustomNavigationPattern,
PatternId.DockPattern: DockPattern,
PatternId.DragPattern: DragPattern,
PatternId.DropTargetPattern: DropTargetPattern,
PatternId.ExpandCollapsePattern: ExpandCollapsePattern,
PatternId.GridItemPattern: GridItemPattern,
PatternId.GridPattern: GridPattern,
PatternId.InvokePattern: InvokePattern,
PatternId.ItemContainerPattern: ItemContainerPattern,
PatternId.LegacyIAccessiblePattern: LegacyIAccessiblePattern,
PatternId.MultipleViewPattern: MultipleViewPattern,
PatternId.ObjectModelPattern: ObjectModelPattern,
PatternId.RangeValuePattern: RangeValuePattern,
PatternId.ScrollItemPattern: ScrollItemPattern,
PatternId.ScrollPattern: ScrollPattern,
PatternId.SelectionItemPattern: SelectionItemPattern,
PatternId.SelectionPattern: SelectionPattern,
PatternId.SpreadsheetItemPattern: SpreadsheetItemPattern,
PatternId.SpreadsheetPattern: SpreadsheetPattern,
PatternId.StylesPattern: StylesPattern,
PatternId.SynchronizedInputPattern: SynchronizedInputPattern,
PatternId.TableItemPattern: TableItemPattern,
PatternId.TablePattern: TablePattern,
PatternId.TextChildPattern: TextChildPattern,
PatternId.TextEditPattern: TextEditPattern,
PatternId.TextPattern: TextPattern,
PatternId.TextPattern2: TextPattern2,
PatternId.TogglePattern: TogglePattern,
PatternId.TransformPattern: TransformPattern,
PatternId.TransformPattern2: TransformPattern2,
PatternId.ValuePattern: ValuePattern,
PatternId.VirtualizedItemPattern: VirtualizedItemPattern,
PatternId.WindowPattern: WindowPattern,
}
def CreatePattern(patternId: int, pattern: ctypes.POINTER(comtypes.IUnknown)):
"""Create a concreate pattern by pattern id and pattern(POINTER(IUnknown))."""
subPattern = pattern.QueryInterface(GetPatternIdInterface(patternId))
if subPattern:
return PatternConstructors[patternId](pattern=subPattern)
class Control():
ValidKeys = set(['ControlType', 'ClassName', 'AutomationId', 'Name', 'SubName', 'RegexName', 'Depth', 'Compare'])
def __init__(self, searchFromControl: 'Control' = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
"""
searchFromControl: `Control` or its subclass, if it is None, search from root control(Desktop).
searchDepth: int, max search depth from searchFromControl.
foundIndex: int, starts with 1, >= 1.
searchInterval: float, wait searchInterval after every search in self.Refind and self.Exists, the global timeout is TIME_OUT_SECOND.
element: `ctypes.POINTER(IUIAutomationElement)`, internal use only.
searchProperties: defines how to search, the following keys can be used:
ControlType: int, a value in class `ControlType`.
ClassName: str.
AutomationId: str.
Name: str.
SubName: str, a part str in Name.
RegexName: str, supports regex using re.match.
You can only use one of Name, SubName, RegexName in searchProperties.
Depth: int, only search controls in relative depth from searchFromControl, ignore controls in depth(0~Depth-1),
if set, searchDepth will be set to Depth too.
Compare: Callable[[Control, int], bool], custom compare function(control: Control, depth: int) -> bool.
`Control` wraps IUIAutomationElement.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nn-uiautomationclient-iuiautomationelement
"""
self._element = element
self._elementDirectAssign = True if element else False
self.searchFromControl = searchFromControl
self.searchDepth = searchProperties.get('Depth', searchDepth)
self.searchInterval = searchInterval
self.foundIndex = foundIndex
self.searchProperties = searchProperties
regName = searchProperties.get('RegexName', '')
self.regexName = re.compile(regName) if regName else None
self._supportedPatterns = {}
def __str__(self) -> str:
rect = self.BoundingRectangle
return 'ControlType: {0} ClassName: {1} AutomationId: {2} Rect: {3} Name: {4} Handle: 0x{5:X}({5})'.format(
self.ControlTypeName, self.ClassName, self.AutomationId, rect, self.Name, self.NativeWindowHandle)
@property
def runtimeid(self):
return ''.join([str(i) for i in self.GetRuntimeId()])
@staticmethod
def CreateControlFromElement(element) -> 'Control':
"""
Create a concreate `Control` from a com type `IUIAutomationElement`.
element: `ctypes.POINTER(IUIAutomationElement)`.
Return a subclass of `Control`, an instance of the control's real type.
"""
if element:
controlType = element.CurrentControlType
if controlType in ControlConstructors:
return ControlConstructors[controlType](element=element)
else:
Logger.WriteLine("element.CurrentControlType returns {}, invalid ControlType!".format(controlType), ConsoleColor.Red) #rarely happens
@staticmethod
def CreateControlFromControl(control: 'Control') -> 'Control':
"""
Create a concreate `Control` from a control instance, copy it.
control: `Control` or its subclass.
Return a subclass of `Control`, an instance of the control's real type.
For example: if control's ControlType is EditControl, return an EditControl.
"""
newControl = Control.CreateControlFromElement(control.Element)
return newControl
def SetSearchFromControl(self, searchFromControl: 'Control') -> None:
"""searchFromControl: `Control` or its subclass"""
self.searchFromControl = searchFromControl
def SetSearchDepth(self, searchDepth: int) -> None:
self.searchDepth = searchDepth
def AddSearchProperties(self, **searchProperties) -> None:
"""
Add search properties using `dict.update`.
searchProperties: dict, same as searchProperties in `Control.__init__`.
"""
self.searchProperties.update(searchProperties)
if 'Depth' in searchProperties:
self.searchDepth = searchProperties['Depth']
if 'RegexName' in searchProperties:
regName = searchProperties['RegexName']
self.regexName = re.compile(regName) if regName else None
def RemoveSearchProperties(self, **searchProperties) -> None:
"""
searchProperties: dict, same as searchProperties in `Control.__init__`.
"""
for key in searchProperties:
del self.searchProperties[key]
if key == 'RegexName':
self.regexName = None
def GetSearchPropertiesStr(self) -> str:
strs = ['{}: {}'.format(k, ControlTypeNames[v] if k == 'ControlType' else repr(v)) for k, v in self.searchProperties.items()]
return '{' + ', '.join(strs) + '}'
def GetColorfulSearchPropertiesStr(self, keyColor='DarkGreen', valueColor='DarkCyan') -> str:
"""keyColor, valueColor: str, color name in class ConsoleColor"""
strs = ['{}: {}'.format(keyColor if k in Control.ValidKeys else 'DarkYellow', k, valueColor,
ControlTypeNames[v] if k == 'ControlType' else repr(v)) for k, v in self.searchProperties.items()]
return '{' + ', '.join(strs) + '}'
#BuildUpdatedCache
#CachedAcceleratorKey
#CachedAccessKey
#CachedAriaProperties
#CachedAriaRole
#CachedAutomationId
#CachedBoundingRectangle
#CachedClassName
#CachedControlType
#CachedControllerFor
#CachedCulture
#CachedDescribedBy
#CachedFlowsTo
#CachedFrameworkId
#CachedHasKeyboardFocus
#CachedHelpText
#CachedIsContentElement
#CachedIsControlElement
#CachedIsDataValidForForm
#CachedIsEnabled
#CachedIsKeyboardFocusable
#CachedIsOffscreen
#CachedIsPassword
#CachedIsRequiredForForm
#CachedItemStatus
#CachedItemType
#CachedLabeledBy
#CachedLocalizedControlType
#CachedName
#CachedNativeWindowHandle
#CachedOrientation
#CachedProcessId
#CachedProviderDescription
@property
def AcceleratorKey(self) -> str:
"""
Property AcceleratorKey.
Call IUIAutomationElement::get_CurrentAcceleratorKey.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentacceleratorkey
"""
return self.Element.CurrentAcceleratorKey
@property
def AccessKey(self) -> str:
"""
Property AccessKey.
Call IUIAutomationElement::get_CurrentAccessKey.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentaccesskey
"""
return self.Element.CurrentAccessKey
@property
def AriaProperties(self) -> str:
"""
Property AriaProperties.
Call IUIAutomationElement::get_CurrentAriaProperties.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentariaproperties
"""
return self.Element.CurrentAriaProperties
@property
def AriaRole(self) -> str:
"""
Property AriaRole.
Call IUIAutomationElement::get_CurrentAriaRole.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentariarole
"""
return self.Element.CurrentAriaRole
@property
def AutomationId(self) -> str:
"""
Property AutomationId.
Call IUIAutomationElement::get_CurrentAutomationId.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentautomationid
"""
return self.Element.CurrentAutomationId
@property
def BoundingRectangle(self) -> Rect:
"""
Property BoundingRectangle.
Call IUIAutomationElement::get_CurrentBoundingRectangle.
Return `Rect`.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentboundingrectangle
rect = control.BoundingRectangle
print(rect.left, rect.top, rect.right, rect.bottom, rect.width(), rect.height(), rect.xcenter(), rect.ycenter())
"""
rect = self.Element.CurrentBoundingRectangle
return Rect(rect.left, rect.top, rect.right, rect.bottom)
@property
def ClassName(self) -> str:
"""
Property ClassName.
Call IUIAutomationElement::get_CurrentClassName.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentclassname
"""
return self.Element.CurrentClassName
@property
def ControlType(self) -> int:
"""
Property ControlType.
Return int, a value in class `ControlType`.
Call IUIAutomationElement::get_CurrentControlType.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentcontroltype
"""
return self.Element.CurrentControlType
#@property
#def ControllerFor(self):
#return self.Element.CurrentControllerFor
@property
def Culture(self) -> int:
"""
Property Culture.
Call IUIAutomationElement::get_CurrentCulture.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentculture
"""
return self.Element.CurrentCulture
#@property
#def DescribedBy(self):
#return self.Element.CurrentDescribedBy
#@property
#def FlowsTo(self):
#return self.Element.CurrentFlowsTo
@property
def FrameworkId(self) -> str:
"""
Property FrameworkId.
Call IUIAutomationElement::get_CurrentFrameworkId.
Return str, such as Win32, WPF...
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentframeworkid
"""
return self.Element.CurrentFrameworkId
@property
def HasKeyboardFocus(self) -> bool:
"""
Property HasKeyboardFocus.
Call IUIAutomationElement::get_CurrentHasKeyboardFocus.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currenthaskeyboardfocus
"""
return bool(self.Element.CurrentHasKeyboardFocus)
@property
def HelpText(self) -> str:
"""
Property HelpText.
Call IUIAutomationElement::get_CurrentHelpText.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currenthelptext
"""
return self.Element.CurrentHelpText
@property
def IsContentElement(self) -> bool:
"""
Property IsContentElement.
Call IUIAutomationElement::get_CurrentIsContentElement.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentiscontentelement
"""
return bool(self.Element.CurrentIsContentElement)
@property
def IsControlElement(self) -> bool:
"""
Property IsControlElement.
Call IUIAutomationElement::get_CurrentIsControlElement.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentiscontrolelement
"""
return bool(self.Element.CurrentIsControlElement)
@property
def IsDataValidForForm(self) -> bool:
"""
Property IsDataValidForForm.
Call IUIAutomationElement::get_CurrentIsDataValidForForm.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentisdatavalidforform
"""
return bool(self.Element.CurrentIsDataValidForForm)
@property
def IsEnabled(self) -> bool:
"""
Property IsEnabled.
Call IUIAutomationElement::get_CurrentIsEnabled.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentisenabled
"""
return self.Element.CurrentIsEnabled
@property
def IsKeyboardFocusable(self) -> bool:
"""
Property IsKeyboardFocusable.
Call IUIAutomationElement::get_CurrentIsKeyboardFocusable.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentiskeyboardfocusable
"""
return self.Element.CurrentIsKeyboardFocusable
@property
def IsOffscreen(self) -> bool:
"""
Property IsOffscreen.
Call IUIAutomationElement::get_CurrentIsOffscreen.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentisoffscreen
"""
return self.Element.CurrentIsOffscreen
@property
def IsPassword(self) -> bool:
"""
Property IsPassword.
Call IUIAutomationElement::get_CurrentIsPassword.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentispassword
"""
return self.Element.CurrentIsPassword
@property
def IsRequiredForForm(self) -> bool:
"""
Property IsRequiredForForm.
Call IUIAutomationElement::get_CurrentIsRequiredForForm.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentisrequiredforform
"""
return self.Element.CurrentIsRequiredForForm
@property
def ItemStatus(self) -> str:
"""
Property ItemStatus.
Call IUIAutomationElement::get_CurrentItemStatus.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentitemstatus
"""
return self.Element.CurrentItemStatus
@property
def ItemType(self) -> str:
"""
Property ItemType.
Call IUIAutomationElement::get_CurrentItemType.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentitemtype
"""
return self.Element.CurrentItemType
#@property
#def LabeledBy(self):
#return self.Element.CurrentLabeledBy
@property
def LocalizedControlType(self) -> str:
"""
Property LocalizedControlType.
Call IUIAutomationElement::get_CurrentLocalizedControlType.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentlocalizedcontroltype
"""
return self.Element.CurrentLocalizedControlType
@property
def Name(self) -> str:
"""
Property Name.
Call IUIAutomationElement::get_CurrentName.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentname
"""
return self.Element.CurrentName or '' # CurrentName may be None
@property
def NativeWindowHandle(self) -> str:
"""
Property NativeWindowHandle.
Call IUIAutomationElement::get_CurrentNativeWindowHandle.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentnativewindowhandle
"""
handle = self.Element.CurrentNativeWindowHandle
return 0 if handle is None else handle
@property
def Orientation(self) -> int:
"""
Property Orientation.
Return int, a value in class `OrientationType`.
Call IUIAutomationElement::get_CurrentOrientation.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentorientation
"""
return self.Element.CurrentOrientation
@property
def ProcessId(self) -> int:
"""
Property ProcessId.
Call IUIAutomationElement::get_CurrentProcessId.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentprocessid
"""
return self.Element.CurrentProcessId
@property
def ProviderDescription(self) -> str:
"""
Property ProviderDescription.
Call IUIAutomationElement::get_CurrentProviderDescription.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-get_currentproviderdescription
"""
return self.Element.CurrentProviderDescription
#FindAll
#FindAllBuildCache
#FindFirst
#FindFirstBuildCache
#GetCachedChildren
#GetCachedParent
#GetCachedPattern
#GetCachedPatternAs
#GetCachedPropertyValue
#GetCachedPropertyValueEx
def GetClickablePoint(self) -> Tuple[int, int, bool]:
"""
Call IUIAutomationElement::GetClickablePoint.
Return Tuple[int, int, bool], three items tuple (x, y, gotClickable), such as (20, 10, True)
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-getclickablepoint
"""
point, gotClickable = self.Element.GetClickablePoint()
return (point.x, point.y, bool(gotClickable))
def GetPattern(self, patternId: int):
"""
Call IUIAutomationElement::GetCurrentPattern.
Get a new pattern by pattern id if it supports the pattern.
patternId: int, a value in class `PatternId`.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-getcurrentpattern
"""
try:
pattern = self.Element.GetCurrentPattern(patternId)
if pattern:
subPattern = CreatePattern(patternId, pattern)
self._supportedPatterns[patternId] = subPattern
return subPattern
except comtypes.COMError as ex:
pass
def GetPatternAs(self, patternId: int, riid):
"""
Call IUIAutomationElement::GetCurrentPatternAs.
Get a new pattern by pattern id if it supports the pattern, todo.
patternId: int, a value in class `PatternId`.
riid: GUID.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-getcurrentpatternas
"""
return self.Element.GetCurrentPatternAs(patternId, riid)
def GetPropertyValue(self, propertyId: int) -> Any:
"""
Call IUIAutomationElement::GetCurrentPropertyValue.
propertyId: int, a value in class `PropertyId`.
Return Any, corresponding type according to propertyId.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-getcurrentpropertyvalue
"""
return self.Element.GetCurrentPropertyValue(propertyId)
def GetPropertyValueEx(self, propertyId: int, ignoreDefaultValue: int) -> Any:
"""
Call IUIAutomationElement::GetCurrentPropertyValueEx.
propertyId: int, a value in class `PropertyId`.
ignoreDefaultValue: int, 0 or 1.
Return Any, corresponding type according to propertyId.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-getcurrentpropertyvalueex
"""
return self.Element.GetCurrentPropertyValueEx(propertyId, ignoreDefaultValue)
def GetRuntimeId(self) -> List[int]:
"""
Call IUIAutomationElement::GetRuntimeId.
Return List[int], a list of int.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-getruntimeid
"""
return self.Element.GetRuntimeId()
#QueryInterface
#Release
def SetFocus(self) -> bool:
"""
Call IUIAutomationElement::SetFocus.
Refer https://docs.microsoft.com/en-us/windows/desktop/api/uiautomationclient/nf-uiautomationclient-iuiautomationelement-setfocus
"""
try:
return self.Element.SetFocus() == S_OK
except comtypes.COMError as ex:
return False
@property
def Element(self):
"""
Property Element.
Return `ctypes.POINTER(IUIAutomationElement)`.
"""
if not self._element:
self.Refind(maxSearchSeconds=TIME_OUT_SECOND, searchIntervalSeconds=self.searchInterval)
return self._element
@property
def ControlTypeName(self) -> str:
"""
Property ControlTypeName.
"""
return ControlTypeNames[self.ControlType]
def GetCachedPattern(self, patternId: int, cache: bool):
"""
Get a pattern by patternId.
patternId: int, a value in class `PatternId`.
Return a pattern if it supports the pattern else None.
cache: bool, if True, store the pattern for later use, if False, get a new pattern by `self.GetPattern`.
"""
if cache:
pattern = self._supportedPatterns.get(patternId, None)
if pattern:
return pattern
else:
pattern = self.GetPattern(patternId)
if pattern:
self._supportedPatterns[patternId] = pattern
return pattern
else:
pattern = self.GetPattern(patternId)
if pattern:
self._supportedPatterns[patternId] = pattern
return pattern
def GetLegacyIAccessiblePattern(self) -> LegacyIAccessiblePattern:
"""
Return `LegacyIAccessiblePattern` if it supports the pattern else None.
"""
return self.GetPattern(PatternId.LegacyIAccessiblePattern)
def GetAncestorControl(self, condition: Callable[['Control', int], bool]) -> 'Control':
"""
Get an ancestor control that matches the condition.
condition: Callable[[Control, int], bool], function(control: Control, depth: int) -> bool,
depth starts with -1 and decreses when search goes up.
Return `Control` subclass or None.
"""
ancestor = self
depth = 0
while True:
ancestor = ancestor.GetParentControl()
depth -= 1
if ancestor:
if condition(ancestor, depth):
return ancestor
else:
break
def GetParentControl(self) -> 'Control':
"""
Return `Control` subclass or None.
"""
ele = _AutomationClient.instance().ViewWalker.GetParentElement(self.Element)
return Control.CreateControlFromElement(ele)
def GetFirstChildControl(self) -> 'Control':
"""
Return `Control` subclass or None.
"""
ele = _AutomationClient.instance().ViewWalker.GetFirstChildElement(self.Element)
return Control.CreateControlFromElement(ele)
def GetLastChildControl(self) -> 'Control':
"""
Return `Control` subclass or None.
"""
ele = _AutomationClient.instance().ViewWalker.GetLastChildElement(self.Element)
return Control.CreateControlFromElement(ele)
def GetNextSiblingControl(self) -> 'Control':
"""
Return `Control` subclass or None.
"""
ele = _AutomationClient.instance().ViewWalker.GetNextSiblingElement(self.Element)
return Control.CreateControlFromElement(ele)
def GetPreviousSiblingControl(self) -> 'Control':
"""
Return `Control` subclass or None.
"""
ele = _AutomationClient.instance().ViewWalker.GetPreviousSiblingElement(self.Element)
return Control.CreateControlFromElement(ele)
def GetSiblingControl(self, condition: Callable[['Control'], bool], forward: bool = True) -> 'Control':
"""
Get a sibling control that matches the condition.
forward: bool, if True, only search next siblings, if False, search pervious siblings first, then search next siblings.
condition: Callable[[Control], bool], function(control: Control) -> bool.
Return `Control` subclass or None.
"""
if not forward:
prev = self
while True:
prev = prev.GetPreviousSiblingControl()
if prev:
if condition(prev):
return prev
else:
break
next_ = self
while True:
next_ = next_.GetNextSiblingControl()
if next_:
if condition(next_):
return next_
else:
break
def GetChildControl(self, index: int, control_type: str = None) -> 'Control':
"""
Get the nth child control.
index: int, starts with 0.
control_type: `Control` or its subclass, if not None, only return the nth control that matches the control_type.
Return `Control` subclass or None.
"""
children = self.GetChildren()
if control_type:
children = [child for child in children if child.ControlTypeName == control_type]
if index < len(children):
return children[index]
else:
return None
def GetAllProgeny(self) -> List[List['Control']]:
"""
Get all progeny controls.
Return List[List[Control]], a list of list of `Control` subclasses.
"""
all_elements = []
def find_all_elements(element, depth=0):
children = element.GetChildren()
if depth == len(all_elements):
all_elements.append([])
all_elements[depth].append(element)
for child in children:
find_all_elements(child, depth+1)
return all_elements
return find_all_elements(self)
def GetProgenyControl(self, depth: int=1, index: int=0, control_type: str = None) -> 'Control':
"""
Get the nth control in the mth depth.
depth: int, starts with 0.
index: int, starts with 0.
control_type: `Control` or its subclass, if not None, only return the nth control that matches the control_type.
Return `Control` subclass or None.
"""
progeny = self.GetAllProgeny()
try:
controls = progeny[depth]
if control_type:
controls = [child for child in controls if child.ControlTypeName == control_type]
if index < len(progeny):
return controls[index]
except IndexError:
return
def GetChildren(self) -> List['Control']:
"""
Return List[Control], a list of `Control` subclasses.
"""
children = []
child = self.GetFirstChildControl()
while child:
children.append(child)
child = child.GetNextSiblingControl()
return children
def _CompareFunction(self, control: 'Control', depth: int) -> bool:
"""
Define how to search.
control: `Control` or its subclass.
depth: int, tree depth from searchFromControl.
Return bool.
"""
for key, value in self.searchProperties.items():
if 'ControlType' == key:
if value != control.ControlType:
return False
elif 'ClassName' == key:
if value != control.ClassName:
return False
elif 'AutomationId' == key:
if value != control.AutomationId:
return False
elif 'Depth' == key:
if value != depth:
return False
elif 'Name' == key:
if value != control.Name:
return False
elif 'SubName' == key:
if value not in control.Name:
return False
elif 'RegexName' == key:
if not self.regexName.match(control.Name):
return False
elif 'Compare' == key:
if not value(control, depth):
return False
return True
def Exists(self, maxSearchSeconds: float = 5, searchIntervalSeconds: float = SEARCH_INTERVAL, printIfNotExist: bool = False) -> bool:
"""
maxSearchSeconds: float
searchIntervalSeconds: float
Find control every searchIntervalSeconds seconds in maxSearchSeconds seconds.
Return bool, True if find
"""
if self._element and self._elementDirectAssign:
#if element is directly assigned, not by searching, just check whether self._element is valid
#but I can't find an API in UIAutomation that can directly check
rootElement = GetRootControl().Element
if self._element == rootElement:
return True
else:
parentElement = _AutomationClient.instance().ViewWalker.GetParentElement(self._element)
if parentElement:
return True
else:
return False
#find the element
if len(self.searchProperties) == 0:
raise LookupError("control's searchProperties must not be empty!")
self._element = None
startTime = ProcessTime()
# Use same timeout(s) parameters for resolve all parents
prev = self.searchFromControl
if prev and not prev._element and not prev.Exists(maxSearchSeconds, searchIntervalSeconds):
if printIfNotExist or DEBUG_EXIST_DISAPPEAR:
Logger.ColorfullyLog(self.GetColorfulSearchPropertiesStr() + ' does not exist.')
return False
startTime2 = ProcessTime()
if DEBUG_SEARCH_TIME:
startDateTime = datetime.datetime.now()
while True:
control = FindControl(self.searchFromControl, self._CompareFunction, self.searchDepth, False, self.foundIndex)
if control:
self._element = control.Element
control._element = 0 # control will be destroyed, but the element needs to be stroed in self._element
if DEBUG_SEARCH_TIME:
Logger.ColorfullyLog('{} TraverseControls: {}, SearchTime: {:.3f}s[{} - {}]'.format(
self.GetColorfulSearchPropertiesStr(), control.traverseCount, ProcessTime() - startTime2,
startDateTime.time(), datetime.datetime.now().time()))
return True
else:
remain = startTime + maxSearchSeconds - ProcessTime()
if remain > 0:
time.sleep(min(remain, searchIntervalSeconds))
else:
if printIfNotExist or DEBUG_EXIST_DISAPPEAR:
Logger.ColorfullyLog(self.GetColorfulSearchPropertiesStr() + ' does not exist.')
return False
def Disappears(self, maxSearchSeconds: float = 5, searchIntervalSeconds: float = SEARCH_INTERVAL, printIfNotDisappear: bool = False) -> bool:
"""
maxSearchSeconds: float
searchIntervalSeconds: float
Check if control disappears every searchIntervalSeconds seconds in maxSearchSeconds seconds.
Return bool, True if control disappears.
"""
global DEBUG_EXIST_DISAPPEAR
start = ProcessTime()
while True:
temp = DEBUG_EXIST_DISAPPEAR
DEBUG_EXIST_DISAPPEAR = False # do not print for Exists
if not self.Exists(0, 0, False):
DEBUG_EXIST_DISAPPEAR = temp
return True
DEBUG_EXIST_DISAPPEAR = temp
remain = start + maxSearchSeconds - ProcessTime()
if remain > 0:
time.sleep(min(remain, searchIntervalSeconds))
else:
if printIfNotDisappear or DEBUG_EXIST_DISAPPEAR:
Logger.ColorfullyLog(self.GetColorfulSearchPropertiesStr() + ' does not disappear.')
return False
def Refind(self, maxSearchSeconds: float = TIME_OUT_SECOND, searchIntervalSeconds: float = SEARCH_INTERVAL, raiseException: bool = True) -> bool:
"""
Refind the control every searchIntervalSeconds seconds in maxSearchSeconds seconds.
maxSearchSeconds: float.
searchIntervalSeconds: float.
raiseException: bool, if True, raise a LookupError if timeout.
Return bool, True if find.
"""
if not self.Exists(maxSearchSeconds, searchIntervalSeconds, False if raiseException else DEBUG_EXIST_DISAPPEAR):
if raiseException:
# Logger.ColorfullyLog('Find Control Timeout: ' + self.GetColorfulSearchPropertiesStr())
raise LookupError('Find Control Timeout: ' + self.GetSearchPropertiesStr())
else:
return False
return True
def MoveCursorToInnerPos(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, simulateMove: bool = False) -> Tuple[int, int]:
"""
Move cursor to control's internal position, default to center.
x: int, if < 0, move to self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, move to self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
simulateMove: bool.
Return Tuple[int, int], two ints tuple (x, y), the cursor positon relative to screen(0, 0)
after moving or None if control's width or height is 0.
"""
rect = self.BoundingRectangle
if rect.width() == 0 or rect.height() == 0:
Logger.ColorfullyLog('Can not move cursor. {}\'s BoundingRectangle is {}. SearchProperties: {}'.format(
self.ControlTypeName, rect, self.GetColorfulSearchPropertiesStr()))
return
if x is None:
x = rect.left + int(rect.width() * ratioX)
else:
x = (rect.left if x >= 0 else rect.right) + x
if y is None:
y = rect.top + int(rect.height() * ratioY)
else:
y = (rect.top if y >= 0 else rect.bottom) + y
if simulateMove and MAX_MOVE_SECOND > 0:
MoveTo(x, y, waitTime=0)
else:
SetCursorPos(x, y)
return x, y
def MoveCursorToMyCenter(self, simulateMove: bool = False) -> Tuple[int, int]:
"""
Move cursor to control's center.
Return Tuple[int, int], two ints tuple (x, y), the cursor positon relative to screen(0, 0) after moving.
"""
return self.MoveCursorToInnerPos(simulateMove=simulateMove)
def Click(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, simulateMove: bool = False, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
x: int, if < 0, click self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, click self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
simulateMove: bool, if True, first move cursor to control smoothly.
waitTime: float.
Click(), Click(ratioX=0.5, ratioY=0.5): click center.
Click(10, 10): click left+10, top+10.
Click(-10, -10): click right-10, bottom-10.
"""
point = self.MoveCursorToInnerPos(x, y, ratioX, ratioY, simulateMove)
if point:
Click(point[0], point[1], waitTime)
def MiddleClick(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, simulateMove: bool = False, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
x: int, if < 0, middle click self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, middle click self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
simulateMove: bool, if True, first move cursor to control smoothly.
waitTime: float.
MiddleClick(), MiddleClick(ratioX=0.5, ratioY=0.5): middle click center.
MiddleClick(10, 10): middle click left+10, top+10.
MiddleClick(-10, -10): middle click right-10, bottom-10.
"""
point = self.MoveCursorToInnerPos(x, y, ratioX, ratioY, simulateMove)
if point:
MiddleClick(point[0], point[1], waitTime)
def RightClick(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, simulateMove: bool = False, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
x: int, if < 0, right click self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, right click self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
simulateMove: bool, if True, first move cursor to control smoothly.
waitTime: float.
RightClick(), RightClick(ratioX=0.5, ratioY=0.5): right click center.
RightClick(10, 10): right click left+10, top+10.
RightClick(-10, -10): right click right-10, bottom-10.
"""
point = self.MoveCursorToInnerPos(x, y, ratioX, ratioY, simulateMove)
if point:
RightClick(point[0], point[1], waitTime)
def DoubleClick(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, simulateMove: bool = False, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
x: int, if < 0, right click self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, right click self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
simulateMove: bool, if True, first move cursor to control smoothly.
waitTime: float.
DoubleClick(), DoubleClick(ratioX=0.5, ratioY=0.5): double click center.
DoubleClick(10, 10): double click left+10, top+10.
DoubleClick(-10, -10): double click right-10, bottom-10.
"""
x, y = self.MoveCursorToInnerPos(x, y, ratioX, ratioY, simulateMove)
Click(x, y, GetDoubleClickTime() * 1.0 / 2000)
Click(x, y, waitTime)
def DragDrop(self, x1: int, y1: int, x2: int, y2: int, moveSpeed: float=1, waitTime: float = OPERATION_WAIT_TIME) -> None:
rect = self.BoundingRectangle
if rect.width() == 0 or rect.height() == 0:
Logger.ColorfullyLog('Can not move cursor. {}\'s BoundingRectangle is {}. SearchProperties: {}'.format(
self.ControlTypeName, rect, self.GetColorfulSearchPropertiesStr()))
return
x1 = (rect.left if x1 >= 0 else rect.right) + x1
y1 = (rect.top if y1 >= 0 else rect.bottom) + y1
x2 = (rect.left if x2 >= 0 else rect.right) + x2
y2 = (rect.top if y2 >= 0 else rect.bottom) + y2
DragDrop(x1, y1, x2, y2, moveSpeed, waitTime)
def WheelDown(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, wheelTimes: int = 1, interval: float = 0.05, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Make control have focus first, move cursor to the specified position and mouse wheel down.
x: int, if < 0, move x cursor to self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, move y cursor to self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
wheelTimes: int.
interval: float.
waitTime: float.
"""
cursorX, cursorY = GetCursorPos()
self.SetFocus()
self.MoveCursorToInnerPos(x, y, ratioX, ratioY, simulateMove=False)
WheelDown(wheelTimes, interval, waitTime)
SetCursorPos(cursorX, cursorY)
def WheelUp(self, x: int = None, y: int = None, ratioX: float = 0.5, ratioY: float = 0.5, wheelTimes: int = 1, interval: float = 0.05, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Make control have focus first, move cursor to the specified position and mouse wheel up.
x: int, if < 0, move x cursor to self.BoundingRectangle.right + x, if not None, ignore ratioX.
y: int, if < 0, move y cursor to self.BoundingRectangle.bottom + y, if not None, ignore ratioY.
ratioX: float.
ratioY: float.
wheelTimes: int.
interval: float.
waitTime: float.
"""
cursorX, cursorY = GetCursorPos()
self.SetFocus()
self.MoveCursorToInnerPos(x, y, ratioX, ratioY, simulateMove=False)
WheelUp(wheelTimes, interval, waitTime)
SetCursorPos(cursorX, cursorY)
def ShowWindow(self, cmdShow: int, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Get a native handle from self or ancestors until valid and call native `ShowWindow` with cmdShow.
cmdShow: int, a value in in class `SW`.
waitTime: float.
Return bool, True if succeed otherwise False.
"""
handle = self.NativeWindowHandle
if not handle:
control = self
while not handle:
control = control.GetParentControl()
handle = control.NativeWindowHandle
if handle:
ret = ShowWindow(handle, cmdShow)
time.sleep(waitTime)
return ret
def Show(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call native `ShowWindow(SW.Show)`.
Return bool, True if succeed otherwise False.
"""
return self.ShowWindow(SW.Show, waitTime)
def Hide(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Call native `ShowWindow(SW.Hide)`.
waitTime: float
Return bool, True if succeed otherwise False.
"""
return self.ShowWindow(SW.Hide, waitTime)
def MoveWindow(self, x: int, y: int, width: int, height: int, repaint: bool = True) -> bool:
"""
Call native MoveWindow if control has a valid native handle.
x: int.
y: int.
width: int.
height: int.
repaint: bool.
Return bool, True if succeed otherwise False.
"""
handle = self.NativeWindowHandle
if handle:
return MoveWindow(handle, x, y, width, height, int(repaint))
return False
def GetWindowText(self) -> str:
"""
Call native GetWindowText if control has a valid native handle.
"""
handle = self.NativeWindowHandle
if handle:
return GetWindowText(handle)
def SetWindowText(self, text: str) -> bool:
"""
Call native SetWindowText if control has a valid native handle.
"""
handle = self.NativeWindowHandle
if handle:
return SetWindowText(handle, text)
return False
def SendKey(self, key: int, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Make control have focus first and type a key.
`self.SetFocus` may not work for some controls, you may need to click it to make it have focus.
key: int, a key code value in class Keys.
waitTime: float.
"""
self.SetFocus()
SendKey(key, waitTime)
def SendKeys(self, text: str, interval: float = 0.01, waitTime: float = OPERATION_WAIT_TIME, charMode: bool = True) -> None:
"""
Make control have focus first and type keys.
`self.SetFocus` may not work for some controls, you may need to click it to make it have focus.
text: str, keys to type, see the docstring of `SendKeys`.
interval: float, seconds between keys.
waitTime: float.
charMode: bool, if False, the text typied is depend on the input method if a input method is on.
"""
self.SetFocus()
SendKeys(text, interval, waitTime, charMode)
def GetPixelColor(self, x: int, y: int) -> int:
"""
Call native `GetPixelColor` if control has a valid native handle.
Use `self.ToBitmap` if control doesn't have a valid native handle or you get many pixels.
x: int, internal x position.
y: int, internal y position.
Return int, a color value in bgr.
r = bgr & 0x0000FF
g = (bgr & 0x00FF00) >> 8
b = (bgr & 0xFF0000) >> 16
"""
handle = self.NativeWindowHandle
if handle:
return GetPixelColor(x, y, handle)
def ToBitmap(self, x: int = 0, y: int = 0, width: int = 0, height: int = 0) -> Bitmap:
"""
Capture control to a Bitmap object.
x, y: int, the point in control's internal position(from 0,0).
width, height: int, image's width and height from x, y, use 0 for entire area.
If width(or height) < 0, image size will be control's width(or height) - width(or height).
"""
bitmap = Bitmap()
bitmap.FromControl(self, x, y, width, height)
return bitmap
def CaptureToImage(self, savePath: str, x: int = 0, y: int = 0, width: int = 0, height: int = 0) -> bool:
"""
Capture control to a image file.
savePath: str, should end with .bmp, .jpg, .jpeg, .png, .gif, .tif, .tiff.
x, y: int, the point in control's internal position(from 0,0).
width, height: int, image's width and height from x, y, use 0 for entire area.
If width(or height) < 0, image size will be control's width(or height) - width(or height).
Return bool, True if succeed otherwise False.
"""
bitmap = Bitmap()
if bitmap.FromControl(self, x, y, width, height):
return bitmap.ToFile(savePath)
return False
def IsTopLevel(self) -> bool:
"""Determine whether current control is top level."""
handle = self.NativeWindowHandle
if handle:
return GetAncestor(handle, GAFlag.Root) == handle
return False
def GetTopLevelControl(self) -> 'Control':
"""
Get the top level control which current control lays.
If current control is top level, return self.
If current control is root control, return None.
Return `PaneControl` or `WindowControl` or None.
"""
handle = self.NativeWindowHandle
if handle:
topHandle = GetAncestor(handle, GAFlag.Root)
if topHandle:
if topHandle == handle:
return self
else:
return ControlFromHandle(topHandle)
else:
#self is root control
pass
else:
control = self
while True:
control = control.GetParentControl()
handle = control.NativeWindowHandle
if handle:
topHandle = GetAncestor(handle, GAFlag.Root)
return ControlFromHandle(topHandle)
def Control(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'Control':
return Control(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ButtonControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ButtonControl':
return ButtonControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def CalendarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'CalendarControl':
return CalendarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def CheckBoxControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'CheckBoxControl':
return CheckBoxControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ComboBoxControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ComboBoxControl':
return ComboBoxControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def CustomControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'CustomControl':
return CustomControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def DataGridControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'DataGridControl':
return DataGridControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def DataItemControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'DataItemControl':
return DataItemControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def DocumentControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'DocumentControl':
return DocumentControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def EditControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'EditControl':
return EditControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def GroupControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'GroupControl':
return GroupControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def HeaderControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'HeaderControl':
return HeaderControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def HeaderItemControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'HeaderItemControl':
return HeaderItemControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def HyperlinkControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'HyperlinkControl':
return HyperlinkControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ImageControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ImageControl':
return ImageControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ListControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'listControl':
return ListControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ListItemControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ListItemControl':
return ListItemControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def MenuControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'MenuControl':
return MenuControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def MenuBarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'MenuBarControl':
return MenuBarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def MenuItemControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'MenuItemControl':
return MenuItemControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def PaneControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'PaneControl':
return PaneControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ProgressBarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ProgressBarControl':
return ProgressBarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def RadioButtonControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'RadioButtonControl':
return RadioButtonControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ScrollBarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ScrollBarControl':
return ScrollBarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def SemanticZoomControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'SemanticZoomControl':
return SemanticZoomControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def SeparatorControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'SeparatorControl':
return SeparatorControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def SliderControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'SliderControl':
return SliderControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def SpinnerControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'SpinnerControl':
return SpinnerControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def SplitButtonControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'SplitButtonControl':
return SplitButtonControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def StatusBarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'StatusBarControl':
return StatusBarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TabControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TabControl':
return TabControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TabItemControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TabItemControl':
return TabItemControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TableControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TableControl':
return TableControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TextControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TextControl':
return TextControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ThumbControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ThumbControl':
return ThumbControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TitleBarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TitleBarControl':
return TitleBarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ToolBarControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ToolBarControl':
return ToolBarControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def ToolTipControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'ToolTipControl':
return ToolTipControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TreeControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TreeControl':
return TreeControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def TreeItemControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'TreeItemControl':
return TreeItemControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
def WindowControl(self, searchDepth=0xFFFFFFFF, searchInterval=SEARCH_INTERVAL, foundIndex=1, element=0, **searchProperties) -> 'WindowControl':
return WindowControl(searchDepth=searchDepth, searchInterval=searchInterval, foundIndex=foundIndex, element=element, searchFromControl=self, **searchProperties)
class AppBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.AppBarControl)
class ButtonControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ButtonControl)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
def GetTogglePattern(self) -> TogglePattern:
"""
Return `TogglePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TogglePattern)
class CalendarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.CalendarControl)
def GetGridPattern(self) -> GridPattern:
"""
Return `GridPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.GridPattern)
def GetTablePattern(self) -> TablePattern:
"""
Return `TablePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TablePattern)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
class CheckBoxControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.CheckBoxControl)
def GetTogglePattern(self) -> TogglePattern:
"""
Return `TogglePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TogglePattern)
class ComboBoxControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ComboBoxControl)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
def Select(self, itemName: str = '', condition: Callable[[str], bool] = None, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Show combobox's popup menu and select a item by name.
itemName: str.
condition: Callable[[str], bool], function(comboBoxItemName: str) -> bool, if condition is valid, ignore itemName.
waitTime: float.
Some comboboxs doesn't support SelectionPattern, here is a workaround.
This method tries to add selection support.
It may not work for some comboboxes, such as comboboxes in older Qt version.
If it doesn't work, you should write your own version Select, or it doesn't support selection at all.
"""
expandCollapsePattern = self.GetExpandCollapsePattern()
if expandCollapsePattern:
expandCollapsePattern.Expand()
else:
#Windows Form's ComboBoxControl doesn't support ExpandCollapsePattern
self.Click(x=-10, ratioY=0.5, simulateMove=False)
find = False
if condition:
listItemControl = self.ListItemControl(Compare=lambda c, d: condition(c.Name))
else:
listItemControl = self.ListItemControl(Name=itemName)
if listItemControl.Exists(1):
scrollItemPattern = listItemControl.GetScrollItemPattern()
if scrollItemPattern:
scrollItemPattern.ScrollIntoView(waitTime=0.1)
listItemControl.Click(waitTime=waitTime)
find = True
else:
#ComboBox's popup window is a child of root control
listControl = ListControl(searchDepth= 1)
if listControl.Exists(1):
if condition:
listItemControl = listControl.ListItemControl(Compare=lambda c, d: condition(c.Name))
else:
listItemControl = listControl.ListItemControl(Name=itemName)
if listItemControl.Exists(0, 0):
scrollItemPattern = listItemControl.GetScrollItemPattern()
if scrollItemPattern:
scrollItemPattern.ScrollIntoView(waitTime=0.1)
listItemControl.Click(waitTime=waitTime)
find = True
if not find:
Logger.ColorfullyLog('Can\'t find {} in ComboBoxControl or it does not support selection.'.format(itemName), ConsoleColor.Yellow)
if expandCollapsePattern:
expandCollapsePattern.Collapse(waitTime)
else:
self.Click(x=-10, ratioY=0.5, simulateMove=False, waitTime=waitTime)
return find
class CustomControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.CustomControl)
class DataGridControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.DataGridControl)
def GetGridPattern(self) -> GridPattern:
"""
Return `GridPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.GridPattern)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
def GetTablePattern(self) -> TablePattern:
"""
Return `TablePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TablePattern)
class DataItemControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.DataItemControl)
def GetSelectionItemPattern(self) -> SelectionItemPattern:
"""
Return `SelectionItemPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionItemPattern)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetGridItemPattern(self) -> GridItemPattern:
"""
Return `GridItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.GridItemPattern)
def GetScrollItemPattern(self) -> ScrollItemPattern:
"""
Return `ScrollItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollItemPattern)
def GetTableItemPattern(self) -> TableItemPattern:
"""
Return `TableItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TableItemPattern)
def GetTogglePattern(self) -> TogglePattern:
"""
Return `TogglePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TogglePattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class DocumentControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.DocumentControl)
def GetTextPattern(self) -> TextPattern:
"""
Return `TextPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TextPattern)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class EditControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.EditControl)
def GetRangeValuePattern(self) -> RangeValuePattern:
"""
Return `RangeValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.RangeValuePattern)
def GetTextPattern(self) -> TextPattern:
"""
Return `TextPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TextPattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class GroupControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.GroupControl)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
class HeaderControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.HeaderControl)
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
class HeaderItemControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.HeaderItemControl)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
class HyperlinkControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.HyperlinkControl)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class ImageControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ImageControl)
def GetGridItemPattern(self) -> GridItemPattern:
"""
Return `GridItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.GridItemPattern)
def GetTableItemPattern(self) -> TableItemPattern:
"""
Return `TableItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TableItemPattern)
class ListControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ListControl)
def GetGridPattern(self) -> GridPattern:
"""
Return `GridPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.GridPattern)
def GetMultipleViewPattern(self) -> MultipleViewPattern:
"""
Return `MultipleViewPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.MultipleViewPattern)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
class ListItemControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ListItemControl)
def GetSelectionItemPattern(self) -> SelectionItemPattern:
"""
Return `SelectionItemPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionItemPattern)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetGridItemPattern(self) -> GridItemPattern:
"""
Return `GridItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.GridItemPattern)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
def GetScrollItemPattern(self) -> ScrollItemPattern:
"""
Return `ScrollItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollItemPattern)
def GetTogglePattern(self) -> TogglePattern:
"""
Return `TogglePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TogglePattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class MenuControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.MenuControl)
class MenuBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.MenuBarControl)
def GetDockPattern(self) -> DockPattern:
"""
Return `DockPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.DockPattern)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
class MenuItemControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.MenuItemControl)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
def GetSelectionItemPattern(self) -> SelectionItemPattern:
"""
Return `SelectionItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionItemPattern)
def GetTogglePattern(self) -> TogglePattern:
"""
Return `TogglePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TogglePattern)
class TopLevel():
"""Class TopLevel"""
def SetTopmost(self, isTopmost: bool = True, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Set top level window topmost.
isTopmost: bool.
waitTime: float.
"""
if self.IsTopLevel():
ret = SetWindowTopmost(self.NativeWindowHandle, isTopmost)
time.sleep(waitTime)
return ret
return False
def IsTopmost(self) -> bool:
if self.IsTopLevel():
WS_EX_TOPMOST = 0x00000008
return bool(GetWindowLong(self.NativeWindowHandle, GWL.ExStyle) & WS_EX_TOPMOST)
return False
def SwitchToThisWindow(self, waitTime: float = OPERATION_WAIT_TIME) -> None:
if self.IsTopLevel():
SwitchToThisWindow(self.NativeWindowHandle)
time.sleep(waitTime)
def Maximize(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Set top level window maximize.
"""
if self.IsTopLevel():
return self.ShowWindow(SW.ShowMaximized, waitTime)
return False
def IsMaximize(self) -> bool:
if self.IsTopLevel():
return bool(IsZoomed(self.NativeWindowHandle))
return False
def Minimize(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
if self.IsTopLevel():
return self.ShowWindow(SW.Minimize, waitTime)
return False
def IsMinimize(self) -> bool:
if self.IsTopLevel():
return bool(IsIconic(self.NativeWindowHandle))
return False
def Restore(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""
Restore window to normal state.
Similar to SwitchToThisWindow.
"""
if self.IsTopLevel():
return self.ShowWindow(SW.Restore, waitTime)
return False
def MoveToCenter(self) -> bool:
"""
Move window to screen center.
"""
if self.IsTopLevel():
rect = self.BoundingRectangle
screenWidth, screenHeight = GetScreenSize()
x, y = (screenWidth - rect.width()) // 2, (screenHeight - rect.height()) // 2
if x < 0: x = 0
if y < 0: y = 0
return SetWindowPos(self.NativeWindowHandle, SWP.HWND_Top, x, y, 0, 0, SWP.SWP_NoSize)
return False
def SetActive(self, waitTime: float = OPERATION_WAIT_TIME) -> bool:
"""Set top level window active."""
if self.IsTopLevel():
handle = self.NativeWindowHandle
if IsIconic(handle):
ret = ShowWindow(handle, SW.Restore)
elif not IsWindowVisible(handle):
ret = ShowWindow(handle, SW.Show)
ret = SetForegroundWindow(handle) # may fail if foreground windows's process is not python
time.sleep(waitTime)
return ret
return False
class PaneControl(Control, TopLevel):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.PaneControl)
def GetDockPattern(self) -> DockPattern:
"""
Return `DockPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.DockPattern)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
class ProgressBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ProgressBarControl)
def GetRangeValuePattern(self) -> RangeValuePattern:
"""
Return `RangeValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.RangeValuePattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class RadioButtonControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.RadioButtonControl)
def GetSelectionItemPattern(self) -> SelectionItemPattern:
"""
Return `SelectionItemPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionItemPattern)
class ScrollBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ScrollBarControl)
def GetRangeValuePattern(self) -> RangeValuePattern:
"""
Return `RangeValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.RangeValuePattern)
class SemanticZoomControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.SemanticZoomControl)
class SeparatorControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.SeparatorControl)
class SliderControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.SliderControl)
def GetRangeValuePattern(self) -> RangeValuePattern:
"""
Return `RangeValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.RangeValuePattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class SpinnerControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.SpinnerControl)
def GetRangeValuePattern(self) -> RangeValuePattern:
"""
Return `RangeValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.RangeValuePattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
def GetValuePattern(self) -> ValuePattern:
"""
Return `ValuePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ValuePattern)
class SplitButtonControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.SplitButtonControl)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
class StatusBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.StatusBarControl)
def GetGridPattern(self) -> GridPattern:
"""
Return `GridPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.GridPattern)
class TabControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TabControl)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
class TabItemControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TabItemControl)
def GetSelectionItemPattern(self) -> SelectionItemPattern:
"""
Return `SelectionItemPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionItemPattern)
class TableControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TableControl)
def GetGridPattern(self) -> GridPattern:
"""
Return `GridPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.GridPattern)
def GetGridItemPattern(self) -> GridItemPattern:
"""
Return `GridItemPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.GridItemPattern)
def GetTablePattern(self) -> TablePattern:
"""
Return `TablePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TablePattern)
def GetTableItemPattern(self) -> TableItemPattern:
"""
Return `TableItemPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TableItemPattern)
class TextControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TextControl)
def GetGridItemPattern(self) -> GridItemPattern:
"""
Return `GridItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.GridItemPattern)
def GetTableItemPattern(self) -> TableItemPattern:
"""
Return `TableItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TableItemPattern)
def GetTextPattern(self) -> TextPattern:
"""
Return `TextPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TextPattern)
class ThumbControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ThumbControl)
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
class TitleBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TitleBarControl)
class ToolBarControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ToolBarControl)
def GetDockPattern(self) -> DockPattern:
"""
Return `DockPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.DockPattern)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
class ToolTipControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.ToolTipControl)
def GetTextPattern(self) -> TextPattern:
"""
Return `TextPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TextPattern)
def GetWindowPattern(self) -> WindowPattern:
"""
Return `WindowPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.WindowPattern)
class TreeControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TreeControl)
def GetScrollPattern(self) -> ScrollPattern:
"""
Return `ScrollPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollPattern)
def GetSelectionPattern(self) -> SelectionPattern:
"""
Return `SelectionPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionPattern)
class TreeItemControl(Control):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.TreeItemControl)
def GetExpandCollapsePattern(self) -> ExpandCollapsePattern:
"""
Return `ExpandCollapsePattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.ExpandCollapsePattern)
def GetInvokePattern(self) -> InvokePattern:
"""
Return `InvokePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.InvokePattern)
def GetScrollItemPattern(self) -> ScrollItemPattern:
"""
Return `ScrollItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.ScrollItemPattern)
def GetSelectionItemPattern(self) -> SelectionItemPattern:
"""
Return `SelectionItemPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.SelectionItemPattern)
def GetTogglePattern(self) -> TogglePattern:
"""
Return `TogglePattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.TogglePattern)
class WindowControl(Control, TopLevel):
def __init__(self, searchFromControl: Control = None, searchDepth: int = 0xFFFFFFFF, searchInterval: float = SEARCH_INTERVAL, foundIndex: int = 1, element=None, **searchProperties):
Control.__init__(self, searchFromControl, searchDepth, searchInterval, foundIndex, element, **searchProperties)
self.AddSearchProperties(ControlType=ControlType.WindowControl)
self._DockPattern = None
self._TransformPattern = None
def GetTransformPattern(self) -> TransformPattern:
"""
Return `TransformPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.TransformPattern)
def GetWindowPattern(self) -> WindowPattern:
"""
Return `WindowPattern` if it supports the pattern else None(Must support according to MSDN).
"""
return self.GetPattern(PatternId.WindowPattern)
def GetDockPattern(self) -> DockPattern:
"""
Return `DockPattern` if it supports the pattern else None(Conditional support according to MSDN).
"""
return self.GetPattern(PatternId.DockPattern)
def MetroClose(self, waitTime: float = OPERATION_WAIT_TIME) -> None:
"""
Only work on Windows 8/8.1, if current window is Metro UI.
waitTime: float.
"""
if self.ClassName == METRO_WINDOW_CLASS_NAME:
screenWidth, screenHeight = GetScreenSize()
MoveTo(screenWidth // 2, 0, waitTime=0)
DragDrop(screenWidth // 2, 0, screenWidth // 2, screenHeight, waitTime=waitTime)
else:
Logger.WriteLine('Window is not Metro!', ConsoleColor.Yellow)
ControlConstructors = {
ControlType.AppBarControl: AppBarControl,
ControlType.ButtonControl: ButtonControl,
ControlType.CalendarControl: CalendarControl,
ControlType.CheckBoxControl: CheckBoxControl,
ControlType.ComboBoxControl: ComboBoxControl,
ControlType.CustomControl: CustomControl,
ControlType.DataGridControl: DataGridControl,
ControlType.DataItemControl: DataItemControl,
ControlType.DocumentControl: DocumentControl,
ControlType.EditControl: EditControl,
ControlType.GroupControl: GroupControl,
ControlType.HeaderControl: HeaderControl,
ControlType.HeaderItemControl: HeaderItemControl,
ControlType.HyperlinkControl: HyperlinkControl,
ControlType.ImageControl: ImageControl,
ControlType.ListControl: ListControl,
ControlType.ListItemControl: ListItemControl,
ControlType.MenuBarControl: MenuBarControl,
ControlType.MenuControl: MenuControl,
ControlType.MenuItemControl: MenuItemControl,
ControlType.PaneControl: PaneControl,
ControlType.ProgressBarControl: ProgressBarControl,
ControlType.RadioButtonControl: RadioButtonControl,
ControlType.ScrollBarControl: ScrollBarControl,
ControlType.SemanticZoomControl: SemanticZoomControl,
ControlType.SeparatorControl: SeparatorControl,
ControlType.SliderControl: SliderControl,
ControlType.SpinnerControl: SpinnerControl,
ControlType.SplitButtonControl: SplitButtonControl,
ControlType.StatusBarControl: StatusBarControl,
ControlType.TabControl: TabControl,
ControlType.TabItemControl: TabItemControl,
ControlType.TableControl: TableControl,
ControlType.TextControl: TextControl,
ControlType.ThumbControl: ThumbControl,
ControlType.TitleBarControl: TitleBarControl,
ControlType.ToolBarControl: ToolBarControl,
ControlType.ToolTipControl: ToolTipControl,
ControlType.TreeControl: TreeControl,
ControlType.TreeItemControl: TreeItemControl,
ControlType.WindowControl: WindowControl,
}
class UIAutomationInitializerInThread:
def __init__(self, debug: bool = False):
self.debug = debug
InitializeUIAutomationInCurrentThread()
if self.debug:
th = threading.currentThread()
print('\ncall InitializeUIAutomationInCurrentThread in {}'.format(th))
def __del__(self):
UninitializeUIAutomationInCurrentThread()
if self.debug:
th = threading.currentThread()
print('\ncall UninitializeUIAutomationInCurrentThread in {}'.format(th))
def InitializeUIAutomationInCurrentThread() -> None:
"""
Initialize UIAutomation in a new thread.
If you want to use functionalities related to Controls and Patterns in a new thread.
You must call this function first in the new thread.
But you can't use use a Control or a Pattern created in a different thread.
So you can't create a Control or a Pattern in main thread and then pass it to a new thread and use it.
"""
comtypes.CoInitializeEx()
SetDpiAwareness(dpiAwarenessPerMonitor=True)
def UninitializeUIAutomationInCurrentThread() -> None:
"""
Uninitialize UIAutomation in a new thread after calling InitializeUIAutomationInCurrentThread.
You must call this function when the new thread exits if you have called InitializeUIAutomationInCurrentThread in the same thread.
"""
comtypes.CoUninitialize()
def SetGlobalSearchTimeout(seconds: float) -> None:
"""
seconds: float.
To make this available, you need explicitly import uiautomation:
from uiautomation import uiautomation as auto
auto.SetGlobalSearchTimeout(10)
"""
global TIME_OUT_SECOND
TIME_OUT_SECOND = seconds
def WaitForExist(control: Control, timeout: float) -> bool:
"""
Check if control exists in timeout seconds.
control: `Control` or its subclass.
timeout: float.
Return bool.
"""
return control.Exists(timeout, 1)
def WaitForDisappear(control: Control, timeout: float) -> bool:
"""
Check if control disappears in timeout seconds.
control: `Control` or its subclass.
timeout: float.
Return bool.
"""
return control.Disappears(timeout, 1)
def WalkTree(top, getChildren: Callable[[TreeNode], List[TreeNode]] = None,
getFirstChild: Callable[[TreeNode], TreeNode] = None, getNextSibling: Callable[[TreeNode], TreeNode] = None,
yieldCondition: Callable[[TreeNode, int], bool] = None, includeTop: bool = False, maxDepth: int = 0xFFFFFFFF):
"""
Walk a tree not using recursive algorithm.
top: a tree node.
getChildren: Callable[[TreeNode], List[TreeNode]], function(treeNode: TreeNode) -> List[TreeNode].
getNextSibling: Callable[[TreeNode], TreeNode], function(treeNode: TreeNode) -> TreeNode.
getNextSibling: Callable[[TreeNode], TreeNode], function(treeNode: TreeNode) -> TreeNode.
yieldCondition: Callable[[TreeNode, int], bool], function(treeNode: TreeNode, depth: int) -> bool.
includeTop: bool, if True yield top first.
maxDepth: int, enum depth.
If getChildren is valid, ignore getFirstChild and getNextSibling,
yield 3 items tuple: (treeNode, depth, remain children count in current depth).
If getChildren is not valid, using getFirstChild and getNextSibling,
yield 2 items tuple: (treeNode, depth).
If yieldCondition is not None, only yield tree nodes that yieldCondition(treeNode: TreeNode, depth: int)->bool returns True.
For example:
def GetDirChildren(dir_):
if os.path.isdir(dir_):
return [os.path.join(dir_, it) for it in os.listdir(dir_)]
for it, depth, leftCount in WalkTree('D:\\', getChildren= GetDirChildren):
print(it, depth, leftCount)
"""
if maxDepth <= 0:
return
depth = 0
if getChildren:
if includeTop:
if not yieldCondition or yieldCondition(top, 0):
yield top, 0, 0
children = getChildren(top)
childList = [children]
while depth >= 0: #or while childList:
lastItems = childList[-1]
if lastItems:
if not yieldCondition or yieldCondition(lastItems[0], depth + 1):
yield lastItems[0], depth + 1, len(lastItems) - 1
if depth + 1 < maxDepth:
children = getChildren(lastItems[0])
if children:
depth += 1
childList.append(children)
del lastItems[0]
else:
del childList[depth]
depth -= 1
elif getFirstChild and getNextSibling:
if includeTop:
if not yieldCondition or yieldCondition(top, 0):
yield top, 0
child = getFirstChild(top)
childList = [child]
while depth >= 0: #or while childList:
lastItem = childList[-1]
if lastItem:
if not yieldCondition or yieldCondition(lastItem, depth + 1):
yield lastItem, depth + 1
child = getNextSibling(lastItem)
childList[depth] = child
if depth + 1 < maxDepth:
child = getFirstChild(lastItem)
if child:
depth += 1
childList.append(child)
else:
del childList[depth]
depth -= 1
def GetRootControl() -> PaneControl:
"""
Get root control, the Desktop window.
Return `PaneControl`.
"""
return Control.CreateControlFromElement(_AutomationClient.instance().IUIAutomation.GetRootElement())
def GetFocusedControl() -> Control:
"""Return `Control` subclass."""
return Control.CreateControlFromElement(_AutomationClient.instance().IUIAutomation.GetFocusedElement())
def GetForegroundControl() -> Control:
"""Return `Control` subclass."""
return ControlFromHandle(GetForegroundWindow())
#another implement
#focusedControl = GetFocusedControl()
#parentControl = focusedControl
#controlList = []
#while parentControl:
#controlList.insert(0, parentControl)
#parentControl = parentControl.GetParentControl()
#if len(controlList) == 1:
#parentControl = controlList[0]
#else:
#parentControl = controlList[1]
#return parentControl
def GetConsoleWindow() -> WindowControl:
"""Return `WindowControl` or None, a console window that runs python."""
return ControlFromHandle(ctypes.windll.kernel32.GetConsoleWindow())
def ControlFromPoint(x: int, y: int) -> Control:
"""
Call IUIAutomation ElementFromPoint x,y. May return None if mouse is over cmd's title bar icon.
Return `Control` subclass or None.
"""
element = _AutomationClient.instance().IUIAutomation.ElementFromPoint(ctypes.wintypes.POINT(x, y))
return Control.CreateControlFromElement(element)
def ControlFromPoint2(x: int, y: int) -> Control:
"""
Get a native handle from point x,y and call IUIAutomation.ElementFromHandle.
Return `Control` subclass.
"""
return Control.CreateControlFromElement(_AutomationClient.instance().IUIAutomation.ElementFromHandle(WindowFromPoint(x, y)))
def ControlFromCursor() -> Control:
"""
Call ControlFromPoint with current cursor point.
Return `Control` subclass.
"""
x, y = GetCursorPos()
return ControlFromPoint(x, y)
def ControlFromCursor2() -> Control:
"""
Call ControlFromPoint2 with current cursor point.
Return `Control` subclass.
"""
x, y = GetCursorPos()
return ControlFromPoint2(x, y)
def ControlFromHandle(handle: int) -> Control:
"""
Call IUIAutomation.ElementFromHandle with a native handle.
handle: int, a native window handle.
Return `Control` subclass or None.
"""
if handle:
return Control.CreateControlFromElement(_AutomationClient.instance().IUIAutomation.ElementFromHandle(handle))
def ControlsAreSame(control1: Control, control2: Control) -> bool:
"""
control1: `Control` or its subclass.
control2: `Control` or its subclass.
Return bool, True if control1 and control2 represent the same control otherwise False.
"""
return bool(_AutomationClient.instance().IUIAutomation.CompareElements(control1.Element, control2.Element))
def WalkControl(control: Control, includeTop: bool = False, maxDepth: int = 0xFFFFFFFF):
"""
control: `Control` or its subclass.
includeTop: bool, if True, yield (control, 0) first.
maxDepth: int, enum depth.
Yield 2 items tuple (control: Control, depth: int).
"""
if includeTop:
yield control, 0
if maxDepth <= 0:
return
depth = 0
child = control.GetFirstChildControl()
controlList = [child]
while depth >= 0:
lastControl = controlList[-1]
if lastControl:
yield lastControl, depth + 1
child = lastControl.GetNextSiblingControl()
controlList[depth] = child
if depth + 1 < maxDepth:
child = lastControl.GetFirstChildControl()
if child:
depth += 1
controlList.append(child)
else:
del controlList[depth]
depth -= 1
def LogControl(control: Control, depth: int = 0, showAllName: bool = True, showPid: bool = False) -> None:
"""
Print and log control's properties.
control: `Control` or its subclass.
depth: int, current depth.
showAllName: bool, if False, print the first 30 characters of control.Name.
"""
def getKeyName(theDict, theValue):
for key in theDict:
if theValue == theDict[key]:
return key
indent = ' ' * depth * 4
Logger.Write('{0}ControlType: '.format(indent))
Logger.Write(control.ControlTypeName, ConsoleColor.DarkGreen)
Logger.Write(' ClassName: ')
Logger.Write(control.ClassName, ConsoleColor.DarkGreen)
Logger.Write(' AutomationId: ')
Logger.Write(control.AutomationId, ConsoleColor.DarkGreen)
Logger.Write(' Rect: ')
Logger.Write(control.BoundingRectangle, ConsoleColor.DarkGreen)
Logger.Write(' Name: ')
Logger.Write(control.Name, ConsoleColor.DarkGreen, printTruncateLen=0 if showAllName else 30)
Logger.Write(' Handle: ')
Logger.Write('0x{0:X}({0})'.format(control.NativeWindowHandle), ConsoleColor.DarkGreen)
Logger.Write(' Depth: ')
Logger.Write(depth, ConsoleColor.DarkGreen)
if showPid:
Logger.Write(' ProcessId: ')
Logger.Write(control.ProcessId, ConsoleColor.DarkGreen)
supportedPatterns = list(filter(lambda t: t[0], ((control.GetPattern(id_), name) for id_, name in PatternIdNames.items())))
for pt, name in supportedPatterns:
if isinstance(pt, ValuePattern):
Logger.Write(' ValuePattern.Value: ')
Logger.Write(pt.Value, ConsoleColor.DarkGreen, printTruncateLen=0 if showAllName else 30)
elif isinstance(pt, RangeValuePattern):
Logger.Write(' RangeValuePattern.Value: ')
Logger.Write(pt.Value, ConsoleColor.DarkGreen)
elif isinstance(pt, TogglePattern):
Logger.Write(' TogglePattern.ToggleState: ')
Logger.Write('ToggleState.' + getKeyName(ToggleState.__dict__, pt.ToggleState), ConsoleColor.DarkGreen)
elif isinstance(pt, SelectionItemPattern):
Logger.Write(' SelectionItemPattern.IsSelected: ')
Logger.Write(pt.IsSelected, ConsoleColor.DarkGreen)
elif isinstance(pt, ExpandCollapsePattern):
Logger.Write(' ExpandCollapsePattern.ExpandCollapseState: ')
Logger.Write('ExpandCollapseState.' + getKeyName(ExpandCollapseState.__dict__, pt.ExpandCollapseState), ConsoleColor.DarkGreen)
elif isinstance(pt, ScrollPattern):
Logger.Write(' ScrollPattern.HorizontalScrollPercent: ')
Logger.Write(pt.HorizontalScrollPercent, ConsoleColor.DarkGreen)
Logger.Write(' ScrollPattern.VerticalScrollPercent: ')
Logger.Write(pt.VerticalScrollPercent, ConsoleColor.DarkGreen)
elif isinstance(pt, GridPattern):
Logger.Write(' GridPattern.RowCount: ')
Logger.Write(pt.RowCount, ConsoleColor.DarkGreen)
Logger.Write(' GridPattern.ColumnCount: ')
Logger.Write(pt.ColumnCount, ConsoleColor.DarkGreen)
elif isinstance(pt, GridItemPattern):
Logger.Write(' GridItemPattern.Row: ')
Logger.Write(pt.Column, ConsoleColor.DarkGreen)
Logger.Write(' GridItemPattern.Column: ')
Logger.Write(pt.Column, ConsoleColor.DarkGreen)
elif isinstance(pt, TextPattern):
# issue 49: CEF Control as DocumentControl have no "TextPattern.Text" property, skip log this part.
# https://docs.microsoft.com/en-us/windows/win32/api/uiautomationclient/nf-uiautomationclient-iuiautomationtextpattern-get_documentrange
try:
Logger.Write(' TextPattern.Text: ')
Logger.Write(pt.DocumentRange.GetText(30), ConsoleColor.DarkGreen)
except comtypes.COMError as ex:
pass
Logger.Write(' SupportedPattern:')
for pt, name in supportedPatterns:
Logger.Write(' ' + name, ConsoleColor.DarkGreen)
Logger.Write('\n')
def EnumAndLogControl(control: Control, maxDepth: int = 0xFFFFFFFF, showAllName: bool = True, showPid: bool = False, startDepth: int = 0) -> None:
"""
Print and log control and its descendants' propertyies.
control: `Control` or its subclass.
maxDepth: int, enum depth.
showAllName: bool, if False, print the first 30 characters of control.Name.
startDepth: int, control's current depth.
"""
for c, d in WalkControl(control, True, maxDepth):
LogControl(c, d + startDepth, showAllName, showPid)
def EnumAndLogControlAncestors(control: Control, showAllName: bool = True, showPid: bool = False) -> None:
"""
Print and log control and its ancestors' propertyies.
control: `Control` or its subclass.
showAllName: bool, if False, print the first 30 characters of control.Name.
"""
lists = []
while control:
lists.insert(0, control)
control = control.GetParentControl()
for i, control in enumerate(lists):
LogControl(control, i, showAllName, showPid)
def FindControl(control: Control, compare: Callable[[Control, int], bool], maxDepth: int = 0xFFFFFFFF, findFromSelf: bool = False, foundIndex: int = 1) -> Control:
"""
control: `Control` or its subclass.
compare: Callable[[Control, int], bool], function(control: Control, depth: int) -> bool.
maxDepth: int, enum depth.
findFromSelf: bool, if False, do not compare self.
foundIndex: int, starts with 1, >= 1.
Return `Control` subclass or None if not find.
"""
foundCount = 0
if not control:
control = GetRootControl()
traverseCount = 0
for child, depth in WalkControl(control, findFromSelf, maxDepth):
traverseCount += 1
if compare(child, depth):
foundCount += 1
if foundCount == foundIndex:
child.traverseCount = traverseCount
return child
def ShowDesktop(waitTime: float = 1) -> None:
"""Show Desktop by pressing win + d"""
SendKeys('{Win}d')
time.sleep(waitTime)
#another implement
#paneTray = PaneControl(searchDepth = 1, ClassName = 'Shell_TrayWnd')
#if paneTray.Exists():
#WM_COMMAND = 0x111
#MIN_ALL = 419
#MIN_ALL_UNDO = 416
#PostMessage(paneTray.NativeWindowHandle, WM_COMMAND, MIN_ALL, 0)
#time.sleep(1)
def WaitHotKeyReleased(hotkey: Tuple[int, int]) -> None:
"""hotkey: Tuple[int, int], two ints tuple (modifierKey, key)"""
mod = {ModifierKey.Alt: Keys.VK_MENU,
ModifierKey.Control: Keys.VK_CONTROL,
ModifierKey.Shift: Keys.VK_SHIFT,
ModifierKey.Win: Keys.VK_LWIN
}
while True:
time.sleep(0.05)
if IsKeyPressed(hotkey[1]):
continue
for k, v in mod.items():
if k & hotkey[0]:
if IsKeyPressed(v):
break
else:
break
def RunByHotKey(keyFunctions: Dict[Tuple[int, int], Callable], stopHotKey: Tuple[int, int] = None, exitHotKey: Tuple[int, int] = (ModifierKey.Control, Keys.VK_D), waitHotKeyReleased: bool = True) -> None:
"""
Bind functions with hotkeys, the function will be run or stopped in another thread when the hotkey is pressed.
keyFunctions: Dict[Tuple[int, int], Callable], such as {(uiautomation.ModifierKey.Control, uiautomation.Keys.VK_1) : function}
stopHotKey: hotkey tuple
exitHotKey: hotkey tuple
waitHotKeyReleased: bool, if True, hotkey function will be triggered after the hotkey is released
def main(stopEvent):
while True:
if stopEvent.is_set(): # must check stopEvent.is_set() if you want to stop when stop hotkey is pressed
break
print(n)
n += 1
stopEvent.wait(1)
print('main exit')
uiautomation.RunByHotKey({(uiautomation.ModifierKey.Control, uiautomation.Keys.VK_1) : main}
, (uiautomation.ModifierKey.Control | uiautomation.ModifierKey.Shift, uiautomation.Keys.VK_2))
"""
import traceback
def getModName(theDict, theValue):
name = ''
for key in theDict:
if isinstance(theDict[key], int) and theValue & theDict[key]:
if name:
name += '|'
name += key
return name
def getKeyName(theDict, theValue):
for key in theDict:
if theValue == theDict[key]:
return key
def releaseAllKey():
for key, value in Keys.__dict__.items():
if isinstance(value, int) and key.startswith('VK'):
if IsKeyPressed(value):
ReleaseKey(value)
def threadFunc(function, stopEvent, hotkey, hotkeyName):
if waitHotKeyReleased:
WaitHotKeyReleased(hotkey)
try:
function(stopEvent)
except Exception as ex:
Logger.ColorfullyWrite('Catch an exception {} in thread for hotkey {}\n'.format(
ex.__class__.__name__, hotkeyName), writeToFile=False)
print(traceback.format_exc())
finally:
releaseAllKey() #need to release keys if some keys were pressed
Logger.ColorfullyWrite('{} for function {} exits, hotkey {}\n'.format(
threading.currentThread(), function.__name__, hotkeyName), ConsoleColor.DarkYellow, writeToFile=False)
stopHotKeyId = 1
exitHotKeyId = 2
hotKeyId = 3
registed = True
id2HotKey = {}
id2Function = {}
id2Thread = {}
id2Name = {}
for hotkey in keyFunctions:
id2HotKey[hotKeyId] = hotkey
id2Function[hotKeyId] = keyFunctions[hotkey]
id2Thread[hotKeyId] = None
modName = getModName(ModifierKey.__dict__, hotkey[0])
keyName = getKeyName(Keys.__dict__, hotkey[1])
id2Name[hotKeyId] = str((modName, keyName))
if ctypes.windll.user32.RegisterHotKey(0, hotKeyId, hotkey[0], hotkey[1]):
Logger.ColorfullyWrite('Register hotkey {} successfully\n'.format((modName, keyName)), writeToFile=False)
else:
registed = False
Logger.ColorfullyWrite('Register hotkey {} unsuccessfully, maybe it was allready registered by another program\n'.format((modName, keyName)), writeToFile=False)
hotKeyId += 1
if stopHotKey and len(stopHotKey) == 2:
modName = getModName(ModifierKey.__dict__, stopHotKey[0])
keyName = getKeyName(Keys.__dict__, stopHotKey[1])
if ctypes.windll.user32.RegisterHotKey(0, stopHotKeyId, stopHotKey[0], stopHotKey[1]):
Logger.ColorfullyWrite('Register stop hotkey {} successfully\n'.format((modName, keyName)), writeToFile=False)
else:
registed = False
Logger.ColorfullyWrite('Register stop hotkey {} unsuccessfully, maybe it was allready registered by another program\n'.format((modName, keyName)), writeToFile=False)
if not registed:
return
if exitHotKey and len(exitHotKey) == 2:
modName = getModName(ModifierKey.__dict__, exitHotKey[0])
keyName = getKeyName(Keys.__dict__, exitHotKey[1])
if ctypes.windll.user32.RegisterHotKey(0, exitHotKeyId, exitHotKey[0], exitHotKey[1]):
Logger.ColorfullyWrite('Register exit hotkey {} successfully\n'.format((modName, keyName)), writeToFile=False)
else:
Logger.ColorfullyWrite('Register exit hotkey {} unsuccessfully\n'.format((modName, keyName)), writeToFile=False)
funcThread = None
livingThreads = []
stopEvent = threading.Event()
msg = ctypes.wintypes.MSG()
while ctypes.windll.user32.GetMessageW(ctypes.byref(msg), ctypes.c_void_p(0), ctypes.c_uint(0), ctypes.c_uint(0)) != 0:
if msg.message == 0x0312: # WM_HOTKEY=0x0312
if msg.wParam in id2HotKey:
if msg.lParam & 0x0000FFFF == id2HotKey[msg.wParam][0] and msg.lParam >> 16 & 0x0000FFFF == id2HotKey[msg.wParam][1]:
Logger.ColorfullyWrite('----------hotkey {} pressed----------\n'.format(id2Name[msg.wParam]), writeToFile=False)
if not id2Thread[msg.wParam]:
stopEvent.clear()
funcThread = threading.Thread(None, threadFunc, args=(id2Function[msg.wParam], stopEvent, id2HotKey[msg.wParam], id2Name[msg.wParam]))
funcThread.start()
id2Thread[msg.wParam] = funcThread
else:
if id2Thread[msg.wParam].is_alive():
Logger.WriteLine('There is a {} that is already running for hotkey {}'.format(id2Thread[msg.wParam], id2Name[msg.wParam]), ConsoleColor.Yellow, writeToFile=False)
else:
stopEvent.clear()
funcThread = threading.Thread(None, threadFunc, args=(id2Function[msg.wParam], stopEvent, id2HotKey[msg.wParam], id2Name[msg.wParam]))
funcThread.start()
id2Thread[msg.wParam] = funcThread
elif stopHotKeyId == msg.wParam:
if msg.lParam & 0x0000FFFF == stopHotKey[0] and msg.lParam >> 16 & 0x0000FFFF == stopHotKey[1]:
Logger.Write('----------stop hotkey pressed----------\n', ConsoleColor.DarkYellow, writeToFile=False)
stopEvent.set()
for id_ in id2Thread:
if id2Thread[id_]:
if id2Thread[id_].is_alive():
livingThreads.append((id2Thread[id_], id2Name[id_]))
id2Thread[id_] = None
elif exitHotKeyId == msg.wParam:
if msg.lParam & 0x0000FFFF == exitHotKey[0] and msg.lParam >> 16 & 0x0000FFFF == exitHotKey[1]:
Logger.Write('Exit hotkey pressed. Exit\n', ConsoleColor.DarkYellow, writeToFile=False)
stopEvent.set()
for id_ in id2Thread:
if id2Thread[id_]:
if id2Thread[id_].is_alive():
livingThreads.append((id2Thread[id_], id2Name[id_]))
id2Thread[id_] = None
break
for thread, hotkeyName in livingThreads:
if thread.is_alive():
Logger.Write('join {} triggered by hotkey {}\n'.format(thread, hotkeyName), ConsoleColor.DarkYellow, writeToFile=False)
thread.join(2)
os._exit(0)
if __name__ == '__main__':
print('\nUIAutomationCore:----')
for i in sorted([it for it in dir(_AutomationClient.instance().UIAutomationCore) if not it.startswith('_')]):
print(i)
print('\nIUIAutomation:----')
for i in sorted([it for it in dir(_AutomationClient.instance().IUIAutomation) if not it.startswith('_')]):
print(i)
print('\nViewWalker:----')
for i in sorted([it for it in dir(_AutomationClient.instance().ViewWalker) if not it.startswith('_')]):
print(i)
print()
for ct, ctor in ControlConstructors.items():
c = ctor()
print(type(c))
notepad = WindowControl(searchDepth=1, ClassName='Notepad')
if not notepad.Exists(0, 0):
import subprocess
subprocess.Popen('notepad.exe')
notepad.Refind()
print('\n', notepad)
print('Control:----')
for i in sorted([it for it in dir(notepad) if not it.startswith('_')]):
print(i)
print('\n', notepad.Element)
print('Control.Element:----')
for i in sorted([it for it in dir(notepad.Element) if not it.startswith('_')]):
print(i)
lp = notepad.GetLegacyIAccessiblePattern()
print('\n', lp)
print('Control.LegacyIAccessiblePattern:----')
for i in sorted([it for it in dir(lp.pattern) if not it.startswith('_')]):
print(i)
print('\nControl.Properties:----')
for k, v in PropertyIdNames.items():
try:
value = notepad.GetPropertyValue(k)
print('GetPropertyValue, {} = {}, type: {}'.format(v, value, type(value)))
except (KeyError, comtypes.COMError) as ex:
print('GetPropertyValue, {}, error'.format(v))
children = notepad.GetChildren()
print('\n notepad children:----', len(children))
for c in notepad.GetChildren():
print(c)
del lp
del notepad
hello = '{Ctrl}{End}{Enter}Hello World! 你好世界!'
SendKeys(hello)