Showing preview only (295K chars total). Download the full file or copy to clipboard to get everything.
Repository: asweigart/pyautogui
Branch: master
Commit: b4255d0be42c
Files: 31
Total size: 283.1 KB
Directory structure:
gitextract_73sr2if3/
├── .gitignore
├── AUTHORS.txt
├── CHANGES.txt
├── LICENSE.txt
├── MANIFEST.in
├── Pipfile
├── README.md
├── docs/
│ ├── Makefile
│ ├── conf.py
│ ├── index.rst
│ ├── install.rst
│ ├── keyboard.rst
│ ├── make.bat
│ ├── mouse.rst
│ ├── msgbox.rst
│ ├── quickstart.rst
│ ├── roadmap.rst
│ ├── screenshot.rst
│ ├── simplified-chinese.ipynb
│ ├── source/
│ │ ├── modules.rst
│ │ └── pyautogui.rst
│ └── tests.rst
├── pyautogui/
│ ├── __init__.py
│ ├── __main__.py
│ ├── _pyautogui_java.py
│ ├── _pyautogui_osx.py
│ ├── _pyautogui_win.py
│ └── _pyautogui_x11.py
├── setup.py
├── tests/
│ └── test_pyautogui.py
└── tox.ini
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
venv/
.tox/
*.pyc
__pycache__/
instance/
.pytest_cache/
.coverage
htmlcov/
dist/
build/
*.egg-info/
Pipfile.lock
================================================
FILE: AUTHORS.txt
================================================
Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
people who have submitted patches, reported bugs, added translations, helped
answer newbie questions, and generally made PyAutoGUI that much better:
Abhijeet Singh https://github.com/cseas
Al Sweigart https://github.com/asweigart/
Alexandr Orlov https://github.com/hey-sancho
alphaCTzo7G https://github.com/alphaCTzo7G
Andrew Selzer https://github.com/afs2015
Andy Dam https://github.com/andydam
Anwar A. Ruff https://github.com/aaruff
Ari Lacenski https://github.com/tensory
Ashok Fernandez https://github.com/ashokfernandez/
Brian Redmond https://github.com/bredmond
Christopher Valles https://github.com/christophervalles
clach04 https://github.com/clach04
Clayton A. Alves https://github.com/claytonaalves
cryzed https://github.com/cryzed
Daniel D. Beck https://github.com/ddbeck
danielboone https://github.com/danielboone
Davee Nguyen https://github.com/daveenguyen
David Siah https://github.com/dsiah
Denilson Figueiredo de Sá https://github.com/denilsonsa
Dominik Schmelz https://github.com/DIDoS
dragon778 https://github.com/dragon788
Duxxi https://github.com/sjhhh3
Eric https://github.com/bleuetnoir
ErtugrulSener https://github.com/ErtugrulSener
Fornost461 https://github.com/Fornost461
Harrison https://github.com/Sentdex
Hugo Salvador https://github.com/hugoesb
i-need-to-tell-you-something https://github.com/i-need-to-tell-you-something
jakibaki https://github.com/
Jeff Triplett https://github.com/jefftriplett
Jeremy R. Gray https://github.com/jeremygray
Jeromie Kirchoff https://github.com/JayRizzo
Joel Gomes da Silva https://github.com/joelgomes1994
johnborgmann https://github.com/johnborgmann
Jon Winsley https://github.com/glitchassassin
jorg-j https://github.com/jorg-j
Jose Riha https://github.com/jose1711
Julien Schueller https://github.com/jschueller
Korons https://github.com/Korons
lb1a https://github.com/lb1a
Lesmana Zimmer https://github.com/lesmana
liberme https://github.com/liberme
Matt Olsen https://github.com/digwanderlust
mvbentes https://github.com/mvbentes
nexcvon https://github.com/nexcvon
Oleg Höfling https://github.com/hoefling
optroot https://github.com/optroot
pgkos https://github.com/pgkos
qiujieqiong https://github.com/qiujieqiong
Ricardo Amendoeira https://github.com/ric2b
Scott Noyes https://github.com/snoyes
Sergio Encarnación https://github.com/Sergioenc28
sneakypete81 https://github.com/sneakypete81
Stefan Hoelzl https://github.com/stefanhoelzl
Stephen Ellis https://github.com/saellis
Steven Shave https://github.com/stevenshave
Tim Gates https://github.com/timgates42
Timothy Crory https://github.com/tcrory
undefx https://github.com/undefx
Vélmer Oliveira https://github.com/velmer
Valdemar B. Petersen https://github.com/ValdemarBirkegaardPetersen
Yoshiaki Ono https://github.com/fx-kirin
Stefan Hoelzl https://github.com/stefanhoelzl
Zander Møysal https://github.com/Zandertaiko
================================================
FILE: CHANGES.txt
================================================
v0.9.53, 2021/07/07 -- Fixed a compatibility issue with the pystray module.
v0.9.52, 2020/10/06 -- Fixed hotkey() to work with PAUSE.
v0.9.51, 2020/10/04 -- Added the hold() context manager, several bug fixes for mac mouse functions.
v0.9.50, 2020/04/01 -- The 0.9.49 changes were incredibly buggy and have been reverted.
v0.9.49, 2020/03/27 -- Migrated from Quartz to Rubicon
v0.9.46, 2019/07/09 -- Added mouseinfo module.
v0.9.45, 2019/06/18 -- Added left-click, made mouse buttons more explicit and fixed it so that the right mouse button is 2 and middle mouse button is 3. Added failsafe points in all corners. Added screenshot logging. Fixed _autoPause().
v0.9.44, 2019/05/30 -- Adding ability to pass 4-integer box tuples to click() and other functions.
v0.9.43, 2019/05/27 -- Renamed getFocusedWindow to getActiveWindow to keep it up to date with pygetwindow.
v0.9.40, 2018/12/26 -- Created FAILSAFE_POINT constant instead of hard coding (0, 0), add move(), drag(), write() names. Adding PyGetWindow.
v0.9.39, 2018/09/05 -- Added tox and fixed setup.py for Python 2 compatibility.
v0.9.38, 2018/07/21 -- Removing non-ascii characters from readme because it causes failures when displaying on Windows.
v0.9.37, 2018/07/18 -- Updating setup.py
v0.9.36, 2017/04/20 -- Fixed Windows XP problem with the DPI scaling API call.
v0.9.35, 2017/03/19 -- Fixed Windows DPI scaling issue.
v0.9.34, 2017/03/18 -- Fixed several bugs after the Sentry OSS sprint, including Windows permission errors.
v0.9.33, 2016/01/08 -- Fixed bug with missing keyword arg in hotkey(). Thanks jmcduffie!
v0.9.32, 2015/10/28 -- Updated setup.py to pull info from source
v0.9.31, 2015/09/06 -- Incorporated many fixes and changes from Denilson Figueiredo de Sá. Thanks!
v0.9.30, 2015/05/06 -- Fixed issue #12 (size() on Mac Retina displays)
v0.9.29, 2015/05/05 -- Fixed issue #29 (press('enter') doesn't work on Linux)
v0.9.28, 2015/05/05 -- Fixed a small bug wheel scroll on OS X.
v0.9.27, 2015/05/02 -- Fixed a bug with Linux's button parameter.
v0.9.26, 2015/02/02 -- Added 'super' key to Windows and the presses keyword argument to press().
v0.9.25, 2015/01/27 -- Fixed dragTo() bug on OS X
v0.9.24, 2015/01/07 -- Added -x silent option to os x screencapture command.
v0.9.23, 2015/01/06 -- Now allowing lists in addition to tuples for XY coordinate arguments.
v0.9.22, 2015/01/06 -- Added "pause" keyword argument to functions to override PAUSE setting for specific calls.
v0.9.21, 2014/12/15 -- Added keyword arguments to functions, improved unit tests.
v0.9.20, 2014/10/11 -- Fixed parameter order bug on Linux.
v0.9.19, 2014/09/24 -- Set fail-safe and pause features to be enabled by default.
v0.9.18, 2014/09/16 -- Moved screenshot features to a separate "PyScreeze" module.
v0.9.17, 2014/09/15 -- Added pixel() and pixelMatchesColor() functions.
v0.9.16, 2014/09/15 -- Added locateCenterOnScreen() function.
v0.9.15, 2014/09/12 -- Added fail-safe feature.
v0.9.14, 2014/09/11 -- Fixed bug with locateOnScreen().
v0.9.13, 2014/09/11 -- Fixed OS X scrolling bug. Added screenshot features.
v0.9.12, 2014/09/10 -- Fixed import bugs.
v0.9.11, 2014/09/08 -- Fixed bug where None was being passed to platform-specific mouse functions.
v0.9.10, 2014/09/08 -- Fixing the previous bug, for real this time.
v0.9.9, 2014/09/03 -- Bug fix with the mouseUp and mouseDown functions due to rearranging the parameters.
v0.9.8, 2014/09/03 -- Moved tweening functions into pyautogui instead of separate pyautogui.tweens
v0.9.7, 2014/09/03 -- Fixing a bug where single-character strings sent to press() were dropped. Added a unit test for this bug.
v0.9.6, 2014/09/03 -- Added PyMsgBox & PyTweening as dependencies.
v0.9.5, 2014/08/28 -- Made parameter order for mouseDown() and mouseUp() consistent with click().
v0.9.4, 2014/08/28 -- Fixed uppercase bug.
v0.9.3, 2014/08/21 -- Added ability to pass a list to press().
v0.9.2, 2014/08/19 -- Added complete set of tween functions.
v0.9.0, 2014/07/28 -- Initial release.
================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2014, Al Sweigart
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the PyAutoGUI nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: MANIFEST.in
================================================
include *.md
include LICENSE.txt
recursive-include docs *.bat
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs Makefile
recursive-include pyautogui *.py
recursive-include tests *.py
================================================
FILE: Pipfile
================================================
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
pyautogui = {editable = true, path = "."}
[dev-packages]
[requires]
python_version = "3.11"
================================================
FILE: README.md
================================================
PyAutoGUI
=========
PyAutoGUI is a cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard.
`pip install pyautogui`
Full documentation available at https://pyautogui.readthedocs.org
Simplified Chinese documentation available at https://github.com/asweigart/pyautogui/blob/master/docs/simplified-chinese.ipynb
Source code available at https://github.com/asweigart/pyautogui
If you need help installing Python, visit https://installpython3.com/
Dependencies
============
PyAutoGUI supports Python 2 and 3. If you are installing PyAutoGUI from PyPI using pip:
Windows has no dependencies. The Win32 extensions do not need to be installed.
macOS needs the pyobjc-core and pyobjc module installed (in that order).
Linux needs the python3-xlib (or python-xlib for Python 2) module installed.
Pillow needs to be installed, and on Linux you may need to install additional libraries to make sure Pillow's PNG/JPEG works correctly. See:
https://stackoverflow.com/questions/7648200/pip-install-pil-e-tickets-1-no-jpeg-png-support
http://ubuntuforums.org/showthread.php?t=1751455
If you want to do development and contribute to PyAutoGUI, you will need to install these modules from PyPI:
* pyscreeze
* pymsgbox
* pytweening
Example Usage
=============
Keyboard and Mouse Control
--------------------------
The x, y coordinates used by PyAutoGUI has the 0, 0 origin coordinates in the top left corner of the screen. The x coordinates increase going to the right (just as in mathematics) but the y coordinates increase going down (the opposite of mathematics). On a screen that is 1920 x 1080 pixels in size, coordinates 0, 0 are for the top left while 1919, 1079 is for the bottom right.
Currently, PyAutoGUI only works on the primary monitor. PyAutoGUI isn't reliable for the screen of a second monitor (the mouse functions may or may not work on multi-monitor setups depending on your operating system and version).
All keyboard presses done by PyAutoGUI are sent to the window that currently has focus, as if you had pressed the physical keyboard key.
```python
>>> import pyautogui
>>> screenWidth, screenHeight = pyautogui.size() # Returns two integers, the width and height of the screen. (The primary monitor, in multi-monitor setups.)
>>> currentMouseX, currentMouseY = pyautogui.position() # Returns two integers, the x and y of the mouse cursor's current position.
>>> pyautogui.moveTo(100, 150) # Move the mouse to the x, y coordinates 100, 150.
>>> pyautogui.click() # Click the mouse at its current location.
>>> pyautogui.click(200, 220) # Click the mouse at the x, y coordinates 200, 220.
>>> pyautogui.move(None, 10) # Move mouse 10 pixels down, that is, move the mouse relative to its current position.
>>> pyautogui.doubleClick() # Double click the mouse at the
>>> pyautogui.moveTo(500, 500, duration=2, tween=pyautogui.easeInOutQuad) # Use tweening/easing function to move mouse over 2 seconds.
>>> pyautogui.write('Hello world!', interval=0.25) # Type with quarter-second pause in between each key.
>>> pyautogui.press('esc') # Simulate pressing the Escape key.
>>> pyautogui.keyDown('shift')
>>> pyautogui.write(['left', 'left', 'left', 'left', 'left', 'left'])
>>> pyautogui.keyUp('shift')
>>> pyautogui.hotkey('ctrl', 'c')
```
Display Message Boxes
---------------------
```python
>>> import pyautogui
>>> pyautogui.alert('This is an alert box.')
'OK'
>>> pyautogui.confirm('Shall I proceed?')
'Cancel'
>>> pyautogui.confirm('Enter option.', buttons=['A', 'B', 'C'])
'B'
>>> pyautogui.prompt('What is your name?')
'Al'
>>> pyautogui.password('Enter password (text will be hidden)')
'swordfish'
```
Screenshot Functions
--------------------
(PyAutoGUI uses Pillow for image-related features.)
```python
>>> import pyautogui
>>> im1 = pyautogui.screenshot()
>>> im1.save('my_screenshot.png')
>>> im2 = pyautogui.screenshot('my_screenshot2.png')
```
You can also locate where an image is on the screen:
```python
>>> import pyautogui
>>> button7location = pyautogui.locateOnScreen('button.png') # returns (left, top, width, height) of matching region
>>> button7location
(1416, 562, 50, 41)
>>> buttonx, buttony = pyautogui.center(button7location)
>>> buttonx, buttony
(1441, 582)
>>> pyautogui.click(buttonx, buttony) # clicks the center of where the button was found
```
The locateCenterOnScreen() function returns the center of this match region:
```python
>>> import pyautogui
>>> buttonx, buttony = pyautogui.locateCenterOnScreen('button.png') # returns (x, y) of matching region
>>> buttonx, buttony
(1441, 582)
>>> pyautogui.click(buttonx, buttony) # clicks the center of where the button was found
```
How Does PyAutoGUI Work?
========================
The three major operating systems (Windows, macOS, and Linux) each have different ways to programmatically control the mouse and keyboard. This can often involve confusing, obscure, and deeply technical details. The job of PyAutoGUI is to hide all of this complexity behind a simple API.
* On Windows, PyAutoGUI accesses the Windows API (also called the WinAPI or win32 API) through the built-in `ctypes` module. The `nicewin` module at https://github.com/asweigart/nicewin provides a demonstration for how Windows API calls can be made through Python.
* On macOS, PyAutoGUI uses the `rubicon-objc` module to access the Cocoa API.
* On Linux, PyAutoGUI uses the `Xlib` module to access the X11 or X Window System.
Support
-------
If you find this project helpful and would like to support its development, [consider donating to its creator on Patreon](https://www.patreon.com/AlSweigart).
================================================
FILE: docs/Makefile
================================================
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyAutoGUI.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyAutoGUI.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/PyAutoGUI"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyAutoGUI"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
================================================
FILE: docs/conf.py
================================================
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../'))
#sys.path.insert(0, os.path.abspath('../pyautogui'))
# -- Project information -----------------------------------------------------
project = 'PyAutoGUI'
copyright = '2019, Al Sweigart'
author = 'Al Sweigart'
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = ''
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path .
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'PyAutoGUIdoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PyAutoGUI.tex', 'PyAutoGUI Documentation',
'Al Sweigart', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pyautogui', 'PyAutoGUI Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'PyAutoGUI', 'PyAutoGUI Documentation',
author, 'PyAutoGUI', 'One line description of project.',
'Miscellaneous'),
]
================================================
FILE: docs/index.rst
================================================
.. PyAutoGUI documentation master file, created by
sphinx-quickstart on Sun Jul 20 12:59:43 2014.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to PyAutoGUI's documentation!
=====================================
PyAutoGUI lets your Python scripts control the mouse and keyboard to automate interactions with other applications. The API is designed to be simple. PyAutoGUI works on Windows, macOS, and Linux, and runs on Python 2 and 3.
To install with pip, run ``pip install pyautogui``. See the :doc:`install` page for more details.
The source code is available on: https://github.com/asweigart/pyautogui
PyAutoGUI has several features:
* Moving the mouse and clicking in the windows of other applications.
* Sending keystrokes to applications (for example, to fill out forms).
* Take screenshots, and given an image (for example, of a button or checkbox), and find it on the screen.
* Locate an application's window, and move, resize, maximize, minimize, or close it (Windows-only, currently).
* Display alert and message boxes.
Here's `a YouTube video of a bot automatically playing the game Sushi Go Round <https://www.youtube.com/watch?v=lfk_T6VKhTE>`_. The bot watches the game's application window and searches for images of sushi orders. When it finds one, it clicks the ingredient buttons to make the sushi. It also clicks the phone in the game to order more ingredients as needed. The bot is completely autonomous and can finish all seven days of the game. This is the kind of automation that PyAutoGUI is capable of.
Examples
========
.. code:: python
>>> import pyautogui
>>> screenWidth, screenHeight = pyautogui.size() # Get the size of the primary monitor.
>>> screenWidth, screenHeight
(2560, 1440)
>>> currentMouseX, currentMouseY = pyautogui.position() # Get the XY position of the mouse.
>>> currentMouseX, currentMouseY
(1314, 345)
>>> pyautogui.moveTo(100, 150) # Move the mouse to XY coordinates.
>>> pyautogui.click() # Click the mouse.
>>> pyautogui.click(100, 200) # Move the mouse to XY coordinates and click it.
>>> pyautogui.click('button.png') # Find where button.png appears on the screen and click it.
>>> pyautogui.move(400, 0) # Move the mouse 400 pixels to the right of its current position.
>>> pyautogui.doubleClick() # Double click the mouse.
>>> pyautogui.moveTo(500, 500, duration=2, tween=pyautogui.easeInOutQuad) # Use tweening/easing function to move mouse over 2 seconds.
>>> pyautogui.write('Hello world!', interval=0.25) # type with quarter-second pause in between each key
>>> pyautogui.press('esc') # Press the Esc key. All key names are in pyautogui.KEY_NAMES
>>> with pyautogui.hold('shift'): # Press the Shift key down and hold it.
pyautogui.press(['left', 'left', 'left', 'left']) # Press the left arrow key 4 times.
>>> # Shift key is released automatically.
>>> pyautogui.hotkey('ctrl', 'c') # Press the Ctrl-C hotkey combination.
>>> pyautogui.alert('This is the message to display.') # Make an alert box appear and pause the program until OK is clicked.
This example drags the mouse in a square spiral shape in MS Paint (or any graphics drawing program):
.. code:: python
>>> distance = 200
>>> while distance > 0:
pyautogui.drag(distance, 0, duration=0.5) # move right
distance -= 5
pyautogui.drag(0, distance, duration=0.5) # move down
pyautogui.drag(-distance, 0, duration=0.5) # move left
distance -= 5
pyautogui.drag(0, -distance, duration=0.5) # move up
.. image:: square_spiral.png
The benefit of using PyAutoGUI, as opposed to a script that directly generates the image file, is that you can use the brush tools that MS Paint provides.
FAQ: Frequently Asked Questions
===============================
Send questions to al@inventwithpython.com
**Q: Can PyAutoGUI work on Android, iOS, or tablet/smartphone apps.**
A: Unfortunately no. PyAutoGUI only runs on Windows, macOS, and Linux.
**Q: Does PyAutoGUI work on multi-monitor setups.**
A: No, right now PyAutoGUI only handles the primary monitor.
**Q: Does PyAutoGUI do OCR?**
A: No, but this is a feature that's on the roadmap.
**Q: Can PyAutoGUI do keylogging, or detect if a key is currently pressed down?**
A: No, PyAutoGUI cannot do this currently.
Fail-Safes
==========
.. image:: sorcerers_apprentice_brooms.png
Like the enchanted brooms from the Sorcerer’s Apprentice programmed to keep filling (and then overfilling) the bath with water, a bug in your program could make it go out of control. It's hard to use the mouse to close a program if the mouse cursor is moving around on its own.
As a safety feature, a fail-safe feature is enabled by default. When a PyAutoGUI function is called, if the mouse is in any of the four corners of the primary monitor, they will raise a ``pyautogui.FailSafeException``. There is a one-tenth second delay after calling every PyAutoGUI functions to give the user time to slam the mouse into a corner to trigger the fail safe.
You can disable this failsafe by setting ``pyautogui.FAILSAFE = False``. **I HIGHLY RECOMMEND YOU DO NOT DISABLE THE FAILSAFE.**
The tenth-second delay is set by the ``pyautogui.PAUSE`` setting, which is ``0.1`` by default. You can change this value. There is also a ``pyautogui.DARWIN_CATCH_UP_TIME`` setting which adds an additional delay on macOS after keyboard and mouse events, since the operating system appears to need a delay after PyAutoGUI issues these events. It is set to ``0.01`` by default, adding an additional hundredth-second delay.
Contents:
.. toctree::
:maxdepth: 2
install.rst
quickstart.rst
mouse.rst
keyboard.rst
msgbox.rst
screenshot.rst
tests.rst
roadmap.rst
source/modules.rst
This documentation is still a work in progress.
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
================================================
FILE: docs/install.rst
================================================
.. default-role:: code
============
Installation
============
To install PyAutoGUI, install the `pyautogui` package from PyPI by running `pip install pyautogui` (on Windows) or `pip3 install pyautogui` (on macOS and Linux). (On macOS and Linux, `pip` refers to Python 2's pip tool.)
OS-specific instructions are below.
Windows
-------
On Windows, you can use the ``py.exe`` program to run the latest version of Python:
``py -m pip install pyautogui``
If you have multiple versions of Python installed, you can select which one with a command line argument to ``py``. For example, for Python 3.8, run:
``py -3.8 -m pip install pyautogui``
(This is the same as running ``pip install pyautogui``.)
macOS
-----
On macOS and Linux, you need to run ``python3``:
``python3 -m pip install pyautogui``
If you are running El Capitan and have problems installing pyobjc try:
``MACOSX_DEPLOYMENT_TARGET=10.11 pip install pyobjc``
Linux
-----
On macOS and Linux, you need to run ``python3``:
``python3 -m pip install pyautogui``
On Linux, additionally you need to install the ``scrot`` application, as well as Tkinter:
``sudo apt-get install scrot``
``sudo apt-get install python3-tk``
``sudo apt-get install python3-dev``
PyAutoGUI install the modules it depends on, including PyTweening, PyScreeze, PyGetWindow, PymsgBox, and MouseInfo.
================================================
FILE: docs/keyboard.rst
================================================
.. default-role:: code
==========================
Keyboard Control Functions
==========================
The write() Function
========================
The primary keyboard function is ``write()``. This function will type the characters in the string that is passed. To add a delay interval in between pressing each character key, pass an int or float for the ``interval`` keyword argument.
For example:
.. code:: python
>>> pyautogui.write('Hello world!') # prints out "Hello world!" instantly
>>> pyautogui.write('Hello world!', interval=0.25) # prints out "Hello world!" with a quarter second delay after each character
You can only press single-character keys with ``write()``, so you can't press the Shift or F1 keys, for example.
The press(), keyDown(), and keyUp() Functions
=============================================
To press these keys, call the ``press()`` function and pass it a string from the ``pyautogui.KEYBOARD_KEYS`` such as ``enter``, ``esc``, ``f1``. See `KEYBOARD_KEYS`_.
For example:
.. code:: python
>>> pyautogui.press('enter') # press the Enter key
>>> pyautogui.press('f1') # press the F1 key
>>> pyautogui.press('left') # press the left arrow key
The ``press()`` function is really just a wrapper for the ``keyDown()`` and ``keyUp()`` functions, which simulate pressing a key down and then releasing it up. These functions can be called by themselves. For example, to press the left arrow key three times while holding down the Shift key, call the following:
.. code:: python
>>> pyautogui.keyDown('shift') # hold down the shift key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.keyUp('shift') # release the shift key
To press multiple keys similar to what ``write()`` does, pass a list of strings to ``press()``. For example:
.. code:: python
>>> pyautogui.press(['left', 'left', 'left'])
Or you can set how many presses `left`:
.. code:: python
>>> pyautogui.press('left', presses=3)
To add a delay interval in between each press, pass an int or float for the ``interval`` keyword argument.
The hold() Context Manager
==========================
To make holding a key convenient, the ``hold()`` function can be used as a context manager and passed a string from the ``pyautogui.KEYBOARD_KEYS`` such as ``shift``, ``ctrl``, ``alt``, and this key will be held for the duration of the ``with`` context block. See `KEYBOARD_KEYS`_.
.. code:: python
>>> with pyautogui.hold('shift'):
pyautogui.press(['left', 'left', 'left'])
. . .is equivalent to this code:
.. code:: python
>>> pyautogui.keyDown('shift') # hold down the shift key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.press('left') # press the left arrow key
>>> pyautogui.keyUp('shift') # release the shift key
The hotkey() Function
=====================
To make pressing hotkeys or keyboard shortcuts convenient, the ``hotkey()`` can be passed several key strings which will be pressed down in order, and then released in reverse order. This code:
.. code:: python
>>> pyautogui.hotkey('ctrl', 'shift', 'esc')
. . .is equivalent to this code:
.. code:: python
>>> pyautogui.keyDown('ctrl')
>>> pyautogui.keyDown('shift')
>>> pyautogui.keyDown('esc')
>>> pyautogui.keyUp('esc')
>>> pyautogui.keyUp('shift')
>>> pyautogui.keyUp('ctrl')
To add a delay interval in between each press, pass an int or float for the ``interval`` keyword argument.
KEYBOARD_KEYS
=============
The following are the valid strings to pass to the ``press()``, ``keyDown()``, ``keyUp()``, and ``hotkey()`` functions:
.. code:: python
['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(',
')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`',
'a', 'b', 'c', 'd', 'e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace',
'browserback', 'browserfavorites', 'browserforward', 'browserhome',
'browserrefresh', 'browsersearch', 'browserstop', 'capslock', 'clear',
'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal', 'del', 'delete',
'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10',
'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20',
'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9',
'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja',
'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail',
'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack',
'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6',
'num7', 'num8', 'num9', 'numlock', 'pagedown', 'pageup', 'pause', 'pgdn',
'pgup', 'playpause', 'prevtrack', 'print', 'printscreen', 'prntscrn',
'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select', 'separator',
'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab',
'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen',
'command', 'option', 'optionleft', 'optionright']
================================================
FILE: docs/make.bat
================================================
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PyAutoGUI.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PyAutoGUI.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end
================================================
FILE: docs/mouse.rst
================================================
.. default-role:: code
=======================
Mouse Control Functions
=======================
The Screen and Mouse Position
=============================
Locations on your screen are referred to by X and Y Cartesian coordinates. The X coordinate starts at 0 on the left side and increases going right. Unlike in mathematics, the Y coordinate starts at 0 on the top and increases going down.
.. code::
0,0 X increases -->
+---------------------------+
| | Y increases
| | |
| 1920 x 1080 screen | |
| | V
| |
| |
+---------------------------+ 1919, 1079
The pixel at the top-left corner is at coordinates 0, 0. If your screen's resolution is 1920 x 1080, the pixel in the lower right corner will be 1919, 1079 (since the coordinates begin at 0, not 1).
The screen resolution size is returned by the ``size()`` function as a tuple of two integers. The current X and Y coordinates of the mouse cursor are returned by the ``position()`` function.
For example:
.. code:: python
>>> pyautogui.size()
(1920, 1080)
>>> pyautogui.position()
(187, 567)
Here is a short Python 3 program that will constantly print out the position of the mouse cursor:
.. code:: python
#! python3
import pyautogui, sys
print('Press Ctrl-C to quit.')
try:
while True:
x, y = pyautogui.position()
positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4)
print(positionStr, end='')
print('\b' * len(positionStr), end='', flush=True)
except KeyboardInterrupt:
print('\n')
Here is the Python 2 version:
.. code:: python
#! python
import pyautogui, sys
print('Press Ctrl-C to quit.')
try:
while True:
x, y = pyautogui.position()
positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4)
print positionStr,
print '\b' * (len(positionStr) + 2),
sys.stdout.flush()
except KeyboardInterrupt:
print '\n'
To check if XY coordinates are on the screen, pass them (either as two integer arguments or a single tuple/list arguments with two integers) to the ``onScreen()`` function, which will return ``True`` if they are within the screen's boundaries and ``False`` if not. For example:
.. code:: python
>>> pyautogui.onScreen(0, 0)
True
>>> pyautogui.onScreen(0, -1)
False
>>> pyautogui.onScreen(0, 99999999)
False
>>> pyautogui.size()
(1920, 1080)
>>> pyautogui.onScreen(1920, 1080)
False
>>> pyautogui.onScreen(1919, 1079)
True
Mouse Movement
==============
The ``moveTo()`` function will move the mouse cursor to the X and Y integer coordinates you pass it. The ``None`` value can be passed for a coordinate to mean "the current mouse cursor position". For example:
.. code:: python
>>> pyautogui.moveTo(100, 200) # moves mouse to X of 100, Y of 200.
>>> pyautogui.moveTo(None, 500) # moves mouse to X of 100, Y of 500.
>>> pyautogui.moveTo(600, None) # moves mouse to X of 600, Y of 500.
Normally the mouse cursor will instantly move to the new coordinates. If you want the mouse to gradually move to the new location, pass a third argument for the duration (in seconds) the movement should take. For example:
.. code:: python
>>> pyautogui.moveTo(100, 200, 2) # moves mouse to X of 100, Y of 200 over 2 seconds
(If the duration is less than ``pyautogui.MINIMUM_DURATION`` the movement will be instant. By default, ``pyautogui.MINIMUM_DURATION`` is 0.1.)
If you want to move the mouse cursor over a few pixels *relative* to its current position, use the ``move()`` function. This function has similar parameters as ``moveTo()``. For example:
.. code:: python
>>> pyautogui.moveTo(100, 200) # moves mouse to X of 100, Y of 200.
>>> pyautogui.move(0, 50) # move the mouse down 50 pixels.
>>> pyautogui.move(-30, 0) # move the mouse left 30 pixels.
>>> pyautogui.move(-30, None) # move the mouse left 30 pixels.
Mouse Drags
===========
PyAutoGUI's ``dragTo()`` and ``drag()`` functions have similar parameters as the ``moveTo()`` and ``move()`` functions. In addition, they have a ``button`` keyword which can be set to ``'left'``, ``'middle'``, and ``'right'`` for which mouse button to hold down while dragging. For example:
.. code:: python
>>> pyautogui.dragTo(100, 200, button='left') # drag mouse to X of 100, Y of 200 while holding down left mouse button
>>> pyautogui.dragTo(300, 400, 2, button='left') # drag mouse to X of 300, Y of 400 over 2 seconds while holding down left mouse button
>>> pyautogui.drag(30, 0, 2, button='right') # drag the mouse right 30 pixels over 2 seconds while holding down the right mouse button
Tween / Easing Functions
========================
Tweening is an extra feature to make the mouse movements fancy. You can probably skip this section if you don't care about this.
A tween or easing function dictates the progress of the mouse as it moves to its destination. Normally when moving the mouse over a duration of time, the mouse moves directly towards the destination in a straight line at a constant speed. This is known as a *linear tween* or *linear easing* function.
PyAutoGUI has other tweening functions available in the ``pyautogui`` module. The ``pyautogui.easeInQuad`` function can be passed for the 4th argument to ``moveTo()``, ``move()``, ``dragTo()``, and ``drag()`` functions to have the mouse cursor start off moving slowly and then speeding up towards the destination. The total duration is still the same as the argument passed to the function. The ``pyautogui.easeOutQuad`` is the reverse: the mouse cursor starts moving fast but slows down as it approaches the destination. The ``pyautogui.easeOutElastic`` will overshoot the destination and "rubber band" back and forth until it settles at the destination.
For example:
.. code:: python
>>> pyautogui.moveTo(100, 100, 2, pyautogui.easeInQuad) # start slow, end fast
>>> pyautogui.moveTo(100, 100, 2, pyautogui.easeOutQuad) # start fast, end slow
>>> pyautogui.moveTo(100, 100, 2, pyautogui.easeInOutQuad) # start and end fast, slow in middle
>>> pyautogui.moveTo(100, 100, 2, pyautogui.easeInBounce) # bounce at the end
>>> pyautogui.moveTo(100, 100, 2, pyautogui.easeInElastic) # rubber band at the end
These tweening functions are copied from Al Sweigart's PyTweening module: https://pypi.python.org/pypi/PyTweening https://github.com/asweigart/pytweening This module does not have to be installed to use the tweening functions.
If you want to create your own tweening function, define a function that takes a single float argument between ``0.0`` (representing the start of the mouse travelling) and ``1.0`` (representing the end of the mouse travelling) and returns a float value between ``0.0`` and ``1.0``.
Mouse Clicks
============
The ``click()`` function simulates a single, left-button mouse click at the mouse's current position. A "click" is defined as pushing the button down and then releasing it up. For example:
.. code:: python
>>> pyautogui.click() # click the mouse
To combine a ``moveTo()`` call before the click, pass integers for the ``x`` and ``y`` keyword argument:
.. code:: python
>>> pyautogui.click(x=100, y=200) # move to 100, 200, then click the left mouse button.
To specify a different mouse button to click, pass ``'left'``, ``'middle'``, or ``'right'`` for the ``button`` keyword argument:
.. code:: python
>>> pyautogui.click(button='right') # right-click the mouse
To do multiple clicks, pass an integer to the ``clicks`` keyword argument. Optionally, you can pass a float or integer to the ``interval`` keyword argument to specify the amount of pause between the clicks in seconds. For example:
.. code:: python
>>> pyautogui.click(clicks=2) # double-click the left mouse button
>>> pyautogui.click(clicks=2, interval=0.25) # double-click the left mouse button, but with a quarter second pause in between clicks
>>> pyautogui.click(button='right', clicks=3, interval=0.25) ## triple-click the right mouse button with a quarter second pause in between clicks
As a convenient shortcut, the ``doubleClick()`` function will perform a double click of the left mouse button. It also has the optional ``x``, ``y``, ``interval``, and ``button`` keyword arguments. For example:
.. code:: python
>>> pyautogui.doubleClick() # perform a left-button double click
There is also a ``tripleClick()`` function with similar optional keyword arguments.
The ``rightClick()`` function has optional ``x`` and ``y`` keyword arguments.
The mouseDown() and mouseUp() Functions
=======================================
Mouse clicks and drags are composed of both pressing the mouse button down and releasing it back up. If you want to perform these actions separately, call the ``mouseDown()`` and ``mouseUp()`` functions. They have the same ``x``, ``y``, and ``button``. For example:
.. code:: python
>>> pyautogui.mouseDown(); pyautogui.mouseUp() # does the same thing as a left-button mouse click
>>> pyautogui.mouseDown(button='right') # press the right button down
>>> pyautogui.mouseUp(button='right', x=100, y=200) # move the mouse to 100, 200, then release the right button up.
Mouse Scrolling
===============
The mouse scroll wheel can be simulated by calling the ``scroll()`` function and passing an integer number of "clicks" to scroll. The amount of scrolling in a "click" varies between platforms. Optionally, integers can be passed for the the ``x`` and ``y`` keyword arguments to move the mouse cursor before performing the scroll. For example:
.. code:: python
>>> pyautogui.scroll(10) # scroll up 10 "clicks"
>>> pyautogui.scroll(-10) # scroll down 10 "clicks"
>>> pyautogui.scroll(10, x=100, y=100) # move mouse cursor to 100, 200, then scroll up 10 "clicks"
On OS X and Linux platforms, PyAutoGUI can also perform horizontal scrolling by calling the hscroll() function. For example:
.. code:: python
>>> pyautogui.hscroll(10) # scroll right 10 "clicks"
>>> pyautogui.hscroll(-10) # scroll left 10 "clicks"
The ``scroll()`` function is a wrapper for ``vscroll()``, which performs vertical scrolling.
================================================
FILE: docs/msgbox.rst
================================================
.. default-role:: code
=====================
Message Box Functions
=====================
PyAutoGUI makes use of the message box functions in PyMsgBox to provide a cross-platform, pure Python way to display JavaScript-style message boxes. There are four message box functions provided:
The alert() Function
====================
>>> alert(text='', title='', button='OK')
Displays a simple message box with text and a single OK button. Returns the text of the button clicked on.
The confirm() Function
======================
>>> confirm(text='', title='', buttons=['OK', 'Cancel'])
Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on.
The prompt() Function
=====================
>>> prompt(text='', title='' , default='')
Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked.
The password() Function
=======================
>>> password(text='', title='', default='', mask='*')
Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as ``*``. Returns the text entered, or None if Cancel was clicked.
================================================
FILE: docs/quickstart.rst
================================================
.. default-role:: code
===========
Cheat Sheet
===========
This is a quickstart reference to using PyAutoGUI. PyAutoGUI is cross-platform GUI automation module that works on Python 2 & 3. You can control the mouse and keyboard as well as perform basic image recognition to automate tasks on your computer.
**All the keyword arguments in the examples on this page are optional.**
>>> import pyautogui
PyAutoGUI works on Windows/Mac/Linux and on Python 2 & 3. Install from PyPI with `pip install pyautogui`.
General Functions
-----------------
>>> pyautogui.position() # current mouse x and y
(968, 56)
>>> pyautogui.size() # current screen resolution width and height
(1920, 1080)
>>> pyautogui.onScreen(x, y) # True if x & y are within the screen.
True
Fail-Safes
----------
Set up a 2.5 second pause after each PyAutoGUI call:
>>> import pyautogui
>>> pyautogui.PAUSE = 2.5
When fail-safe mode is `True`, moving the mouse to the upper-left will raise a `pyautogui.FailSafeException` that can abort your program:
>>> import pyautogui
>>> pyautogui.FAILSAFE = True
Mouse Functions
---------------
XY coordinates have 0, 0 origin at top left corner of the screen. X increases going right, Y increases going down.
>>> pyautogui.moveTo(x, y, duration=num_seconds) # move mouse to XY coordinates over num_second seconds
>>> pyautogui.moveRel(xOffset, yOffset, duration=num_seconds) # move mouse relative to its current position
If `duration` is 0 or unspecified, movement is immediate. Note: dragging on Mac can't be immediate.
>>> pyautogui.dragTo(x, y, duration=num_seconds) # drag mouse to XY
>>> pyautogui.dragRel(xOffset, yOffset, duration=num_seconds) # drag mouse relative to its current position
Calling `click()` just clicks the mouse once with the left button at the mouse's current location, but the keyword arguments can change that:
>>> pyautogui.click(x=moveToX, y=moveToY, clicks=num_of_clicks, interval=secs_between_clicks, button='left')
The `button` keyword argument can be `'left'`, `'middle'`, or `'right'`.
All clicks can be done with `click()`, but these functions exist for readability. Keyword args are optional:
>>> pyautogui.rightClick(x=moveToX, y=moveToY)
>>> pyautogui.middleClick(x=moveToX, y=moveToY)
>>> pyautogui.doubleClick(x=moveToX, y=moveToY)
>>> pyautogui.tripleClick(x=moveToX, y=moveToY)
Positive scrolling will scroll up, negative scrolling will scroll down:
>>> pyautogui.scroll(amount_to_scroll, x=moveToX, y=moveToY)
Individual button down and up events can be called separately:
>>> pyautogui.mouseDown(x=moveToX, y=moveToY, button='left')
>>> pyautogui.mouseUp(x=moveToX, y=moveToY, button='left')
Keyboard Functions
------------------
Key presses go to wherever the keyboard cursor is at function-calling time.
>>> pyautogui.typewrite('Hello world!\n', interval=secs_between_keys) # useful for entering text, newline is Enter
A list of key names can be passed too:
>>> pyautogui.typewrite(['a', 'b', 'c', 'left', 'backspace', 'enter', 'f1'], interval=secs_between_keys)
The full list of key names is in `pyautogui.KEYBOARD_KEYS`.
Keyboard hotkeys like Ctrl-S or Ctrl-Shift-1 can be done by passing a list of key names to `hotkey()`:
>>> pyautogui.hotkey('ctrl', 'c') # ctrl-c to copy
>>> pyautogui.hotkey('ctrl', 'v') # ctrl-v to paste
Individual button down and up events can be called separately:
>>> pyautogui.keyDown(key_name)
>>> pyautogui.keyUp(key_name)
Message Box Functions
---------------------
If you need to pause the program until the user clicks OK on something, or want to display some information to the user, the message box functions have similar names that JavaScript has:
>>> pyautogui.alert('This displays some text with an OK button.')
>>> pyautogui.confirm('This displays text and has an OK and Cancel button.')
'OK'
>>> pyautogui.prompt('This lets the user type in a string and press OK.')
'This is what I typed in.'
The `prompt()` function will return `None` if the user clicked Cancel.
Screenshot Functions
--------------------
PyAutoGUI uses Pillow/PIL for its image-related data.
On Linux, you must run `sudo apt-get install scrot` to use the screenshot features.
>>> pyautogui.screenshot() # returns a Pillow/PIL Image object
<PIL.Image.Image image mode=RGB size=1920x1080 at 0x24C3EF0>
>>> pyautogui.screenshot('foo.png') # returns a Pillow/PIL Image object, and saves it to a file
<PIL.Image.Image image mode=RGB size=1920x1080 at 0x31AA198>
If you have an image file of something you want to click on, you can find it on the screen with `locateOnScreen()`.
>>> pyautogui.locateOnScreen('looksLikeThis.png') # returns (left, top, width, height) of first place it is found
(863, 417, 70, 13)
The `locateAllOnScreen()` function will return a generator for all the locations it is found on the screen:
>>> for i in pyautogui.locateAllOnScreen('looksLikeThis.png')
...
...
(863, 117, 70, 13)
(623, 137, 70, 13)
(853, 577, 70, 13)
(883, 617, 70, 13)
(973, 657, 70, 13)
(933, 877, 70, 13)
>>> list(pyautogui.locateAllOnScreen('looksLikeThis.png'))
[(863, 117, 70, 13), (623, 137, 70, 13), (853, 577, 70, 13), (883, 617, 70, 13), (973, 657, 70, 13), (933, 877, 70, 13)]
The `locateCenterOnScreen()` function just returns the XY coordinates of the middle of where the image is found on the screen:
>>> pyautogui.locateCenterOnScreen('looksLikeThis.png') # returns center x and y
(898, 423)
These functions return `None` if the image couldn't be found on the screen.
Note: The locate functions are slow and can take a full second or two.
================================================
FILE: docs/roadmap.rst
================================================
=======
Roadmap
=======
PyAutoGUI is planned as a replacement for other Python GUI automation scripts, such as PyUserInput, PyKeyboard, PyMouse, pykey, etc. Eventually it would be great to offer the same type of features that Sikuli_ offers.
For now, the primary aim for PyAutoGUI is cross-platform mouse and keyboard control and a simple API.
Future features planned (specific versions not planned yet):
- A tool for determining why an image can't be found in a particular screenshot. (This is a common source of questions for users.)
- Full compatibility on Raspberry Pis.
- "Wave" function, which is used just to see where the mouse is by shaking the mouse cursor a bit. A small helper function.
- locateNear() function, which is like the other locate-related screen reading functions except it finds the first instance near an xy point on the screen.
- Find a list of all windows and their captions.
- Click coordinates relative to a window, instead of the entire screen.
- Make it easier to work on systems with multiple monitors.
- GetKeyState() type of function
- Ability to set global hotkey on all platforms so that there can be an easy "kill switch" for GUI automation programs.
- Optional nonblocking pyautogui calls.
- "strict" mode for keyboard - passing an invalid keyboard key causes an exception instead of silently skipping it.
- rename keyboardMapping to KEYBOARD_MAPPING
- Ability to convert png and other image files into a string that can be copy/pasted directly in the source code, so that they don't have to be shared separately with people's pyautogui scripts.
- Test to make sure pyautogui works in Windows/mac/linux VMs.
- A way to compare two images and highlight differences between them (good for pointing out when a UI changes, etc.)
Window handling features:
- pyautogui.getWindows() # returns a dict of window titles mapped to window IDs
- pyautogui.getWindow(str_title_or_int_id) # returns a "Win" object
- win.move(x, y)
- win.resize(width, height)
- win.maximize()
- win.minimize()
- win.restore()
- win.close()
- win.position() # returns (x, y) of top-left corner
- win.moveRel(x=0, y=0) # moves relative to the x, y of top-left corner of the window
- win.clickRel(x=0, y=0, clicks=1, interval=0.0, button='left') # click relative to the x, y of top-left corner of the window
- Additions to screenshot functionality so that it can capture specific windows instead of full screen.
.. _Sikuli: http://www.sikuli.org
================================================
FILE: docs/screenshot.rst
================================================
.. default-role:: code
====================
Screenshot Functions
====================
PyAutoGUI can take screenshots, save them to files, and locate images within the screen. This is useful if you have a small image of, say, a button that needs to be clicked and want to locate it on the screen. These features are provided by the PyScreeze module, which is installed with PyAutoGUI.
Screenshot functionality requires the Pillow module. OS X uses the `screencapture` command, which comes with the operating system. Linux uses the `scrot` command, which can be installed by running `sudo apt-get install scrot`.
The screenshot() Function
=========================
Calling `screenshot()` will return an Image object (see the Pillow or PIL module documentation for details). Passing a string of a filename will save the screenshot to a file as well as return it as an Image object.
.. code:: python
>>> import pyautogui
>>> im1 = pyautogui.screenshot()
>>> im2 = pyautogui.screenshot('my_screenshot.png')
On a 1920 x 1080 screen, the `screenshot()` function takes roughly 100 milliseconds - it's not fast but it's not slow.
There is also an optional `region` keyword argument, if you do not want a screenshot of the entire screen. You can pass a four-integer tuple of the left, top, width, and height of the region to capture:
>>> import pyautogui
>>> im = pyautogui.screenshot(region=(0,0, 300, 400))
The Locate Functions
====================
NOTE: As of version 0.9.41, if the locate functions can't find the provided image, they'll raise `ImageNotFoundException` instead of returning `None`.
You can visually locate something on the screen if you have an image file of it. For example, say the calculator app was running on your computer and looked like this:
.. image:: calculator.png
You can't call the `moveTo()` and `click()` functions if you don't know the exact screen coordinates of where the calculator buttons are. The calculator can appear in a slightly different place each time it is launched, causing you to re-find the coordinates each time. However, if you have an image of the button, such as the image of the 7 button:
.. image:: calc7key.png
. . . you can call the `locateOnScreen('calc7key.png')` function to get the screen coordinates. The return value is a 4-integer tuple: (left, top, width, height). This tuple can be passed to `center()` to get the X and Y coordinates at the center of this region. If the image can't be found on the screen, `locateOnScreen()` raises `ImageNotFoundException`.
>>> import pyautogui
>>> button7location = pyautogui.locateOnScreen('calc7key.png')
>>> button7location
Box(left=1416, top=562, width=50, height=41)
>>> button7location[0]
1416
>>> button7location.left
1416
>>> button7point = pyautogui.center(button7location)
>>> button7point
Point(x=1441, y=582)
>>> button7point[0]
1441
>>> button7point.x
1441
>>> button7x, button7y = button7point
>>> pyautogui.click(button7x, button7y) # clicks the center of where the 7 button was found
>>> pyautogui.click('calc7key.png') # a shortcut version to click on the center of where the 7 button was found
The optional `confidence` keyword argument specifies the accuracy with which the function should locate the image on screen. This is helpful in case the function is not able to locate an image due to negligible pixel differences:
>>> import pyautogui
>>> button7location = pyautogui.locateOnScreen('calc7key.png', confidence=0.9)
>>> button7location
Box(left=1416, top=562, width=50, height=41)
**Note**: You need to have `OpenCV <https://pypi.org/project/opencv-python/>`_ installed for the `confidence` keyword to work.
The `locateCenterOnScreen()` function combines `locateOnScreen()` and `center()`:
>>> import pyautogui
>>> x, y = pyautogui.locateCenterOnScreen('calc7key.png')
>>> pyautogui.click(x, y)
On a 1920 x 1080 screen, the locate function calls take about 1 or 2 seconds. This may be too slow for action video games, but works for most purposes and applications.
There are several "locate" functions. They all start looking at the top-left corner of the screen (or image) and look to the right and then down. The arguments can either be a
- `locateOnScreen(image, grayscale=False)` - Returns (left, top, width, height) coordinate of first found instance of the `image` on the screen. Raises `ImageNotFoundException` if not found on the screen.
- `locateCenterOnScreen(image, grayscale=False)` - Returns (x, y) coordinates of the center of the first found instance of the `image` on the screen. Raises `ImageNotFoundException` if not found on the screen.
- `locateAllOnScreen(image, grayscale=False)` - Returns a generator that yields (left, top, width, height) tuples for where the image is found on the screen.
- `locate(needleImage, haystackImage, grayscale=False)` - Returns (left, top, width, height) coordinate of first found instance of `needleImage` in `haystackImage`. Raises `ImageNotFoundException` if not found on the screen.
- `locateAll(needleImage, haystackImage, grayscale=False)` - Returns a generator that yields (left, top, width, height) tuples for where `needleImage` is found in `haystackImage`.
The "locate all" functions can be used in for loops or passed to `list()`:
>>> import pyautogui
>>> for pos in pyautogui.locateAllOnScreen('someButton.png')
... print(pos)
...
(1101, 252, 50, 50)
(59, 481, 50, 50)
(1395, 640, 50, 50)
(1838, 676, 50, 50)
>>> list(pyautogui.locateAllOnScreen('someButton.png'))
[(1101, 252, 50, 50), (59, 481, 50, 50), (1395, 640, 50, 50), (1838, 676, 50, 50)]
These "locate" functions are fairly expensive; they can take a full second to run. The best way to speed them up is to pass a `region` argument (a 4-integer tuple of (left, top, width, height)) to only search a smaller region of the screen instead of the full screen:
>>> import pyautogui
>>> pyautogui.locateOnScreen('someButton.png', region=(0,0, 300, 400))
Grayscale Matching
------------------
Optionally, you can pass `grayscale=True` to the locate functions to give a slight speedup (about 30%-ish). This desaturates the color from the images and screenshots, speeding up the locating but potentially causing false-positive matches.
>>> import pyautogui
>>> button7location = pyautogui.locateOnScreen('calc7key.png', grayscale=True)
>>> button7location
(1416, 562, 50, 41)
Pixel Matching
--------------
To obtain the RGB color of a pixel in a screenshot, use the Image object's `getpixel()` method:
>>> import pyautogui
>>> im = pyautogui.screenshot()
>>> im.getpixel((100, 200))
(130, 135, 144)
Or as a single function, call the `pixel()` PyAutoGUI function, which is a wrapper for the previous calls:
>>> import pyautogui
>>> pix = pyautogui.pixel(100, 200)
>>> pix
RGB(red=130, green=135, blue=144)
>>> pix[0]
130
>>> pix.red
130
If you just need to verify that a single pixel matches a given pixel, call the `pixelMatchesColor()` function, passing it the X coordinate, Y coordinate, and RGB tuple of the color it represents:
>>> import pyautogui
>>> pyautogui.pixelMatchesColor(100, 200, (130, 135, 144))
True
>>> pyautogui.pixelMatchesColor(100, 200, (0, 0, 0))
False
The optional `tolerance` keyword argument specifies how much each of the red, green, and blue values can vary while still matching:
>>> import pyautogui
>>> pyautogui.pixelMatchesColor(100, 200, (130, 135, 144))
True
>>> pyautogui.pixelMatchesColor(100, 200, (140, 125, 134))
False
>>> pyautogui.pixelMatchesColor(100, 200, (140, 125, 134), tolerance=10)
True
================================================
FILE: docs/simplified-chinese.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# PyAutoGUI——让所有GUI都自动化"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"本教程译自大神[Al Sweigart](http://inventwithpython.com/)的[PyAutoGUI](https://pyautogui.readthedocs.org/)项目,Python自动化工具,更适合处理GUI任务,网页任务推荐:\n",
"- [Selenium](https://selenium-python.readthedocs.org/)+Firefox记录(Chromedriver和Phantomjs也很给力,Phantomjs虽然是无头浏览器,但有时定位不准),然后用Python写单元测试\n",
"- [request](http://www.python-requests.org/en/latest/)处理get/post请求写一堆代码自动化处理,都在后台运行,不用运行浏览器,非常适合处理表单\n",
"\n",
"没有[sikuli](http://www.sikuli.org/)功能多,但是Python让生活更简单,[人生苦短,Python当歌](http://cn.pycon.org/2015/)。\n",
"\n",
"同时推荐一本Python网络数据采集(图灵社区取的名字^_^)的基础书籍[Ryan Mitchell的《Web Scraping with Python》](http://shop.oreilly.com/product/0636920034391.do),可以和PyAutoGUI结合使用。\n",
"\n",
"tl;dr\n",
"\n",
"<!-- TEASER_END -->"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2015-08-17:输入中文bug没有解决,目前的解决方案是Python 2.X环境下安装[pyperclip](https://github.com/asweigart/pyperclip)和pyautogui,用复制粘贴来实现。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyperclip\n",
"import pyautogui\n",
"\n",
"# PyAutoGUI中文输入需要用粘贴实现\n",
"# Python 2版本的pyperclip提供中文复制\n",
"def paste(foo):\n",
" pyperclip.copy(foo)\n",
" pyautogui.hotkey('ctrl', 'v')\n",
"\n",
"foo = u'学而时习之'\n",
"# 移动到文本框\n",
"pyautogui.click(130,30)\n",
"paste(foo)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 1.简介"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.1 目的"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyAutoGUI是一个纯Python的GUI自动化工具,其目的是可以用程序自动控制鼠标和键盘操作,多平台支持(Windows,OS X,Linux)。可以用`pip`安装,Github上有[源代码](https://github.com/asweigart/pyautogui)。\n",
"\n",
"下面的代码让鼠标移到屏幕中央。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"screenWidth, screenHeight = pyautogui.size()\n",
"pyautogui.moveTo(screenWidth / 2, screenHeight / 2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyAutoGUI可以模拟鼠标的移动、点击、拖拽,键盘按键输入、按住操作,以及鼠标+键盘的热键同时按住等操作,可以说手能动的都可以。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.2 例子"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import pyautogui\n",
"screenWidth, screenHeight = pyautogui.size()\n",
"currentMouseX, currentMouseY = pyautogui.position()\n",
"pyautogui.moveTo(100, 150)\n",
"pyautogui.click()\n",
"# 鼠标向下移动10像素\n",
"pyautogui.moveRel(None, 10)\n",
"pyautogui.doubleClick()\n",
"# 用缓动/渐变函数让鼠标2秒后移动到(500,500)位置\n",
"# use tweening/easing function to move mouse over 2 seconds.\n",
"pyautogui.moveTo(1800, 500, duration=2, tween=pyautogui.easeInOutQuad)\n",
"# 在每次输入之间暂停0.25秒\n",
"pyautogui.typewrite('Hello world!', interval=0.25)\n",
"pyautogui.press('esc')\n",
"pyautogui.keyDown('shift')\n",
"pyautogui.press(['left', 'left', 'left', 'left', 'left', 'left'])\n",
"pyautogui.keyUp('shift')\n",
"pyautogui.hotkey('ctrl', 'c')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"distance = 200\n",
"while distance > 0:\n",
" pyautogui.dragRel(distance, 0, duration=0.5) # 向右\n",
" distance -= 5\n",
" pyautogui.dragRel(0, distance, duration=0.5) # 向下\n",
" pyautogui.draIn gRel(-distance, 0, duration=0.5) # 向左\n",
" distance -= 5\n",
" pyautogui.dragRel(0, -distance, duration=0.5) # 向上"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.4 保护措施(Fail-Safes)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"就像《魔法师的学徒》(Sorcerer’s Apprentice)会担水的扫帚,可以担水,却无力阻止水漫浴室。你的程序也可能会失控(即使是按照你的意思执行的),那时就需要中断。如果鼠标还在自动操作,就很难在程序窗口关闭它。\n",
"\n",
"为了能够及时中断,PyAutoGUI提供了一个保护措施。当`pyautogui.FAILSAFE = True`时,如果把鼠标光标在屏幕左上角,PyAutoGUI函数就会产生`pyautogui.FailSafeException`异常。如果失控了,需要中断PyAutoGUI函数,就把鼠标光标在屏幕左上角。要禁用这个特性,就把`FAILSAFE`设置成`False`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"pyautogui.FAILSAFE = False"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"通过把`pyautogui.PAUSE`设置成`float`或`int`时间(秒),可以为所有的PyAutoGUI函数增加延迟。默认延迟时间是0.1秒。在函数循环执行的时候,这样做可以让PyAutoGUI运行的慢一点,非常有用。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"pyautogui.PAUSE = 2.5\n",
"pyautogui.moveTo(100,100); pyautogui.click()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"所有的PyAutoGUI函数在延迟完成前都处于阻塞状态(block)。(未来计划增加一个可选的非阻塞模式来调用函数。)\n",
"\n",
"**建议`PAUSE`和`FAILSAFE`一起使用。**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 2 安装与依赖\n",
"\n",
"PyAutoGUI支持Python 2.x和Python 3.x\n",
"- Windows:PyAutoGUI没有任何依赖,因为它用Python的`ctypes`模块所以不需要`pywin32`\n",
"```\n",
"pip3 install pyautogui\n",
"```\n",
"- OS X:PyAutoGUI需要[PyObjC](http://pythonhosted.org/pyobjc/install.html)运行AppKit和Quartz模块。这个模块在PyPI上的按住顺序是`pyobjc-core`和`pyobjc`\n",
"```\n",
"sudo pip3 install pyobjc-core\n",
"sudo pip3 install pyobjc\n",
"sudo pip3 install pyautogui\n",
"```\n",
"- Linux:PyAutoGUI需要`python-xlib`(Python 2)、`python3-Xlib`(Python 3)\n",
"```\n",
"sudo pip3 install python3-xlib\n",
"sudo apt-get scrot\n",
"sudo apt-get install python-tk\n",
"sudo apt-get install python3-dev\n",
"sudo pip3 install pyautogui```"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## 3.速查表(小抄,Cheat Sheet)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"### 3.1 常用函数"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(123, 372)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pyautogui\n",
"# 当前鼠标的坐标\n",
"pyautogui.position()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(1920, 1080)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 当前屏幕的分辨率(宽度和高度)\n",
"pyautogui.size()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# (x,y)是否在屏幕上\n",
"x, y = 122, 244\n",
"pyautogui.onScreen(x, y)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"### 3.2 保护措施"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"PyAutoGUI函数增加延迟为2.5秒:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"pyautogui.PAUSE = 2.5"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"当pyautogui.FAILSAFE = True时,如果把鼠标光标在屏幕左上角,PyAutoGUI函数就会产生pyautogui.FailSafeException异常。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"pyautogui.FAILSAFE = True"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"### 3.3 鼠标函数"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"坐标系的原点是左上角。X轴(水平)坐标向右增大,Y轴(竖直)坐标向下增大。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"num_seconds = 1.2\n",
"# 用num_seconds秒的时间把光标移动到(x, y)位置\n",
"pyautogui.moveTo(x, y, duration=num_seconds)\n",
"# 用num_seconds秒的时间把光标的X轴(水平)坐标移动xOffset,\n",
"# Y轴(竖直)坐标向下移动yOffset。\n",
"xOffset, yOffset = 50, 100\n",
"pyautogui.moveRel(xOffset, yOffset, duration=num_seconds)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"`click()`函数就是让鼠标点击,默认是单击左键,参数可以设置:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.click(x=moveToX, y=moveToY, clicks=num_of_clicks, interval=secs_between_clicks, button='left')"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"其中,`button`属性可以设置成`left`,`middle`和`right`。\n",
"\n",
"所有的点击都可以用这个函数,不过下面的函数可读性更好:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.rightClick(x=moveToX, y=moveToY)\n",
"pyautogui.middleClick(x=moveToX, y=moveToY)\n",
"pyautogui.doubleClick(x=moveToX, y=moveToY)\n",
"pyautogui.tripleClick(x=moveToX, y=moveToY)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"`scroll`函数控制鼠标滚轮的滚动,`amount_to_scroll`参数表示滚动的格数。正数则页面向上滚动,负数则向下滚动:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.scroll(clicks=amount_to_scroll, x=moveToX, y=moveToY)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"每个按键按下和松开两个事件可以分开处理:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.mouseDown(x=moveToX, y=moveToY, button='left')\n",
"pyautogui.mouseUp(x=moveToX, y=moveToY, button='left')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.4 键盘函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"键盘上可以按的键都可以调用:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 每次键入的时间间隔\n",
"secs_between_keys = 0.1\n",
"pyautogui.typewrite('Hello world!\\n', interval=secs_between_keys)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"多个键也可以:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.typewrite(['a', 'b', 'c', 'left', 'backspace', 'enter', 'f1'], interval=secs_between_keys)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"按键名称列表:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['\\t', '\\n', '\\r', ' ', '!', '\"', '#', '$', '%', '&']"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.KEYBOARD_KEYS[:10]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"键盘的一些热键像`Ctrl-S`或`Ctrl-Shift-1`都可以用`hotkey()`函数来实现:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.hotkey('ctrl', 'a') # 全选\n",
"pyautogui.hotkey('ctrl', 'c') # 复制\n",
"pyautogui.hotkey('ctrl', 'v') # 粘贴"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"每个按键的按下和松开也可以单独调用:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.keyDown(key_name)\n",
"pyautogui.keyUp(key_name)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"### 3.5 消息弹窗函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果你需要消息弹窗,通过单击OK暂停程序,或者向用户显示一些信息,消息弹窗函数就会有类似JavaScript的功能:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"''"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.alert('这个消息弹窗是文字+OK按钮')\n",
"pyautogui.confirm('这个消息弹窗是文字+OK+Cancel按钮')\n",
"pyautogui.prompt('这个消息弹窗是让用户输入字符串,单击OK')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在`prompt()`函数中,如果用户什么都不输入,就会返回`None`。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.6 截屏函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyAutoGUI用Pillow/PIL库实现图片相关的识别和操作。\n",
"\n",
"在Linux里面,你必须执行`sudo apt-get install scrot`来使用截屏特性。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# 返回一个Pillow/PIL的Image对象\n",
"pyautogui.screenshot()\n",
"pyautogui.screenshot('foo.png')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果你有一个图片文件想在上面做点击操作,你可以用`locateOnScreen()`函数来定位。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(0, 1040, 48, 40)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 返回(最左x坐标,最顶y坐标,宽度,高度)\n",
"pyautogui.locateOnScreen('pyautogui/looks.png')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`locateAllOnScreen()`函数会寻找所有相似图片,返回一个生成器:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(0, 1040, 48, 40)\n"
]
}
],
"source": [
"for i in pyautogui.locateAllOnScreen('pyautogui/looks.png'):\n",
" print(i)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(0, 1040, 48, 40)]"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(pyautogui.locateAllOnScreen('pyautogui/looks.png'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`locateCenterOnScreen()`函数会返回图片在屏幕上的中心XY轴坐标值:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(24, 1060)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.locateCenterOnScreen('pyautogui/looks.png')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果没找到图片会返回`None`。\n",
">定位比较慢,一般得用1~2秒"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 4 常用函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- `position()`:返回整数元组(x, y),分别表示鼠标光标所在位置的XY轴坐标\n",
"- `size()`:返回显示器的尺寸整数元组(x, y)。未来将加入多屏支持"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 5 鼠标控制函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.1 屏幕与鼠标位置"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"屏幕位置使用X和Y轴的笛卡尔坐标系。原点`(0,0)`在左上角,分别向右、向下增大。\n",
"\n",
"如果屏幕像素是$1920 \\times 1080$,那么右下角的坐标是`(1919, 1079)`。\n",
"\n",
"分辨率大小可以通过`size()`函数返回整数元组。光标的位置用`position()`返回。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(1920, 1080)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.size()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(272, 688)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.position()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面是Python 3版本的光标位置记录程序:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# ! python 3\n",
"import pyautogui\n",
"print('Press Ctrl-C to quit')\n",
"try:\n",
" while True:\n",
" x, y = pyautogui.position()\n",
" positionStr = 'X: {} Y: {}'.format(*[str(x).rjust(4) for x in [x, y]])\n",
" print(positionStr, end='')\n",
" print('\\b' * len(positionStr), end='', flush=True)\n",
"except KeyboardInterrupt:\n",
" print('\\n')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python 2版本是:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# ! python\n",
"import pyautogui, sys\n",
"print('Press Ctrl-C to quit.')\n",
"try:\n",
" while True:\n",
" x, y = pyautogui.position()\n",
" positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4)\n",
" print positionStr,\n",
" print '\\b' * (len(positionStr) + 2),\n",
" sys.stdout.flush()\n",
"except KeyboardInterrupt:\n",
" print '\\n'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"要检查XY坐标是否在屏幕上,需要用`onScreen()`函数来检验,如果在屏幕上返回`True`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pyautogui\n",
"pyautogui.onScreen(0, 0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.onScreen(0, -1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.onScreen(0, 2080)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.onScreen(1920, 1080)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.onScreen(1919, 1079)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.2 鼠标行为"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`moveTo()`函数会把鼠标光标移动到指定的XY轴坐标处。如果传入`None`值,则表示使用当前光标的对象轴坐标值。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.moveTo(100, 200) # 光标移动到(100, 200)位置\n",
"pyautogui.moveTo(None, 500) # 光标移动到(100, 500)位置\n",
"pyautogui.moveTo(600, None) # 光标移动到(600, 500)位置"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"一般鼠标光标都是瞬间移动到指定的位置,如果你想让鼠标移动的慢点,可以设置持续时间:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.moveTo(100, 200, duration=2) # 用2秒把光标移动到(100, 200)位置"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"默认的持续时间`pyautogui.MINIMUM_DURATION `是0.1秒,如果你设置的时间比默认值还短,那么就会瞬间执行。\n",
"\n",
"如果你想让光标以当前位置为原点,进行相对移动,就用`pyautogui.moveRel()`函数。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.moveTo(100, 200) #把光标移动到(100, 200)位置\n",
"pyautogui.moveRel(0, 50) #向下移动50\n",
"pyautogui.moveRel(30, 0, 2) #向右移动30\n",
"pyautogui.moveRel(30, None) #向右移动30"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.3 鼠标拖拽"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyAutoGUI的`dragTo()`和`dragRel()`函数与`moveTo()`和`moveRel()`函数类似。另外,他们有一个`button`参数可以设置成`left`,`middle`和`right`三个键。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 按住鼠标左键,把鼠标拖拽到(100, 200)位置\n",
"pyautogui.dragTo(100, 200, button='left')\n",
"# 按住鼠标左键,用2秒钟把鼠标拖拽到(300, 400)位置\n",
"pyautogui.dragTo(300, 400, 2, button='left')\n",
"# 按住鼠标右键,用2秒钟把鼠标拖拽到(30,0)位置\n",
"pyautogui.dragTo(30, 0, 2, button='right')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.4 缓动/渐变(Tween / Easing)函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"缓动/渐变函数的作用是让光标的移动更炫。如果你不需要用到的话,你可以忽略这些。\n",
"\n",
"缓动/渐变函数可以改变光标移动过程的速度和方向。通常鼠标是匀速直线运动,这就是线性缓动/渐变函数。PyAutoGUI有30种缓动/渐变函数,可以通过`pyautogui.ease*?`查看。其中,`pyautogui.easeInQuad()`函数可以用于`moveTo()`,`moveRel()`,`dragTo()`和`dragRel()`函数,光标移动呈现先慢后快的效果,整个过程的时间还是和原来一样。而`pyautogui.easeOutQuad`函数的效果相反:光标开始移动很快,然后慢慢减速。`pyautogui.easeOutElastic`是弹簧效果,首先越过终点,然后再反弹回来。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# 开始很慢,不断加速\n",
"pyautogui.moveTo(100, 100, 2, pyautogui.easeInQuad)\n",
"# 开始很快,不断减速\n",
"pyautogui.moveTo(100, 100, 2, pyautogui.easeOutQuad)\n",
"# 开始和结束都快,中间比较慢\n",
"pyautogui.moveTo(100, 100, 2, pyautogui.easeInOutQuad)\n",
"# 一步一徘徊前进\n",
"pyautogui.moveTo(100, 100, 2, pyautogui.easeInBounce)\n",
"# 徘徊幅度更大,甚至超过起点和终点\n",
"pyautogui.moveTo(100, 100, 2, pyautogui.easeInElastic)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这些效果函数是模仿Al Sweigart的[PyTweening](https://github.com/asweigart/pytweening)模块,可以直接使用,不需要额外安装。\n",
"\n",
"如果你想创建自己的效果,也可以定义一个函数,其参数是(0.0,1.0),表示起点和终点,返回值是介于[0.0,1.0]之间的数。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.5 鼠标单击"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`click()`函数模拟单击鼠标左键一次的行为。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.click()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果单机之前要先移动,可以把目标的XY坐标值传入函数:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 先移动到(100, 200)再单击\n",
"pyautogui.click(x=100, y=200, duration=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以通过`button`参数设置`left`,`middle`和`right`三个键。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.click(button='right')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"要做多次单击可以设置`clicks`参数,还有`interval`参数可以设置每次单击之间的时间间隔。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 双击左键\n",
"pyautogui.click(clicks=2)\n",
"# 两次单击之间停留0.25秒\n",
"pyautogui.click(clicks=2, interval=0.25)\n",
"# 三击右键\n",
"pyautogui.click(button='right', clicks=2, interval=0.25)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"为了操作方便,PyAutoGUI提供了`doubleClick()`,`tripleClick()`和`rightClick()`来实现双击、三击和右击操作。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.6 鼠标按下和松开函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`mouseDown()`和`mouseUp()`函数可以实现鼠标按下和鼠标松开的操作。两者参数相同,有`x`,`y`和`button`。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 鼠标左键按下再松开\n",
"pyautogui.mouseDown(); pyautogui.mouseUp() \n",
"# 按下鼠标右键\n",
"pyautogui.mouseDown(button='right') \n",
"# 移动到(100, 200)位置,然后松开鼠标右键\n",
"pyautogui.mouseUp(button='right', x=100, y=200) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5.7 滚轮滚动函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"鼠标滚轮滚动可以用`scroll()`函数和`clicks`次数参数来模拟。不同平台上的`clicks`次数不太一样。还有`x`和`y`参数可以在滚动之前定位到(x, y)位置。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 向上滚动10格\n",
"pyautogui.scroll(10)\n",
"# 向下滚动10格\n",
"pyautogui.scroll(-10)\n",
"# 移动到(100, 100)位置再向上滚动10格\n",
"pyautogui.scroll(10, x=100, y=100)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在OS X和Linux平台上,PyAutoGUI还可以用`hscroll()`实现水平滚动。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 向右滚动10格\n",
"pyautogui.hscroll(10)\n",
"# 向左滚动10格\n",
"pyautogui.hscroll(-10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`scroll()`函数是`vscroll()`的一个包装(`wrapper`),执行竖直滚动。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6 键盘控制函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6.1 `typewrite()`输入函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"键盘控制的主要函数就是`typewrite()`。这个函数可以实现字符输入。要在两次输入间增加时间间隔,可以用`interval`参数。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 输入Hello world!\n",
"pyautogui.typewrite('Hello world!')\n",
"# 每次输入间隔0.25秒,输入Hello world!\n",
"pyautogui.typewrite('Hello world!', interval=0.25)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`typewrite()`函数只能用于单个字符键,不能按SHITF和F1这些功能键。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6.2 `press()`,`keyDown()`和`keyUp()`函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"要按那些功能键,可以用`press()`函数把`pyautogui.KEYBOARD_KEYS`里面按键对应的字符串输入进去。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# ENTER键\n",
"pyautogui.press('enter')\n",
"# F1键\n",
"pyautogui.press('f1')\n",
"# 左方向键\n",
"pyautogui.press('left')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`press()`函数其实是`keyDown()`和`keyUp()`函数的包装,模拟的按下然后松开两个动作。这两个函数可以单独调用。例如,按下`shift`键的同时按3次左方向键:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# 按下`shift`键\n",
"pyautogui.keyDown('shift')\n",
"pyautogui.press('left')\n",
"pyautogui.press('left')\n",
"pyautogui.press('left')\n",
"# 松开`shift`键\n",
"pyautogui.keyUp('shift')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"和`typewrite()`函数一样,可以用数组把一组键传入`press()`。例如:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.press(['left', 'left', 'left'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6.3 `hotkey()`函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"为了更高效的输入热键,PyAutoGUI提供了`hotkey()`函数来绑定若干按键:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"pyautogui.hotkey('ctrl', 'shift', 'ese')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"等价于:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.keyDown('ctrl')\n",
"pyautogui.keyDown('shift')\n",
"pyautogui.keyDown('esc')\n",
"pyautogui.keyUp('esc')\n",
"pyautogui.keyUp('shift')\n",
"pyautogui.keyUp('ctrl')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6.4 KEYBOARD_KEYS"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"下面就是`press()`,`keyDown()`,`keyUp()`和`hotkey()`函数可以输入的按键名称:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false,
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['\\t', '\\n', '\\r', ' ', '!', '\"', '#', '$', '%', '&', \"'\", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', '[', '\\\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace', 'browserback', 'browserfavorites', 'browserforward', 'browserhome', 'browserrefresh', 'browsersearch', 'browserstop', 'capslock', 'clear', 'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal', 'del', 'delete', 'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', 'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja', 'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail', 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack', 'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8', 'num9', 'numlock', 'pagedown', 'pageup', 'pause', 'pgdn', 'pgup', 'playpause', 'prevtrack', 'print', 'printscreen', 'prntscrn', 'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select', 'separator', 'shift', 'shiftleft', 'shiftright', 'sleep', 'stop', 'subtract', 'tab', 'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen', 'command', 'option', 'optionleft', 'optionright']\n"
]
}
],
"source": [
"print(pyautogui.KEYBOARD_KEYS)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7 消息弹窗函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyAutoGUI通过Tkinter实现了4种纯Python的消息弹窗函数,和JavaScript类似。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7.1 alert()函数"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'OK'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.alert(text='', title='', button='OK')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"显示一个简单的带文字和OK按钮的消息弹窗。用户点击后返回`button`的文字。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7.2 The confirm() Function"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'0'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# OK和Cancel按钮的消息弹窗\n",
"pyautogui.confirm(text='', title='', buttons=['OK', 'Cancel'])\n",
"# 10个按键0-9的消息弹窗\n",
"pyautogui.confirm(text='', title='', buttons=range(10))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"显示一个简单的带文字、OK和Cancel按钮的消息弹窗,用户点击后返回被点击button的文字,支持自定义数字、文字的列表。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7.3 The prompt() Function"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.prompt(text='', title='' , default='')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以输入的消息弹窗,带OK和Cancel按钮。用户点击OK按钮返回输入的文字,点击Cancel按钮返回`None`。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7.4 The password() Function"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.password(text='', title='', default='', mask='*')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"样式同`prompt()`,用于输入密码,消息用`*`表示。带OK和Cancel按钮。用户点击OK按钮返回输入的文字,点击Cancel按钮返回`None`。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8 截屏函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyAutoGUI可以截屏并保存为图片文件,然后定位这些截屏在屏幕上的位置。与[sikuli](http://www.sikuli.org/)类似,把屏幕上的按键截取下来,然后定位,就可以执行点击等操作了。\n",
"\n",
"截屏功能需要安装Pillow模块。OS X用`screencapture`命令,是系统自带的。Linux用户用`scrot`命令,可以通过`sudo apt-get install scrot`安装。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8.1 Ubuntu注意事项"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"由于Ubuntu上安装Pillow时缺少PNG和JPEG依赖,所以安装比较复杂,具体可以看[Ubuntu论坛](http://conda.pydata.org/miniconda.html)。不过用[miniconda](http://conda.pydata.org/miniconda.html)可以解决这些问题,如果Ubuntu或Mint上安装了miniconda,可以直接`conda install pillow`来安装。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8.2 `screenshot()`函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`screenshot()`函数会返回`Image`对象(参考[Pillow或PIL模块文档](http://python-pillow.github.io/)),也可以设置文件名:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"im1 = pyautogui.screenshot()\n",
"im2 = pyautogui.screenshot('my_screenshot.png')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在一个$1920 \\times 1080$的屏幕上,`screenshot()`函数要消耗100微秒——不快也不慢。\n",
"\n",
"如果你不需要截取整个屏幕,还有一个可选的`region`参数。你可以把截取区域的左上角XY坐标值和宽度、高度传入截取。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"im = pyautogui.screenshot(region=(0, 0, 300 ,400))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8.3 定位函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以定位截图在屏幕上的坐标位置。比如,你需要在计算器里输入:\n",
"\n",
"\n",
"如果你不知道按钮的位置,就不能用`moveTo()`定位和`click()`点击。而且每次计算器的位置可能会变化,这时即使有来坐标也不好用了。但是如果你有要点击按钮的截图,比如数字`7`:\n",
"\n",
"\n",
"你可以调用`pyautogui.locateOnScreen('calc7key.png')`函数来获得`7`的屏幕坐标。返回的是一个元组`(top, left, width, height)`。这个元组可以用`pyautogui.center()`函数来获取截图屏幕的中心坐标。如果截图没找到,`pyautogui.locateOnScreen()`函数返回`None`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(1226, 546, 29, 28)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pyautogui\n",
"button7location = pyautogui.locateOnScreen('pyautogui/calc7key.png')\n",
"button7location"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(1240, 560)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"button7x, button7y = pyautogui.center(button7location)\n",
"button7x, button7y"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"pyautogui.click(button7x, button7y) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`locateCenterOnScreen()`等价于上面的前两布操作,直接获得截屏屏幕中心坐标:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import pyautogui\n",
"x, y = pyautogui.locateCenterOnScreen('pyautogui/calc7key.png')\n",
"pyautogui.click(x, y)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在$1920 \\times 1080$的屏幕上,定位函数需要1~2秒时间。对视频游戏(LOL、DOTA)来说就太慢了,但是上班干活还是绰绰有余。\n",
"\n",
"还是几个定位函数。都是从左上角原点开始向右向下搜索截图位置:\n",
"\n",
"- locateOnScreen(image, grayscale=False):返回找到的第一个截图`Image`对象在屏幕上的坐标`(left, top, width, height)`,如果没找到返回`None`\n",
"- locateCenterOnScreen(image, grayscale=False):返回找到的第一个截图`Image`对象在屏幕上的中心坐标`(x, y)`,如果没找到返回`None`\n",
"- locateAllOnScreen(image, grayscale=False):返回找到的所有相同截图`Image`对象在屏幕上的坐标`(left, top, width, height)`的生成器\n",
"- locate(needleImage, haystackImage, grayscale=False):返回找到的第一个截图`Image`对象在`haystackImage`里面的坐标`(left, top, width, height)`,如果没找到返回`None`\n",
"- locateAll(needleImage, haystackImage, grayscale=False):返回找到的所有相同截图`Image`对象在`haystackImage`里面的坐标`(left, top, width, height)`的生成器\n",
"\n",
"两个`locateAll*`函数都可以用`for`循环和`list()`输出:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(1227, 546, 29, 28)\n"
]
}
],
"source": [
"for pos in pyautogui.locateAllOnScreen('pyautogui/calc7key.png'):\n",
" print(pos)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"[(1227, 546, 29, 28)]"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(pyautogui.locateAllOnScreen('pyautogui/calc7key.png'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 8.3.1 灰度值匹配"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"可以把`grayscale`参数设置为`True`来加速定位(大约提升30%),默认为`False`。这种去色(desaturate)方法可以加速定位,但是也可能导致假阳性(false-positive)匹配:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(1227, 546, 29, 28)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pyautogui\n",
"button7location = pyautogui.locateOnScreen('pyautogui/calc7key.png', grayscale=True)\n",
"button7location"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 8.3.2 像素匹配"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"要获取截屏某个位置的RGB像素值,可以用`Image`对象的`getpixel()`方法:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(255, 255, 255)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pyautogui\n",
"im = pyautogui.screenshot()\n",
"im.getpixel((100, 200))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"也可以用PyAutoGUI的`pixel()`函数,是之前调用的包装:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(255, 255, 255)"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.pixel(100, 200)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"如果你只是要检验一下指定位置的像素值,可以用`pixelMatchesColor()`函数,把X、Y和RGB元组值穿入即可:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.pixelMatchesColor(100, 200, (255, 255, 255))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.pixelMatchesColor(100, 200, (255, 255, 245))"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"`tolerance`参数可以指定红、绿、蓝3种颜色误差范围:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.pixelMatchesColor(100, 200, (255, 255, 245), tolerance=10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.pixelMatchesColor(100, 200, (248, 250, 245), tolerance=10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pyautogui.pixelMatchesColor(100, 200, (205, 255, 245), tolerance=10)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
================================================
FILE: docs/source/modules.rst
================================================
pyautogui
=========
.. toctree::
:maxdepth: 4
pyautogui
================================================
FILE: docs/source/pyautogui.rst
================================================
pyautogui package
=================
Submodules
----------
pyautogui.keynames module
-------------------------
.. automodule:: pyautogui.keynames
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: pyautogui
:members:
:undoc-members:
:show-inheritance:
================================================
FILE: docs/tests.rst
================================================
.. default-role:: code
=======
Testing
=======
The unit tests for PyAutoGUI are currently not comprehensive. The tests (in basicTests.py) cover the following:
- onScreen()
- size()
- position()
- moveTo()
- moveRel()
- typewrite()
- PAUSE
Platforms Tested
================
- Python 3.4, 3.3, 3.2, 3.1, 2.7, 2.6, 2.5
- Windows
- OS X
- Raspberry Pi
(If you have run the unit tests successfully on other platforms, please tell al@inventwithpython.com.)
PyAutoGUI is not compatible with Python 2.4 or before.
The keyboard functions do not work on Ubuntu when run in VirtualBox on Windows.
================================================
FILE: pyautogui/__init__.py
================================================
# PyAutoGUI lets Python control the mouse and keyboard, and other GUI automation tasks. For Windows, macOS, and Linux,
# on Python 3 and 2.
# https://github.com/asweigart/pyautogui
# Al Sweigart al@inventwithpython.com (Send me feedback & suggestions!)
# TODO - the following features are half-implemented right now:
# snapshot logging
# non-qwerty keyboard mapping
# primary secondary mouse button awareness
from __future__ import absolute_import, division, print_function
__version__ = "0.9.54"
import collections
import sys
import time
import datetime
import os
import platform
import re
import functools
from contextlib import contextmanager
class PyAutoGUIException(Exception):
"""
PyAutoGUI code will raise this exception class for any invalid actions. If PyAutoGUI raises some other exception,
you should assume that this is caused by a bug in PyAutoGUI itself. (Including a failure to catch potential
exceptions raised by PyAutoGUI.)
"""
pass
class FailSafeException(PyAutoGUIException):
"""
This exception is raised by PyAutoGUI functions when the user puts the mouse cursor into one of the "failsafe
points" (by default, one of the four corners of the primary monitor). This exception shouldn't be caught; it's
meant to provide a way to terminate a misbehaving script.
"""
pass
class ImageNotFoundException(PyAutoGUIException):
"""
This exception is the PyAutoGUI version of PyScreeze's `ImageNotFoundException`, which is raised when a locate*()
function call is unable to find an image.
Ideally, `pyscreeze.ImageNotFoundException` should never be raised by PyAutoGUI.
"""
if sys.version_info[0] == 2 or sys.version_info[0:2] in ((3, 1), (3, 2)):
# Python 2 and 3.1 and 3.2 uses collections.Sequence
from collections import Sequence
else:
# Python 3.3+ uses collections.abc.Sequence
from collections.abc import Sequence
try:
from pytweening import (
easeInQuad,
easeOutQuad,
easeInOutQuad,
easeInCubic,
easeOutCubic,
easeInOutCubic,
easeInQuart,
easeOutQuart,
easeInOutQuart,
easeInQuint,
easeOutQuint,
easeInOutQuint,
easeInSine,
easeOutSine,
easeInOutSine,
easeInExpo,
easeOutExpo,
easeInOutExpo,
easeInCirc,
easeOutCirc,
easeInOutCirc,
easeInElastic,
easeOutElastic,
easeInOutElastic,
easeInBack,
easeOutBack,
easeInOutBack,
easeInBounce,
easeOutBounce,
easeInOutBounce,
)
# getLine is not needed.
# getPointOnLine has been redefined in this file, to avoid dependency on pytweening.
# linear has also been redefined in this file.
except ImportError:
def _couldNotImportPyTweening(*unused_args, **unused_kwargs):
"""
This function raises ``PyAutoGUIException``. It's used for the PyTweening function names if the PyTweening
module failed to be imported.
"""
raise PyAutoGUIException(
"PyAutoGUI was unable to import pytweening. Please install this module to enable the function you tried to call."
)
easeInQuad = _couldNotImportPyTweening
easeOutQuad = _couldNotImportPyTweening
easeInOutQuad = _couldNotImportPyTweening
easeInCubic = _couldNotImportPyTweening
easeOutCubic = _couldNotImportPyTweening
easeInOutCubic = _couldNotImportPyTweening
easeInQuart = _couldNotImportPyTweening
easeOutQuart = _couldNotImportPyTweening
easeInOutQuart = _couldNotImportPyTweening
easeInQuint = _couldNotImportPyTweening
easeOutQuint = _couldNotImportPyTweening
easeInOutQuint = _couldNotImportPyTweening
easeInSine = _couldNotImportPyTweening
easeOutSine = _couldNotImportPyTweening
easeInOutSine = _couldNotImportPyTweening
easeInExpo = _couldNotImportPyTweening
easeOutExpo = _couldNotImportPyTweening
easeInOutExpo = _couldNotImportPyTweening
easeInCirc = _couldNotImportPyTweening
easeOutCirc = _couldNotImportPyTweening
easeInOutCirc = _couldNotImportPyTweening
easeInElastic = _couldNotImportPyTweening
easeOutElastic = _couldNotImportPyTweening
easeInOutElastic = _couldNotImportPyTweening
easeInBack = _couldNotImportPyTweening
easeOutBack = _couldNotImportPyTweening
easeInOutBack = _couldNotImportPyTweening
easeInBounce = _couldNotImportPyTweening
easeOutBounce = _couldNotImportPyTweening
easeInOutBounce = _couldNotImportPyTweening
try:
from pymsgbox import alert, confirm, prompt, password
except ImportError:
# If pymsgbox module is not found, those methods will not be available.
def _couldNotImportPyMsgBox(*unused_args, **unused_kwargs):
"""
This function raises ``PyAutoGUIException``. It's used for the PyMsgBox function names if the PyMsgbox module
failed to be imported.
"""
raise PyAutoGUIException(
"PyAutoGUI was unable to import pymsgbox. Please install this module to enable the function you tried to call."
)
alert = confirm = prompt = password = _couldNotImportPyMsgBox
def raisePyAutoGUIImageNotFoundException(wrappedFunction):
"""
A decorator that wraps PyScreeze locate*() functions so that the PyAutoGUI user sees them raise PyAutoGUI's
ImageNotFoundException rather than PyScreeze's ImageNotFoundException. This is because PyScreeze should be
invisible to PyAutoGUI users.
"""
@functools.wraps(wrappedFunction)
def wrapper(*args, **kwargs):
try:
return wrappedFunction(*args, **kwargs)
except pyscreeze.ImageNotFoundException:
raise ImageNotFoundException # Raise PyAutoGUI's ImageNotFoundException.
return wrapper
try:
import pyscreeze
from pyscreeze import center, pixel, pixelMatchesColor, screenshot
# Change the locate*() functions so that they raise PyAutoGUI's ImageNotFoundException instead.
@raisePyAutoGUIImageNotFoundException
def locate(*args, **kwargs):
return pyscreeze.locate(*args, **kwargs)
locate.__doc__ = pyscreeze.locate.__doc__
@raisePyAutoGUIImageNotFoundException
def locateAll(*args, **kwargs):
return pyscreeze.locateAll(*args, **kwargs)
locateAll.__doc__ = pyscreeze.locateAll.__doc__
@raisePyAutoGUIImageNotFoundException
def locateAllOnScreen(*args, **kwargs):
return pyscreeze.locateAllOnScreen(*args, **kwargs)
locateAllOnScreen.__doc__ = pyscreeze.locateAllOnScreen.__doc__
@raisePyAutoGUIImageNotFoundException
def locateCenterOnScreen(*args, **kwargs):
return pyscreeze.locateCenterOnScreen(*args, **kwargs)
locateCenterOnScreen.__doc__ = pyscreeze.locateCenterOnScreen.__doc__
@raisePyAutoGUIImageNotFoundException
def locateOnScreen(*args, **kwargs):
return pyscreeze.locateOnScreen(*args, **kwargs)
locateOnScreen.__doc__ = pyscreeze.locateOnScreen.__doc__
@raisePyAutoGUIImageNotFoundException
def locateOnWindow(*args, **kwargs):
return pyscreeze.locateOnWindow(*args, **kwargs)
locateOnWindow.__doc__ = pyscreeze.locateOnWindow.__doc__
except ImportError:
# If pyscreeze module is not found, screenshot-related features will simply not work.
def _couldNotImportPyScreeze(*unused_args, **unsed_kwargs):
"""
This function raises ``PyAutoGUIException``. It's used for the PyScreeze function names if the PyScreeze module
failed to be imported.
"""
raise PyAutoGUIException(
"PyAutoGUI was unable to import pyscreeze. (This is likely because you're running a version of Python that Pillow (which pyscreeze depends on) doesn't support currently.) Please install this module to enable the function you tried to call."
)
center = _couldNotImportPyScreeze
#grab = _couldNotImportPyScreeze # grab() was removed, use screenshot() instead
locate = _couldNotImportPyScreeze
locateAll = _couldNotImportPyScreeze
locateAllOnScreen = _couldNotImportPyScreeze
locateCenterOnScreen = _couldNotImportPyScreeze
locateOnScreen = _couldNotImportPyScreeze
locateOnWindow = _couldNotImportPyScreeze
pixel = _couldNotImportPyScreeze
pixelMatchesColor = _couldNotImportPyScreeze
screenshot = _couldNotImportPyScreeze
try:
import mouseinfo
def mouseInfo():
"""
Launches the MouseInfo app. This application provides mouse coordinate information which can be useful when
planning GUI automation tasks. This function blocks until the application is closed.
"""
mouseinfo.MouseInfoWindow()
except ImportError:
def mouseInfo():
"""
This function raises PyAutoGUIException. It's used for the MouseInfo function names if the MouseInfo module
failed to be imported.
"""
raise PyAutoGUIException(
"PyAutoGUI was unable to import mouseinfo. Please install this module to enable the function you tried to call."
)
def useImageNotFoundException(value=None):
"""
When called with no arguments, PyAutoGUI will raise ImageNotFoundException when the PyScreeze locate*() functions
can't find the image it was told to locate. The default behavior is to return None. Call this function with no
arguments (or with True as the argument) to have exceptions raised, which is a better practice.
You can also disable raising exceptions by passing False for the argument.
"""
if value is None:
value = True
# TODO - this will cause a NameError if PyScreeze couldn't be imported:
try:
pyscreeze.USE_IMAGE_NOT_FOUND_EXCEPTION = value
except NameError:
raise PyAutoGUIException("useImageNotFoundException() ws called but pyscreeze isn't installed.")
if sys.platform == "win32": # PyGetWindow currently only supports Windows.
try:
from pygetwindow import (
Window,
getActiveWindow,
getActiveWindowTitle,
getWindowsAt,
getWindowsWithTitle,
getAllWindows,
getAllTitles,
)
except ImportError:
# If pygetwindow module is not found, those methods will not be available.
def _couldNotImportPyGetWindow(*unused_args, **unused_kwargs):
"""
This function raises PyAutoGUIException. It's used for the PyGetWindow function names if the PyGetWindow
module failed to be imported.
"""
raise PyAutoGUIException(
"PyAutoGUI was unable to import pygetwindow. Please install this module to enable the function you tried to call."
)
Window = _couldNotImportPyGetWindow
getActiveWindow = _couldNotImportPyGetWindow
getActiveWindowTitle = _couldNotImportPyGetWindow
getWindowsAt = _couldNotImportPyGetWindow
getWindowsWithTitle = _couldNotImportPyGetWindow
getAllWindows = _couldNotImportPyGetWindow
getAllTitles = _couldNotImportPyGetWindow
KEY_NAMES = [
"\t",
"\n",
"\r",
" ",
"!",
'"',
"#",
"$",
"%",
"&",
"'",
"(",
")",
"*",
"+",
",",
"-",
".",
"/",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
":",
";",
"<",
"=",
">",
"?",
"@",
"[",
"\\",
"]",
"^",
"_",
"`",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"{",
"|",
"}",
"~",
"accept",
"add",
"alt",
"altleft",
"altright",
"apps",
"backspace",
"browserback",
"browserfavorites",
"browserforward",
"browserhome",
"browserrefresh",
"browsersearch",
"browserstop",
"capslock",
"clear",
"convert",
"ctrl",
"ctrlleft",
"ctrlright",
"decimal",
"del",
"delete",
"divide",
"down",
"end",
"enter",
"esc",
"escape",
"execute",
"f1",
"f10",
"f11",
"f12",
"f13",
"f14",
"f15",
"f16",
"f17",
"f18",
"f19",
"f2",
"f20",
"f21",
"f22",
"f23",
"f24",
"f3",
"f4",
"f5",
"f6",
"f7",
"f8",
"f9",
"final",
"fn",
"hanguel",
"hangul",
"hanja",
"help",
"home",
"insert",
"junja",
"kana",
"kanji",
"launchapp1",
"launchapp2",
"launchmail",
"launchmediaselect",
"left",
"modechange",
"multiply",
"nexttrack",
"nonconvert",
"num0",
"num1",
"num2",
"num3",
"num4",
"num5",
"num6",
"num7",
"num8",
"num9",
"numlock",
"pagedown",
"pageup",
"pause",
"pgdn",
"pgup",
"playpause",
"prevtrack",
"print",
"printscreen",
"prntscrn",
"prtsc",
"prtscr",
"return",
"right",
"scrolllock",
"select",
"separator",
"shift",
"shiftleft",
"shiftright",
"sleep",
"space",
"stop",
"subtract",
"tab",
"up",
"volumedown",
"volumemute",
"volumeup",
"win",
"winleft",
"winright",
"yen",
"command",
"option",
"optionleft",
"optionright",
]
KEYBOARD_KEYS = KEY_NAMES # keeping old KEYBOARD_KEYS for backwards compatibility
# Constants for the mouse button names:
LEFT = "left"
MIDDLE = "middle"
RIGHT = "right"
PRIMARY = "primary"
SECONDARY = "secondary"
# Different keyboard mappings:
# TODO - finish this feature.
# NOTE: Eventually, I'd like to come up with a better system than this. For now, this seems like it works.
QWERTY = r"""`1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?"""
QWERTZ = r"""=1234567890/0qwertzuiop89-asdfghjkl,\yxcvbnm,.7+!@#$%^&*()?)QWERTZUIOP*(_ASDFGHJKL<|YXCVBNM<>&"""
def isShiftCharacter(character):
"""
Returns True if the ``character`` is a keyboard key that would require the shift key to be held down, such as
uppercase letters or the symbols on the keyboard's number row.
"""
# NOTE TODO - This will be different for non-qwerty keyboards.
return character.isupper() or character in set('~!@#$%^&*()_+{}|:"<>?')
# The platformModule is where we reference the platform-specific functions.
if sys.platform.startswith("java"):
# from . import _pyautogui_java as platformModule
raise NotImplementedError("Jython is not yet supported by PyAutoGUI.")
elif sys.platform == "darwin":
from . import _pyautogui_osx as platformModule
elif sys.platform == "win32":
from . import _pyautogui_win as platformModule
elif platform.system() == "Linux":
from . import _pyautogui_x11 as platformModule
else:
raise NotImplementedError("Your platform (%s) is not supported by PyAutoGUI." % (platform.system()))
# TODO: Having module-wide user-writable global variables is bad. It makes
# restructuring the code very difficult. For instance, what if we decide to
# move the mouse-related functions to a separate file (a submodule)? How that
# file will access this module vars? It will probably lead to a circular
# import.
# In seconds. Any duration less than this is rounded to 0.0 to instantly move
# the mouse.
MINIMUM_DURATION = 0.1
# If sleep_amount is less than MINIMUM_DURATION, time.sleep() will be a no-op and the mouse cursor moves there instantly.
# TODO: This value should vary with the platform. http://stackoverflow.com/q/1133857
MINIMUM_SLEEP = 0.05
# The number of seconds to pause after EVERY public function call. Useful for debugging:
PAUSE = 0.1 # Tenth-second pause by default.
# Interface need some catch up time on darwin (macOS) systems. Possible values probably differ based on your system performance.
# This value affects mouse moveTo, dragTo and key event duration.
# TODO: Find a dynamic way to let the system catch up instead of blocking with a magic number.
DARWIN_CATCH_UP_TIME = 0.01
# If the mouse is over a coordinate in FAILSAFE_POINTS and FAILSAFE is True, the FailSafeException is raised.
# The rest of the points are added to the FAILSAFE_POINTS list at the bottom of this file, after size() has been defined.
# The points are for the corners of the screen, but note that these points don't automatically change if the screen resolution changes.
FAILSAFE = True
FAILSAFE_POINTS = [(0, 0)]
LOG_SCREENSHOTS = False # If True, save screenshots for clicks and key presses.
# If not None, PyAutoGUI deletes old screenshots when this limit has been reached:
LOG_SCREENSHOTS_LIMIT = 10
G_LOG_SCREENSHOTS_FILENAMES = [] # TODO - make this a deque
Point = collections.namedtuple("Point", "x y")
Size = collections.namedtuple("Size", "width height")
def _genericPyAutoGUIChecks(wrappedFunction):
"""
A decorator that calls failSafeCheck() before the decorated function and
_handlePause() after it.
"""
@functools.wraps(wrappedFunction)
def wrapper(*args, **kwargs):
failSafeCheck()
returnVal = wrappedFunction(*args, **kwargs)
_handlePause(kwargs.get("_pause", True))
return returnVal
return wrapper
# General Functions
# =================
def getPointOnLine(x1, y1, x2, y2, n):
"""
Returns an (x, y) tuple of the point that has progressed a proportion ``n`` along the line defined by the two
``x1``, ``y1`` and ``x2``, ``y2`` coordinates.
This function was copied from pytweening module, so that it can be called even if PyTweening is not installed.
"""
x = ((x2 - x1) * n) + x1
y = ((y2 - y1) * n) + y1
return (x, y)
def linear(n):
"""
Returns ``n``, where ``n`` is the float argument between ``0.0`` and ``1.0``. This function is for the default
linear tween for mouse moving functions.
This function was copied from PyTweening module, so that it can be called even if PyTweening is not installed.
"""
# We use this function instead of pytweening.linear for the default tween function just in case pytweening couldn't be imported.
if not 0.0 <= n <= 1.0:
raise PyAutoGUIException("Argument must be between 0.0 and 1.0.")
return n
def _handlePause(_pause):
"""
A helper function for performing a pause at the end of a PyAutoGUI function based on some settings.
If ``_pause`` is ``True``, then sleep for ``PAUSE`` seconds (the global pause setting).
"""
if _pause:
assert isinstance(PAUSE, int) or isinstance(PAUSE, float)
time.sleep(PAUSE)
def _normalizeXYArgs(firstArg, secondArg):
"""
Returns a ``Point`` object based on ``firstArg`` and ``secondArg``, which are the first two arguments passed to
several PyAutoGUI functions. If ``firstArg`` and ``secondArg`` are both ``None``, returns the current mouse cursor
position.
``firstArg`` and ``secondArg`` can be integers, a sequence of integers, or a string representing an image filename
to find on the screen (and return the center coordinates of).
"""
if firstArg is None and secondArg is None:
return position()
elif firstArg is None and secondArg is not None:
return Point(int(position()[0]), int(secondArg))
elif secondArg is None and firstArg is not None and not isinstance(firstArg, Sequence):
return Point(int(firstArg), int(position()[1]))
elif isinstance(firstArg, str):
# If x is a string, we assume it's an image filename to locate on the screen:
try:
location = locateOnScreen(firstArg)
# The following code only runs if pyscreeze.USE_IMAGE_NOT_FOUND_EXCEPTION is not set to True, meaning that
# locateOnScreen() returns None if the image can't be found.
if location is not None:
return center(location)
else:
return None
except pyscreeze.ImageNotFoundException:
raise ImageNotFoundException
return center(locateOnScreen(firstArg))
elif isinstance(firstArg, Sequence):
if len(firstArg) == 2:
# firstArg is a two-integer tuple: (x, y)
if secondArg is None:
return Point(int(firstArg[0]), int(firstArg[1]))
else:
raise PyAutoGUIException(
"When passing a sequence for firstArg, secondArg must not be passed (received {0}).".format(
repr(secondArg)
)
)
elif len(firstArg) == 4:
# firstArg is a four-integer tuple, (left, top, width, height), we should return the center point
if secondArg is None:
return center(firstArg)
else:
raise PyAutoGUIException(
"When passing a sequence for firstArg, secondArg must not be passed and default to None (received {0}).".format(
repr(secondArg)
)
)
else:
raise PyAutoGUIException(
"The supplied sequence must have exactly 2 or exactly 4 elements ({0} were received).".format(
len(firstArg)
)
)
else:
return Point(int(firstArg), int(secondArg)) # firstArg and secondArg are just x and y number values
def _logScreenshot(logScreenshot, funcName, funcArgs, folder="."):
"""
A helper function that creates a screenshot to act as a logging mechanism. When a PyAutoGUI function is called,
this function is also called to capture the state of the screen when that function was called.
If ``logScreenshot`` is ``False`` (or None and the ``LOG_SCREENSHOTS`` constant is ``False``), no screenshot is taken.
The ``funcName`` argument is a string of the calling function's name. It's used in the screenshot's filename.
The ``funcArgs`` argument is a string describing the arguments passed to the calling function. It's limited to
twelve characters to keep it short.
The ``folder`` argument is the folder to place the screenshot file in, and defaults to the current working directory.
"""
if not logScreenshot:
return # Don't take a screenshot.
if logScreenshot is None and LOG_SCREENSHOTS is False:
return # Don't take a screenshot.
# Ensure that the "specifics" string isn't too long for the filename:
if len(funcArgs) > 12:
funcArgs = funcArgs[:12] + "..."
now = datetime.datetime.now()
filename = "%s-%s-%s_%s-%s-%s-%s_%s_%s.png" % (
now.year,
str(now.month).rjust(2, "0"),
str(now.day).rjust(2, "0"),
now.hour,
now.minute,
now.second,
str(now.microsecond)[:3],
funcName,
funcArgs,
)
filepath = os.path.join(folder, filename)
# Delete the oldest screenshot if we've reached the maximum:
if (LOG_SCREENSHOTS_LIMIT is not None) and (len(G_LOG_SCREENSHOTS_FILENAMES) >= LOG_SCREENSHOTS_LIMIT):
os.unlink(os.path.join(folder, G_LOG_SCREENSHOTS_FILENAMES[0]))
del G_LOG_SCREENSHOTS_FILENAMES[0]
screenshot(filepath)
G_LOG_SCREENSHOTS_FILENAMES.append(filename)
def position(x=None, y=None):
"""
Returns the current xy coordinates of the mouse cursor as a two-integer tuple.
Args:
x (int, None, optional) - If not None, this argument overrides the x in
the return value.
y (int, None, optional) - If not None, this argument overrides the y in
the return value.
Returns:
(x, y) tuple of the current xy coordinates of the mouse cursor.
NOTE: The position() function doesn't check for failsafe.
"""
posx, posy = platformModule._position()
posx = int(posx)
posy = int(posy)
if x is not None: # If set, the x parameter overrides the return value.
posx = int(x)
if y is not None: # If set, the y parameter overrides the return value.
posy = int(y)
return Point(posx, posy)
def size():
"""Returns the width and height of the screen as a two-integer tuple.
Returns:
(width, height) tuple of the screen size, in pixels.
"""
return Size(*platformModule._size())
resolution = size # resolution() is an alias for size()
def onScreen(x, y=None):
"""Returns whether the given xy coordinates are on the primary screen or not.
Note that this function doesn't work for secondary screens.
Args:
Either the arguments are two separate values, first arg for x and second
for y, or there is a single argument of a sequence with two values, the
first x and the second y.
Example: onScreen(x, y) or onScreen([x, y])
Returns:
bool: True if the xy coordinates are on the screen at its current
resolution, otherwise False.
"""
x, y = _normalizeXYArgs(x, y)
x = int(x)
y = int(y)
width, height = platformModule._size()
return 0 <= x < width and 0 <= y < height
# Mouse Functions
# ===============
"""
NOTE: Although "mouse1" and "mouse2" buttons usually refer to the left and
right mouse buttons respectively, in PyAutoGUI 1, 2, and 3 refer to the left,
middle, and right buttons, respectively. This is because Xlib interprets
button 2 as the middle button and button 3 as the right button, so we hold
that for Windows and macOS as well (since those operating systems don't use
button numbers but rather just "left" or "right").
"""
def _normalizeButton(button):
"""
The left, middle, and right mouse buttons are button numbers 1, 2, and 3 respectively. This is the numbering that
Xlib on Linux uses (while Windows and macOS don't care about numbers; they just use "left" and "right").
This function takes one of ``LEFT``, ``MIDDLE``, ``RIGHT``, ``PRIMARY``, ``SECONDARY``, ``1``, ``2``, ``3``, ``4``,
``5``, ``6``, or ``7`` for the button argument and returns either ``LEFT``, ``MIDDLE``, ``RIGHT``, ``4``, ``5``,
``6``, or ``7``. The ``PRIMARY``, ``SECONDARY``, ``1``, ``2``, and ``3`` values are never returned.
The ``'left'`` and ``'right'`` mouse buttons will always refer to the physical left and right
buttons on the mouse. The same applies for buttons 1 and 3.
However, if ``button`` is ``'primary'`` or ``'secondary'``, then we must check if
the mouse buttons have been "swapped" (for left-handed users) by the operating system's mouse
settings.
If the buttons are swapped, the primary button is the right mouse button and the secondary button is the left mouse
button. If not swapped, the primary and secondary buttons are the left and right buttons, respectively.
NOTE: Swap detection has not been implemented yet.
"""
# TODO - The swap detection hasn't been done yet. For Windows, see https://stackoverflow.com/questions/45627956/check-if-mouse-buttons-are-swapped-or-not-in-c
# TODO - We should check the OS settings to see if it's a left-hand setup, where button 1 would be "right".
# Check that `button` has a valid value:
button = button.lower()
if platform.system() == "Linux":
# Check for valid button arg on Linux:
if button not in (LEFT, MIDDLE, RIGHT, PRIMARY, SECONDARY, 1, 2, 3, 4, 5, 6, 7):
raise PyAutoGUIException(
"button argument must be one of ('left', 'middle', 'right', 'primary', 'secondary', 1, 2, 3, 4, 5, 6, 7)"
)
else:
# Check for valid button arg on Windows and macOS:
if button not in (LEFT, MIDDLE, RIGHT, PRIMARY, SECONDARY, 1, 2, 3):
raise PyAutoGUIException(
"button argument must be one of ('left', 'middle', 'right', 'primary', 'secondary', 1, 2, 3)"
)
# TODO - Check if the primary/secondary mouse buttons have been swapped:
if button in (PRIMARY, SECONDARY):
swapped = platformModule._mouse_is_swapped()
if swapped:
if button == PRIMARY:
return RIGHT
elif button == SECONDARY:
return LEFT
else:
if button == PRIMARY:
return LEFT
elif button == SECONDARY:
return RIGHT
# Return a mouse button integer value, not a string like 'left':
return {LEFT: LEFT, MIDDLE: MIDDLE, RIGHT: RIGHT, 1: LEFT, 2: MIDDLE, 3: RIGHT, 4: 4, 5: 5, 6: 6, 7: 7}[button]
@_genericPyAutoGUIChecks
def mouseDown(x=None, y=None, button=PRIMARY, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs pressing a mouse button down (but not up).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
mouse down happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
mouse down happens. None by default.
button (str, int, optional): The mouse button pressed down. TODO
Returns:
None
Raises:
PyAutoGUIException: If button is not one of 'left', 'middle', 'right', 1, 2, or 3
"""
button = _normalizeButton(button)
x, y = _normalizeXYArgs(x, y)
_mouseMoveDrag("move", x, y, 0, 0, duration=0, tween=None)
_logScreenshot(logScreenshot, "mouseDown", "%s,%s" % (x, y), folder=".")
platformModule._mouseDown(x, y, button)
@_genericPyAutoGUIChecks
def mouseUp(x=None, y=None, button=PRIMARY, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs releasing a mouse button up (but not down beforehand).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
mouse up happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
mouse up happens. None by default.
button (str, int, optional): The mouse button released. TODO
Returns:
None
Raises:
PyAutoGUIException: If button is not one of 'left', 'middle', 'right', 1, 2, or 3
"""
button = _normalizeButton(button)
x, y = _normalizeXYArgs(x, y)
_mouseMoveDrag("move", x, y, 0, 0, duration=0, tween=None)
_logScreenshot(logScreenshot, "mouseUp", "%s,%s" % (x, y), folder=".")
platformModule._mouseUp(x, y, button)
@_genericPyAutoGUIChecks
def click(
x=None, y=None, clicks=1, interval=0.0, button=PRIMARY, duration=0.0, tween=linear, logScreenshot=None, _pause=True
):
"""
Performs pressing a mouse button down and then immediately releasing it. Returns ``None``.
When no arguments are passed, the primary mouse button is clicked at the mouse cursor's current location.
If integers for ``x`` and ``y`` are passed, the click will happen at that XY coordinate. If ``x`` is a string, the
string is an image filename that PyAutoGUI will attempt to locate on the screen and click the center of. If ``x``
is a sequence of two coordinates, those coordinates will be used for the XY coordinate to click on.
The ``clicks`` argument is an int of how many clicks to make, and defaults to ``1``.
The ``interval`` argument is an int or float of how many seconds to wait in between each click, if ``clicks`` is
greater than ``1``. It defaults to ``0.0`` for no pause in between clicks.
The ``button`` argument is one of the constants ``LEFT``, ``MIDDLE``, ``RIGHT``, ``PRIMARY``, or ``SECONDARY``.
It defaults to ``PRIMARY`` (which is the left mouse button, unless the operating system has been set for
left-handed users.)
If ``x`` and ``y`` are specified, and the click is not happening at the mouse cursor's current location, then
the ``duration`` argument is an int or float of how many seconds it should take to move the mouse to the XY
coordinates. It defaults to ``0`` for an instant move.
If ``x`` and ``y`` are specified and ``duration`` is not ``0``, the ``tween`` argument is a tweening function
that specifies the movement pattern of the mouse cursor as it moves to the XY coordinates. The default is a
simple linear tween. See the PyTweening module documentation for more details.
The ``pause`` parameter is deprecated. Call the ``pyautogui.sleep()`` function to implement a pause.
Raises:
PyAutoGUIException: If button is not one of 'left', 'middle', 'right', 1, 2, 3
"""
# TODO: I'm leaving buttons 4, 5, 6, and 7 undocumented for now. I need to understand how they work.
button = _normalizeButton(button)
x, y = _normalizeXYArgs(x, y)
# Move the mouse cursor to the x, y coordinate:
_mouseMoveDrag("move", x, y, 0, 0, duration, tween)
_logScreenshot(logScreenshot, "click", "%s,%s,%s,%s" % (button, clicks, x, y), folder=".")
if sys.platform == 'darwin':
for i in range(clicks):
failSafeCheck()
if button in (LEFT, MIDDLE, RIGHT):
platformModule._multiClick(x, y, button, 1, interval)
else:
for i in range(clicks):
failSafeCheck()
if button in (LEFT, MIDDLE, RIGHT):
platformModule._click(x, y, button)
time.sleep(interval)
@_genericPyAutoGUIChecks
def leftClick(x=None, y=None, interval=0.0, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs a left mouse button click.
This is a wrapper function for click('left', x, y).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
interval (float, optional): The number of seconds in between each click,
if the number of clicks is greater than 1. 0.0 by default, for no
pause in between clicks.
Returns:
None
"""
# TODO - Do we need the decorator for this function? Should click() handle this? (Also applies to other alias functions.)
click(x, y, 1, interval, LEFT, duration, tween, logScreenshot, _pause=_pause)
@_genericPyAutoGUIChecks
def rightClick(x=None, y=None, interval=0.0, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs a right mouse button click.
This is a wrapper function for click('right', x, y).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
interval (float, optional): The number of seconds in between each click,
if the number of clicks is greater than 1. 0.0 by default, for no
pause in between clicks.
Returns:
None
"""
click(x, y, 1, interval, RIGHT, duration, tween, logScreenshot, _pause=_pause)
@_genericPyAutoGUIChecks
def middleClick(x=None, y=None, interval=0.0, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs a middle mouse button click.
This is a wrapper function for click('middle', x, y).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
Returns:
None
"""
click(x, y, 1, interval, MIDDLE, duration, tween, logScreenshot, _pause=_pause)
@_genericPyAutoGUIChecks
def doubleClick(x=None, y=None, interval=0.0, button=LEFT, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs a double click.
This is a wrapper function for click('left', x, y, 2, interval).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
interval (float, optional): The number of seconds in between each click,
if the number of clicks is greater than 1. 0.0 by default, for no
pause in between clicks.
button (str, int, optional): The mouse button released. TODO
Returns:
None
Raises:
PyAutoGUIException: If button is not one of 'left', 'middle', 'right', 1, 2, 3, 4,
5, 6, or 7
"""
# Multiple clicks work different in OSX
if sys.platform == "darwin":
x, y = _normalizeXYArgs(x, y)
_mouseMoveDrag("move", x, y, 0, 0, duration=0, tween=None)
x, y = platformModule._position()
platformModule._multiClick(x, y, button, 2)
_logScreenshot(logScreenshot, 'click', '%s,%s,%s,2' % (x, y, button), folder='.')
else:
# Click for Windows or Linux:
click(x, y, 2, interval, button, duration, tween, logScreenshot, _pause=False)
@_genericPyAutoGUIChecks
def tripleClick(x=None, y=None, interval=0.0, button=LEFT, duration=0.0, tween=linear, logScreenshot=None, _pause=True):
"""Performs a triple click.
This is a wrapper function for click('left', x, y, 3, interval).
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
interval (float, optional): The number of seconds in between each click,
if the number of clicks is greater than 1. 0.0 by default, for no
pause in between clicks.
button (str, int, optional): The mouse button released. TODO
Returns:
None
Raises:
PyAutoGUIException: If button is not one of 'left', 'middle', 'right', 1, 2, 3, 4,
5, 6, or 7
"""
# Multiple clicks work different in OSX
if sys.platform == "darwin":
x, y = _normalizeXYArgs(x, y)
_mouseMoveDrag("move", x, y, 0, 0, duration=0, tween=None)
x, y = platformModule._position()
_logScreenshot(logScreenshot, "click", "%s,%s,%s,3" % (x, y, button), folder=".")
platformModule._multiClick(x, y, button, 3)
else:
# Click for Windows or Linux:
click(x, y, 3, interval, button, duration, tween, logScreenshot, _pause=False)
@_genericPyAutoGUIChecks
def scroll(clicks, x=None, y=None, logScreenshot=None, _pause=True):
"""Performs a scroll of the mouse scroll wheel.
Whether this is a vertical or horizontal scroll depends on the underlying
operating system.
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
clicks (int, float): The amount of scrolling to perform.
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
Returns:
None
"""
if type(x) in (tuple, list):
x, y = x[0], x[1]
x, y = position(x, y)
_logScreenshot(logScreenshot, "scroll", "%s,%s,%s" % (clicks, x, y), folder=".")
platformModule._scroll(clicks, x, y)
@_genericPyAutoGUIChecks
def hscroll(clicks, x=None, y=None, logScreenshot=None, _pause=True):
"""Performs an explicitly horizontal scroll of the mouse scroll wheel,
if this is supported by the operating system. (Currently just Linux.)
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
clicks (int, float): The amount of scrolling to perform.
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
Returns:
None
"""
if type(x) in (tuple, list):
x, y = x[0], x[1]
x, y = position(x, y)
_logScreenshot(logScreenshot, "hscroll", "%s,%s,%s" % (clicks, x, y), folder=".")
platformModule._hscroll(clicks, x, y)
@_genericPyAutoGUIChecks
def vscroll(clicks, x=None, y=None, logScreenshot=None, _pause=True):
"""Performs an explicitly vertical scroll of the mouse scroll wheel,
if this is supported by the operating system. (Currently just Linux.)
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
clicks (int, float): The amount of scrolling to perform.
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
Returns:
None
"""
if type(x) in (tuple, list):
x, y = x[0], x[1]
x, y = position(x, y)
_logScreenshot(logScreenshot, "vscroll", "%s,%s,%s" % (clicks, x, y), folder=".")
platformModule._vscroll(clicks, x, y)
@_genericPyAutoGUIChecks
def moveTo(x=None, y=None, duration=0.0, tween=linear, logScreenshot=False, _pause=True):
"""Moves the mouse cursor to a point on the screen.
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): The x position on the screen where the
click happens. None by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): The y position on the screen where the
click happens. None by default.
duration (float, optional): The amount of time it takes to move the mouse
cursor to the xy coordinates. If 0, then the mouse cursor is moved
instantaneously. 0.0 by default.
tween (func, optional): The tweening function used if the duration is not
0. A linear tween is used by default.
Returns:
None
"""
x, y = _normalizeXYArgs(x, y)
_logScreenshot(logScreenshot, "moveTo", "%s,%s" % (x, y), folder=".")
_mouseMoveDrag("move", x, y, 0, 0, duration, tween)
@_genericPyAutoGUIChecks
def moveRel(xOffset=None, yOffset=None, duration=0.0, tween=linear, logScreenshot=False, _pause=True):
"""Moves the mouse cursor to a point on the screen, relative to its current
position.
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): How far left (for negative values) or
right (for positive values) to move the cursor. 0 by default. If tuple, this is used for x and y.
y (int, float, None, optional): How far up (for negative values) or
down (for positive values) to move the cursor. 0 by default.
duration (float, optional): The amount of time it takes to move the mouse
cursor to the new xy coordinates. If 0, then the mouse cursor is moved
instantaneously. 0.0 by default.
tween (func, optional): The tweening function used if the duration is not
0. A linear tween is used by default.
Returns:
None
"""
xOffset, yOffset = _normalizeXYArgs(xOffset, yOffset)
_logScreenshot(logScreenshot, "moveRel", "%s,%s" % (xOffset, yOffset), folder=".")
_mouseMoveDrag("move", None, None, xOffset, yOffset, duration, tween)
move = moveRel # For PyAutoGUI 1.0, move() replaces moveRel().
@_genericPyAutoGUIChecks
def dragTo(
x=None, y=None, duration=0.0, tween=linear, button=PRIMARY, logScreenshot=None, _pause=True, mouseDownUp=True
):
"""Performs a mouse drag (mouse movement while a button is held down) to a
point on the screen.
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): How far left (for negative values) or
right (for positive values) to move the cursor. 0 by default. If tuple, this is used for x and y.
If x is a str, it's considered a filename of an image to find on
the screen with locateOnScreen() and click the center of.
y (int, float, None, optional): How far up (for negative values) or
down (for positive values) to move the cursor. 0 by default.
duration (float, optional): The amount of time it takes to move the mouse
cursor to the new xy coordinates. If 0, then the mouse cursor is moved
instantaneously. 0.0 by default.
tween (func, optional): The tweening function used if the duration is not
0. A linear tween is used by default.
button (str, int, optional): The mouse button released. TODO
mouseDownUp (True, False): When true, the mouseUp/Down actions are not performed.
Which allows dragging over multiple (small) actions. 'True' by default.
Returns:
None
"""
x, y = _normalizeXYArgs(x, y)
_logScreenshot(logScreenshot, "dragTo", "%s,%s" % (x, y), folder=".")
if mouseDownUp:
mouseDown(button=button, logScreenshot=False, _pause=False)
_mouseMoveDrag("drag", x, y, 0, 0, duration, tween, button)
if mouseDownUp:
mouseUp(button=button, logScreenshot=False, _pause=False)
@_genericPyAutoGUIChecks
def dragRel(
xOffset=0, yOffset=0, duration=0.0, tween=linear, button=PRIMARY, logScreenshot=None, _pause=True, mouseDownUp=True
):
"""Performs a mouse drag (mouse movement while a button is held down) to a
point on the screen, relative to its current position.
The x and y parameters detail where the mouse event happens. If None, the
current mouse position is used. If a float value, it is rounded down. If
outside the boundaries of the screen, the event happens at edge of the
screen.
Args:
x (int, float, None, tuple, optional): How far left (for negative values) or
right (for positive values) to move the cursor. 0 by default. If tuple, this is used for xOffset and yOffset.
y (int, float, None, optional): How far up (for negative values) or
down (for positive values) to move the cursor. 0 by default.
duration (float, optional): The amount of time it takes to move the mouse
cursor to the new xy coordinates. If 0, then the mouse cursor is moved
instantaneously. 0.0 by default.
tween (func, optional): The tweening function used if the duration is not
0. A linear tween is used by default.
button (str, int, optional): The mouse button released. TODO
mouseDownUp (True, False): When true, the mouseUp/Down actions are not performed.
Which allows dragging over multiple (small) actions. 'True' by default.
Returns:
None
"""
if xOffset is None:
xOffset = 0
if yOffset is None:
yOffset = 0
if type(xOffset) in (tuple, list):
xOffset, yOffset = xOffset[0], xOffset[1]
if xOffset == 0 and yOffset == 0:
return # no-op case
mousex, mousey = platformModule._position()
_logScreenshot(logScreenshot, "dragRel", "%s,%s" % (xOffset, yOffset), folder=".")
if mouseDownUp:
mouseDown(button=button, logScreenshot=False, _pause=False)
_mouseMoveDrag("drag", mousex, mousey, xOffset, yOffset, duration, tween, button)
if mouseDownUp:
mouseUp(button=button, logScreenshot=False, _pause=False)
drag = dragRel # For PyAutoGUI 1.0, we want drag() to replace dragRel().
def _mouseMoveDrag(moveOrDrag, x, y, xOffset, yOffset, duration, tween=linear, button=None):
"""Handles the actual move or drag event, since different platforms
implement them differently.
On Windows & Linux, a drag is a normal mouse move while a mouse button is
held down. On OS X, a distinct "drag" event must be used instead.
The code for moving and dragging the mouse is similar, so this function
handles both. Users should call the moveTo() or dragTo() functions instead
of calling _mouseMoveDrag().
Args:
moveOrDrag (str): Either 'move' or 'drag', for the type of action this is.
x (int, float, None, optional): How far left (for negative values) or
right (for positive values) to move the cursor. 0 by default.
y (int, float, None, optional): How far up (for negative values) or
down (for positive values) to move the cursor. 0 by default.
xOffset (int, float, None, optional): How far left (for negative values) or
right (for positive values) to move the cursor. 0 by default.
yOffset (int, float, None, optional): How far up (for negative values) or
down (for positive values) to move the cursor. 0 by default.
duration (float, optional): The amount of time it takes to move the mouse
cursor to the new xy coordinates. If 0, then the mouse cursor is moved
instantaneously. 0.0 by default.
tween (func, optional): The tweening function used if the duration is not
0. A linear tween is used by default.
button (str, int, optional): The mouse button released. TODO
Returns:
None
"""
# The move and drag code is similar, but OS X requires a special drag event instead of just a move event when dragging.
# See https://stackoverflow.com/a/2696107/1893164
assert moveOrDrag in ("move", "drag"), "moveOrDrag must be in ('move', 'drag'), not %s" % (moveOrDrag)
if sys.platform != "darwin":
moveOrDrag = "move" # Only OS X needs the drag event specifically.
xOffset = int(xOffset) if xOffset is not None else 0
yOffset = int(yOffset) if yOffset is not None else 0
if x is None and y is None and xOffset == 0 and yOffset == 0:
return # Special case for no mouse movement at all.
startx, starty = position()
x = int(x) if x is not None else startx
y = int(y) if y is not None else starty
# x, y, xOffset, yOffset are now int.
x += xOffset
y += yOffset
width, height = size()
# Make sure x and y are within the screen bounds.
# x = max(0, min(x, width - 1))
# y = max(0, min(y, height - 1))
# If the duration is small enough, just move the cursor there instantly.
steps = [(x, y)]
if duration > MINIMUM_DURATION:
# Non-instant moving/dragging involves tweening:
num_steps = max(width, height)
sleep_amount = duration / num_steps
if sleep_amount < MINIMUM_SLEEP:
num_steps = int(duration / MINIMUM_SLEEP)
sleep_amount = duration / num_steps
steps = [getPointOnLine(startx, starty, x, y, tween(n / num_steps)) for n in range(num_steps)]
# Making sure the last position is the actual destination.
steps.append((x, y))
for tweenX, tweenY in steps:
if len(steps) > 1:
# A single step does not require tweening.
time.sleep(sleep_amount)
tweenX = int(round(tweenX))
tweenY = int(round(tweenY))
# Do a fail-safe check to see if the user moved the mouse to a fail-safe position, but not if the mouse cursor
# moved there as a result of this function. (Just because tweenX and tweenY aren't in a fail-safe position
# doesn't mean the user couldn't have moved the mouse cursor to a fail-safe position.)
if (tweenX, tweenY) not in FAILSAFE_POINTS:
failSafeCheck()
if moveOrDrag == "move":
platformModule._moveTo(tweenX, tweenY)
elif moveOrDrag == "drag":
platformModule._dragTo(tweenX, tweenY, button)
else:
raise NotImplementedError("Unknown value of moveOrDrag: {0}".format(moveOrDrag))
if (tweenX, tweenY) not in FAILSAFE_POINTS:
failSafeCheck()
# Keyboard Functions
# ==================
def isValidKey(key):
"""Returns a Boolean value if the given key is a valid value to pass to
PyAutoGUI's keyboard-related functions for the current platform.
This function is here because passing an invalid value to the PyAutoGUI
keyboard functions currently is a no-op that does not raise an exception.
Some keys are only valid on some platforms. For example, while 'esc' is
valid for the Escape key on all platforms, 'browserback' is only used on
Windows operating systems.
Args:
key (str): The key value.
Returns:
bool: True if key is a valid value, False if not.
"""
return platformModule.keyboardMapping.get(key, None) is not None
@_genericPyAutoGUIChecks
def keyDown(key, logScreenshot=None, _pause=True):
"""Performs a keyboard key press without the release. This will put that
key in a held down state.
NOTE: For some reason, this does not seem to cause key repeats like would
happen if a keyboard key was held down on a text field.
Args:
key (str): The key to be pressed down. The valid names are listed in
KEYBOARD_KEYS.
Returns:
None
"""
if len(key) > 1:
key = key.lower()
_logScreenshot(logScreenshot, "keyDown", key, folder=".")
platformModule._keyDown(key)
@_genericPyAutoGUIChecks
def keyUp(key, logScreenshot=None, _pause=True):
"""Performs a keyboard key release (without the press down beforehand).
Args:
key (str): The key to be released up. The valid names are listed in
KEYBOARD_KEYS.
Returns:
None
"""
if len(key) > 1:
key = key.lower()
_logScreenshot(logScreenshot, "keyUp", key, folder=".")
platformModule._keyUp(key)
@_genericPyAutoGUIChecks
def press(keys, presses=1, interval=0.0, logScreenshot=None, _pause=True):
"""Performs a keyboard key press down, followed by a release.
Args:
key (str, list): The key to be pressed. The valid names are listed in
KEYBOARD_KEYS. Can also be a list of such strings.
presses (integer, optional): The number of press repetitions.
1 by default, for just one press.
interval (float, optional): How many seconds between each press.
0.0 by default, for no pause between presses.
pause (float, optional): How many seconds in the end of function process.
None by default, for no pause in the end of function process.
Returns:
None
"""
if type(keys) == str:
if len(keys) > 1:
keys = keys.lower()
keys = [keys] # If keys is 'enter', convert it to ['enter'].
else:
lowerKeys = []
for s in keys:
if len(s) > 1:
lowerKeys.append(s.lower())
else:
lowerKeys.append(s)
keys = lowerKeys
interval = float(interval)
_logScreenshot(logScreenshot, "press", ",".join(keys), folder=".")
for i in range(presses):
for k in keys:
failSafeCheck()
platformModule._keyDown(k)
platformModule._keyUp(k)
time.sleep(interval)
@contextmanager
@_genericPyAutoGUIChecks
def hold(keys, logScreenshot=None, _pause=True):
"""Context manager that performs a keyboard key press down upon entry,
followed by a release upon exit.
Args:
key (str, list): The key to be pressed. The valid names are listed in
KEYBOARD_KEYS. Can also be a list of such strings.
pause (float, optional): How many seconds in the end of function process.
None by default, for no pause in the end of function process.
Returns:
None
"""
if type(keys) == str:
if len(keys) > 1:
keys = keys.lower()
keys = [keys] # If keys is 'enter', convert it to ['enter'].
else:
lowerKeys = []
for s in keys:
if len(s) > 1:
lowerKeys.append(s.lower())
else:
lowerKeys.append(s)
keys = lowerKeys
_logScreenshot(logScreenshot, "press", ",".join(keys), folder=".")
for k in keys:
failSafeCheck()
platformModule._keyDown(k)
try:
yield
finally:
for k in keys:
failSafeCheck()
platformModule._keyUp(k)
@_genericPyAutoGUIChecks
def typewrite(message, interval=0.0, logScreenshot=None, _pause=True):
"""Performs a keyboard key press down, followed by a release, for each of
the characters in message.
The message argument can also be list of strings, in which case any valid
keyboard name can be used.
Since this performs a sequence of keyboard presses and does not hold down
keys, it cannot be used to perform keyboard shortcuts. Use the hotkey()
function for that.
Args:
message (str, list): If a string, then the characters to be pressed. If a
list, then the key names of the keys to press in order. The valid names
are listed in KEYBOARD_KEYS.
interval (float, optional): The number of seconds in between each press.
0.0 by default, for no pause in between presses.
Returns:
None
"""
interval = float(interval) # TODO - this should be taken out.
_logScreenshot(logScreenshot, "write", message, folder=".")
for c in message:
if len(c) > 1:
c = c.lower()
press(c, _pause=False)
time.sleep(interval)
failSafeCheck()
write = typewrite # In PyAutoGUI 1.0, write() replaces typewrite().
@_genericPyAutoGUIChecks
def hotkey(*args, **kwargs):
"""Performs key down presses on the arguments passed in order, then performs
key releases in reverse order.
The effect is that calling hotkey('ctrl', 'shift', 'c') would perform a
"Ctrl-Shift-C" hotkey/keyboard shortcut press.
Args:
key(s) (str): The series of keys to press, in order. This can also be a
list of key strings to press.
interval (float, optional): The number of seconds in between each press.
0.0 by default, for no pause in between presses.
Returns:
None
"""
interval = float(kwargs.get("interval", 0.0)) # TODO - this should be taken out.
if len(args) and isinstance(args[0], Sequence) and not isinstance(args[0], str):
# Let the user pass a list of strings
args = tuple(args[0])
_logScreenshot(kwargs.get("logScreenshot"), "hotkey", ",".join(args), folder=".")
for c in args:
if len(c) > 1:
c = c.lower()
platformModule._keyDown(c)
time.sleep(interval)
for c in reversed(args):
if len(c) > 1:
c = c.lower()
platformModule._keyUp(c)
time.sleep(interval)
shortcut = hotkey # shortcut() is an alias for htotkey()
def failSafeCheck():
if FAILSAFE and tuple(position()) in FAILSAFE_POINTS:
raise FailSafeException(
"PyAutoGUI fail-safe triggered from mouse moving to a corner of the screen. To disable this fail-safe, set pyautogui.FAILSAFE to False. DISABLING FAIL-SAFE IS NOT RECOMMENDED."
)
def displayMousePosition(xOffset=0, yOffset=0):
"""This function is meant to be run from the command line. It will
automatically display the location and RGB of the mouse cursor."""
try:
runningIDLE = sys.stdin.__module__.startswith("idlelib")
except AttributeError:
runningIDLE = False
print("Press Ctrl-C to quit.")
if xOffset != 0 or yOffset != 0:
print("xOffset: %s yOffset: %s" % (xOffset, yOffset))
try:
while True:
# Get and print the mouse coordinates.
x, y = position()
positionStr = "X: " + str(x - xOffset).rjust(4) + " Y: " + str(y - yOffset).rjust(4)
if not onScreen(x - xOffset, y - yOffset) or sys.platform == "darwin":
# Pixel color can only be found for the primary monitor, and also not on mac due to the screenshot having the mouse cursor in the way.
pixelColor = ("NaN", "NaN", "NaN")
else:
pixelColor = pyscreeze.screenshot().getpixel(
(x, y)
) # NOTE: On Windows & Linux, getpixel() returns a 3-integer tuple, but on macOS it returns a 4-integer tuple.
positionStr += " RGB: (" + str(pixelColor[0]).rjust(3)
positionStr += ", " + str(pixelColor[1]).rjust(3)
positionStr += ", " + str(pixelColor[2]).rjust(3) + ")"
sys.stdout.write(positionStr)
if not runningIDLE:
# If this is a terminal, than we can erase the text by printing \b backspaces.
sys.stdout.write("\b" * len(positionStr))
else:
# If this isn't a terminal (i.e. IDLE) then we can only append more text. Print a newline instead and pause a second (so we don't send too much output).
sys.stdout.write("\n")
time.sleep(1)
sys.stdout.flush()
except KeyboardInterrupt:
sys.stdout.write("\n")
sys.stdout.flush()
def _snapshot(tag, folder=None, region=None, radius=None):
# TODO feature not finished
if region is not None and radius is not None:
raise Exception("Either region or radius arguments (or neither) can be passed to snapshot, but not both")
if radius is not None:
x, y = platformModule._position()
if folder is None:
folder = os.getcwd()
now = datetime.datetime.now()
filename = "%s-%s-%s_%s-%s-%s-%s_%s.png" % (
now.year,
str(now.month).rjust(2, "0"),
str(now.day).rjust(2, "0"),
now.hour,
now.minute,
now.second,
str(now.microsecond)[:3],
tag,
)
filepath = os.path.join(folder, filename)
screenshot(filepath)
def sleep(seconds):
time.sleep(seconds)
def countdown(seconds):
for i in range(seconds, 0, -1):
print(str(i), end=" ", flush=True)
time.sleep(1)
print()
def _getNumberToken(commandStr):
"""Gets the number token at the start of commandStr.
Given '5hello' returns '5'
Given ' 5hello' returns ' 5'
Given '-42hello' returns '-42'
Given '+42hello' returns '+42'
Given '3.14hello' returns '3.14'
Raises an exception if it can't tokenize a number.
"""
pattern = re.compile(r"^(\s*(\+|\-)?\d+(\.\d+)?)")
mo = pattern.search(commandStr)
if mo is None:
raise PyAutoGUIException("Invalid command at index 0: a number was expected")
return mo.group(1)
def _getQuotedStringToken(commandStr):
"""Gets the quoted string token at the start of commandStr.
The quoted string must use single quotes.
Given "'hello'world" returns "'hello'"
Given " 'hello'world" returns " 'hello'"
Raises an exception if it can't tokenize a quoted string.
"""
pattern = re.compile(r"^((\s*)('(.*?)'))")
mo = pattern.search(commandStr)
if mo is None:
raise PyAutoGUIException("Invalid command at index 0: a quoted string was expected")
return mo.group(1)
def _getParensCommandStrToken(commandStr):
"""Gets the command string token at the start of commandStr. It will also
be enclosed with parentheses.
Given "(ccc)world" returns "(ccc)"
Given " (ccc)world" returns " (ccc)"
Given "(ccf10(r))world" returns "(ccf10(r))"
Raises an exception if it can't tokenize a quoted string.
"""
# Check to make sure at least one open parenthesis exists:
pattern = re.compile(r"^\s*\(")
mo = pattern.search(commandStr)
if mo is None:
raise PyAutoGUIException("Invalid command at index 0: No open parenthesis found.")
# Check to make sure the parentheses are balanced:
i = 0
openParensCount = 0
while i < len(commandStr):
if commandStr[i] == "(":
openParensCount += 1
elif commandStr[i] == ")":
openParensCount -= 1
if openParensCount == 0:
i += 1 # Remember to increment i past the ) before breaking.
break
elif openParensCount == -1:
raise PyAutoGUIException("Invalid command at index 0: No open parenthesis for this close parenthesis.")
i += 1
if openParensCount > 0:
raise PyAutoGUIException("Invalid command at index 0: Not enough close parentheses.")
return commandStr[0:i]
def _getCommaToken(commandStr):
"""Gets the comma token at the start of commandStr.
Given ',' returns ','
Given ' ,', returns ' ,'
Raises an exception if a comma isn't found.
"""
pattern = re.compile(r"^((\s*),)")
mo = pattern.search(commandStr)
if mo is None:
raise PyAutoGUIException("Invalid command at index 0: a comma was expected")
return mo.group(1)
def _tokenizeCommandStr(commandStr):
"""Tokenizes commandStr into a list of commands and their arguments for
the run() function. Returns the list."""
commandPattern = re.compile(r"^(su|sd|ss|c|l|m|r|g|d|k|w|h|f|s|a|p)")
# Tokenize the command string.
commandList = []
i = 0 # Points to the current index in commandStr that is being tokenized.
while i < len(commandStr):
if commandStr[i] in (" ", "\t", "\n", "\r"):
# Skip over whitespace:
i += 1
continue
mo = commandPattern.match(commandStr[i:])
if mo is None:
raise PyAutoGUIException("Invalid command at index %s: %s is not a valid command" % (i, commandStr[i]))
individualCommand = mo.group(1)
commandList.append(individualCommand)
i += len(individualCommand)
# Handle the no argument commands (c, l, m, r, su, sd, ss):
if individualCommand in ("c", "l", "m", "r", "su", "sd", "ss"):
pass # This just exists so these commands are covered by one of these cases.
# Handle the arguments of the mouse (g)o and mouse (d)rag commands:
elif individualCommand in ("g", "d"):
try:
x = _getNumberToken(commandStr[i:])
i += len(x) # Increment past the x number.
comma = _getCommaToken(commandStr[i:])
i += len(comma) # Increment past the comma (and any whitespace).
y = _getNumberToken(commandStr[i:])
i += len(y) # Increment past the y number.
except PyAutoGUIException as excObj:
# Exception message starts with something like "Invalid command at index 0:"
# Change the index number and reraise it.
indexPart, colon, message = str(excObj).partition(":")
indexNum = indexPart[len("Invalid command at index ") :]
newIndexNum = int(indexNum) + i
raise PyAutoGUIException("Invalid command at index %s:%s" % (newIndexNum, message))
# Make sure either both x and y have +/- or neither of them do:
if x.lstrip()[0].isdecimal() and not y.lstrip()[0].isdecimal():
raise PyAutoGUIException("Invalid command at index %s: Y has a +/- but X does not." % (i - len(y)))
if not x.lstrip()[0].isdecimal() and y.lstrip()[0].isdecimal():
raise PyAutoGUIException(
"Invalid command at index %s: Y does not have a +/- but X does." % (i - len(y))
)
# Get rid of any whitespace at the front:
commandList.append(x.lstrip())
commandList.append(y.lstrip())
# Handle the arguments of the (s)leep and (p)ause commands:
elif individualCommand in ("s", "p"):
try:
num = _getNumberToken(commandStr[i:])
i += len(num) # Increment past the number.
# TODO - raise an exception if a + or - is in the number.
except PyAutoGUIException as excObj:
# Exception message starts with something like "Invalid command at index 0:"
# Change the index number and reraise it.
indexPart, colon, message = str(excObj).partition(":")
indexNum = indexPart[len("Invalid command at index ") :]
newIndexNum = int(indexNum) + i
raise PyAutoGUIException("Invalid command at index %s:%s" % (newIndexNum, message))
# Get rid of any whitespace at the front:
commandList.append(num.lstrip())
# Handle the arguments of the (k)ey press, (w)rite, (h)otkeys, and (a)lert commands:
elif individualCommand in ("k", "w", "h", "a"):
try:
quotedString = _getQuotedStringToken(commandStr[i:])
i += len(quotedString) # Increment past the quoted string.
except PyAutoGUIException as excObj:
# Exception message starts with something like "Invalid command at index 0:"
# Change the index number and reraise it.
indexPart, colon, message = str(excObj).partition(":")
indexNum = indexPart[len("Invalid command at index ") :]
newIndexNum = int(indexNum) + i
raise PyAutoGUIException("Invalid command at index %s:%s" % (newIndexNum, message))
# Get rid of any whitespace at the front and the quotes:
commandList.append(quotedString[1:-1].lstrip())
# Handle the arguments of the (f)or loop command:
elif individualCommand == "f":
try:
numberOfLoops = _getNumberToken(commandStr[i:])
i += len(numberOfLoops) # Increment past the number of loops.
subCommandStr = _getParensCommandStrToken(commandStr[i:])
i += len(subCommandStr) # Increment past the sub-command string.
except PyAutoGUIException as excObj:
# Exception message starts with something like "Invalid command at index 0:"
# Change the index number and reraise it.
indexPart, colon, message = str(excObj).partition(":")
indexNum = indexPart[len("Invalid command at index ") :]
newIndexNum = int(indexNum) + i
raise PyAutoGUIException("Invalid command at index %s:%s" % (newIndexNum, message))
# Get rid of any whitespace at the front:
commandList.append(numberOfLoops.lstrip())
# Get rid of any whitespace at the front and the quotes:
subCommandStr = subCommandStr.lstrip()[1:-1]
# Recursively call this function and append the list it returns:
commandList.append(_tokenizeCommandStr(subCommandStr))
return commandList
def _runCommandList(commandList, _ssCount):
global PAUSE
i = 0
while i < len(commandList):
command = commandList[i]
if command == "c":
click(button=PRIMARY)
elif command == "l":
click(button=LEFT)
elif command == "m":
click(button=MIDDLE)
elif command == "r":
click(button=RIGHT)
elif command == "su":
scroll(1) # scroll up
elif command == "sd":
scroll(-1) # scroll down
elif command == "ss":
screenshot("screenshot%s.png" % (_ssCount[0]))
_ssCount[0] += 1
elif command == "s":
sleep(float(commandList[i + 1]))
i += 1
elif command == "p":
PAUSE = float(commandList[i + 1])
i += 1
elif command == "g":
if commandList[i + 1][0] in ("+", "-") and commandList[i + 2][0] in ("+", "-"):
move(int(commandList[i + 1]), int(commandList[i + 2]))
else:
moveTo(int(commandList[i + 1]), int(commandList[i + 2]))
i += 2
elif command == "d":
if commandList[i + 1][0] in ("+", "-") and commandList[i + 2][0] in ("+", "-"):
drag(int(commandList[i + 1]), int(commandList[i + 2]))
else:
dragTo(int(commandList[i + 1]), int(commandList[i + 2]))
i += 2
elif command == "k":
press(commandList[i + 1])
i += 1
elif command == "w":
write(commandList[i + 1])
i += 1
elif command == "h":
hotkey(*commandList[i + 1].replace(" ", "").split(","))
i += 1
elif command == "a":
alert(commandList[i + 1])
i += 1
elif command == "f":
for j in range(int(commandList[i + 1])):
_runCommandList(commandList[i + 2], _ssCount)
i += 2
i += 1
def run(commandStr, _ssCount=None):
"""Run a series of PyAutoGUI function calls according to a mini-language
made for this function. The `commandStr` is composed of character
commands that represent PyAutoGUI function calls.
For example, `run('ccg-20,+0c')` clicks the mouse
gitextract_73sr2if3/ ├── .gitignore ├── AUTHORS.txt ├── CHANGES.txt ├── LICENSE.txt ├── MANIFEST.in ├── Pipfile ├── README.md ├── docs/ │ ├── Makefile │ ├── conf.py │ ├── index.rst │ ├── install.rst │ ├── keyboard.rst │ ├── make.bat │ ├── mouse.rst │ ├── msgbox.rst │ ├── quickstart.rst │ ├── roadmap.rst │ ├── screenshot.rst │ ├── simplified-chinese.ipynb │ ├── source/ │ │ ├── modules.rst │ │ └── pyautogui.rst │ └── tests.rst ├── pyautogui/ │ ├── __init__.py │ ├── __main__.py │ ├── _pyautogui_java.py │ ├── _pyautogui_osx.py │ ├── _pyautogui_win.py │ └── _pyautogui_x11.py ├── setup.py ├── tests/ │ └── test_pyautogui.py └── tox.ini
SYMBOL INDEX (178 symbols across 5 files)
FILE: pyautogui/__init__.py
class PyAutoGUIException (line 29) | class PyAutoGUIException(Exception):
class FailSafeException (line 39) | class FailSafeException(PyAutoGUIException):
class ImageNotFoundException (line 49) | class ImageNotFoundException(PyAutoGUIException):
function _couldNotImportPyTweening (line 105) | def _couldNotImportPyTweening(*unused_args, **unused_kwargs):
function _couldNotImportPyMsgBox (line 150) | def _couldNotImportPyMsgBox(*unused_args, **unused_kwargs):
function raisePyAutoGUIImageNotFoundException (line 162) | def raisePyAutoGUIImageNotFoundException(wrappedFunction):
function locate (line 185) | def locate(*args, **kwargs):
function locateAll (line 191) | def locateAll(*args, **kwargs):
function locateAllOnScreen (line 197) | def locateAllOnScreen(*args, **kwargs):
function locateCenterOnScreen (line 203) | def locateCenterOnScreen(*args, **kwargs):
function locateOnScreen (line 209) | def locateOnScreen(*args, **kwargs):
function locateOnWindow (line 215) | def locateOnWindow(*args, **kwargs):
function _couldNotImportPyScreeze (line 223) | def _couldNotImportPyScreeze(*unused_args, **unsed_kwargs):
function mouseInfo (line 248) | def mouseInfo():
function mouseInfo (line 257) | def mouseInfo():
function useImageNotFoundException (line 267) | def useImageNotFoundException(value=None):
function _couldNotImportPyGetWindow (line 297) | def _couldNotImportPyGetWindow(*unused_args, **unused_kwargs):
function isShiftCharacter (line 526) | def isShiftCharacter(character):
function _genericPyAutoGUIChecks (line 585) | def _genericPyAutoGUIChecks(wrappedFunction):
function getPointOnLine (line 605) | def getPointOnLine(x1, y1, x2, y2, n):
function linear (line 617) | def linear(n):
function _handlePause (line 631) | def _handlePause(_pause):
function _normalizeXYArgs (line 642) | def _normalizeXYArgs(firstArg, secondArg):
function _logScreenshot (line 706) | def _logScreenshot(logScreenshot, funcName, funcArgs, folder="."):
function position (line 752) | def position(x=None, y=None):
function size (line 777) | def size():
function onScreen (line 789) | def onScreen(x, y=None):
function _normalizeButton (line 825) | def _normalizeButton(button):
function mouseDown (line 883) | def mouseDown(x=None, y=None, button=PRIMARY, duration=0.0, tween=linear...
function mouseUp (line 916) | def mouseUp(x=None, y=None, button=PRIMARY, duration=0.0, tween=linear, ...
function click (line 949) | def click(
function leftClick (line 1007) | def leftClick(x=None, y=None, interval=0.0, duration=0.0, tween=linear, ...
function rightClick (line 1037) | def rightClick(x=None, y=None, interval=0.0, duration=0.0, tween=linear,...
function middleClick (line 1065) | def middleClick(x=None, y=None, interval=0.0, duration=0.0, tween=linear...
function doubleClick (line 1090) | def doubleClick(x=None, y=None, interval=0.0, button=LEFT, duration=0.0,...
function tripleClick (line 1133) | def tripleClick(x=None, y=None, interval=0.0, button=LEFT, duration=0.0,...
function scroll (line 1175) | def scroll(clicks, x=None, y=None, logScreenshot=None, _pause=True):
function hscroll (line 1205) | def hscroll(clicks, x=None, y=None, logScreenshot=None, _pause=True):
function vscroll (line 1233) | def vscroll(clicks, x=None, y=None, logScreenshot=None, _pause=True):
function moveTo (line 1261) | def moveTo(x=None, y=None, duration=0.0, tween=linear, logScreenshot=Fal...
function moveRel (line 1292) | def moveRel(xOffset=None, yOffset=None, duration=0.0, tween=linear, logS...
function dragTo (line 1325) | def dragTo(
function dragRel (line 1366) | def dragRel(
function _mouseMoveDrag (line 1417) | def _mouseMoveDrag(moveOrDrag, x, y, xOffset, yOffset, duration, tween=l...
function isValidKey (line 1521) | def isValidKey(key):
function keyDown (line 1542) | def keyDown(key, logScreenshot=None, _pause=True):
function keyUp (line 1564) | def keyUp(key, logScreenshot=None, _pause=True):
function press (line 1582) | def press(keys, presses=1, interval=0.0, logScreenshot=None, _pause=True):
function hold (line 1621) | def hold(keys, logScreenshot=None, _pause=True):
function typewrite (line 1658) | def typewrite(message, interval=0.0, logScreenshot=None, _pause=True):
function hotkey (line 1694) | def hotkey(*args, **kwargs):
function failSafeCheck (line 1732) | def failSafeCheck():
function displayMousePosition (line 1739) | def displayMousePosition(xOffset=0, yOffset=0):
function _snapshot (line 1779) | def _snapshot(tag, folder=None, region=None, radius=None):
function sleep (line 1805) | def sleep(seconds):
function countdown (line 1809) | def countdown(seconds):
function _getNumberToken (line 1816) | def _getNumberToken(commandStr):
function _getQuotedStringToken (line 1835) | def _getQuotedStringToken(commandStr):
function _getParensCommandStrToken (line 1852) | def _getParensCommandStrToken(commandStr):
function _getCommaToken (line 1889) | def _getCommaToken(commandStr):
function _tokenizeCommandStr (line 1905) | def _tokenizeCommandStr(commandStr):
function _runCommandList (line 2031) | def _runCommandList(commandList, _ssCount):
function run (line 2089) | def run(commandStr, _ssCount=None):
function printInfo (line 2150) | def printInfo(dontPrint=False):
function getInfo (line 2165) | def getInfo():
FILE: pyautogui/_pyautogui_osx.py
function _keyDown (line 219) | def _keyDown(key):
function _keyUp (line 228) | def _keyUp(key):
function _normalKeyEvent (line 238) | def _normalKeyEvent(key, upDown):
function _specialKeyEvent (line 264) | def _specialKeyEvent(key, upDown):
function _position (line 295) | def _position():
function _size (line 300) | def _size():
function _scroll (line 305) | def _scroll(clicks, x=None, y=None):
function _vscroll (line 315) | def _vscroll(clicks, x=None, y=None):
function _hscroll (line 334) | def _hscroll(clicks, x=None, y=None):
function _mouseDown (line 355) | def _mouseDown(x, y, button):
function _mouseUp (line 366) | def _mouseUp(x, y, button):
function _click (line 377) | def _click(x, y, button):
function _mouse_is_swapped (line 394) | def _mouse_is_swapped():
function _multiClick (line 404) | def _multiClick(x, y, button, num, interval=0.0):
function _sendMouseEvent (line 430) | def _sendMouseEvent(ev, x, y, button):
function _dragTo (line 435) | def _dragTo(x, y, button):
function _moveTo (line 446) | def _moveTo(x, y):
FILE: pyautogui/_pyautogui_win.py
class MOUSEINPUT (line 62) | class MOUSEINPUT(ctypes.Structure):
class KEYBDINPUT (line 72) | class KEYBDINPUT(ctypes.Structure):
class HARDWAREINPUT (line 81) | class HARDWAREINPUT(ctypes.Structure):
class INPUT (line 88) | class INPUT(ctypes.Structure):
class _I (line 89) | class _I(ctypes.Union):
function _keyDown (line 250) | def _keyDown(key):
function _keyUp (line 295) | def _keyUp(key):
function _position (line 335) | def _position():
function _size (line 348) | def _size():
function _moveTo (line 357) | def _moveTo(x, y):
function _mouseDown (line 375) | def _mouseDown(x, y, button):
function _mouseUp (line 404) | def _mouseUp(x, y, button):
function _click (line 432) | def _click(x, y, button):
function _mouse_is_swapped (line 461) | def _mouse_is_swapped():
function _sendMouseEvent (line 466) | def _sendMouseEvent(ev, x, y, dwData=0):
function _scroll (line 507) | def _scroll(clicks, x=None, y=None):
function _hscroll (line 544) | def _hscroll(clicks, x, y):
function _vscroll (line 560) | def _vscroll(clicks, x, y):
FILE: pyautogui/_pyautogui_x11.py
function _position (line 26) | def _position():
function _size (line 37) | def _size():
function _vscroll (line 42) | def _vscroll(clicks, x=None, y=None):
function _hscroll (line 55) | def _hscroll(clicks, x=None, y=None):
function _scroll (line 68) | def _scroll(clicks, x=None, y=None):
function _click (line 72) | def _click(x, y, button):
function _mouse_is_swapped (line 83) | def _mouse_is_swapped():
function _moveTo (line 100) | def _moveTo(x, y):
function _mouseDown (line 105) | def _mouseDown(x, y, button):
function _mouseUp (line 113) | def _mouseUp(x, y, button):
function _keyDown (line 121) | def _keyDown(key):
function _keyUp (line 154) | def _keyUp(key):
FILE: tests/test_pyautogui.py
class P (line 47) | class P(namedtuple("P", ["x", "y"])):
method __str__ (line 52) | def __str__(self):
method __repr__ (line 55) | def __repr__(self):
method __eq__ (line 58) | def __eq__(self, other):
method __ne__ (line 61) | def __ne__(self, other):
method __add__ (line 64) | def __add__(self, other):
method __sub__ (line 67) | def __sub__(self, other):
method __mul__ (line 70) | def __mul__(self, other):
method __rmul__ (line 73) | def __rmul__(self, other):
method __floordiv__ (line 76) | def __floordiv__(self, other):
method __truediv__ (line 79) | def __truediv__(self, other):
method __neg__ (line 82) | def __neg__(self):
method __pos__ (line 85) | def __pos__(self):
method __neg__ (line 88) | def __neg__(self):
class TestGeneral (line 92) | class TestGeneral(unittest.TestCase):
method setUp (line 93) | def setUp(self):
method tearDown (line 99) | def tearDown(self):
method test_accessibleNames (line 102) | def test_accessibleNames(self):
method test_size (line 183) | def test_size(self):
method test_position (line 191) | def test_position(self):
method test_onScreen (line 207) | def test_onScreen(self):
method test_pause (line 244) | def test_pause(self):
class TestHelperFunctions (line 259) | class TestHelperFunctions(unittest.TestCase):
method test__normalizeXYArgs (line 260) | def test__normalizeXYArgs(self):
class TestDoctests (line 272) | class TestDoctests(unittest.TestCase):
method test_doctests (line 273) | def test_doctests(self):
class TestMouse (line 277) | class TestMouse(unittest.TestCase):
method setUp (line 291) | def setUp(self):
method tearDown (line 299) | def tearDown(self):
method test_moveTo (line 302) | def test_moveTo(self):
method test_moveToWithTween (line 344) | def test_moveToWithTween(self):
method test_moveRel (line 364) | def test_moveRel(self):
method test_moveRelWithTween (line 425) | def test_moveRelWithTween(self):
method test_scroll (line 446) | def test_scroll(self):
method test_mouse_button_swap (line 456) | def test_mouse_button_swap(self):
class TestRun (line 460) | class TestRun(unittest.TestCase):
method test_getNumberToken (line 461) | def test_getNumberToken(self):
method test_getQuotedStringToken (line 484) | def test_getQuotedStringToken(self):
method test_getCommaToken (line 506) | def test_getCommaToken(self):
method test_getParensCommandStrToken (line 519) | def test_getParensCommandStrToken(self):
method test_tokenizeCommandStr (line 549) | def test_tokenizeCommandStr(self):
class TypewriteThread (line 623) | class TypewriteThread(threading.Thread):
method __init__ (line 624) | def __init__(self, msg, interval=0.0):
method run (line 629) | def run(self):
class PressThread (line 634) | class PressThread(threading.Thread):
method __init__ (line 635) | def __init__(self, keysArg):
method run (line 639) | def run(self):
class HoldThread (line 644) | class HoldThread(threading.Thread):
method __init__ (line 645) | def __init__(self, holdKeysArg, pressKeysArg=None):
method run (line 651) | def run(self):
class TestKeyboard (line 660) | class TestKeyboard(unittest.TestCase):
method setUp (line 664) | def setUp(self):
method tearDown (line 670) | def tearDown(self):
method test_typewrite (line 673) | def test_typewrite(self):
method checkForValidCharacters (line 697) | def checkForValidCharacters(self, msg):
method test_typewrite_slow (line 701) | def test_typewrite_slow(self):
method test_typewrite_editable (line 712) | def test_typewrite_editable(self):
method test_press (line 739) | def test_press(self):
method test_hold (line 758) | def test_hold(self):
method test_press_during_hold (line 777) | def test_press_during_hold(self):
method test_typewrite_space (line 796) | def test_typewrite_space(self):
method test_isShiftCharacter (line 803) | def test_isShiftCharacter(self):
class TestFailSafe (line 810) | class TestFailSafe(unittest.TestCase):
method test_failsafe (line 811) | def test_failsafe(self):
class TestPyScreezeFunctions (line 847) | class TestPyScreezeFunctions(unittest.TestCase):
method test_locateFunctions (line 848) | def test_locateFunctions(self):
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (306K chars).
[
{
"path": ".gitignore",
"chars": 117,
"preview": "venv/\n.tox/\n\n*.pyc\n__pycache__/\n\ninstance/\n\n.pytest_cache/\n.coverage\nhtmlcov/\n\ndist/\nbuild/\n*.egg-info/\n\nPipfile.lock"
},
{
"path": "AUTHORS.txt",
"chars": 2920,
"preview": "Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --\npeople who have submitted patches, reported bu"
},
{
"path": "CHANGES.txt",
"chars": 3985,
"preview": "v0.9.53, 2021/07/07 -- Fixed a compatibility issue with the pystray module.\nv0.9.52, 2020/10/06 -- Fixed hotkey() to wor"
},
{
"path": "LICENSE.txt",
"chars": 1482,
"preview": "Copyright (c) 2014, Al Sweigart\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without"
},
{
"path": "MANIFEST.in",
"chars": 213,
"preview": "include *.md\ninclude LICENSE.txt\nrecursive-include docs *.bat\nrecursive-include docs *.py\nrecursive-include docs *.rst\nr"
},
{
"path": "Pipfile",
"chars": 181,
"preview": "[[source]]\nurl = \"https://pypi.org/simple\"\nverify_ssl = true\nname = \"pypi\"\n\n[packages]\npyautogui = {editable = true, pat"
},
{
"path": "README.md",
"chars": 5836,
"preview": "PyAutoGUI\n=========\n\nPyAutoGUI is a cross-platform GUI automation Python module for human beings. Used to programmatica"
},
{
"path": "docs/Makefile",
"chars": 6774,
"preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHINXBUILD "
},
{
"path": "docs/conf.py",
"chars": 4857,
"preview": "# -*- coding: utf-8 -*-\n#\n# Configuration file for the Sphinx documentation builder.\n#\n# This file does only contain a s"
},
{
"path": "docs/index.rst",
"chars": 6093,
"preview": ".. PyAutoGUI documentation master file, created by\n sphinx-quickstart on Sun Jul 20 12:59:43 2014.\n You can adapt th"
},
{
"path": "docs/install.rst",
"chars": 1380,
"preview": ".. default-role:: code\n\n============\nInstallation\n============\n\nTo install PyAutoGUI, install the `pyautogui` package fr"
},
{
"path": "docs/keyboard.rst",
"chars": 5575,
"preview": ".. default-role:: code\n\n==========================\nKeyboard Control Functions\n==========================\n\nThe write() Fu"
},
{
"path": "docs/make.bat",
"chars": 6465,
"preview": "@ECHO OFF\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-build\n)\nset BUI"
},
{
"path": "docs/mouse.rst",
"chars": 10507,
"preview": ".. default-role:: code\n\n=======================\nMouse Control Functions\n=======================\n\nThe Screen and Mouse Po"
},
{
"path": "docs/msgbox.rst",
"chars": 1217,
"preview": ".. default-role:: code\n\n=====================\nMessage Box Functions\n=====================\n\nPyAutoGUI makes use of the me"
},
{
"path": "docs/quickstart.rst",
"chars": 5783,
"preview": ".. default-role:: code\n\n===========\nCheat Sheet\n===========\n\nThis is a quickstart reference to using PyAutoGUI. PyAutoGU"
},
{
"path": "docs/roadmap.rst",
"chars": 2480,
"preview": "\n=======\nRoadmap\n=======\n\nPyAutoGUI is planned as a replacement for other Python GUI automation scripts, such as PyUserI"
},
{
"path": "docs/screenshot.rst",
"chars": 7800,
"preview": ".. default-role:: code\n\n====================\nScreenshot Functions\n====================\n\nPyAutoGUI can take screenshots, "
},
{
"path": "docs/simplified-chinese.ipynb",
"chars": 45745,
"preview": "{\n \"cells\": [\n {\n \"cell_type\": \"markdown\",\n \"metadata\": {},\n \"source\": [\n \"# PyAutoGUI——让所有GUI都自动化\"\n ]\n },\n"
},
{
"path": "docs/source/modules.rst",
"chars": 64,
"preview": "pyautogui\n=========\n\n.. toctree::\n :maxdepth: 4\n\n pyautogui\n"
},
{
"path": "docs/source/pyautogui.rst",
"chars": 317,
"preview": "pyautogui package\n=================\n\nSubmodules\n----------\n\npyautogui.keynames module\n-------------------------\n\n.. auto"
},
{
"path": "docs/tests.rst",
"chars": 594,
"preview": ".. default-role:: code\n\n=======\nTesting\n=======\n\nThe unit tests for PyAutoGUI are currently not comprehensive. The tests"
},
{
"path": "pyautogui/__init__.py",
"chars": 79299,
"preview": "# PyAutoGUI lets Python control the mouse and keyboard, and other GUI automation tasks. For Windows, macOS, and Linux,\n#"
},
{
"path": "pyautogui/__main__.py",
"chars": 57,
"preview": "from . import displayMousePosition\ndisplayMousePosition()"
},
{
"path": "pyautogui/_pyautogui_java.py",
"chars": 0,
"preview": ""
},
{
"path": "pyautogui/_pyautogui_osx.py",
"chars": 15284,
"preview": "import time\nimport sys\n\ntry:\n import Quartz\nexcept:\n assert False, \"You must first install pyobjc-core and pyobjc:"
},
{
"path": "pyautogui/_pyautogui_win.py",
"chars": 20343,
"preview": "# Windows implementation of PyAutoGUI functions.\n# BSD license\n# Al Sweigart al@inventwithpython.com\n\nimport ctypes\nimpo"
},
{
"path": "pyautogui/_pyautogui_x11.py",
"chars": 16398,
"preview": "# NOTE - It is a known issue that the keyboard-related functions don't work on Ubuntu VMs in Virtualbox.\n\nimport pyautog"
},
{
"path": "setup.py",
"chars": 2588,
"preview": "import io\nimport os\nimport re\nfrom setuptools import setup\n\nscriptFolder = os.path.dirname(os.path.realpath(__file__))\no"
},
{
"path": "tests/test_pyautogui.py",
"chars": 35143,
"preview": "from __future__ import division, print_function\n\nimport os\nimport random\nimport sys\nimport threading\nimport time\nimport "
},
{
"path": "tox.ini",
"chars": 438,
"preview": "# tox (https://tox.readthedocs.io/) is a tool for running tests\n# in multiple virtualenvs. This configuration file will "
}
]
About this extraction
This page contains the full source code of the asweigart/pyautogui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (283.1 KB), approximately 85.2k tokens, and a symbol index with 178 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.