def __init__(self, anchorimage, offsetx = 0, offsety = 0, width = 0, height = 0, parentregion = SCREEN, name = 'anchored region'): """Creates a new anchored region that will be identified by the specified image. The anchor() method must be called to actually identify the region and calculate its position. The image's top-left corner will be positioned offsetx pixels from the left edge and offsety pixels from the top edge of the region. Width and height are the region's dimensions. If the parent region is specified, the anchor image will only be searched in that region, otherwise in the entire screen. Note that for finding the anchor image, the parent region's position and dimension at the time the anchor() method is called are relevant, not those at the time this instance is created. If width and height are 0, offsetx and offsety must also be 0, and the region is set to the match region of the anchor image. If name is provided, it is printed in debug statements. """ if width == 0 or height == 0: if offsetx != 0 or offsety != 0 or width != 0 or height != 0: raise Exception('if width or height are 0, all offsets and dimensions must be 0') Region.__init__(self, 0, 0, width, height) self.anchorimage = anchorimage self.offsetx = offsetx self.offsety = offsety if parentregion is not None: self.parentregion = parentregion else: self.parentregion = SCREEN self.name = name self.anchormatch = None self.findcount = 0
def update_element(self, element_index): """Updates the specified element with its true state. """ region = Region(self.element_regions[element_index]) # add some space since images may have slightly different size marginx = int(region.getW() * 0.2) marginy = int(region.getH() * 0.2) extendRegion(region, left = marginx, right = marginx, top = marginy, bottom = marginy) best_checked_score = 0 best_unchecked_score = 0 try: best_checked = bestMatch(self.images['checked'], region = region, minOverlap = 0.5) if best_checked is not None: best_checked_score = best_checked[1].getScore() except FindFailed: pass try: best_unchecked = bestMatch(self.images['unchecked'], region = region, minOverlap = 0.5) if best_unchecked is not None: best_unchecked_score = best_unchecked[1].getScore() except FindFailed: pass if best_checked_score == best_unchecked_score: if best_checked_score == 0: raise Exception('no %s found in region %d' % (self.element_types, element_index)) raise Exception('score tie: cannot decide whether %s %d is checked or unchecked (score=%f)' % (self.element_type, element_index, best_checked_score)) state = best_checked_score > best_unchecked_score if state != self.is_checked(element_index): self._toggle_state(element_index)
def run(self): """Runs the installer.""" self._ensure(running=False) _LOGGER.info('Running %s', self.path) openApp(self.path) self.running = True self.installing = False self.anchor(WELCOME_WINDOW_TIMEOUT) _LOGGER.info('Installer window has appeared') self.page = self.welcome_page self.button_region = Region( self.getX(), self.getY() + self.getH() - BUTTON_REGION_HEIGHT, self.getW(), BUTTON_REGION_HEIGHT) self.buttons = Buttons(self.button_images, self.disabled_button_images, region=self.button_region) self.buttons.find_buttons() self.buttons_valid = True self.buttons.waitUntilButtonIsEnabled('next', NEXT_BUTTON_ENABLED_TIMEOUT) self.confirm_window_open = False self.confirm_window_region = Region( self.getX() + (self.getW() - CONFIRM_WINDOW_WIDTH) / 2, self.getY() + (self.getH() - CONFIRM_WINDOW_HEIGHT) / 2, CONFIRM_WINDOW_WIDTH, CONFIRM_WINDOW_HEIGHT) self.confirm_buttons = Buttons(self.confirm_button_images, region=self.confirm_window_region) _LOGGER.info('Waiting for Next button to be enabled') self.shortcut_checkboxes = None
class Window: """A window has a title bar that contains buttons to minimize, maximize and close the window in the upper right. A window can get focus by clicking on its title bar. """ def __init__(self, region, title): """Creates a new window that covers the specified region. The region includes the title bar. """ self.region = region self.title = title self.titlebar_region = Region(region.getX(), region.getY(), region.getW(), windowflavor.WINDOW_TITLEBAR_HEIGHT) self.minimize_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_MINIMIZE_BUTTON_OFFSET) self.maximize_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_MAXIMIZE_BUTTON_OFFSET) self.close_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_CLOSE_BUTTON_OFFSET) def getButtonLocation(self, button_offset): """Returns a Location instance at the specified horizontal offset in the title bar, vertically centered in the title bar. """ if button_offset > 0: button_x = self.titlebar_region.getX() + button_offset else: button_x = self.titlebar_region.getX() \ + self.titlebar_region.getW() + button_offset return Location(button_x, self.titlebar_region.getY() + windowflavor.WINDOW_TITLEBAR_HEIGHT / 2) def setFocus(self): """Clicks on the center of this window's title bar.""" _LOGGER.debug('setFocus: %s', self.title) SCREEN.click(self.titlebar_region) def minimize(self): """Clicks on the minimize button in this window's title bar.""" _LOGGER.debug('minimize window: %s', self.title) SCREEN.click(self.minimize_button) def maximize(self): """Clicks on the maximize button in this window's title bar.""" _LOGGER.debug('maximize window: %s', self.title) SCREEN.click(self.maximize_button) def close(self): """Clicks on the close button in this window's title bar.""" _LOGGER.debug('close window: %s', self.title) SCREEN.click(self.close_button) def kill(self): """Attempts to kill the process that owns this window, using the window title. """ _LOGGER.debug('kill window: %s', self.title) closeApp(self.title)
def goto(self, x, y): if self.enabled: self.queue.append([x, y]) if not self.region: self.region = Region(x, y, 1, 1) else: self.region = self.region.add(Location(x, y))
def performFind(self): """ Loads the baseline images from disk and finds them on the screen. Works with the Transforms class to load extra data stored in the PNG's to control how they're matched. """ # sequence and series for series in self.seriesRange: regions = [] lastRegion = self.region nextRegion = Region(self.region) # try to match all images in the sequence try: for (sequence, filename) in enumerate(self.getImageNames(series=series,state=self.state)): transform = self.transform(filename, entity=self.entity, regionsMatched=regions, context=self) # Apply prev search attribs nextRegion = transform.apply(nextRegion, self.transform.CONTEXT_PREVIOUS) # Apply search attribs pattern = transform.apply(Pattern(filename), self.transform.CONTEXT_CURRENT) self.logger.trace("Loading %%s", self.logger.getFormatter()(pattern)) # find the image on the screen lastRegion = nextRegion.wait( pattern ) # If we don't set to zero wait time (dialog handler threads wait indefinitely) lastRegion = transform.apply(lastRegion, self.transform.CONTEXT_MATCH) self.logger.trace("validated %%s %%s in region %%s nameType=%s colType=%s ser=%s seq=%s" % (self.nameType, self.collectionType, series, sequence), self.logger.getFormatter()(pattern), self.logger.getFormatter()(lastRegion), self.logger.getFormatter()(nextRegion)) regions.append( lastRegion ) # Transform next region with the spacial region # spacialRegion is only used if there are spacial modifiers nextRegion = transform.apply(Region(nextRegion), self.transform.CONTEXT_NEXT, override=lastRegion) except FindFailed, e: self.logger.trace("failed to find on screen %%s in %%s nameType=%s colType=%s ser=%s seq=%s" % (self.nameType, self.collectionType, series, sequence), self.logger.getFormatter()(self).setLabel("Images"), self.logger.getFormatter()(nextRegion)) else: region = None for currentRegion in regions: if not region: region = Region(currentRegion) else: region.add(currentRegion) region = transform.apply(region, self.transform.CONTEXT_FINAL) # Apply entity transforms transform.apply(self.entity, self.transform.CONTEXT_ENTITY) self.lastRegionFound = region self.lastSeriesFound = series return region
def waitUntilComplete(self, timeout=60, resultArgs={}): self.validate() # Convert Match to Region -> workaround: https://bugs.launchpad.net/sikuli/+bug/905435 r = Region(self.region) r.onChange(self.__changed) r.observe(FOREVER, background=True) # start observing progress bar startTime = time.time() self.lastChange = time.time() # loop while things are still changing while (time.time() - self.lastChange) < timeout: sleep(1) r.stopObserver() # stop observing progress bar self.logger.trace("stopped changing after %ds" % (time.time() - startTime)) # try and click the button state = "complete" ir = self.regionFinder(self, region=self.region, state=state) # image region of the button try: region = ir.find() except FindExhaustedException, e: raise StateFailedException("incorrect state [%s]" % state)
def __init__(self, region, title): """Creates a new window that covers the specified region. The region includes the title bar. """ self.region = region self.title = title self.titlebar_region = Region(region.getX(), region.getY(), region.getW(), windowflavor.WINDOW_TITLEBAR_HEIGHT) self.minimize_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_MINIMIZE_BUTTON_OFFSET) self.maximize_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_MAXIMIZE_BUTTON_OFFSET) self.close_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_CLOSE_BUTTON_OFFSET)
def _add_match(self, match, state, regions, checked_region_scores, unchecked_region_scores): """Find the region in regions that is similar to the match. Update the score for that region. If there is no similar region, create a new region from the match. """ match_region = None for region in regions: if sameRegion(region, match, 0.5): match_region = region break if match_region is None: match_region = Region(match) regions.append(match_region) region_id = self._region_id(match_region) if region_id not in checked_region_scores: checked_region_scores[region_id] = 0 if region_id not in unchecked_region_scores: unchecked_region_scores[region_id] = 0 if state == 'checked': if match.getScore() > checked_region_scores[region_id]: checked_region_scores[region_id] = match.getScore() else: if match.getScore() > unchecked_region_scores[region_id]: unchecked_region_scores[region_id] = match.getScore()
def update_button(self, name): """Updates the specified button so that this button set reflects the current state of the button. """ _LOGGER.debug("%sgetting current state of '%s' button", self._debugprefix, name) i, match = self._button_matches[name] button_region = Region(match).nearby(15) images = [] images.extend(self._buttons[name]) if self._disabled_buttons is not None and \ name in self._disabled_buttons: images.extend(self._disabled_buttons[name]) i_best, m_best = bestMatch(images, region=button_region, minOverlap=0.5) disabled = i_best >= len(self._buttons[name]) if disabled: _LOGGER.info("'%s' button (image %d) is disabled", name, i_best - len(self._buttons[name])) s = self._disabled_button_index[name] self._button_matches[name] = \ (s + i_best - len(self._buttons[name]), m_best) else: _LOGGER.info("'%s' button (image %d) is enabled", name, i_best) s = self._button_index[name] self._button_matches[name] = (s + i_best, m_best)
def waitUntilComplete(self, timeout=60, resultArgs={}): self.validate() # Convert Match to Region -> workaround: https://bugs.launchpad.net/sikuli/+bug/905435 r = Region(self.region) r.onChange(self.__changed) r.observe(FOREVER, background=True) # start observing progress bar startTime = time.time() self.lastChange = time.time() # loop while things are still changing while (time.time()-self.lastChange) < timeout: sleep(1) r.stopObserver() # stop observing progress bar self.logger.trace("stopped changing after %ds" % (time.time()-startTime)) # try and click the button state = "complete" ir = self.regionFinder(self, region=self.region, state=state) # image region of the button try: region = ir.find() except FindExhaustedException, e: raise StateFailedException("incorrect state [%s]" % state)
def update_element(self, element_index): """Updates the specified element with its true state. """ region = Region(self.element_regions[element_index]) # add some space since images may have slightly different size marginx = int(region.getW() * 0.2) marginy = int(region.getH() * 0.2) extendRegion(region, left=marginx, right=marginx, top=marginy, bottom=marginy) best_checked_score = 0 best_unchecked_score = 0 try: best_checked = bestMatch(self.images['checked'], region=region, minOverlap=0.5) if best_checked is not None: best_checked_score = best_checked[1].getScore() except FindFailed: pass try: best_unchecked = bestMatch(self.images['unchecked'], region=region, minOverlap=0.5) if best_unchecked is not None: best_unchecked_score = best_unchecked[1].getScore() except FindFailed: pass if best_checked_score == best_unchecked_score: if best_checked_score == 0: raise Exception('no %s found in region %d' % (self.element_types, element_index)) raise Exception( 'score tie: cannot decide whether %s %d is checked or unchecked (score=%f)' % (self.element_type, element_index, best_checked_score)) state = best_checked_score > best_unchecked_score if state != self.is_checked(element_index): self._toggle_state(element_index)
class PracticeDrawingStrategy(DrawingStrategy): region = None def goto(self, x, y): if not self.region: self.region = Region(x, y, 1, 1) else: self.region = self.region.add(Location(x,y)) def on(self): self.region = None super(PracticeDrawingStrategy, self).on() def off(self): self.obj.center(self.region) super(PracticeDrawingStrategy, self).off()
class ContiniousDrawingStrategy(DrawingStrategy): queue = None region = None def goto(self, x, y): if self.enabled: self.queue.append([x, y]) if not self.region: self.region = Region(x, y, 1, 1) else: self.region = self.region.add(Location(x, y)) def on(self): super(ContiniousDrawingStrategy, self).on() self.queue = [] self.region = None def off(self): super(ContiniousDrawingStrategy, self).off() # Prepare to draw annotation self.obj.center(self.region) # Move to first location self.obj.mouseMove(self.queue[0][0], self.queue[0][1]) self.obj.startDrawing() for location in self.queue[1:]: self.obj.mouseMove(location[0], location[1]) self.obj.stopDrawing()
class Window: """A window has a title bar that contains buttons to minimize, maximize and close the window in the upper right. A window can get focus by clicking on its title bar. """ def __init__(self, region, title): """Creates a new window that covers the specified region. The region includes the title bar. """ self.region = region self.title = title self.titlebar_region = Region(region.getX(), region.getY(), region.getW(), windowflavor.WINDOW_TITLEBAR_HEIGHT) self.minimize_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_MINIMIZE_BUTTON_OFFSET) self.maximize_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_MAXIMIZE_BUTTON_OFFSET) self.close_button = self.getButtonLocation( windowflavor.WINDOW_TITLEBAR_CLOSE_BUTTON_OFFSET) def getButtonLocation(self, button_offset): """Returns a Location instance at the specified horizontal offset in the title bar, vertically centered in the title bar. """ if button_offset > 0: button_x = self.titlebar_region.getX() + button_offset else: button_x = self.titlebar_region.getX() \ + self.titlebar_region.getW() + button_offset return Location( button_x, self.titlebar_region.getY() + windowflavor.WINDOW_TITLEBAR_HEIGHT / 2) def setFocus(self): """Clicks on the center of this window's title bar.""" _LOGGER.debug('setFocus: %s', self.title) SCREEN.click(self.titlebar_region) def minimize(self): """Clicks on the minimize button in this window's title bar.""" _LOGGER.debug('minimize window: %s', self.title) SCREEN.click(self.minimize_button) def maximize(self): """Clicks on the maximize button in this window's title bar.""" _LOGGER.debug('maximize window: %s', self.title) SCREEN.click(self.maximize_button) def close(self): """Clicks on the close button in this window's title bar.""" _LOGGER.debug('close window: %s', self.title) SCREEN.click(self.close_button) def kill(self): """Attempts to kill the process that owns this window, using the window title. """ _LOGGER.debug('kill window: %s', self.title) closeApp(self.title)
def find(self, timeout=0): return Region(0, 0, 100, 100)
def getLastRegionFound(self): return Region(0, 0, 100, 100)
def testCanDisplayRegion(self): # Should have simplified Region coords and a md5 of active region formatter = Formatter(Region(0, 0, 100, 100)) self.assertEqual(str(formatter), '["Region[0,0 100x100]"](md5.png:Actual)')
def getLastRegionMatched(self): return Region(0, 0, 100, 100)
def goto(self, x, y): if not self.region: self.region = Region(x, y, 1, 1) else: self.region = self.region.add(Location(x,y))
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ # TODO: copied from windowsxp.py, need to fix! from sikuli.Region import Region from sikuli.Sikuli import SCREEN """Window theme """ WINDOW_TITLEBAR_HEIGHT = 30 WINDOW_TITLEBAR_MINIMIZE_BUTTON_OFFSET = -62 WINDOW_TITLEBAR_MAXIMIZE_BUTTON_OFFSET = -39 WINDOW_TITLEBAR_CLOSE_BUTTON_OFFSET = -16 """Windows task bar """ WINDOWS_TASKBAR_REGION = Region(0, SCREEN.getH() - 31, SCREEN.getW(), 31) """Paths """ INTERNET_EXPLORER_PATH = r'C:\Program Files\Internet Explorer\IEXPLORE.EXE' MSOFFICE_ROOT_PATH = r'C:\Program Files\Microsoft Office' WINDOWS_EXPLORER_PATH = r'C:\WINDOWS\explorer.exe' CONTROL_PANEL_PATH = r'C:\WINDOWS\system32\control.exe' NOTEPAD_PATH = r'C:\WINDOWS\system32\notepad.exe'
def performFind(self): """ Loads the baseline images from disk and finds them on the screen. Works with the Transforms class to load extra data stored in the PNG's to control how they're matched. """ # sequence and series for series in self.seriesRange: regions = [] lastRegion = self.region nextRegion = Region(self.region) # try to match all images in the sequence try: for (sequence, filename) in enumerate( self.getImageNames(series=series, state=self.state)): transform = self.transform(filename, entity=self.entity, regionsMatched=regions, context=self) # Apply prev search attribs nextRegion = transform.apply( nextRegion, self.transform.CONTEXT_PREVIOUS) # Apply search attribs pattern = transform.apply(Pattern(filename), self.transform.CONTEXT_CURRENT) self.logger.trace("Loading %%s", self.logger.getFormatter()(pattern)) # find the image on the screen lastRegion = nextRegion.wait( pattern ) # If we don't set to zero wait time (dialog handler threads wait indefinitely) lastRegion = transform.apply(lastRegion, self.transform.CONTEXT_MATCH) self.logger.trace( "validated %%s %%s in region %%s nameType=%s colType=%s ser=%s seq=%s" % (self.nameType, self.collectionType, series, sequence), self.logger.getFormatter()(pattern), self.logger.getFormatter()(lastRegion), self.logger.getFormatter()(nextRegion)) regions.append(lastRegion) # Transform next region with the spacial region # spacialRegion is only used if there are spacial modifiers nextRegion = transform.apply(Region(nextRegion), self.transform.CONTEXT_NEXT, override=lastRegion) except FindFailed, e: self.logger.trace( "failed to find on screen %%s in %%s nameType=%s colType=%s ser=%s seq=%s" % (self.nameType, self.collectionType, series, sequence), self.logger.getFormatter()(self).setLabel("Images"), self.logger.getFormatter()(nextRegion)) else: region = None for currentRegion in regions: if not region: region = Region(currentRegion) else: region.add(currentRegion) region = transform.apply(region, self.transform.CONTEXT_FINAL) # Apply entity transforms transform.apply(self.entity, self.transform.CONTEXT_ENTITY) self.lastRegionFound = region self.lastSeriesFound = series return region