def _find_by_UIA(self, translated_identifier, scope=UIA.UIA_wrapper.TreeScope_Descendants): target_UIAElement = self.UIAElement.FindFirst(scope, translated_identifier) if target_UIAElement == ctypes.POINTER(UIA.UIA_wrapper.IUIAutomationElement)(): LOGGER.debug("Find no element matching identifier") return None return UIElement(target_UIAElement)
def __call__(self, *in_args): ''' For output value, use original value For input arguments: 1. If required argument is an enum, check if input argument fit requirement 2. If required argument is "POINTER(IUIAutomationElement)", we accept UIElement object, get required pointer object from UIElement, and send it to function 3. Other, no change ''' args = list(in_args) if len(self.args) != len(args): LOGGER.warn("Input arguments number not match expected") return None for index, expected_arg in enumerate(self.args): expected_arg_type = expected_arg[0] if expected_arg_type == "POINTER(IUIAutomationElement)": #get the UIAElment args[index] = args[index].UIAElement elif expected_arg_type in UIA.UIA_enums: #enum should be an int value, if argument is a string, should translate to int if args[index] in UIA.UIA_enums[expected_arg_type]: args[index] = UIA.UIA_enums[expected_arg_type][args[index]] if args[index] not in list( UIA.UIA_enums[expected_arg_type].values()): LOGGER.debug("Input argument not in expected value: %s", args[index]) return None return self.function_object(*args)
def get_pattern_by_id(UIAElement, pattern_identifier): '''get UIA element pattern by identifier, return None if fail Arguments: UIAElement: UIA Element instance pattern_identifier: pattern identifier Returns: pattern instance if success None if pattern_identifier not valid or not supported by UIA Element ''' if pattern_identifier in UIA_control_pattern_identifers_mapping: UIA_pattern_identifier = UIA_control_pattern_identifers_mapping[ pattern_identifier][0] UIA_pattern_interface = UIA_control_pattern_identifers_mapping[ pattern_identifier][1] pattern = UIAElement.GetCurrentPatternAs(UIA_pattern_identifier, UIA_pattern_interface._iid_) if pattern is None: LOGGER.debug("This pattern:%s is not supported by this UIAElment", pattern_identifier) return None return ctypes.POINTER(UIA_pattern_interface)(pattern) ''' #Use GetCurrentPatternAs to check if get pattern success pattern = UIAElement.GetCurrentPattern(UIA_pattern_identifier).QueryInterface(UIA_pattern_interface) return pattern ''' else: LOGGER.debug( "This pattern identifier is not support: %s, cannot get it from UIA typelib", pattern_identifier) return None
def __call__(self, *in_args): ''' For output value, use original value For input arguments: 1. If required argument is an enum, check if input argument fit requirement 2. If required argument is "POINTER(IUIAutomationElement)", we accept UIElement object, get required pointer object from UIElement, and send it to function 3. Other, no change ''' args = list(in_args) if len(self.args) != len(args): LOGGER.warn("Input arguments number not match expected") return None for index, expected_arg in enumerate(self.args): expected_arg_type = expected_arg[0] if expected_arg_type == "POINTER(IUIAutomationElement)": #get the UIAElment args[index] = args[index].UIAElement elif expected_arg_type in UIA.UIA_enums: #enum should be an int value, if argument is a string, should translate to int if args[index] in UIA.UIA_enums[expected_arg_type]: args[index] = UIA.UIA_enums[expected_arg_type][args[index]] if args[index] not in list(UIA.UIA_enums[expected_arg_type].values()): LOGGER.debug("Input argument not in expected value: %s" , args[index]) return None return self.function_object(*args)
def image_compare(image1, image2, diff_image_name="diff.bmp"): '''compare two images, return difference percentage #code from http://rosettacode.org/wiki/Percentage_difference_between_images#Python ''' gen_diff_image = image_config.gen_diff_image diff_image_location = image_config.diff_image_location i1 = Image.open(image1) i2 = Image.open(image2) assert i1.mode == i2.mode, "Different kinds of images: %s VS %s" % (i1.mode, i2.mode) assert i1.size == i2.size, "Different sizes: %s, %s" % (i1.size, i2.size) #generate diff bitmap if gen_diff_image: diff = ImageChops.difference(i1, i2) diff_image_path = os.path.join(diff_image_location, diff_image_name) diff.save(diff_image_path) LOGGER.debug("Diff image save to: %s" % diff_image_path) #caculate the diff percentage pairs = zip(i1.getdata(), i2.getdata()) if len(i1.getbands()) == 1: # for gray-scale jpegs dif = sum((p1==p2) and 1 or 0 for p1,p2 in pairs) else: dif = sum((c1==c2) and 1 or 0 for p1,p2 in pairs for c1,c2 in zip(p1,p2)) ncomponents = i1.size[0] * i1.size[1] * 3 dif_percentage = float(dif) / ncomponents LOGGER.debug("Difference (percentage): %f" % dif_percentage) return dif_percentage
def get_pattern_by_id(UIAElement, pattern_identifier): '''get UIA element pattern by identifier, return None if fail Arguments: UIAElement: UIA Element instance pattern_identifier: pattern identifier Returns: pattern instance if success None if pattern_identifier not valid or not supported by UIA Element ''' if pattern_identifier in UIA_control_pattern_identifers_mapping: UIA_pattern_identifier = UIA_control_pattern_identifers_mapping[pattern_identifier][0] UIA_pattern_interface = UIA_control_pattern_identifers_mapping[pattern_identifier][1] pattern = UIAElement.GetCurrentPatternAs(UIA_pattern_identifier, UIA_pattern_interface._iid_) if pattern is None: LOGGER.debug("This pattern:%s is not supported by this UIAElment" , pattern_identifier) return None return ctypes.POINTER(UIA_pattern_interface)(pattern) ''' #Use GetCurrentPatternAs to check if get pattern success pattern = UIAElement.GetCurrentPattern(UIA_pattern_identifier).QueryInterface(UIA_pattern_interface) return pattern ''' else: LOGGER.debug("This pattern identifier is not support: %s, cannot get it from UIA typelib" , pattern_identifier) return None
def __init__(self, UIAElement, pattern_identifier): self.UIAElement = UIAElement self.pattern_object = UIA.get_pattern_by_id(UIAElement, pattern_identifier) if self.pattern_object is None: raise DriverException( "Cannot get pattern, stop init pattern object") self.methods = {} self.properties = {} interface_description = UIA.UIA_control_pattern_interfaces[ pattern_identifier] for member_description in interface_description: flag, name, args = _unpack(*member_description) #do a check, see if member exist in pattern object #if not, skip this member try: getattr(self.pattern_object, name) except AttributeError: LOGGER.debug("%s not exist in Pattern:%s", name, pattern_identifier) continue if flag == "method": self.methods[name] = args elif flag == "property": self.properties[name] = args else: raise DriverException("Unrecognised flag %s" % flag)
def image_compare(image1, image2, diff_image_name="diff.bmp"): '''compare two images, return difference percentage #code from http://rosettacode.org/wiki/Percentage_difference_between_images#Python ''' gen_diff_image = image_config.gen_diff_image diff_image_location = image_config.diff_image_location i1 = Image.open(image1) i2 = Image.open(image2) assert i1.mode == i2.mode, "Different kinds of images: %s VS %s" % ( i1.mode, i2.mode) assert i1.size == i2.size, "Different sizes: %s, %s" % (i1.size, i2.size) #generate diff bitmap if gen_diff_image: diff = ImageChops.difference(i1, i2) diff_image_path = os.path.join(diff_image_location, diff_image_name) diff.save(diff_image_path) LOGGER.debug("Diff image save to: %s" % diff_image_path) #caculate the diff percentage pairs = zip(i1.getdata(), i2.getdata()) if len(i1.getbands()) == 1: # for gray-scale jpegs dif = sum((p1 == p2) and 1 or 0 for p1, p2 in pairs) else: dif = sum((c1 == c2) and 1 or 0 for p1, p2 in pairs for c1, c2 in zip(p1, p2)) ncomponents = i1.size[0] * i1.size[1] * 3 dif_percentage = float(dif) / ncomponents LOGGER.debug("Difference (percentage): %f" % dif_percentage) return dif_percentage
def gui_execute(self, command): '''execute gui command command like "app_map1.app_map2...element1.element2...operation [parameter1 parameter2 ...]" ''' (object_name_list, parameter_list) = gui_command_parser.parse(command, lexer=gui_command_lexer) object_= self._get_object_by_name_list(object_name_list) LOGGER.debug("GUI execute %s %s" , object_name_list, parameter_list) object_(*parameter_list)
def run(self): if self.type == "GUI": LOGGER.debug("run gui command: %s" , self.command) self.app_map.gui_execute(self.command) elif self.type == "CLI": LOGGER.debug("run cli command: %s" , self.command) self.app_map.cli_execute(self.command) else: raise ValueError("step type must be GUI or CLI, get: %s" % self.type)
def drag_drop(self, abs_source_coords, abs_dest_coords): '''Move: move mouse from source_coords to dest_coords mouse drag drop is not related with UI element so need use abs coords ''' LOGGER.debug("Mouse drag drop from: %s to %s" , repr(abs_source_coords), repr(abs_dest_coords)) self.UIElement.set_focus() SendMouseInput(abs_source_coords, button_down=True, button_up=False) self.Move(abs_source_coords, abs_dest_coords) SendMouseInput(abs_dest_coords, button_down=False, button_up=True)
def gui_execute(self, command): '''execute gui command command like "app_map1.app_map2...element1.element2...operation [parameter1 parameter2 ...]" ''' (object_name_list, parameter_list) = gui_command_parser.parse(command, lexer=gui_command_lexer) object_ = self._get_object_by_name_list(object_name_list) LOGGER.debug("GUI execute %s %s", object_name_list, parameter_list) object_(*parameter_list)
def verification(self): '''verify the app map xml using according schema, need pyxb module ''' try: import pyxb except ImportError: LOGGER.debug("pyxb not install, skip app map verification") return from .validate import check_app_map check_app_map(core_config.query_schema_file("AXUI_app_map.xsd"), self.app_map_xml)
def drag_drop(self, abs_source_coords, abs_dest_coords): '''Move: move mouse from source_coords to dest_coords mouse drag drop is not related with UI element so need use abs coords ''' LOGGER.debug("Mouse drag drop from: %s to %s", repr(abs_source_coords), repr(abs_dest_coords)) self.UIElement.set_focus() SendMouseInput(abs_source_coords, button_down=True, button_up=False) self.Move(abs_source_coords, abs_dest_coords) SendMouseInput(abs_dest_coords, button_down=False, button_up=True)
def _find_by_UIA(self, translated_identifier, scope=UIA.UIA_wrapper.TreeScope_Descendants): target_UIAElement = self.UIAElement.FindFirst(scope, translated_identifier) if target_UIAElement == ctypes.POINTER( UIA.UIA_wrapper.IUIAutomationElement)(): LOGGER.debug("Find no element matching identifier") return None return UIElement(target_UIAElement)
def find_element(self, parsed_identifier): ''' find the first child UI element via identifier, return one UIAElement if success, return None if not find ''' translated_identifier = Translater.ID_Translater(parsed_identifier).get_translated() try: selenium_element = self.selenium_element.find_element(by=translated_identifier[0], value=translated_identifier[1]) except NoSuchElementException: LOGGER.debug("Cannot find target element") return None else: return UIElement(selenium_element)
def move(self, abs_source_coords, abs_dest_coords): '''Move: move mouse from source_coords to dest_coords mouse move is not related with UI element so need use abs coords ''' import time import random x_range = abs(abs_source_coords[0] - abs_dest_coords[0]) y_range = abs(abs_source_coords[1] - abs_dest_coords[1]) x_sample_size = x_range / 10 y_sample_size = y_range / 10 #choose the bigger one sample_size = x_sample_size > y_sample_size and x_sample_size or y_sample_size #build population if abs_source_coords[0] < abs_dest_coords[0]: x_population = list(range(abs_source_coords[0], abs_dest_coords[0])) else: x_population = list(range(abs_dest_coords[0], abs_source_coords[0])) while len(x_population) < sample_size: x_population = x_population * 2 if abs_source_coords[1] < abs_dest_coords[1]: y_population = list(range(abs_source_coords[1], abs_dest_coords[1])) else: y_population = list(range(abs_dest_coords[1], abs_source_coords[1])) while len(y_population) < sample_size: y_population = y_population * 2 #get coords if abs_source_coords[0] < abs_dest_coords[0]: x_coords = sorted(random.sample(x_population, sample_size)) else: x_coords = sorted(random.sample(x_population, sample_size), reverse=True) if abs_source_coords[1] < abs_dest_coords[1]: y_coords = sorted(random.sample(y_population, sample_size)) else: y_coords = sorted(random.sample(y_population, sample_size), reverse=True) #move mouse LOGGER.debug("Mouse move from: %s to %s", repr(abs_source_coords), repr(abs_dest_coords)) self.UIElement.set_focus() for i in range(sample_size): SendMouseInput([x_coords[i], y_coords[i]], button_down=False, button_up=False) time.sleep(0.1)
def find_element(self, parsed_identifier): ''' find the first child UI element via identifier, return one UIAElement if success, return None if not find ''' translated_identifier = Translater.ID_Translater( parsed_identifier).get_translated() try: selenium_element = self.selenium_element.find_element( by=translated_identifier[0], value=translated_identifier[1]) except NoSuchElementException: LOGGER.debug("Cannot find target element") return None else: return UIElement(selenium_element)
def right_click(self, relative_coords = None): '''RightClick: right click the UI element, or taget coords Arguments: coords: coordinate indicate where mouse click, default use UI element click point Returns: ''' if relative_coords is None: coords = self.UIElement.get_clickable_point() else: coords = [0, 0] coords[0] = relative_coords[0]+self.UIElement.coordinate[0] coords[1] = relative_coords[1]+self.UIElement.coordinate[1] LOGGER.debug("Mouse right click at: %s" , repr(coords)) self.UIElement.set_focus() SendMouseInput(coords, button="right")
def right_click(self, relative_coords=None): '''RightClick: right click the UI element, or taget coords Arguments: coords: coordinate indicate where mouse click, default use UI element click point Returns: ''' if relative_coords is None: coords = self.UIElement.get_clickable_point() else: coords = [0, 0] coords[0] = relative_coords[0] + self.UIElement.coordinate[0] coords[1] = relative_coords[1] + self.UIElement.coordinate[1] LOGGER.debug("Mouse right click at: %s", repr(coords)) self.UIElement.set_focus() SendMouseInput(coords, button="right")
def cli_execute(self, command): '''execute cli command command like "app parameter1 parameter 2" may contain variables ''' args = cli_command_parser.parse(command, lexer=cli_command_lexer) #replace variables for i, arg in enumerate(args): if not re.match("^{.*}$", arg) is None: args[i] = self.variables[arg.strip("{").strip("}")] #some app need to execute in their folder app_path = os.path.dirname(args[0]) if app_path: os.chdir(app_path) LOGGER.debug("CLI execute: %s" , repr(args)) p = subprocess.Popen(args, shell=True)
def check_app_map(XSD_file, app_map_file): XSD_module_name = os.path.basename(XSD_file).split(".")[0] XSD_module_dir = os.path.dirname(XSD_file) generate_module(XSD_file, XSD_module_name, XSD_module_dir) sys.path.insert(0, XSD_module_dir) XSD_module = __import__(XSD_module_name) with open(app_map_file) as app_map: try: XSD_module.CreateFromDocument(app_map.read()) LOGGER.debug("Check successful") except pyxb.UnrecognizedContentError as e: LOGGER.warn(e.details()) except pyxb.IncompleteElementContentError as e: LOGGER.warn(e.details()) except pyxb.ValidationError as e: LOGGER.warn(e.details())
def cli_execute(self, command): '''execute cli command command like "app parameter1 parameter 2" may contain variables ''' args = cli_command_parser.parse(command, lexer=cli_command_lexer) #replace variables for i, arg in enumerate(args): if not re.match("^{.*}$", arg) is None: args[i] = self.variables[arg.strip("{").strip("}")] #some app need to execute in their folder app_path = os.path.dirname(args[0]) if app_path: os.chdir(app_path) LOGGER.debug("CLI execute: %s", repr(args)) p = subprocess.Popen(args, shell=True)
def move(self, abs_source_coords, abs_dest_coords): '''Move: move mouse from source_coords to dest_coords mouse move is not related with UI element so need use abs coords ''' import time import random x_range = abs(abs_source_coords[0] - abs_dest_coords[0]) y_range = abs(abs_source_coords[1] - abs_dest_coords[1]) x_sample_size = x_range/10 y_sample_size = y_range/10 #choose the bigger one sample_size = x_sample_size > y_sample_size and x_sample_size or y_sample_size #build population if abs_source_coords[0] < abs_dest_coords[0]: x_population = list(range(abs_source_coords[0], abs_dest_coords[0])) else: x_population = list(range(abs_dest_coords[0], abs_source_coords[0])) while len(x_population)<sample_size: x_population = x_population*2 if abs_source_coords[1] < abs_dest_coords[1]: y_population = list(range(abs_source_coords[1], abs_dest_coords[1])) else: y_population = list(range(abs_dest_coords[1], abs_source_coords[1])) while len(y_population)<sample_size: y_population = y_population*2 #get coords if abs_source_coords[0] < abs_dest_coords[0]: x_coords = sorted(random.sample(x_population, sample_size)) else: x_coords = sorted(random.sample(x_population, sample_size), reverse=True) if abs_source_coords[1] < abs_dest_coords[1]: y_coords = sorted(random.sample(y_population, sample_size)) else: y_coords = sorted(random.sample(y_population, sample_size), reverse=True) #move mouse LOGGER.debug("Mouse move from: %s to %s" , repr(abs_source_coords), repr(abs_dest_coords)) self.UIElement.set_focus() for i in range(sample_size): SendMouseInput([x_coords[i], y_coords[i]], button_down=False, button_up=False) time.sleep(0.1)
def screenshot(filename, coordinate=None): '''screenshot for target UI area parameters: handle: window handler for target UI filename: screenshot filename, should be .bmp file coordinate: (left, top, right, bottom) coordinate for target area ''' current_dir = os.path.dirname(__file__) screenshot_app = os.path.join(current_dir, "screenshot.exe") if coordinate is None: cmd = '"%s" -f %s' % (screenshot_app, filename) else: cmd = '"%s" -f %s -l %s -t %s -r %s -b %s' %\ (screenshot_app, filename, coordinate[0], coordinate[1], coordinate[2], coordinate[3]) LOGGER.debug("screenshot command: %s" , cmd) process = subprocess.Popen(cmd) return process.wait()
def screenshot(filename, coordinate=None): '''screenshot for target UI area parameters: handle: window handler for target UI filename: screenshot filename, should be .bmp file coordinate: (left, top, right, bottom) coordinate for target area ''' current_dir = os.path.dirname(__file__) screenshot_app = os.path.join(current_dir, "screenshot.exe") if coordinate is None: cmd = '"%s" -f %s' % (screenshot_app, filename) else: cmd = '"%s" -f %s -l %s -t %s -r %s -b %s' %\ (screenshot_app, filename, coordinate[0], coordinate[1], coordinate[2], coordinate[3]) LOGGER.debug("screenshot command: %s", cmd) process = subprocess.Popen(cmd) return process.wait()
def get_property_by_id(UIAElement, property_identifier): '''get UIA element property by identifier, return None if fail Arguments: UIAElement: UIA Element instance property_identifier: property identifier Returns: property_value if success None if property_identifier not valid or not supported by UIA Element ''' if property_identifier in UIA_automation_element_property_identifers_mapping: property_value = UIAElement.GetCurrentPropertyValue(UIA_automation_element_property_identifers_mapping[property_identifier]) if property_value is None: LOGGER.debug("This property:%s is not supported by this UIAElment" , property_identifier) return "" return property_value elif property_identifier in UIA_control_pattern_availability_property_identifiers_mapping: property_value = UIAElement.GetCurrentPropertyValue(UIA_control_pattern_availability_property_identifiers_mapping[property_identifier]) if property_value is None: LOGGER.debug("This property:%s is not supported by this UIAElment" , property_identifier) return "" return property_value else: LOGGER.debug("This property identifier is not support: %s, cannot get it from UIA typelib" % property_identifier) return None
def get_property_by_id(UIAElement, property_identifier): '''get UIA element property by identifier, return None if fail Arguments: UIAElement: UIA Element instance property_identifier: property identifier Returns: property_value if success None if property_identifier not valid or not supported by UIA Element ''' if property_identifier in UIA_automation_element_property_identifers_mapping: property_value = UIAElement.GetCurrentPropertyValue( UIA_automation_element_property_identifers_mapping[ property_identifier]) if property_value is None: LOGGER.debug("This property:%s is not supported by this UIAElment", property_identifier) return "" return property_value elif property_identifier in UIA_control_pattern_availability_property_identifiers_mapping: property_value = UIAElement.GetCurrentPropertyValue( UIA_control_pattern_availability_property_identifiers_mapping[ property_identifier]) if property_value is None: LOGGER.debug("This property:%s is not supported by this UIAElment", property_identifier) return "" return property_value else: LOGGER.debug( "This property identifier is not support: %s, cannot get it from UIA typelib" % property_identifier) return None
def __init__(self, UIAElement, pattern_identifier): self.UIAElement = UIAElement self.pattern_object = UIA.get_pattern_by_id(UIAElement, pattern_identifier) if self.pattern_object is None: raise DriverException("Cannot get pattern, stop init pattern object") self.methods = {} self.properties = {} interface_description = UIA.UIA_control_pattern_interfaces[pattern_identifier] for member_description in interface_description: flag, name, args = _unpack(*member_description) #do a check, see if member exist in pattern object #if not, skip this member try: getattr(self.pattern_object, name) except AttributeError: LOGGER.debug("%s not exist in Pattern:%s", name, pattern_identifier) continue if flag == "method": self.methods[name] = args elif flag == "property": self.properties[name] = args else: raise DriverException("Unrecognised flag %s" % flag)
def get_property(self, name): ''' get property value ''' try: obj = getattr(self.selenium_element, name) except AttributeError: LOGGER.debug("Cannot find this attribute: %s" , name) if hasattr(self.selenium_element, "get_attribute"): LOGGER.debug("Try get_attribute method") return self.selenium_element.get_attribute(name) else: if inspect.ismethod(obj): LOGGER.debug("This is a method, not a property: %s" , name) return None else: return obj
def get_property(self, name): ''' get property value ''' try: obj = getattr(self.selenium_element, name) except AttributeError: LOGGER.debug("Cannot find this attribute: %s", name) if hasattr(self.selenium_element, "get_attribute"): LOGGER.debug("Try get_attribute method") return self.selenium_element.get_attribute(name) else: if inspect.ismethod(obj): LOGGER.debug("This is a method, not a property: %s", name) return None else: return obj
def get_mouse(self): ''' get mouse class to use mouse related methods ''' LOGGER.debug("Browser not support mouse action") return None
def get_keyboard(self): ''' get keyboard class to use keyboard related methods ''' LOGGER.debug("Browser not support keyboard action") return None
#Control Pattern Availability Property Identifiers UIA_control_pattern_availability_property_identifiers = \ [ "Is"+identifier+"Available" for identifier in UIA_control_pattern_identifers ] #check if enum exist in current version UIA namespace #set the value if exist for enum in list(UIA_enums.items()): enum_name = enum[0] enum_contents = enum[1] #check if enum name in current UIA namespace enum_name_type = getattr(UIA_wrapper, enum_name, None) if enum_name_type is not ctypes.c_int: #enum type should be c_int in UIA wrapper namespace #skip this enum if enum type is not c_int LOGGER.debug("Enum: %s not exist in current UIA namespace" , enum_name) continue for enum_content_name in enum_contents: enum_content_value = getattr(UIA_wrapper, enum_content_name, None) #set the value to UIA_enums dict UIA_enums[enum_name][enum_content_name] = enum_content_value #build map for property identifiers UIA_automation_element_property_identifers_mapping = {} for identifier in UIA_automation_element_property_identifers: value = getattr(UIA_wrapper, "UIA_"+identifier+"PropertyId", None) if value is None: LOGGER.debug("Automation element property identifier: %s not exist in current UIA namespace" , identifier) continue UIA_automation_element_property_identifers_mapping[identifier] = value
def get_touch(self): ''' get touch class to use touch related methods ''' LOGGER.debug("Browser not support touch action") return None
def p_error(p): LOGGER.debug("Syntax error in input: %s, Ln: %d" , repr(p.value), p.lineno) raise Exception("")
def t_error(t): LOGGER.debug("Illegal character %s in Ln: %d" , repr(t.value[0]), t.lexer.lineno) raise Exception("") t.lexer.skip(1)
#set DPI awareness for win8.1 and win10 from AXUI.logger import LOGGER import subprocess p = subprocess.Popen("wmic path win32_operatingsystem get version", stdout=subprocess.PIPE) (stdout, stderr) = p.communicate() windows_version = stdout.split()[1] LOGGER.debug("Windows verison: %s" , windows_version) #need set DPI awareness for win8.1 and win10 if (int(windows_version.split(".")[0]) >= 6 and int(windows_version.split(".")[1]) >= 3) \ or int(windows_version.split(".")[0]) >= 10: LOGGER.debug("Set DPI awareness for windows verison: %s" , windows_version) import ctypes shcore = ctypes.windll.shcore shcore.SetProcessDpiAwareness(2) from .UIElement import UIElement, Root
def __getattr__(self, name): if name in self.interfaces: return getattr(self.selenium_element, name) else: LOGGER.debug("This method not exist in NormalPattern: %s", name)
#Control Pattern Availability Property Identifiers UIA_control_pattern_availability_property_identifiers = \ [ "Is"+identifier+"Available" for identifier in UIA_control_pattern_identifers ] #check if enum exist in current version UIA namespace #set the value if exist for enum in list(UIA_enums.items()): enum_name = enum[0] enum_contents = enum[1] #check if enum name in current UIA namespace enum_name_type = getattr(UIA_wrapper, enum_name, None) if enum_name_type is not ctypes.c_int: #enum type should be c_int in UIA wrapper namespace #skip this enum if enum type is not c_int LOGGER.debug("Enum: %s not exist in current UIA namespace", enum_name) continue for enum_content_name in enum_contents: enum_content_value = getattr(UIA_wrapper, enum_content_name, None) #set the value to UIA_enums dict UIA_enums[enum_name][enum_content_name] = enum_content_value #build map for property identifiers UIA_automation_element_property_identifers_mapping = {} for identifier in UIA_automation_element_property_identifers: value = getattr(UIA_wrapper, "UIA_" + identifier + "PropertyId", None) if value is None: LOGGER.debug( "Automation element property identifier: %s not exist in current UIA namespace", identifier)
def input(self, *values): '''take a string, translate to win32 event, and input to system Arguments: string: a string represent the keys input pause: global pause time during each key input, default to 0.05s Returns: Keyboard input string introduce: (1) For normal charactors like [0~9][a~z][A~Z], input directly (2) For special charactors like "space", "tab", "newline", "F1~F12" You use {key_name} to replace them Here are the support key list: backspace : {BACK}, {BACKSPACE}, {BKSP}, {BS} break : {BREAK} capslock : {CAP}, {CAPSLOCK} delete : {DEL}, {DELETE} down : {DOWN} end : {END} enter : {ENTER} ESC : {ESC} F1~F24 : {F1}~{F24} help : {HELP} home : {HOME} insert : {INS}, {INSERT} left : {LEFT} left windows : {LWIN} number lock : {NUMLOCK} page down : {PGDN} page up : {PGUP} print screen : {PRTSC} right : {RIGHT} right menu : {RMENU} right windows : {RWIN} scroll lock : {SCROLLLOCK} space : {SPACE} tab : {TAB} up : {UP} (3) For key combinations ctrl+X : {CTRL+X} shift+X : {SHIFT+X} menu+X : {MENU+X} windows key+X : {LWIN+X} ctrl+shift+X : {CTRL+SHIFT+X} ctrl+(XYZ) : {CTRL+XYZ} ''' #set focus before input keys self.UIElement.set_focus() #translate arguments to a string LOGGER.debug("Before translate, value: %s" , repr(values)) string = "" for value in values: #value should only allow to be string or int if isinstance(value, int): translated_value = str(value) string += translated_value elif isinstance(value, str): if re.match("^{\+*}$", value) != None: #for key combinations, we need to do some translation #like "{CTRL+A}" to "^A", "{CTRL+SHIFT+B}" to "^+B" keys = value.lstrip("{").rstrip("}").split("+") for key in keys: if key.upper() in self.key_combinations: translated_value += self.key_combinations[key.upper()] else: translated_value += "("+key+")" else: translated_value = value string += translated_value else: LOGGER.warning("keyboard input method arguments can only be string or int value, other value will be skipped") LOGGER.debug("Translated string: %s" , string) keys = parse_keys(string) LOGGER.debug("Keyboard input string: %s, parsed keys: %s" , string, repr(keys)) for k in keys: k.Run() time.sleep(0.05)