"""
:class:`Region` and :class:`SikuliEvent` classes to fulfill the roles of those
described at http://doc.sikuli.org/region.html
.. toctree::
:maxdepth: 2
"""
from python_sikuli_client.asserts import (assert_positive_int,
assert_PS,
assert_PSMRL,
assert_positive_num,
assert_PSRM)
from python_sikuli_client.misc import (dropNones,
constructor,
return_from_remote,
DEFERRED,
TODO,
run_on_remote)
__author__ = 'Alistair Broomhead'
from python_sikuli_client.sikuli_class import (UnimplementedSikuliClass,
SikuliClass)
[docs]class SikuliEvent(UnimplementedSikuliClass):
"""
Manages interaction with Sikuli's SikuliEvent, reflecting
http://doc.sikuli.org/region.html#SikuliEvent
.. todo:: Implement
"""
#TODO: SikuliEvent class
pass
#noinspection PyUnusedLocal
[docs]class Region(SikuliClass):
"""
Manages interaction with Sikuli's Region, reflecting
http://doc.sikuli.org/region.html#Region
"""
@run_on_remote
[docs] def setX(self, num):
"""
:param num: number - the new value
Set the respective attribute of the region to the new value. This
effectively moves the region around and/or changes its dimension.
"""
pass
@run_on_remote
[docs] def setY(self, num):
"""
:param num: number - the new value
Set the respective attribute of the region to the new value. This
effectively moves the region around and/or changes its dimension.
"""
pass
@run_on_remote
[docs] def setW(self, num):
"""
:param num: number - the new value
Set the respective attribute of the region to the new value. This
effectively moves the region around and/or changes its dimension.
"""
pass
@run_on_remote
[docs] def setH(self, num):
"""
:param num: number - the new value
Set the respective attribute of the region to the new value. This
effectively moves the region around and/or changes its dimension.
"""
pass
@return_from_remote('Region')
[docs] def moveTo(self, location):
"""
:param location: :class:`~python_sikuli_client.location.Location` - the new top
left corner
:rtype: :class:`Region` -- the modified region object
Set the position of this region regarding its top left corner to the
given location (the x and y values are modified).
"""
pass
@run_on_remote
[docs] def setROI(self, x, y, w, h):
"""
:param x: number
:param y: number
:param w: number
:param h: number
Set position and dimension to new values. The motivation for this alias
is to make scripts more readable: setROI() is intended to restrict the
search to a smaller area to speed up processing searches (region of
interest).
"""
pass
@run_on_remote
[docs] def setRect(self, x, y, w, h):
"""
:param x: number
:param y: number
:param w: number
:param h: number
Set position and dimension to new values. The motivation for this alias
is to make scripts more readable: setRect() should be used to redefine a
region (which could be enlarging it).
"""
pass
@run_on_remote
[docs] def morphTo(self, region):
"""
:param region: :class:`Region`
Set the position and dimension of this region to the
corresponding values of the region given as parameter.
"""
pass
@run_on_remote
[docs] def getX(self):
"""
:rtype: int
Get the respective attribute of the region.
"""
pass
@run_on_remote
[docs] def getY(self):
"""
:rtype: int
Get the respective attribute of the region.
"""
pass
@run_on_remote
[docs] def getW(self):
"""
:rtype: int
Get the respective attribute of the region.
"""
pass
@run_on_remote
[docs] def getH(self):
"""
:rtype: int
Get the respective attribute of the region.
"""
pass
@return_from_remote('Location')
[docs] def getCenter(self):
"""
:rtype: :class:`~python_sikuli_client.location.Location`
Get the center of the region.
"""
pass
@return_from_remote('Location')
[docs] def getTopLeft(self):
"""
:rtype: :class:`~python_sikuli_client.location.Location`
Get the location of the region's respective corner.
"""
pass
@return_from_remote('Location')
[docs] def getTopRight(self):
"""
:rtype: :class:`~python_sikuli_client.location.Location`
Get the location of the region's respective corner.
"""
pass
@return_from_remote('Location')
[docs] def getBottomLeft(self):
"""
:rtype: :class:`~python_sikuli_client.location.Location`
Get the location of the region's respective corner.
"""
pass
@return_from_remote('Location')
[docs] def getBottomRight(self):
"""
:rtype: :class:`~python_sikuli_client.location.Location`
Get the location of the region's respective corner.
"""
pass
@return_from_remote('Screen')
[docs] def getScreen(self):
"""
:rtype: :class:`~python_sikuli_client.screen.Screen`
Returns the screen object that contains this region.
This method only makes sense in Multi Monitor Environments, since it
always returns the default screen in a single monitor environment.
"""
pass
@return_from_remote('Match')
[docs] def getLastMatch(self):
"""
:rtype: :class:`~python_sikuli_client.match.Match`
All successful find operations (explicit like find() or implicit like
click()), store the best match in the lastMatch attribute of the region
that was searched.
"""
pass
@run_on_remote
def getLastMatches(self):
"""
:rtype: generator
findAll() stores all found matches into lastMatches attribute of the
region that was searched as a generator.
"""
pass
@getLastMatches.func
[docs] def getLastMatches(self):
""" :rtype: generator """
location_ids = self.remote._eval(
"[self._new_jython_object(x) for x in"
" self._get_jython_object(%r).getLastMatches()]" % self._id)
from python_sikuli_client.match import Match
return (Match(remote=self.remote, server_id=location_id)
for location_id in location_ids)
@run_on_remote
[docs] def setAutoWaitTimeout(self, seconds):
"""
:param seconds: float - The internal granularity is milliseconds.
Set the maximum waiting time for all subsequent find operations.
This method enables all find operations to wait for the given pattern to
appear until the specified amount of time has elapsed. The default is
3.0 seconds. This method is intended for users to override this default
setting. As such it lets Region.find() work like Region.wait(), without
being able to set an individual timeout value for a specific find
operation.
"""
pass
@run_on_remote
[docs] def getAutoWaitTimeout(self):
"""
:rtype: float
Get the current value of the maximum waiting time for find operations
"""
pass
@return_from_remote('Region')
[docs] def offset(self, location):
"""
Returns a new Region object, whose upper left corner is relocated adding
the location's x and y value to the respective values of the given
region. Width and height are the same. So this clones a region at a
different place.
:param location: :class:`~python_sikuli_client.location.Location`
:rtype: :class:`Region`
.. code-block:: python
new_reg = reg.offset(Location(xoff, yoff)) # same as
new_reg = Region(reg.x + xoff, reg.y + yoff, reg.w, reg.h)
"""
pass
@return_from_remote('Region')
[docs] def inside(self):
"""
Returns the same object. Retained for upward compatibility.
This method can be used to make scripts more readable.
``region.inside().find()`` is totally equivalent to ``region.find()``.
:rtype: :class:`Region`
"""
pass
@return_from_remote('Region')
[docs] def nearby(self, range_px=50):
"""
Returns a new Region that includes the nearby neighbourhood of the
the current region. The new region is defined by extending the
current region's dimensions in all directions by range number of
pixels. The center of the new region remains the same.
:param range_px: int > 0, default = 50
:rtype: :class:`Region`
"""
assert_positive_int(range_px, self.nearby)
@return_from_remote('Region')
[docs] def above(self, range_px):
"""
Returns a new :py:class:`Region` that is defined above the current
region's
top border with a height of *range* number of pixels.
So it does not include the current region.
If *range* is omitted, it reaches to the top
of the screen. The new region has the same width and x-position as the
current region.
:param range_px: a positive integer defining the new height
:rtype: a :class:`Region` object
"""
assert_positive_int(range_px, self.above)
@return_from_remote('Region')
[docs] def below(self, range_px):
"""
Returns a new :py:class:`Region` that is defined below the current
region's
bottom border with a height of *range* number of pixels.
So it does not include the current region.
If *range* is omitted, it reaches to the bottom
of the screen. The new region has the same width and x-position as the
current region.
:param range_px: a positive integer defining the new height
:rtype: a :class:`Region` object
"""
assert_positive_int(range_px, self.below)
@return_from_remote('Region')
[docs] def left(self, range_px):
"""
Returns a new :py:class:`Region` that is defined left of the current
region's
left border with a width of *range* number of pixels.
So it does not include the current region.
If *range* is omitted, it reaches to the left border
of the screen. The new region has the same height and y-position as the
current region.
:param range_px: a positive integer defining the new width
:rtype: a :py:class:`Region` object
"""
assert_positive_int(range_px, self.left)
@return_from_remote('Region')
[docs] def right(self, range_px):
"""
Returns a new :py:class:`Region` that is defined right of the current
region's right border with a width of *range* number of pixels.
So it does not include the current region.
If *range* is omitted, it reaches to the right border
of the screen. The new region has the same height and y-position as the
current region.
:param range_px: a positive integer defining the new width
:rtype: a :py:class:`Region` object
"""
assert_positive_int(range_px, self.right)
@return_from_remote('Match')
[docs] def find(self, PS):
"""
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
:rtype: a :class:`~python_sikuli_client.match.Match` object that contains the
best match or fails if PatternNotFound
Find a particular GUI element, which is seen as the given image or
just plain text. The given file name of an image specifies the
element's
appearance. It searches within the region and returns the best match,
which shows a similarity greater than the minimum similarity given by
the pattern. If no similarity was set for the pattern by
:py:meth:`Pattern.similar` before, a default minimum similarity of 0.7
is set automatically.
If autoWaitTimeout is set to a non-zero value, find() just acts as a
wait().
**Side Effect** *lastMatch*: the best match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
"""
assert_PS(PS, self.find)
@run_on_remote
def findAll(self, PS):
"""
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
:rtype: one or more :class:`~python_sikuli_client.match.Match` objects as an
iterator object or fails if PatternNotFound
Repeatedly find ALL instances of a pattern, until no match can be
found anymore, that meets the requirements for a single
:py:meth:`Region.find()` with the specified pattern.
By default, the returned matches are sorted by the similiarty.
If you need them ordered by their positions, say the Y coordinates,
you have to use Python's `sorted <http://wiki.python
.org/moin/HowTo/Sorting/>`_ function. Here is a example of sorting the
matches from top to bottom.
.. code-block:: python
def by_y(match):
return match.y
icons = findAll("png_icon.png")
# sort the icons by their y coordinates and put them into a new
sorted_icons = sorted(icons, key=by_y)
# another shorter version is using lambda.
sorted_icons = sorted(icons, key=lambda m:m.y)
for icon in sorted_icons:
pass # do whatever you want to do with the sorted icons
**Side Effect** *lastMatches*: a reference to the returned iterator
object containing the
found matches is stored with the region that was searched. It can be
accessed using getLastMatches() afterwards.
"""
assert_PS(PS, self.find)
pass
@findAll.func
[docs] def findAll(self, PS):
"""
:rtype: generator
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
"""
match_ids = self.remote._eval(
"[self._new_jython_object(x) for x in"
" self._get_jython_object(%r).findAll(%s)]"
% (self._id,
PS._str_get if isinstance(PS, SikuliClass) else PS))
from python_sikuli_client.match import Match
return (Match(remote=self.remote, server_id=match_id)
for match_id in match_ids)
@return_from_remote('Match')
def wait(self, PS=None, seconds=None):
"""
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
:param seconds: a number, which can have a fraction, as maximum waiting
time in seconds. The internal granularity is milliseconds. If not
specified, the auto wait timeout value set by
:py:meth:`Region.setAutoWaitTimeout` is used. Use the string
*'FOREVER'* to wait for an infinite time.
:rtype: a :class:`~python_sikuli_client.match.Match` object that contains the
best match or fails if PatternNotFound
If *PS* is not specified, the script just pauses for the specified
amount of time. It is still possible to use ``sleep(seconds)`` instead,
but this is deprecated.
If *PS* is specified, it keeps searching the given pattern in the
region until the image appears ( would have been found with
:py:meth:`Region.find`) or the specified amount of time has elapsed. At
least one find operation is performed, even if 0 seconds is
specified.)
**Side Effect** *lastMatch*: the best match can be accessed using
:meth:`Region.getLastMatch` afterwards.
Note: You may adjust the scan rate (how often a search during the wait
takes place) by setting :py:attr:`Settings.WaitScanRate` appropriately.
"""
if PS is not None:
assert_PS(PS, self.wait)
if seconds is not None and not seconds == 'FOREVER':
assert_positive_num(seconds, self.wait)
@wait.func
[docs] def wait(self, PS=None, seconds=None):
"""
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
:param seconds: a number, which can have a fraction, as maximum waiting
time in seconds. The internal granularity is milliseconds. If not
specified, the auto wait timeout value set by
:py:meth:`Region.setAutoWaitTimeout` is used. Use the constant
*FOREVER* to wait for an infinite time.
:rtype: a :class:`~python_sikuli_client.match.Match` object that contains the
best match or fails if PatternNotFound
"""
if PS is None:
from time import sleep
sleep(seconds)
return
ps_str = PS._str_get if isinstance(PS, SikuliClass) else PS
if seconds is None:
sec_str = repr(self.getAutoWaitTimeout())
elif isinstance(seconds, int):
sec_str = repr(seconds)
else:
sec_str = seconds
match_id = self.remote._eval(
"self._new_jython_object(self._get_jython_object(%r).wait("
"PS=%s, seconds=%s))" % (self._id, ps_str, sec_str))
from python_sikuli_client.match import Match
return Match(remote=self.remote, server_id=match_id)
@run_on_remote
def waitVanish(self, PS, seconds=None):
"""
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
:param seconds: a number, which can have a fraction, as maximum waiting
time in seconds. The internal granularity is milliseconds. If not
specified, the auto wait timeout value set by
:py:meth:`Region.setAutoWaitTimeout` is used. Use the string
*'FOREVER'* to wait for an infinite time.
:rtype: *True* if the pattern vanishes within the specified waiting
time, or *False* if the pattern stays visible after the waiting
time has elapsed.
This method keeps searching the given pattern in the region until the
image vanishes (can not be found with :py:meth:`Region.find` any
longer) or the specified amount of time has elapsed. At least one find
operation is performed, even if 0 seconds is specified.
**Note**: You may adjust the scan rate (how often a search during the
wait
takes place) by setting :py:attr:`Settings.WaitScanRate` appropriately.
"""
assert_PS(PS, self.waitVanish)
if seconds is not None and not seconds == 'FOREVER':
assert_positive_num(seconds, self.waitVanish)
@wait.func
[docs] def waitVanish(self, PS, seconds=None):
"""
:param PS: a :class:`~python_sikuli_client.pattern.Pattern` object or a string
(path to an image file or just plain text)
:param seconds: a number, which can have a fraction, as maximum waiting
time in seconds. The internal granularity is milliseconds. If not
specified, the auto wait timeout value set by
:py:meth:`Region.setAutoWaitTimeout` is used. Use the string
*'FOREVER'* to wait for an infinite time.
:rtype: *True* if the pattern vanishes within the specified waiting
time, or *False* if the pattern stays visible after the waiting
time has elapsed.
"""
ps_str = PS._str_get if isinstance(PS, SikuliClass) else PS
if seconds is None:
sec_str = repr(self.getAutoWaitTimeout())
elif isinstance(seconds, int):
sec_str = repr(seconds)
else:
sec_str = seconds
return self.remote._eval("self._get_jython_object(%r).waitVanish(PS=%s,"
" seconds=%s)" % (self._id, ps_str, sec_str))
@run_on_remote
def exists(self, PS, seconds=None):
"""
Check whether the give pattern is visible on the screen.
:param PS: a :py:class:`Pattern` object or a string (path to an image
file or just plain text)
:param seconds: a number, which can have a fraction, as maximum waiting
time in seconds. The internal granularity is milliseconds. If not
specified, the auto wait timeout value set by
:py:meth:`Region.setAutoWaitTimeout` is used. Use the constant
*FOREVER* to wait for an infinite time.
:rtype: a :class:`~python_sikuli_client.match.Match` object that contains the
best match or fails if PatternNotFound. None is returned, if nothing
is found within the specified waiting time.
Does exactly the same as :py:meth:`Region.wait()`, but no exception is
raised in case of FindFailed. So it can be used to symplify scripting
in case that you only want to know wether something is there or not to
decide how to proceed in your workflow. So it is typically used with an
if statement. At least one find operation is performed, even if 0
seconds is specified. So specifying 0 seconds saves some time, in case
there is no need to wait, since its your intention to get the
information "not found" directly.
**Side Effect** *lastMatch*: the best match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
**Note**: You may adjust the scan rate (how often a search during the
wait
takes place) by setting :py:attr:`Settings.WaitScanRate` appropriately.
"""
assert_PS(PS, self.exists)
if seconds is not None and not seconds == 'FOREVER':
assert_positive_num(seconds, self.exists)
@exists.func
[docs] def exists(self, PS, seconds=None):
"""
:param PS: a :py:class:`Pattern` object or a string (path to an image
file or just plain text)
:param seconds: a number, which can have a fraction, as maximum waiting
time in seconds. The internal granularity is milliseconds. If not
specified, the auto wait timeout value set by
:py:meth:`Region.setAutoWaitTimeout` is used. Use the constant
*FOREVER* to wait for an infinite time.
:rtype: a :class:`~python_sikuli_client.match.Match` object that contains the
best match or fails if PatternNotFound. None is returned, if nothing
is found within the specified waiting time.
"""
ps_str = PS._str_get if isinstance(PS, SikuliClass) else PS
if seconds is None:
sec_str = repr(self.getAutoWaitTimeout())
elif isinstance(seconds, int):
sec_str = repr(seconds)
else:
sec_str = seconds
match_id = self.remote._eval(
"self._new_jython_object(self._get_jython_object(%r)"
".exists(PS=%s, seconds=%s))" % (self._id, ps_str, sec_str))
from python_sikuli_client.match import Match
return (Match(remote=self.remote, server_id=match_id) if match_id is not
None else match_id)
@DEFERRED
[docs] def onAppear(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def onVanish(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def onChange(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def observe(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def stopObserver(self):
"""
.. todo:: Implement
"""
pass
@run_on_remote
def click(self, PSMRL, modifiers=None):
"""
Perform a mouse click on the click point using the left button.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: key modifiers
:rtype: the number of performed clicks (actually 1). A 0 (integer null)
means that because of some reason, no click could be performed (in
case of *PS* may be PatternNotFound).
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
**Example:**
.. code-block:: python
# Windows XP
click("xpstart.png")
# Windows Vista
click("vistastart.png")
# Windows 7
click("w7start.png")
# Mac
click("apple.png")
"""
assert_PSMRL(PSMRL, self.click)
@click.arg
[docs] def click(self, PSMRL, modifiers=None):
"""
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: key modifiers
"""
return dropNones(1, None, PSMRL, modifiers)
@run_on_remote
def doubleClick(self, PSMRL, modifiers=None):
"""
Perform a mouse double-click on the click point using the left button.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: one or more key modifiers
:rtype: the number of performed double-clicks (actually 1). A 0 (
integer null) means that because of some reason, no click could be
performed (in case of *PS* may be PatternNotFound).
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
"""
assert_PSMRL(PSMRL, self.doubleClick)
@doubleClick.arg
[docs] def doubleClick(self, PSMRL, modifiers=None):
"""
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: one or more key modifiers
"""
return dropNones(1, None, PSMRL, modifiers)
@run_on_remote
[docs] def rightClick(self, PSMRL, *modifiers):
"""
Perform a mouse click on the click point using the right button.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: one or more key modifiers
:rtype: the number of performed double-clicks (actually 1). A 0 (
integer null) means that because of some reason, no c
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
"""
assert_PSMRL(PSMRL, self.doubleClick)
@run_on_remote
def highlight(self, seconds=None):
"""
Highlight the region for some period of time.
:param seconds: a decimal number taken as duration in seconds
The region is highlighted showing a red colored frame around it. If the
parameter seconds is given, the script is suspended for the specified
time. If no time is given, the highlighting is started and the script
continues.
When later on the same highlight call without a parameter is made, the
highlighting is stopped (behaves like a toggling switch).
Example::
m = find(some_image)
# the red frame will blink for about 7 - 8 seconds
for i in range(5):
m.highlight(1)
wait(0.5)
# a second red frame will blink as an overlay to the first one
m.highlight()
for i in range(5):
m.highlight(1)
wait(0.5)
m.highlight()
# the red frame will grow 5 times
for i in range(5):
m.highlight(1)
m = m.nearby(20)
**Note**: The red frame is just an overlay in front of all other screen
content and stays in its place, independently from the behavior of this
other content, which means it is not "connected" to the *content* of the
defining region. But it will be adjusted automatically, if you change
position and/or dimension of this region in your script, while it is
highlighted.
"""
pass
@highlight.arg
[docs] def highlight(self, seconds=None):
"""
:param seconds: a decimal number taken as duration in seconds
"""
return dropNones(0, None, seconds)
@run_on_remote
def hover(self, PSMRL, modifiers=None):
"""
Move the mouse cursor to hover above a click point.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: one or more key modifiers
:rtype: the number 1 if the mousepointer could be moved to the click
point. A 0 (integer null) returned means that because of some
reason, no move could be performed (in case of *PS* may be
PatternNotFound).
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
"""
assert_PSMRL(PSMRL, self.hover)
@hover.arg
[docs] def hover(self, PSMRL, modifiers=None):
"""
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param modifiers: one or more key modifiers
"""
return dropNones(1, None, PSMRL, modifiers)
@run_on_remote
def dragDrop(self, PSMRL_drag, PSMRL_drop, modifiers=None):
"""
Perform a drag-and-drop operation from a starting click point to the
target click point indicated by the two PSMRLs respectively.
:param PSMRL_drag: a pattern, a string, a match, a region or a location
that evaluates to a click point.
:param PSMRL_drop: a pattern, a string, a match, a region or a location
that evaluates to a click point.
:param modifiers: one or more key modifiers
If one of the parameters is *PS*, the operation might fail due to
PatternNotFound.
**Sideeffect**: when using *PS*, the match of the target can be accessed
using :py:meth:`Region.getLastMatch` afterwards. If only the first
parameter is given as *PS*, this match is returned by
:py:meth:`Region.getLastMatch`.
**When the operation does not perform as expected** (usually caused by
timing problems due to delayed reactions of applications), you may
adjust the internal timing parameters :py:attr:`Settings.DelayAfterDrag`
and :py:attr:`Settings.DelayBeforeDrop` eventually combined with the
internal timing parameter :py:attr:`Settings.MoveMouseDelay`.
Another solution might be, to use a combination of
:py:meth:`Region.drag` and :py:meth:`Region.dropAt` combined with your
own ``wait()`` usages. If the mouse movement from source to target is
the problem, you might break up the move path into short steps using
:py:meth:`Region.mouseMove`.
"""
assert_PSMRL(PSMRL_drag, self.dragDrop)
assert_PSMRL(PSMRL_drop, self.dragDrop)
@dragDrop.arg
[docs] def dragDrop(self, PSMRL_drag, PSMRL_drop, modifiers=None):
"""
:param PSMRL_drag: a pattern, a string, a match, a region or a location
that evaluates to a click point.
:param PSMRL_drop: a pattern, a string, a match, a region or a location
that evaluates to a click point.
:param modifiers: one or more key modifiers
"""
return dropNones(2, None, PSMRL_drag, PSMRL_drop, modifiers)
@run_on_remote
[docs] def drag(self, PSMRL):
"""
Start a drag-and-drop operation by dragging at the given click point.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:rtype: the number 1 if the operation could be performed. A 0 (integer
null) returned means that because of some reason, no move could be
performed (in case of *PS* may be PatternNotFound).
The mousepointer is moved to the click point and the left mouse
button is pressed and held, until another mouse action is performed
(e.g. a :py:meth:`Region.dropAt()` afterwards). This is nomally used to
start a drag-and-drop operation.
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
"""
assert_PSMRL(PSMRL, self.drag)
@run_on_remote
def dropAt(self, PSMRL, delay=None):
"""
Complete a drag-and-drop operation by dropping a previously dragged
item at
the given target click point.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param delay: time to wait after in seconds as decimal value
:rtype: the number 1 if the operation could be performed. A 0
(integer null) returned means that because of some reason, no move
could be performed (in case of *PS* may be PatternNotFound).
The mousepointer is moved to the click point. After waiting for delay
seconds the left mouse button is released. This is normally used to
finalize
a drag-and-drop operation. If it is necessary to visit one ore more
click
points after dragging and before dropping, you can use
:py:meth:`Region.mouseMove` inbetween.
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
"""
assert_PSMRL(PSMRL, self.dropAt)
@dropAt.arg
[docs] def dropAt(self, PSMRL, delay=None):
"""
Complete a drag-and-drop operation by dropping a previously dragged
item at
the given target click point.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param delay: time to wait after in seconds as decimal value
:rtype: the number 1 if the operation could be performed. A 0
(integer null) returned means that because of some reason, no move
could be performed (in case of *PS* may be PatternNotFound).
"""
return dropNones(1, None, PSMRL, delay)
#noinspection PyUnusedLocal,PyDocstring
@run_on_remote
[docs] def type(self, *args, **kwargs):
"""
Type the text at the current focused input field or at a click point
specified by *PSMRL*.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param text: a string to type.
:param modifiers: one or more key modifiers
:rtype: the number 1 if the operation could be
performed, otherwise 0 (integer null), which means,
that because of some reason, it was not possible or the click
could be performed (in case of *PS* may be PatternNotFound).
This method simulates keyboard typing interpreting the characters of
text
based on the layout/keymap of the **standard US keyboard (QWERTY)**.
Special keys (ENTER, TAB, BACKSPACE, ...) can be incorporated into text
by using the constants defined in
`Class Key <http://doc.sikuli.org/keys.html>`_ using the standard
string concatenation (+).
If *PSMRL* is given, a click on the clickpoint is performed before
typing, to gain the focus. (Mac: it might be necessary, to use
:py:func:`switchApp` to give focus to a target application before, to
accept typed/pasted characters.)
If *PSMRL* is omitted, it performs the typing on the current focused
visual component (normally an input field or an menu entry that can be
selected by typing something).
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
**Note**: If you need to type international characters or you are using
layouts/keymaps other than US-QWERTY, you should use
:py:meth:`Region.paste` instead. Since type() is rather slow because it
simulates each key press, for longer text it is preferrable to use
:py:meth:`Region.paste`.
**Best Practice**: As a general guideline, the best choice is to use
``paste()`` for readable text and ``type()`` for action keys like TAB,
ENTER, ESC, ....
Use one ``type()`` for each key or key combination and be aware,
that in some cases a short ``wait()`` after a ``type()`` might be
necessary to give the target application some time to react and be
prepared for the next Sikuli action.
"""
# Why would anyone in their right mind put optional args in front of
# mandatory ones? I hope you know I hate you, whoever you are...
def _raise_error():
raise TypeError("Incorrect call signature for method %r. args=%r, "
"kwargs=%r:\n%s"
% (self.type, args, kwargs, self.type.__doc__))
PSMRL = None
text = None
modifiers = None
if kwargs:
for k in kwargs:
if k not in ('text', 'PSMRL', 'modifiers'):
_raise_error()
if args and kwargs:
if 'PSMRL' in kwargs:
PSMRL = kwargs['PSMRL']
if 'text' in kwargs:
text = kwargs['text']
if 'modifiers' in kwargs:
modifiers = kwargs['modifiers']
num_unset = len([x for x in (PSMRL, text, modifiers) if x is None])
if len(args) > num_unset:
_raise_error()
if text is None:
if PSMRL is not None:
text = args[0]
elif not isinstance(args[0], basestring):
if len(args) == 1:
_raise_error()
elif len(args) == 2:
PSMRL, text = args
elif not isinstance(args[0], basestring):
PSMR = args[0]
if PSMRL is not None:
assert_PSMRL(PSMRL, self.type)
return # I'm screwwed
elif args:
if len(args) == 3:
(PSMRL, text, modifiers) = args
elif len(args) == 1:
text = args[0]
else:
if not isinstance(args[0], basestring):
PSMRL, text = args
else:
return # pray to god as there's nothing I can do here...
else:
text = kwargs['text'] if 'text' in kwargs else None
if 'PSMRL' in kwargs:
PSMRL = kwargs['PSMRL']
if PSMRL is not None:
assert_PSMRL(PSMRL, self.type)
if text is None or not isinstance(text, basestring):
_raise_error()
@run_on_remote
def paste(self, PSMRL, text=None):
"""
Paste the text at a click point.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param text: text to paste
:rtype: the number 1 if the operation could be performed, otherwise 0
(integer null), which means,
that because of some reason, it was not possible or the click
could be performed (in case of *PS* may be PatternNotFound).
Pastes *text* using the clipboard (OS-level shortcut (Ctrl-V or
Cmd-V)). So
afterwards your clipboard contains *text*. ``paste()`` is a temporary
solution for
typing international characters or typing on keyboard layouts other
than
US-QWERTY.
If *PSMRL* is given, a click on the clickpoint is performed before
typing, to
gain the focus. (Mac: it might be necessary,
to use :py:func:`switchApp`
to give focus to a target application before, to accept typed/pasted
characters.)
If *PSMRL* is omitted, it performs the paste on the current focused
component
(normally an input field).
**Side Effect** if *PS* was used, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards.
**Note**: Special keys (ENTER, TAB, BACKSPACE, ...) cannot be used
with ``paste()``.
If needed, you have to split your complete text into two or more
``paste()``
and use ``type()`` for typing the special keys inbetween.
Characters like \\n (enter/new line) and \\t (tab) should work as
expected with ``paste()``,
but be aware of timing problems, when using e.g. intervening \\t to
jump
to the next input field of a form.
"""
pass
@paste.arg
[docs] def paste(self, PSMRL, text=None):
"""
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:param text: text to paste
"""
return dropNones(1, None, PSMRL, text)
@run_on_remote
[docs] def text(self):
"""
Extract the text contained in the region using OCR.
:rtype: the text as a string.
**Note**: Since this feature is still in an **experimental state**,
be aware, that in some cases it might not work as expected. If you face
any problems look at the
`Questions & Answers / FAQ's <https://answers.launchpad .net/sikuli>`_
and the `Bugs <https://answers.launchpad.net/sikuli>`_.
"""
pass
@run_on_remote
[docs] def mouseDown(self, button):
"""
Press the mouse *button* down.
:param button: one or a combination of the button constants
``Button.LEFT``, ``Button.MIDDLE``, ``Button.RIGHT``.
:rtype: the number 1 if the operation is performed successfully, and
zero if otherwise.
The mouse button or buttons specified by *button* are pressed until
another
mouse action is performed.
"""
pass
@run_on_remote
def mouseUp(self, button=None):
"""
Release the mouse button previously pressed.
:param button: one or a combination of the button constants
``Button.LEFT``, ``Button.MIDDLE``, ``Button.RIGHT``.
:rtype: the number 1 if the operation is performed successfully, and
zero if otherwise.
The button specified by *button* is released. If *button* is omitted,
all currently pressed buttons are released.
"""
pass
@run_on_remote
[docs] def mouseUp(self, button=None):
"""
:param button: one or a combination of the button constants
"""
dropNones(0, None, button)
@run_on_remote
[docs] def mouseMove(self, PSMRL):
"""
Move the mouse pointer to a location indicated by PSRML.
:param PSMRL: a pattern, a string, a match, a region or a location that
evaluates to a click point.
:rtype: the number 1 if the operation could be performed. If using *PS*
(which invokes an implicity find operation), find fails and you have
switched off FindFailed exception, a 0 (integer null) is returned.
Otherwise, the script is stopped with a FindFailed exception.
**Sideeffects**: when using *PS*, the match can be accessed using
:py:meth:`Region.getLastMatch` afterwards
"""
assert_PSMRL(PSMRL, self.mouseMove)
@TODO
[docs] def wheel(self):
"""
.. todo:: Implement
"""
pass
@run_on_remote
[docs] def keyDown(self, key):
"""
Press and hold the specified key(s) until released by a later call to
:py:meth:`Region.keyUp`.
:param key: one or more keys (use the consts of class Key). A
list of keys is a concatenation of several key constants using "+".
:rtype: the number 1 if the operation could be performed and 0 if
otherwise.
"""
pass
@run_on_remote
def keyUp(self, key=None):
"""
Release given keys. If no key is given, all currently pressed keys are
released.
:param key: one or more keys (use the consts of class Key). A
list of keys is a concatenation of several key constants using "+".
:rtype: the number 1 if the operation could be performed and 0 if
otherwise.
"""
pass
@keyUp.arg
[docs] def keyUp(self, key=None):
"""
Release given keys. If no key is given, all currently pressed keys are
released.
:param key: one or more keys (use the consts of class Key). A
list of keys is a concatenation of several key constants using "+".
:rtype: the number 1 if the operation could be performed and 0 if
otherwise.
"""
return dropNones(0, None, key)
@DEFERRED
[docs] def setFindFailedResponse(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def getFindFailedResponse(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def setThrowException(self):
"""
.. todo:: Implement
"""
pass
@DEFERRED
[docs] def getThrowException(self):
"""
.. todo:: Implement
"""
pass
@return_from_remote('Region')
[docs] def getRegionFromPSRM(self, PSRM):
"""
Returns a new Region object derived from the given parameter. In case
of PS, internally a find() is done inside this region. If found,
the match is returned. In case RM, just a copy of the given region is
returned.
:param PSRM: a Pattern, String, Region or Match object
:rtype: a new Region object
"""
assert_PSRM(PSRM, self.getRegionFromPSRM)
@return_from_remote('Location')
[docs] def getLocationFromPSRML(self, PSMRL):
"""
Returns a new Location object derived from the given parameter. In
case of PS, internally a find() is done inside this region. If found,
the match's target offset position is returned. In case RM,
just a copy of the given region's respective location (center or
target offset) is returned.
:param PSMRL: a Pattern, String, Region, Match or Location object
:rtype: a new Location object
"""
assert_PSMRL(PSMRL, self.getLocationFromPSRML)
[docs] def get_xy_from_PSRML(self, PSMRL):
from python_sikuli_client.misc import s_repr
r = "self._get_jython_object(%r)" % self._id
l = "%s.getLocationFromPSRML(%s)" % (r, s_repr(PSMRL))
cmd = "(lambda l: [l.getX(), l.getY()])(%s)" % l
return self.remote._eval(cmd)
[docs] def find_one_of(self, images):
"""
:param images: list of strings giving paths to images
:return: found images
"""
from python_sikuli_client.match import Match
match_ids = self.remote._eval_foreach(
"self._new_jython_object(self._get_jython_object(%r).find(arg))"
% self._id,
images)
from robot.api import logger
matches = {}
for (k, v) in sorted(match_ids.items(), key=lambda k: int(k[0])):
img, match_id = v
if match_id is None or not match_id:
logger.debug("Did not find %r" % img)
else:
try:
matches[k] = Match(remote=self.remote, server_id=match_id)
logger.debug("Found %r" % img)
except BaseException:
pass
return matches
@constructor(Region)
def _region_constructor(x, y, w, h):
return "Sikuli.Region(%r, %r, %r, %r)" % (x, y, w, h)
@constructor(Region)
def _region_constructor(region):
return "Sikuli.Region(%s)" % region._str_get
@constructor(Region)
def _region_constructor():
return ('Sikuli.Region('
' *(lambda x: [x.x, x.y, x.width, x.height])('
' Sikuli.SCREEN.getBounds()))')