#StudioPlanLogWeb

dev-linux
Ivan Maslov 6 years ago
parent 723b2b4037
commit 84d4412f31

@ -83,6 +83,28 @@
}); });
} }
mGlobal.Info.TablePlanLogListRefresh=function() {
///Обнулить таблицу
$(".openrpa-info-table-planloglist").html("")
$.ajax({
type: "POST",
url: 'ProcessingRun',
data: '{"actionList":[{"type":"PlanLogListGet"}]}',
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
lResponseJSON["actionListResult"][0]["result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON["actionListResult"][0]);
///Установить HTML код
$(".openrpa-info-table-planloglist").html(lHTMLCode)
},
dataType: "text"
});
}
////////////////////////// //////////////////////////
/////Controller JS module /////Controller JS module
////////////////////////// //////////////////////////
@ -198,6 +220,7 @@
///Инициализация страницы ///Инициализация страницы
//////////////////////////////////// ////////////////////////////////////
mGlobal.Info.TableActivityLogScheduleListRefresh(); mGlobal.Info.TableActivityLogScheduleListRefresh();
mGlobal.Info.TablePlanLogListRefresh();
}) })
; ;
</script> </script>
@ -299,8 +322,41 @@
</table> </table>
</script> </script>
</div> </div>
<div class="eight wide column rpa-property-list" > <div class="ten wide column rpa-property-list" >
<h4 class="ui horizontal divider header">
<i class="clipboard list icon"></i>
Plan log
</h4>
<div class="ui info message">
<button class="ui icon button labeled" onclick="mGlobal.Info.TablePlanLogListRefresh();">
<i class="sync alternate icon"></i>
Refresh
</button>
</div>
<div class="openrpa-info-table-planloglist">
</div >
<script class="openrpa-hidden-info-table-planloglist" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>#</th>
<th>Activity type</th>
<th>Time</th>
<th>Process path/Process name</th>
</tr>
</thead>
<tbody>
{{#result}}
<tr>
<td>{{@index}}</td>
<td>{{activityType}}</td>
<td>{{time}}</td>
<td>{{processPathName}}</td>
</tr>
{{/result}}
</tbody>
</table>
</script>
</div> </div>
</div> </div>
<div class="row black"> <div class="row black">
@ -320,7 +376,7 @@
Look machine screenshot Look machine screenshot
</button> </button>
<button class="ui labeled icon button red" onclick="mGlobal.Controller.OrchestratorRestart();"> <button class="ui labeled icon button red" onclick="mGlobal.Controller.OrchestratorRestart();">
<i class="down icon"></i> <i class="redo icon"></i>
Restart Orchestrator Restart Orchestrator
</button> </button>

@ -57,7 +57,7 @@
{ {
"activityType":"loopActivity", "activityType":"loopActivity",
"loopSeconds":6, "loopSeconds":6,
"loopTimeStart":"10:45", "loopTimeStart":"21:45",
"loopTimeEnd":"21:46", "loopTimeEnd":"21:46",
"pythonPackageName":"CheckActivity", "pythonPackageName":"CheckActivity",
"pythonFunctionName":"test_activity", "pythonFunctionName":"test_activity",

@ -77,7 +77,7 @@ while True:
#Запустить процесс #Запустить процесс
lItemArgs=[lItem["processPath"]] lItemArgs=[lItem["processPath"]]
lItemArgs.extend(lItem["processArgs"]) lItemArgs.extend(lItem["processArgs"])
subprocess.Popen(lItemArgs,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) subprocess.Popen(lItemArgs,shell=True)
#Определить вид активности #Определить вид активности
if lItem["activityType"]=="processStop": if lItem["activityType"]=="processStop":
#Вид активности - остановка процесса #Вид активности - остановка процесса

@ -62,6 +62,10 @@ def ProcessingRun(inConfigurationDict):
if lItem["type"]=="ActivityLogScheduleListGet": if lItem["type"]=="ActivityLogScheduleListGet":
#pdb.set_trace() #pdb.set_trace()
lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":mGlobalDict["ActivityLogScheduleList"]}} lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":mGlobalDict["ActivityLogScheduleList"]}}
#Обработка команды PlanLogListGet
if lItem["type"]=="PlanLogListGet":
#pdb.set_trace()
lResult["actionListResult"][-1] = {**lResult["actionListResult"][-1], **{"result":mGlobalDict["JSONConfigurationDict"]["activityList"]}}
#Обработка команды ActivityCMDRun #Обработка команды ActivityCMDRun
if lItem["type"]=="ActivityCMDRun": if lItem["type"]=="ActivityCMDRun":
lCMDCode="cmd /c "+lItem["code"] lCMDCode="cmd /c "+lItem["code"]

@ -0,0 +1,27 @@
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.

@ -0,0 +1,138 @@
Metadata-Version: 2.1
Name: PyAutoGUI
Version: 0.9.44
Summary: A cross-platform module for GUI automation for human beings. Control the keyboard and mouse from a Python script.
Home-page: https://github.com/asweigart/pyautogui
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: BSD
Keywords: gui automation test testing keyboard mouse cursor click press keystroke control
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Environment :: MacOS X
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Description-Content-Type: text/markdown
Requires-Dist: pymsgbox
Requires-Dist: PyTweening (>=1.0.1)
Requires-Dist: Pillow
Requires-Dist: pyscreeze (>=0.1.21)
Requires-Dist: pygetwindow (>=0.0.5)
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://muxuezi.github.io/posts/doc-pyautogui.html
Source code available at https://github.com/asweigart/pyautogui
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.
OS X 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
--------------------------
```python
>>> import pyautogui
>>> screenWidth, screenHeight = pyautogui.size()
>>> currentMouseX, currentMouseY = pyautogui.position()
>>> pyautogui.moveTo(100, 150)
>>> pyautogui.click()
>>> pyautogui.moveRel(None, 10) # move mouse 10 pixels down
>>> pyautogui.doubleClick()
>>> pyautogui.moveTo(500, 500, duration=2, tween=pyautogui.tweens.easeInOutQuad) # use tweening/easing function to move mouse over 2 seconds.
>>> pyautogui.typewrite('Hello world!', interval=0.25) # type with quarter-second pause in between each key
>>> pyautogui.press('esc')
>>> pyautogui.keyDown('shift')
>>> pyautogui.typewrite(['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
```

@ -0,0 +1,26 @@
PyAutoGUI-0.9.44.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyAutoGUI-0.9.44.dist-info/LICENSE.txt,sha256=rNMjpKuy_R62UDcXVGvAbRWA3qmJw7EzjRdrp8N8Zl0,1509
PyAutoGUI-0.9.44.dist-info/METADATA,sha256=K2mubdEMFXv_Opkrn5f9Ax140-njnxIRCEpFClBe6YU,4964
PyAutoGUI-0.9.44.dist-info/RECORD,,
PyAutoGUI-0.9.44.dist-info/WHEEL,sha256=JtBte-IW7C3UcYx3ZpZORq-KtnjVj4xdM4AJCTZPivc,98
PyAutoGUI-0.9.44.dist-info/top_level.txt,sha256=YztmWux-iPoF3Dv9x530vZvae0kMBsGbPAoKgWRGAvk,10
pyautogui/__init__.py,sha256=RlRUdaTYdsfwwLXCANjBSCJGZhssrguuUoSJQ9g7auI,45305
pyautogui/__main__.py,sha256=P8Ny3OScHrutsXUz-UsqKamaFihW-Yuq0YzKHkRGADI,58
pyautogui/__pycache__/__init__.cpython-37.pyc,,
pyautogui/__pycache__/__main__.cpython-37.pyc,,
pyautogui/__pycache__/_pyautogui_java.cpython-37.pyc,,
pyautogui/__pycache__/_pyautogui_osx.cpython-37.pyc,,
pyautogui/__pycache__/_pyautogui_win.cpython-37.pyc,,
pyautogui/__pycache__/_pyautogui_x11.cpython-37.pyc,,
pyautogui/__pycache__/_window_win.cpython-37.pyc,,
pyautogui/__pycache__/screenshotUtil.cpython-37.pyc,,
pyautogui/__pycache__/test1.cpython-37.pyc,,
pyautogui/__pycache__/tweens.cpython-37.pyc,,
pyautogui/_pyautogui_java.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyautogui/_pyautogui_osx.py,sha256=LwG6oFs9-MUxxga7Pj15B2UcGFxBJieuoH6yx5jHnSo,15647
pyautogui/_pyautogui_win.py,sha256=qAwFfQk5G1kF8EI5wWa5MVewYuCMZQQnnM-xPCbtQhk,21294
pyautogui/_pyautogui_x11.py,sha256=_g7VOXO6HjFvrhEr9bt2R1o1un3s-VzOmTkkPqTvCoE,15634
pyautogui/_window_win.py,sha256=ReLnzdOoS-hlsTWkD2dQ-qyU_yuOEplJYHcZNtZxA04,3902
pyautogui/screenshotUtil.py,sha256=S6pwcQZV7wMPvplAsp_pkcENcjIQdXqLqxBP926Z-OA,8363
pyautogui/test1.py,sha256=hNr3BL5Dv2JSZNzXd_h-NkixMWbrm3EPB10MnB3-iUA,106
pyautogui/tweens.py,sha256=NqjZcusP6jcxfQxa3zsMVft5PZrpouxlpDhOy_kd8s8,1440

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: cp37-none-any

@ -0,0 +1,99 @@
Metadata-Version: 2.1
Name: PyGetWindow
Version: 0.0.5
Summary: A simple, cross-platform module for obtaining GUI information on application's windows.
Home-page: https://github.com/asweigart/pygetwindow
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: BSD
Keywords: gui window geometry resize minimize maximize close title
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Environment :: MacOS X
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Description-Content-Type: text/markdown
Requires-Dist: pyrect
PyGetWindow
===========
A simple, cross-platform module for obtaining GUI information on and controlling application's windows.
Still under development. Currently only the Windows platform is implemented. If you want to help contribute, please contact al@inventwithpython.com!
Install
-------
pip install pygetwindow
Examples
--------
(For this example, I'm using Winodws and opened the Notepad application, which has a title of "Untitled - Notepad". Most of the effects of these functions can't be seen in text.)
PyGetWindow has functions for obtaining ``Window`` objects from a place on the screen, from the window title, or just getting all windows. (``hWnd`` is specific to the Windows platform.)
>>> import pygetwindow as gw
>>> gw.getAllTitles()
('', 'C:\\WINDOWS\\system32\\cmd.exe - pipenv shell - python', 'C:\\github\\PyGetWindow\\README.md • - Sublime Text', "asweigart/PyGetWindow: A simple, cross-platform module for obtaining GUI information on application's windows. - Google Chrome", 'Untitled - Notepad', 'C:\\Users\\Al\\Desktop\\xlibkey.py • - Sublime Text', 'https://tronche.com/gui/x/xlib/ - Google Chrome', 'Xlib Programming Manual: XGetWindowAttributes - Google Chrome', 'Generic Ubuntu Box [Running] - Oracle VM VirtualBox', 'Oracle VM VirtualBox Manager', 'Microsoft Edge', 'Microsoft Edge', 'Microsoft Edge', '', 'Microsoft Edge', 'Settings', 'Settings', 'Microsoft Store', 'Microsoft Store', '', '', 'Backup and Sync', 'Google Hangouts - asweigart@gmail.com', 'Downloads', '', '', 'Program Manager')
>>> gw.getAllWindows()
(Win32Window(hWnd=131318), Win32Window(hWnd=1050492), Win32Window(hWnd=67206), Win32Window(hWnd=66754), Win32Window(hWnd=264354), Win32Window(hWnd=329210), Win32Window(hWnd=1114374), Win32Window(hWnd=852550), Win32Window(hWnd=328358), Win32Window(hWnd=66998), Win32Window(hWnd=132508), Win32Window(hWnd=66964), Win32Window(hWnd=66882), Win32Window(hWnd=197282), Win32Window(hWnd=393880), Win32Window(hWnd=66810), Win32Window(hWnd=328466), Win32Window(hWnd=132332), Win32Window(hWnd=262904), Win32Window(hWnd=65962), Win32Window(hWnd=65956), Win32Window(hWnd=197522), Win32Window(hWnd=131944), Win32Window(hWnd=329334), Win32Window(hWnd=395034), Win32Window(hWnd=132928), Win32Window(hWnd=65882))
>>> gw.getWindowsWithTitle('Untitled')
(Win32Window(hWnd=264354),)
>>> gw.getFocusedWindow()
Win32Window(hWnd=1050492)
>>> gw.getFocusedWindow().title
'C:\\WINDOWS\\system32\\cmd.exe - pipenv shell - python'
>>> gw.getWindowsAt(10, 10)
(Win32Window(hWnd=67206), Win32Window(hWnd=66754), Win32Window(hWnd=329210), Win32Window(hWnd=1114374), Win32Window(hWnd=852550), Win32Window(hWnd=132508), Win32Window(hWnd=66964), Win32Window(hWnd=66882), Win32Window(hWnd=197282), Win32Window(hWnd=393880), Win32Window(hWnd=66810), Win32Window(hWnd=328466), Win32Window(hWnd=395034), Win32Window(hWnd=132928), Win32Window(hWnd=65882))
``Window`` objects can be minimized/maximized/restored/focused/resized/moved/closed and also have attributes for their current position, size, and state.
>>> notepadWindow = gw.getWindowsWithTitle('Untitled')[0]
>>> notepadWindow.isMaximized
False
>>> notepadWindow.maximize()
>>> notepadWindow.isMaximized
True
>>> notepadWindow.restore()
>>> notepadWindow.minimize()
>>> notepadWindow.restore()
>>> notepadWindow.focus()
>>> notepadWindow.resize(10, 10) # increase by 10, 10
>>> notepadWindow.resizeTo(100, 100) # set size to 100x100
>>> notepadWindow.move(10, 10) # move 10 pixels right and 10 down
>>> notepadWindow.moveTo(10, 10) # move window to 10, 10
>>> notepadWindow.size
(132, 100)
>>> notepadWindow.width
132
>>> notepadWindow.height
100
>>> notepadWindow.topleft
(10, 10)
>>> notepadWindow.top
10
>>> notepadWindow.left
10
>>> notepadWindow.bottomright
(142, 110)
>>> notepadWindow.close()
>>>

@ -0,0 +1,13 @@
PyGetWindow-0.0.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyGetWindow-0.0.5.dist-info/METADATA,sha256=70cWMr8QUNChH2OwlIYwRKwGkMhXsrNwQh3FWK3PciY,5094
PyGetWindow-0.0.5.dist-info/RECORD,,
PyGetWindow-0.0.5.dist-info/WHEEL,sha256=JtBte-IW7C3UcYx3ZpZORq-KtnjVj4xdM4AJCTZPivc,98
PyGetWindow-0.0.5.dist-info/top_level.txt,sha256=WxTIgZWkYIMB1QQE7SO_vCL5q-sSKu5Fv0rJ0U7pWZk,12
pygetwindow/__init__.py,sha256=Oaj5OilD9O6OP0BoAfivUdBOvkmPKFXAZ5vyIvlhw3I,1730
pygetwindow/__pycache__/__init__.cpython-37.pyc,,
pygetwindow/__pycache__/_pygetwindow_macos.cpython-37.pyc,,
pygetwindow/__pycache__/_pygetwindow_win.cpython-37.pyc,,
pygetwindow/__pycache__/foo.cpython-37.pyc,,
pygetwindow/_pygetwindow_macos.py,sha256=P_JfzLkZNzDtOvpjdFLwngS_YWlWqZd0clpLyTH32OE,12976
pygetwindow/_pygetwindow_win.py,sha256=evD-OUlMQTUb6S96--LlzvGnHaZSNUBeAT8R6F4u7IM,17937
pygetwindow/foo.py,sha256=sYZ4q36T_IhSQrPKUdfW-kXMcJ_j4yHkxi9S2fRvpvU,8

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: cp37-none-any

@ -0,0 +1,31 @@
Metadata-Version: 2.1
Name: PyMsgBox
Version: 1.0.6
Summary: A simple, cross-platform, pure Python module for JavaScript-like message boxes.
Home-page: https://github.com/asweigart/PyMsgBox
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: BSD
Keywords: gui msgbox message box dialog confirmation confirm password alert
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Environment :: MacOS X
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
UNKNOWN

@ -0,0 +1,17 @@
PyMsgBox-1.0.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyMsgBox-1.0.6.dist-info/METADATA,sha256=ecN1wrniIim5bOm7r8WTwWhjn_LFHwfK6HFjJHJgYDU,1178
PyMsgBox-1.0.6.dist-info/RECORD,,
PyMsgBox-1.0.6.dist-info/WHEEL,sha256=JtBte-IW7C3UcYx3ZpZORq-KtnjVj4xdM4AJCTZPivc,98
PyMsgBox-1.0.6.dist-info/top_level.txt,sha256=VhumxHbRDo-rZSH_txL41DQO4DCaSDI0lz2AIhwUHbk,9
pymsgbox/__init__.py,sha256=o_NGGc3p9hn3glO7X1QWq3ZUWZgLR_C8BUZa4aS40M0,13415
pymsgbox/__pycache__/__init__.cpython-37.pyc,,
pymsgbox/__pycache__/_native_java.cpython-37.pyc,,
pymsgbox/__pycache__/_native_osx.cpython-37.pyc,,
pymsgbox/__pycache__/_native_win.cpython-37.pyc,,
pymsgbox/__pycache__/_native_x11.cpython-37.pyc,,
pymsgbox/__pycache__/native.cpython-37.pyc,,
pymsgbox/_native_java.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pymsgbox/_native_osx.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pymsgbox/_native_win.py,sha256=sbuilTAPOvGpn8wIklnxWzGuVbEfQeMKRqowyUVn5Ss,1982
pymsgbox/_native_x11.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pymsgbox/native.py,sha256=QfDD2vsE9pW2MkHhAnLtg6yW62VL2iwXRCREmDCJ56Q,862

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: cp37-none-any

@ -0,0 +1,127 @@
Metadata-Version: 2.1
Name: PyRect
Version: 0.1.4
Summary: PyRect is a simple module with a Rect class for Pygame-like rectangular areas.
Home-page: https://github.com/asweigart/pyrect
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: BSD
Keywords: pygame rect rectangular rectangle area
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: MacOS X
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
======
PyRect
======
PyRect is a simple module with a Rect class for Pygame-like rectangular areas.
This module is like a stand-alone version of Pygame's Rect class. It is similar to the Rect module by Simon Wittber, but compatible with both Python 2 and 3.
Currently under development, though the basic features work.
Installation
============
``pip install rect``
Quickstart Guide
================
First, create a Rect object by providing the XY coordinates of its top-left corner, and then the width and height:
>>> import pyrect
>>> r = pyrect.Rect(0, 0, 10, 20)
There are several attributes that are automatically calculated (they have the same names as Pygame's Rect objects):
>>> r.width, r.height, r.size
(10, 20, (10, 20))
>>> r. left
0
>>> r.right
10
>>> r.top
0
>>> r.bottom
20
>>> r.center
(5, 10)
>>> r.topleft
(0, 0)
>>> r.topright
(10, 0)
>>> r.midleft
(0, 10)
Changing these attributes re-calculates the others. The top-left corner is anchored for any growing or shrinking that takes place.
>>> r.topleft
(0, 0)
>>> r.left = 100
>>> r.topleft
(100, 0)
>>> r.topright
(110, 0)
>>> r.width = 30
>>> r.topright
(130, 0)
Rect objects are locked to integers, unless you set `enableFloat` to `True`:
>>> r = pyrect.Rect(0, 0, 10, 20)
>>> r.width = 10.5
>>> r.width
10
>>> r.enableFloat = True
>>> r.width = 10.5
>>> r.width
10.5
>>> r2 = pyrect.Rect(0, 0, 10.5, 20.5, enableFloat=True)
>>> r2.size
(10.5, 20.5)
Rect Attributes
===============
Rect objects have several attributes that can be read or modified. They are identical to Pygame's Rect objects:
``x, y``
``top, left, bottom, right``
``topleft, bottomleft, topright, bottomright``
``midtop, midleft, midbottom, midright``
``center, centerx, centery``
``size, width, height``
``w, h``
There are a couple other attributes as well:
``box (a tuple (left, top, width, height))``
``area (read-only)``

@ -0,0 +1,7 @@
PyRect-0.1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyRect-0.1.4.dist-info/METADATA,sha256=qviGiMu-arb3aBayzBqGbFt3OUPfnLnWtLgWbr6IP3k,3325
PyRect-0.1.4.dist-info/RECORD,,
PyRect-0.1.4.dist-info/WHEEL,sha256=05Ahrak1u2K61DpLp9CDNSbUImLTITCMom_cqTFk6pE,116
PyRect-0.1.4.dist-info/top_level.txt,sha256=zRKhS2KGlJmow_PYupJ21SKCmAyorrFofAC7QGsXt5g,7
pyrect/__init__.py,sha256=pRHUn6NZRI8NJtM7J5vjuBN3RpfnQcp7547xybl17mI,47934
pyrect/__pycache__/__init__.cpython-37.pyc,,

@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -0,0 +1,27 @@
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 PyScreeze 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.

@ -0,0 +1,156 @@
Metadata-Version: 2.1
Name: PyScreeze
Version: 0.1.21
Summary: A simple, cross-platform screenshot module for Python 2 and 3.
Home-page: https://github.com/asweigart/pyscreeze
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: BSD
Keywords: screenshot screen screencap capture scrot screencapture image
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Environment :: MacOS X
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Requires-Dist: Pillow
PyScreeze
=========
PyScreeze is a simple, cross-platform screenshot module for Python 2 and 3.
About
-----
PyScreeze 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.
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`.
Special Notes About Ubuntu
==========================
Unfortunately, Ubuntu seems to have several deficiencies with installing Pillow. PNG and JPEG support are not included with Pillow out of the box on Ubuntu. The following links have more information
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.
>>> import pyscreeze
>>> im1 = pyscreeze.screenshot()
>>> im2 = pyscreeze.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 pyscreeze
>>> im = pyscreeze.screenshot(region=(0,0, 300, 400))
The Locate Functions
====================
You can visually locate something on the screen if you have an image file of it. You can call the `locateOnScreen('calc7key.png')` function to get the screen coordinates of the 7 button for a calculator app. 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()` returns `None`.
>>> import pyscreeze
>>> button7location = pyscreeze.locateOnScreen('calc7key.png')
>>> button7location
(1416, 562, 50, 41)
>>> button7x, button7y = pyscreeze.center(button7location)
>>> button7x, button7y
(1441, 582)
>>> pyscreeze.click(button7x, button7y) # clicks the center of where the 7 button was found
The `locateCenterOnScreen()` function is probably the one you want to use most often:
>>> import pyscreeze
>>> x, y = pyscreeze.locateCenterOnScreen('calc7key.png')
>>> pyscreeze.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.
If speed is important, install the optional opencv library (`pip install cv2`). The `locateAll` computation will use it if available, and take less than 1 millisecond to find all matches in a full-screen search. (This does not include the time required to capture a screenshot.)
There are several "locate" functions. They all start looking at the top-left corner of the screen (or image) and look to the left 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. Returns None 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. Returns None 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`. Returns None 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 pyscreeze
>>> for pos in pyscreeze.locateAllOnScreen('someButton.png')
... print(pos)
...
(1101, 252, 50, 50)
(59, 481, 50, 50)
(1395, 640, 50, 50)
(1838, 676, 50, 50)
>>> list(pyscreeze.locateAllOnScreen('someButton.png'))
[(1101, 252, 50, 50), (59, 481, 50, 50), (1395, 640, 50, 50), (1838, 676, 50, 50)]
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 pyscreeze
>>> button7location = pyscreeze.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 pyscreeze
>>> im = pyscreeze.screenshot()
>>> im.getpixel((100, 200))
(130, 135, 144)
Or as a single function, call the `pixel()` PyScreeze function, which is a wrapper for the previous calls:
>>> import pyscreeze
>>> pyscreeze.pixel(100, 200)
(130, 135, 144)
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 pyscreeze
>>> pyscreeze.pixelMatchesColor(100, 200, (130, 135, 144))
True
>>> pyscreeze.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 pyscreeze
>>> pyscreeze.pixelMatchesColor(100, 200, (130, 135, 144))
True
>>> pyscreeze.pixelMatchesColor(100, 200, (140, 125, 134))
False
>>> pyscreeze.pixelMatchesColor(100, 200, (140, 125, 134), tolerance=10)
True

@ -0,0 +1,8 @@
PyScreeze-0.1.21.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyScreeze-0.1.21.dist-info/LICENSE.txt,sha256=XcpFE3U9k1S0c5N8Taxr3a_LXnlT4mpnKf4eJu7EUXc,1505
PyScreeze-0.1.21.dist-info/METADATA,sha256=wVTgkGZEKE6RHotcA5XYTXeIjzJy6mdY4o7DDVPqxFc,7418
PyScreeze-0.1.21.dist-info/RECORD,,
PyScreeze-0.1.21.dist-info/WHEEL,sha256=JtBte-IW7C3UcYx3ZpZORq-KtnjVj4xdM4AJCTZPivc,98
PyScreeze-0.1.21.dist-info/top_level.txt,sha256=ExHe4LVkQVDYcMxwsJMTH01lHyk4GLzRxiPv4hGDRjA,10
pyscreeze/__init__.py,sha256=s418376u9o_LTVgNb8awm8LyqWkGS7qkOufkS8N6Vic,20522
pyscreeze/__pycache__/__init__.cpython-37.pyc,,

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: cp37-none-any

@ -0,0 +1,26 @@
Metadata-Version: 2.1
Name: PyTweening
Version: 1.0.3
Summary: A collection of tweening / easing functions.
Home-page: https://github.com/asweigart/pytweening
Author: Al Sweigart
Author-email: al@inventwithpython.com
License: BSD
Keywords: 2D animation tween tweening easing
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Win32 (MS Windows)
Classifier: Environment :: X11 Applications
Classifier: Environment :: MacOS X
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
UNKNOWN

@ -0,0 +1,7 @@
PyTweening-1.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
PyTweening-1.0.3.dist-info/METADATA,sha256=j2Mc5ESJwRYqGY5D_NbLOJiDsiVZ9RwSryRGKORkv1M,854
PyTweening-1.0.3.dist-info/RECORD,,
PyTweening-1.0.3.dist-info/WHEEL,sha256=JtBte-IW7C3UcYx3ZpZORq-KtnjVj4xdM4AJCTZPivc,98
PyTweening-1.0.3.dist-info/top_level.txt,sha256=R8O2tKT6wD9sQ2kol4zYmcnqUOfgA9MMsswf3T9zRIo,11
pytweening/__init__.py,sha256=IykpXFitgL3pv36qy-rFa8OQwhy5A-QK_FF1JCMPLTs,16939
pytweening/__pycache__/__init__.cpython-37.pyc,,

@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.1)
Root-Is-Purelib: true
Tag: cp37-none-any

@ -0,0 +1,2 @@
from . import displayMousePosition
displayMousePosition()

@ -0,0 +1,442 @@
import time
import sys
try:
import Quartz
except:
assert False, "You must first install pyobjc-core and pyobjc: https://pyautogui.readthedocs.io/en/latest/install.html"
import AppKit
import pyautogui
if sys.platform != 'darwin':
raise Exception('The pyautogui_osx module should only be loaded on an OS X system.')
""" Taken from events.h
/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
The *KB dictionaries in pyautogui map a string that can be passed to keyDown(),
keyUp(), or press() into the code used for the OS-specific keyboard function.
They should always be lowercase, and the same keys should be used across all OSes."""
keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES])
keyboardMapping.update({
'a': 0x00, # kVK_ANSI_A
's': 0x01, # kVK_ANSI_S
'd': 0x02, # kVK_ANSI_D
'f': 0x03, # kVK_ANSI_F
'h': 0x04, # kVK_ANSI_H
'g': 0x05, # kVK_ANSI_G
'z': 0x06, # kVK_ANSI_Z
'x': 0x07, # kVK_ANSI_X
'c': 0x08, # kVK_ANSI_C
'v': 0x09, # kVK_ANSI_V
'b': 0x0b, # kVK_ANSI_B
'q': 0x0c, # kVK_ANSI_Q
'w': 0x0d, # kVK_ANSI_W
'e': 0x0e, # kVK_ANSI_E
'r': 0x0f, # kVK_ANSI_R
'y': 0x10, # kVK_ANSI_Y
't': 0x11, # kVK_ANSI_T
'1': 0x12, # kVK_ANSI_1
'!': 0x12, # kVK_ANSI_1
'2': 0x13, # kVK_ANSI_2
'@': 0x13, # kVK_ANSI_2
'3': 0x14, # kVK_ANSI_3
'#': 0x14, # kVK_ANSI_3
'4': 0x15, # kVK_ANSI_4
'$': 0x15, # kVK_ANSI_4
'6': 0x16, # kVK_ANSI_6
'^': 0x16, # kVK_ANSI_6
'5': 0x17, # kVK_ANSI_5
'%': 0x17, # kVK_ANSI_5
'=': 0x18, # kVK_ANSI_Equal
'+': 0x18, # kVK_ANSI_Equal
'9': 0x19, # kVK_ANSI_9
'(': 0x19, # kVK_ANSI_9
'7': 0x1a, # kVK_ANSI_7
'&': 0x1a, # kVK_ANSI_7
'-': 0x1b, # kVK_ANSI_Minus
'_': 0x1b, # kVK_ANSI_Minus
'8': 0x1c, # kVK_ANSI_8
'*': 0x1c, # kVK_ANSI_8
'0': 0x1d, # kVK_ANSI_0
')': 0x1d, # kVK_ANSI_0
']': 0x1e, # kVK_ANSI_RightBracket
'}': 0x1e, # kVK_ANSI_RightBracket
'o': 0x1f, # kVK_ANSI_O
'u': 0x20, # kVK_ANSI_U
'[': 0x21, # kVK_ANSI_LeftBracket
'{': 0x21, # kVK_ANSI_LeftBracket
'i': 0x22, # kVK_ANSI_I
'p': 0x23, # kVK_ANSI_P
'l': 0x25, # kVK_ANSI_L
'j': 0x26, # kVK_ANSI_J
"'": 0x27, # kVK_ANSI_Quote
'"': 0x27, # kVK_ANSI_Quote
'k': 0x28, # kVK_ANSI_K
';': 0x29, # kVK_ANSI_Semicolon
':': 0x29, # kVK_ANSI_Semicolon
'\\': 0x2a, # kVK_ANSI_Backslash
'|': 0x2a, # kVK_ANSI_Backslash
',': 0x2b, # kVK_ANSI_Comma
'<': 0x2b, # kVK_ANSI_Comma
'/': 0x2c, # kVK_ANSI_Slash
'?': 0x2c, # kVK_ANSI_Slash
'n': 0x2d, # kVK_ANSI_N
'm': 0x2e, # kVK_ANSI_M
'.': 0x2f, # kVK_ANSI_Period
'>': 0x2f, # kVK_ANSI_Period
'`': 0x32, # kVK_ANSI_Grave
'~': 0x32, # kVK_ANSI_Grave
' ': 0x31, # kVK_Space
'space': 0x31,
'\r': 0x24, # kVK_Return
'\n': 0x24, # kVK_Return
'enter': 0x24, # kVK_Return
'return': 0x24, # kVK_Return
'\t': 0x30, # kVK_Tab
'tab': 0x30, # kVK_Tab
'backspace': 0x33, # kVK_Delete, which is "Backspace" on OS X.
'\b': 0x33, # kVK_Delete, which is "Backspace" on OS X.
'esc': 0x35, # kVK_Escape
'escape': 0x35, # kVK_Escape
'command': 0x37, # kVK_Command
'shift': 0x38, # kVK_Shift
'shiftleft': 0x38, # kVK_Shift
'capslock': 0x39, # kVK_CapsLock
'option': 0x3a, # kVK_Option
'optionleft': 0x3a, # kVK_Option
'alt': 0x3a, # kVK_Option
'altleft': 0x3a, # kVK_Option
'ctrl': 0x3b, # kVK_Control
'ctrlleft': 0x3b, # kVK_Control
'shiftright': 0x3c, # kVK_RightShift
'optionright': 0x3d, # kVK_RightOption
'ctrlright': 0x3e, # kVK_RightControl
'fn': 0x3f, # kVK_Function
'f17': 0x40, # kVK_F17
'volumeup': 0x48, # kVK_VolumeUp
'volumedown': 0x49, # kVK_VolumeDown
'volumemute': 0x4a, # kVK_Mute
'f18': 0x4f, # kVK_F18
'f19': 0x50, # kVK_F19
'f20': 0x5a, # kVK_F20
'f5': 0x60, # kVK_F5
'f6': 0x61, # kVK_F6
'f7': 0x62, # kVK_F7
'f3': 0x63, # kVK_F3
'f8': 0x64, # kVK_F8
'f9': 0x65, # kVK_F9
'f11': 0x67, # kVK_F11
'f13': 0x69, # kVK_F13
'f16': 0x6a, # kVK_F16
'f14': 0x6b, # kVK_F14
'f10': 0x6d, # kVK_F10
'f12': 0x6f, # kVK_F12
'f15': 0x71, # kVK_F15
'help': 0x72, # kVK_Help
'home': 0x73, # kVK_Home
'pageup': 0x74, # kVK_PageUp
'pgup': 0x74, # kVK_PageUp
'del': 0x75, # kVK_ForwardDelete
'delete': 0x75, # kVK_ForwardDelete
'f4': 0x76, # kVK_F4
'end': 0x77, # kVK_End
'f2': 0x78, # kVK_F2
'pagedown': 0x79, # kVK_PageDown
'pgdn': 0x79, # kVK_PageDown
'f1': 0x7a, # kVK_F1
'left': 0x7b, # kVK_LeftArrow
'right': 0x7c, # kVK_RightArrow
'down': 0x7d, # kVK_DownArrow
'up': 0x7e, # kVK_UpArrow
'yen': 0x5d, # kVK_JIS_Yen
#'underscore' : 0x5e, # kVK_JIS_Underscore (only applies to Japanese keyboards)
#'comma': 0x5f, # kVK_JIS_KeypadComma (only applies to Japanese keyboards)
'eisu': 0x66, # kVK_JIS_Eisu
'kana': 0x68, # kVK_JIS_Kana
})
"""
# TODO - additional key codes to add
kVK_ANSI_KeypadDecimal = 0x41,
kVK_ANSI_KeypadMultiply = 0x43,
kVK_ANSI_KeypadPlus = 0x45,
kVK_ANSI_KeypadClear = 0x47,
kVK_ANSI_KeypadDivide = 0x4B,
kVK_ANSI_KeypadEnter = 0x4C,
kVK_ANSI_KeypadMinus = 0x4E,
kVK_ANSI_KeypadEquals = 0x51,
kVK_ANSI_Keypad0 = 0x52,
kVK_ANSI_Keypad1 = 0x53,
kVK_ANSI_Keypad2 = 0x54,
kVK_ANSI_Keypad3 = 0x55,
kVK_ANSI_Keypad4 = 0x56,
kVK_ANSI_Keypad5 = 0x57,
kVK_ANSI_Keypad6 = 0x58,
kVK_ANSI_Keypad7 = 0x59,
kVK_ANSI_Keypad8 = 0x5B,
kVK_ANSI_Keypad9 = 0x5C,
"""
# add mappings for uppercase letters
for c in 'abcdefghijklmnopqrstuvwxyz':
keyboardMapping[c.upper()] = keyboardMapping[c]
# Taken from ev_keymap.h
# http://www.opensource.apple.com/source/IOHIDFamily/IOHIDFamily-86.1/IOHIDSystem/IOKit/hidsystem/ev_keymap.h
special_key_translate_table = {
'KEYTYPE_SOUND_UP': 0,
'KEYTYPE_SOUND_DOWN': 1,
'KEYTYPE_BRIGHTNESS_UP': 2,
'KEYTYPE_BRIGHTNESS_DOWN': 3,
'KEYTYPE_CAPS_LOCK': 4,
'KEYTYPE_HELP': 5,
'POWER_KEY': 6,
'KEYTYPE_MUTE': 7,
'UP_ARROW_KEY': 8,
'DOWN_ARROW_KEY': 9,
'KEYTYPE_NUM_LOCK': 10,
'KEYTYPE_CONTRAST_UP': 11,
'KEYTYPE_CONTRAST_DOWN': 12,
'KEYTYPE_LAUNCH_PANEL': 13,
'KEYTYPE_EJECT': 14,
'KEYTYPE_VIDMIRROR': 15,
'KEYTYPE_PLAY': 16,
'KEYTYPE_NEXT': 17,
'KEYTYPE_PREVIOUS': 18,
'KEYTYPE_FAST': 19,
'KEYTYPE_REWIND': 20,
'KEYTYPE_ILLUMINATION_UP': 21,
'KEYTYPE_ILLUMINATION_DOWN': 22,
'KEYTYPE_ILLUMINATION_TOGGLE': 23
}
def _keyDown(key):
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if key in special_key_translate_table:
_specialKeyEvent(key, 'down')
else:
_normalKeyEvent(key, 'down')
def _keyUp(key):
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if key in special_key_translate_table:
_specialKeyEvent(key, 'up')
else:
_normalKeyEvent(key, 'up')
def _normalKeyEvent(key, upDown):
assert upDown in ('up', 'down'), "upDown argument must be 'up' or 'down'"
try:
if pyautogui.isShiftCharacter(key):
key_code = keyboardMapping[key.lower()]
event = Quartz.CGEventCreateKeyboardEvent(None,
keyboardMapping['shift'], upDown == 'down')
Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
# Tiny sleep to let OS X catch up on us pressing shift
time.sleep(0.01)
else:
key_code = keyboardMapping[key]
event = Quartz.CGEventCreateKeyboardEvent(None, key_code, upDown == 'down')
Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
time.sleep(0.01)
# TODO - wait, is the shift key's keyup not done?
# TODO - get rid of this try-except.
except KeyError:
raise RuntimeError("Key %s not implemented." % (key))
def _specialKeyEvent(key, upDown):
""" Helper method for special keys.
Source: http://stackoverflow.com/questions/11045814/emulate-media-key-press-on-mac
"""
assert upDown in ('up', 'down'), "upDown argument must be 'up' or 'down'"
key_code = special_key_translate_table[key]
ev = AppKit.NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
Quartz.NSSystemDefined, # type
(0,0), # location
0xa00 if upDown == 'down' else 0xb00, # flags
0, # timestamp
0, # window
0, # ctx
8, # subtype
(key_code << 16) | ((0xa if upDown == 'down' else 0xb) << 8), # data1
-1 # data2
)
Quartz.CGEventPost(0, ev.CGEvent())
def _position():
loc = AppKit.NSEvent.mouseLocation()
return int(loc.x), int(Quartz.CGDisplayPixelsHigh(0) - loc.y)
def _size():
return Quartz.CGDisplayPixelsWide(Quartz.CGMainDisplayID()), Quartz.CGDisplayPixelsHigh(Quartz.CGMainDisplayID())
def _scroll(clicks, x=None, y=None):
_vscroll(clicks, x, y)
"""
According to https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/Quartz.CGEventCreateScrollWheelEvent
"Scrolling movement is generally represented by small signed integer values, typically in a range from -10 to +10. Large values may have unexpected results, depending on the application that processes the event."
The scrolling functions will create multiple events that scroll 10 each, and then scroll the remainder.
"""
def _vscroll(clicks, x=None, y=None):
_moveTo(x, y)
clicks = int(clicks)
for _ in range(abs(clicks) // 10):
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
1, # wheelCount (number of dimensions)
10 if clicks >= 0 else -10) # vertical movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
1, # wheelCount (number of dimensions)
clicks % 10 if clicks >= 0 else -1 * (-clicks % 10)) # vertical movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
def _hscroll(clicks, x=None, y=None):
_moveTo(x, y)
clicks = int(clicks)
for _ in range(abs(clicks) // 10):
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
2, # wheelCount (number of dimensions)
0, # vertical movement
10 if clicks >= 0 else -10) # horizontal movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
2, # wheelCount (number of dimensions)
0, # vertical movement
(clicks % 10) if clicks >= 0 else (-1 * clicks % 10)) # horizontal movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
def _mouseDown(x, y, button):
if button == 'left':
_sendMouseEvent(Quartz.kCGEventLeftMouseDown, x, y, Quartz.kCGMouseButtonLeft)
elif button == 'middle':
_sendMouseEvent(Quartz.kCGEventOtherMouseDown, x, y, Quartz.kCGMouseButtonCenter)
elif button == 'right':
_sendMouseEvent(Quartz.kCGEventRightMouseDown, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _mouseUp(x, y, button):
if button == 'left':
_sendMouseEvent(Quartz.kCGEventLeftMouseUp, x, y, Quartz.kCGMouseButtonLeft)
elif button == 'middle':
_sendMouseEvent(Quartz.kCGEventOtherMouseUp, x, y, Quartz.kCGMouseButtonCenter)
elif button == 'right':
_sendMouseEvent(Quartz.kCGEventRightMouseUp, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _click(x, y, button):
if button == 'left':
_sendMouseEvent(Quartz.kCGEventLeftMouseDown, x, y, Quartz.kCGMouseButtonLeft)
_sendMouseEvent(Quartz.kCGEventLeftMouseUp, x, y, Quartz.kCGMouseButtonLeft)
elif button == 'middle':
_sendMouseEvent(Quartz.kCGEventOtherMouseDown, x, y, Quartz.kCGMouseButtonCenter)
_sendMouseEvent(Quartz.kCGEventOtherMouseUp, x, y, Quartz.kCGMouseButtonCenter)
elif button == 'right':
_sendMouseEvent(Quartz.kCGEventRightMouseDown, x, y, Quartz.kCGMouseButtonRight)
_sendMouseEvent(Quartz.kCGEventRightMouseUp, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _multiClick(x, y, button, num):
btn = None
down = None
up = None
if button == 'left':
btn = Quartz.kCGMouseButtonLeft
down = Quartz.kCGEventLeftMouseDown
up = Quartz.kCGEventLeftMouseUp
elif button == 'middle':
btn = Quartz.kCGMouseButtonCenter
down = Quartz.kCGEventOtherMouseDown
up = Quartz.kCGEventOtherMouseUp
elif button == 'right':
btn = Quartz.kCGMouseButtonRight
down = Quartz.kCGEventRightMouseDown
up = Quartz.kCGEventRightMouseUp
else:
assert False, "button argument not in ('left', 'middle', 'right')"
return
mouseEvent = Quartz.CGEventCreateMouseEvent(None, down, (x, y), btn)
Quartz.CGEventSetIntegerValueField(mouseEvent, Quartz.kCGMouseEventClickState, num)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
Quartz.CGEventSetType(mouseEvent, up)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
for i in range(0, num-1):
Quartz.CGEventSetType(mouseEvent, down)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
Quartz.CGEventSetType(mouseEvent, up)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
def _sendMouseEvent(ev, x, y, button):
mouseEvent = Quartz.CGEventCreateMouseEvent(None, ev, (x, y), button)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
def _dragTo(x, y, button):
if button == 'left':
_sendMouseEvent(Quartz.kCGEventLeftMouseDragged , x, y, Quartz.kCGMouseButtonLeft)
elif button == 'middle':
_sendMouseEvent(Quartz.kCGEventOtherMouseDragged , x, y, Quartz.kCGMouseButtonCenter)
elif button == 'right':
_sendMouseEvent(Quartz.kCGEventRightMouseDragged , x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
time.sleep(0.01) # needed to allow OS time to catch up.
def _moveTo(x, y):
_sendMouseEvent(Quartz.kCGEventMouseMoved, x, y, 0)
time.sleep(0.01) # needed to allow OS time to catch up.

@ -0,0 +1,586 @@
# Windows implementation of PyAutoGUI functions.
# BSD license
# Al Sweigart al@inventwithpython.com
import ctypes
import ctypes.wintypes
import pyautogui
import sys
if sys.platform != 'win32':
raise Exception('The pyautogui_win module should only be loaded on a Windows system.')
# Fixes the scaling issues where PyAutoGUI was reporting the wrong resolution:
try:
ctypes.windll.user32.SetProcessDPIAware()
except AttributeError:
pass # Windows XP doesn't support this, so just do nothing.
"""
A lot of this code is probably repeated from win32 extensions module, but I didn't want to have that dependency.
Note: According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms646260(v=vs.85).aspx
the ctypes.windll.user32.mouse_event() function has been superceded by SendInput.
SendInput() is documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
UPDATE: SendInput() doesn't seem to be working for me. I've switched back to mouse_event()."""
# Event codes to be passed to the mouse_event() win32 function.
# Documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
MOUSEEVENTF_LEFTDOWN = 0x0002
MOUSEEVENTF_LEFTUP = 0x0004
MOUSEEVENTF_LEFTCLICK = MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP
MOUSEEVENTF_RIGHTDOWN = 0x0008
MOUSEEVENTF_RIGHTUP = 0x0010
MOUSEEVENTF_RIGHTCLICK = MOUSEEVENTF_RIGHTDOWN + MOUSEEVENTF_RIGHTUP
MOUSEEVENTF_MIDDLEDOWN = 0x0020
MOUSEEVENTF_MIDDLEUP = 0x0040
MOUSEEVENTF_MIDDLECLICK = MOUSEEVENTF_MIDDLEDOWN + MOUSEEVENTF_MIDDLEUP
MOUSEEVENTF_WHEEL = 0x0800
MOUSEEVENTF_HWHEEL = 0x01000
# Documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx
KEYEVENTF_KEYUP = 0x0002
# Documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
# This ctypes structure is for a Win32 POINT structure,
# which is documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805(v=vs.85).aspx
# The POINT structure is used by GetCursorPos().
class POINT(ctypes.Structure):
_fields_ = [("x", ctypes.c_long),
("y", ctypes.c_long)]
# These ctypes structures are for Win32 INPUT, MOUSEINPUT, KEYBDINPUT, and HARDWAREINPUT structures,
# used by SendInput and documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
# Thanks to BSH for this StackOverflow answer: https://stackoverflow.com/questions/18566289/how-would-you-recreate-this-windows-api-structure-with-ctypes
class MOUSEINPUT(ctypes.Structure):
_fields_ = [
('dx', ctypes.wintypes.LONG),
('dy', ctypes.wintypes.LONG),
('mouseData', ctypes.wintypes.DWORD),
('dwFlags', ctypes.wintypes.DWORD),
('time', ctypes.wintypes.DWORD),
('dwExtraInfo', ctypes.POINTER(ctypes.wintypes.ULONG)),
]
class KEYBDINPUT(ctypes.Structure):
_fields_ = [
('wVk', ctypes.wintypes.WORD),
('wScan', ctypes.wintypes.WORD),
('dwFlags', ctypes.wintypes.DWORD),
('time', ctypes.wintypes.DWORD),
('dwExtraInfo', ctypes.POINTER(ctypes.wintypes.ULONG)),
]
class HARDWAREINPUT(ctypes.Structure):
_fields_ = [
('uMsg', ctypes.wintypes.DWORD),
('wParamL', ctypes.wintypes.WORD),
('wParamH', ctypes.wintypes.DWORD)
]
class INPUT(ctypes.Structure):
class _I(ctypes.Union):
_fields_ = [
('mi', MOUSEINPUT),
('ki', KEYBDINPUT),
('hi', HARDWAREINPUT),
]
_anonymous_ = ('i', )
_fields_ = [
('type', ctypes.wintypes.DWORD),
('i', _I),
]
# End of the SendInput win32 data structures.
""" Keyboard key mapping for pyautogui:
Documented at http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
The *KB dictionaries in pyautogui map a string that can be passed to keyDown(),
keyUp(), or press() into the code used for the OS-specific keyboard function.
They should always be lowercase, and the same keys should be used across all OSes."""
keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES])
keyboardMapping.update({
'backspace': 0x08, # VK_BACK
'\b': 0x08, # VK_BACK
'super': 0x5B, #VK_LWIN
'tab': 0x09, # VK_TAB
'\t': 0x09, # VK_TAB
'clear': 0x0c, # VK_CLEAR
'enter': 0x0d, # VK_RETURN
'\n': 0x0d, # VK_RETURN
'return': 0x0d, # VK_RETURN
'shift': 0x10, # VK_SHIFT
'ctrl': 0x11, # VK_CONTROL
'alt': 0x12, # VK_MENU
'pause': 0x13, # VK_PAUSE
'capslock': 0x14, # VK_CAPITAL
'kana': 0x15, # VK_KANA
'hanguel': 0x15, # VK_HANGUEL
'hangul': 0x15, # VK_HANGUL
'junja': 0x17, # VK_JUNJA
'final': 0x18, # VK_FINAL
'hanja': 0x19, # VK_HANJA
'kanji': 0x19, # VK_KANJI
'esc': 0x1b, # VK_ESCAPE
'escape': 0x1b, # VK_ESCAPE
'convert': 0x1c, # VK_CONVERT
'nonconvert': 0x1d, # VK_NONCONVERT
'accept': 0x1e, # VK_ACCEPT
'modechange': 0x1f, # VK_MODECHANGE
' ': 0x20, # VK_SPACE
'space': 0x20,
'pgup': 0x21, # VK_PRIOR
'pgdn': 0x22, # VK_NEXT
'pageup': 0x21, # VK_PRIOR
'pagedown': 0x22, # VK_NEXT
'end': 0x23, # VK_END
'home': 0x24, # VK_HOME
'left': 0x25, # VK_LEFT
'up': 0x26, # VK_UP
'right': 0x27, # VK_RIGHT
'down': 0x28, # VK_DOWN
'select': 0x29, # VK_SELECT
'print': 0x2a, # VK_PRINT
'execute': 0x2b, # VK_EXECUTE
'prtsc': 0x2c, # VK_SNAPSHOT
'prtscr': 0x2c, # VK_SNAPSHOT
'prntscrn': 0x2c, # VK_SNAPSHOT
'printscreen': 0x2c, # VK_SNAPSHOT
'insert': 0x2d, # VK_INSERT
'del': 0x2e, # VK_DELETE
'delete': 0x2e, # VK_DELETE
'help': 0x2f, # VK_HELP
'win': 0x5b, # VK_LWIN
'winleft': 0x5b, # VK_LWIN
'winright': 0x5c, # VK_RWIN
'apps': 0x5d, # VK_APPS
'sleep': 0x5f, # VK_SLEEP
'num0': 0x60, # VK_NUMPAD0
'num1': 0x61, # VK_NUMPAD1
'num2': 0x62, # VK_NUMPAD2
'num3': 0x63, # VK_NUMPAD3
'num4': 0x64, # VK_NUMPAD4
'num5': 0x65, # VK_NUMPAD5
'num6': 0x66, # VK_NUMPAD6
'num7': 0x67, # VK_NUMPAD7
'num8': 0x68, # VK_NUMPAD8
'num9': 0x69, # VK_NUMPAD9
'multiply': 0x6a, # VK_MULTIPLY ??? Is this the numpad *?
'add': 0x6b, # VK_ADD ??? Is this the numpad +?
'separator': 0x6c, # VK_SEPARATOR ??? Is this the numpad enter?
'subtract': 0x6d, # VK_SUBTRACT ??? Is this the numpad -?
'decimal': 0x6e, # VK_DECIMAL
'divide': 0x6f, # VK_DIVIDE
'f1': 0x70, # VK_F1
'f2': 0x71, # VK_F2
'f3': 0x72, # VK_F3
'f4': 0x73, # VK_F4
'f5': 0x74, # VK_F5
'f6': 0x75, # VK_F6
'f7': 0x76, # VK_F7
'f8': 0x77, # VK_F8
'f9': 0x78, # VK_F9
'f10': 0x79, # VK_F10
'f11': 0x7a, # VK_F11
'f12': 0x7b, # VK_F12
'f13': 0x7c, # VK_F13
'f14': 0x7d, # VK_F14
'f15': 0x7e, # VK_F15
'f16': 0x7f, # VK_F16
'f17': 0x80, # VK_F17
'f18': 0x81, # VK_F18
'f19': 0x82, # VK_F19
'f20': 0x83, # VK_F20
'f21': 0x84, # VK_F21
'f22': 0x85, # VK_F22
'f23': 0x86, # VK_F23
'f24': 0x87, # VK_F24
'numlock': 0x90, # VK_NUMLOCK
'scrolllock': 0x91, # VK_SCROLL
'shiftleft': 0xa0, # VK_LSHIFT
'shiftright': 0xa1, # VK_RSHIFT
'ctrlleft': 0xa2, # VK_LCONTROL
'ctrlright': 0xa3, # VK_RCONTROL
'altleft': 0xa4, # VK_LMENU
'altright': 0xa5, # VK_RMENU
'browserback': 0xa6, # VK_BROWSER_BACK
'browserforward': 0xa7, # VK_BROWSER_FORWARD
'browserrefresh': 0xa8, # VK_BROWSER_REFRESH
'browserstop': 0xa9, # VK_BROWSER_STOP
'browsersearch': 0xaa, # VK_BROWSER_SEARCH
'browserfavorites': 0xab, # VK_BROWSER_FAVORITES
'browserhome': 0xac, # VK_BROWSER_HOME
'volumemute': 0xad, # VK_VOLUME_MUTE
'volumedown': 0xae, # VK_VOLUME_DOWN
'volumeup': 0xaf, # VK_VOLUME_UP
'nexttrack': 0xb0, # VK_MEDIA_NEXT_TRACK
'prevtrack': 0xb1, # VK_MEDIA_PREV_TRACK
'stop': 0xb2, # VK_MEDIA_STOP
'playpause': 0xb3, # VK_MEDIA_PLAY_PAUSE
'launchmail': 0xb4, # VK_LAUNCH_MAIL
'launchmediaselect': 0xb5, # VK_LAUNCH_MEDIA_SELECT
'launchapp1': 0xb6, # VK_LAUNCH_APP1
'launchapp2': 0xb7, # VK_LAUNCH_APP2
#';': 0xba, # VK_OEM_1
#'+': 0xbb, # VK_OEM_PLUS
#',': 0xbc, # VK_OEM_COMMA
#'-': 0xbd, # VK_OEM_MINUS
#'.': 0xbe, # VK_OEM_PERIOD
#'/': 0xbf, # VK_OEM_2
#'~': 0xc0, # VK_OEM_3
#'[': 0xdb, # VK_OEM_4
#'|': 0xdc, # VK_OEM_5
#']': 0xdd, # VK_OEM_6
#"'": 0xde, # VK_OEM_7
#'': 0xdf, # VK_OEM_8
#'': 0xe7, # VK_PACKET
#'': 0xf6, # VK_ATTN
#'': 0xf7, # VK_CRSEL
#'': 0xf8, # VK_EXSEL
#'': 0xf9, # VK_EREOF
#'': 0xfa, # VK_PLAY
#'': 0xfb, # VK_ZOOM
#'': 0xfc, # VK_NONAME
#'': 0xfd, # VK_PA1
#'': 0xfe, # VK_OEM_CLEAR
})
# Populate the basic printable ascii characters.
for c in range(32, 128):
keyboardMapping[chr(c)] = ctypes.windll.user32.VkKeyScanA(ctypes.wintypes.WCHAR(chr(c)))
def _keyDown(key):
"""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
pyautogui.KEY_NAMES.
Returns:
None
"""
if key not in keyboardMapping or keyboardMapping[key] is None:
return
needsShift = pyautogui.isShiftCharacter(key)
"""
# OLD CODE: The new code relies on having all keys be loaded in keyboardMapping from the start.
if key in keyboardMapping.keys():
vkCode = keyboardMapping[key]
elif len(key) == 1:
# note: I could use this case to update keyboardMapping to cache the VkKeyScan results, but I've decided not to just to make any possible bugs easier to reproduce.
vkCode = ctypes.windll.user32.VkKeyScanW(ctypes.wintypes.WCHAR(key))
if vkCode == -1:
raise ValueError('There is no VK code for key "%s"' % (key))
if vkCode > 0x100: # the vk code will be > 0x100 if it needs shift
vkCode -= 0x100
needsShift = True
"""
mods, vkCode = divmod(keyboardMapping[key], 0x100)
for apply_mod, vk_mod in [(mods & 4, 0x12), (mods & 2, 0x11),
(mods & 1 or needsShift, 0x10)]: #HANKAKU not suported! mods & 8
if apply_mod:
ctypes.windll.user32.keybd_event(vk_mod, 0, 0, 0) #
ctypes.windll.user32.keybd_event(vkCode, 0, 0, 0)
for apply_mod, vk_mod in [(mods & 1 or needsShift, 0x10), (mods & 2, 0x11),
(mods & 4, 0x12)]: #HANKAKU not suported! mods & 8
if apply_mod:
ctypes.windll.user32.keybd_event(vk_mod, 0, KEYEVENTF_KEYUP, 0) #
def _keyUp(key):
"""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
pyautogui.KEY_NAMES.
Returns:
None
"""
if key not in keyboardMapping or keyboardMapping[key] is None:
return
needsShift = pyautogui.isShiftCharacter(key)
"""
# OLD CODE: The new code relies on having all keys be loaded in keyboardMapping from the start.
if key in keyboardMapping.keys():
vkCode = keyboardMapping[key]
elif len(key) == 1:
# note: I could use this case to update keyboardMapping to cache the VkKeyScan results, but I've decided not to just to make any possible bugs easier to reproduce.
vkCode = ctypes.windll.user32.VkKeyScanW(ctypes.wintypes.WCHAR(key))
if vkCode == -1:
raise ValueError('There is no VK code for key "%s"' % (key))
if vkCode > 0x100: # the vk code will be > 0x100 if it needs shift
vkCode -= 0x100
needsShift = True
"""
mods, vkCode = divmod(keyboardMapping[key], 0x100)
for apply_mod, vk_mod in [(mods & 4, 0x12), (mods & 2, 0x11),
(mods & 1 or needsShift, 0x10)]: #HANKAKU not suported! mods & 8
if apply_mod:
ctypes.windll.user32.keybd_event(vk_mod, 0, 0, 0) #
ctypes.windll.user32.keybd_event(vkCode, 0, KEYEVENTF_KEYUP, 0)
for apply_mod, vk_mod in [(mods & 1 or needsShift, 0x10), (mods & 2, 0x11),
(mods & 4, 0x12)]: #HANKAKU not suported! mods & 8
if apply_mod:
ctypes.windll.user32.keybd_event(vk_mod, 0, KEYEVENTF_KEYUP, 0) #
def _position():
"""Returns the current xy coordinates of the mouse cursor as a two-integer
tuple by calling the GetCursorPos() win32 function.
Returns:
(x, y) tuple of the current xy coordinates of the mouse cursor.
"""
cursor = POINT()
ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
return (cursor.x, cursor.y)
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 (ctypes.windll.user32.GetSystemMetrics(0), ctypes.windll.user32.GetSystemMetrics(1))
def _moveTo(x, y):
"""Send the mouse move event to Windows by calling SetCursorPos() win32
function.
Args:
button (str): The mouse button, either 'left', 'middle', or 'right'
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
Returns:
None
"""
ctypes.windll.user32.SetCursorPos(x, y)
def _mouseDown(x, y, button):
"""Send the mouse down event to Windows by calling the mouse_event() win32
function.
Args:
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
button (str): The mouse button, either 'left', 'middle', or 'right'
Returns:
None
"""
if button == 'left':
try:
_sendMouseEvent(MOUSEEVENTF_LEFTDOWN, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
elif button == 'middle':
try:
_sendMouseEvent(MOUSEEVENTF_MIDDLEDOWN, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
elif button == 'right':
try:
_sendMouseEvent(MOUSEEVENTF_RIGHTDOWN, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _mouseUp(x, y, button):
"""Send the mouse up event to Windows by calling the mouse_event() win32
function.
Args:
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
button (str): The mouse button, either 'left', 'middle', or 'right'
Returns:
None
"""
if button == 'left':
try:
_sendMouseEvent(MOUSEEVENTF_LEFTUP, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
elif button == 'middle':
try:
_sendMouseEvent(MOUSEEVENTF_MIDDLEUP, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
elif button == 'right':
try:
_sendMouseEvent(MOUSEEVENTF_RIGHTUP, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _click(x, y, button):
"""Send the mouse click event to Windows by calling the mouse_event() win32
function.
Args:
button (str): The mouse button, either 'left', 'middle', or 'right'
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
Returns:
None
"""
if button == 'left':
try:
_sendMouseEvent(MOUSEEVENTF_LEFTCLICK, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
elif button == 'middle':
try:
_sendMouseEvent(MOUSEEVENTF_MIDDLECLICK, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
elif button == 'right':
try:
_sendMouseEvent(MOUSEEVENTF_RIGHTCLICK, x, y)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _sendMouseEvent(ev, x, y, dwData=0):
"""The helper function that actually makes the call to the mouse_event()
win32 function.
Args:
ev (int): The win32 code for the mouse event. Use one of the MOUSEEVENTF_*
constants for this argument.
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
dwData (int): The argument for mouse_event()'s dwData parameter. So far
this is only used by mouse scrolling.
Returns:
None
"""
assert x != None and y != None, 'x and y cannot be set to None'
# TODO: ARG! For some reason, SendInput isn't working for mouse events. I'm switching to using the older mouse_event win32 function.
#mouseStruct = MOUSEINPUT()
#mouseStruct.dx = x
#mouseStruct.dy = y
#mouseStruct.mouseData = ev
#mouseStruct.time = 0
#mouseStruct.dwExtraInfo = ctypes.pointer(ctypes.c_ulong(0)) # according to https://stackoverflow.com/questions/13564851/generate-keyboard-events I can just set this. I don't really care about this value.
#inputStruct = INPUT()
#inputStruct.mi = mouseStruct
#inputStruct.type = INPUT_MOUSE
#ctypes.windll.user32.SendInput(1, ctypes.pointer(inputStruct), ctypes.sizeof(inputStruct))
width, height = _size()
convertedX = 65536 * x // width + 1
convertedY = 65536 * y // height + 1
ctypes.windll.user32.mouse_event(ev, ctypes.c_long(convertedX), ctypes.c_long(convertedY), dwData, 0)
# TODO: Too many false positives with this code: See: https://github.com/asweigart/pyautogui/issues/108
#if ctypes.windll.kernel32.GetLastError() != 0:
# raise ctypes.WinError()
def _scroll(clicks, x=None, y=None):
"""Send the mouse vertical scroll event to Windows by calling the
mouse_event() win32 function.
Args:
clicks (int): The amount of scrolling to do. A positive value is the mouse
wheel moving forward (scrolling up), a negative value is backwards (down).
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
Returns:
None
"""
startx, starty = _position()
width, height = _size()
if x is None:
x = startx
else:
if x < 0:
x = 0
elif x >= width:
x = width - 1
if y is None:
y = starty
else:
if y < 0:
y = 0
elif y >= height:
y = height - 1
try:
_sendMouseEvent(MOUSEEVENTF_WHEEL, x, y, dwData=clicks)
except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
pass
def _hscroll(clicks, x, y):
"""Send the mouse horizontal scroll event to Windows by calling the
mouse_event() win32 function.
Args:
clicks (int): The amount of scrolling to do. A positive value is the mouse
wheel moving right, a negative value is moving left.
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
Returns:
None
"""
return _scroll(clicks, x, y)
def _vscroll(clicks, x, y):
"""A wrapper for _scroll(), which does vertical scrolling.
Args:
clicks (int): The amount of scrolling to do. A positive value is the mouse
wheel moving forward (scrolling up), a negative value is backwards (down).
x (int): The x position of the mouse event.
y (int): The y position of the mouse event.
Returns:
None
"""
return _scroll(clicks, x, y)

@ -0,0 +1,298 @@
# NOTE - It is a known issue that the keyboard-related functions don't work on Ubuntu VMs in Virtualbox.
import pyautogui
import sys
import os
from Xlib.display import Display
from Xlib import X
from Xlib.ext.xtest import fake_input
import Xlib.XK
BUTTON_NAME_MAPPING = {'left': 1, 'middle': 2, 'right': 3, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7}
if sys.platform in ('java', 'darwin', 'win32'):
raise Exception('The pyautogui_x11 module should only be loaded on a Unix system that supports X11.')
#from pyautogui import *
"""
Much of this code is based on information gleaned from Paul Barton's PyKeyboard in PyUserInput from 2013, itself derived from Akkana Peck's pykey in 2008 ( http://www.shallowsky.com/software/crikey/pykey-0.1 ), itself derived from her "Crikey" lib.
"""
def _position():
"""Returns the current xy coordinates of the mouse cursor as a two-integer
tuple.
Returns:
(x, y) tuple of the current xy coordinates of the mouse cursor.
"""
coord = _display.screen().root.query_pointer()._data
return coord["root_x"], coord["root_y"]
def _size():
return _display.screen().width_in_pixels, _display.screen().height_in_pixels
def _vscroll(clicks, x=None, y=None):
clicks = int(clicks)
if clicks == 0:
return
elif clicks > 0:
button = 4 # scroll up
else:
button = 5 # scroll down
for i in range(abs(clicks)):
_click(x, y, button=button)
def _hscroll(clicks, x=None, y=None):
clicks = int(clicks)
if clicks == 0:
return
elif clicks > 0:
button = 7 # scroll right
else:
button = 6 # scroll left
for i in range(abs(clicks)):
_click(x, y, button=button)
def _scroll(clicks, x=None, y=None):
return _vscroll(clicks, x, y)
def _click(x, y, button):
assert button in BUTTON_NAME_MAPPING.keys(), "button argument not in ('left', 'middle', 'right', 4, 5, 6, 7)"
button = BUTTON_NAME_MAPPING[button]
_mouseDown(x, y, button)
_mouseUp(x, y, button)
def _moveTo(x, y):
fake_input(_display, X.MotionNotify, x=x, y=y)
_display.sync()
def _mouseDown(x, y, button):
_moveTo(x, y)
assert button in BUTTON_NAME_MAPPING.keys(), "button argument not in ('left', 'middle', 'right', 4, 5, 6, 7)"
button = BUTTON_NAME_MAPPING[button]
fake_input(_display, X.ButtonPress, button)
_display.sync()
def _mouseUp(x, y, button):
_moveTo(x, y)
assert button in BUTTON_NAME_MAPPING.keys(), "button argument not in ('left', 'middle', 'right', 4, 5, 6, 7)"
button = BUTTON_NAME_MAPPING[button]
fake_input(_display, X.ButtonRelease, button)
_display.sync()
def _keyDown(key):
"""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
pyautogui.KEY_NAMES.
Returns:
None
"""
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if type(key) == int:
fake_input(_display, X.KeyPress, key)
_display.sync()
return
needsShift = pyautogui.isShiftCharacter(key)
if needsShift:
fake_input(_display, X.KeyPress, keyboardMapping['shift'])
fake_input(_display, X.KeyPress, keyboardMapping[key])
if needsShift:
fake_input(_display, X.KeyRelease, keyboardMapping['shift'])
_display.sync()
def _keyUp(key):
"""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
pyautogui.KEY_NAMES.
Returns:
None
"""
"""
Release a given character key. Also works with character keycodes as
integers, but not keysyms.
"""
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if type(key) == int:
keycode = key
else:
keycode = keyboardMapping[key]
fake_input(_display, X.KeyRelease, keycode)
_display.sync()
# Taken from PyKeyboard's ctor function.
_display = Display(os.environ['DISPLAY'])
""" Information for keyboardMapping derived from PyKeyboard's special_key_assignment() function.
The *KB dictionaries in pyautogui map a string that can be passed to keyDown(),
keyUp(), or press() into the code used for the OS-specific keyboard function.
They should always be lowercase, and the same keys should be used across all OSes."""
keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES])
keyboardMapping.update({
'backspace': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')),
'\b': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')),
'tab': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')),
'enter': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')),
'return': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')),
'shift': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')),
'ctrl': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')),
'alt': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')),
'pause': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Pause')),
'capslock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Caps_Lock')),
'esc': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
'escape': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
'pgup': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')),
'pgdn': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')),
'pageup': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')),
'pagedown': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')),
'end': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('End')),
'home': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Home')),
'left': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Left')),
'up': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Up')),
'right': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Right')),
'down': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Down')),
'select': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Select')),
'print': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'execute': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Execute')),
'prtsc': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'prtscr': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'prntscrn': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'printscreen': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'insert': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Insert')),
'del': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Delete')),
'delete': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Delete')),
'help': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Help')),
'winleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_L')),
'winright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_R')),
'apps': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_L')),
'num0': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_0')),
'num1': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_1')),
'num2': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_2')),
'num3': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_3')),
'num4': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_4')),
'num5': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_5')),
'num6': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_6')),
'num7': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_7')),
'num8': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_8')),
'num9': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_9')),
'multiply': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Multiply')),
'add': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Add')),
'separator': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Separator')),
'subtract': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Subtract')),
'decimal': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Decimal')),
'divide': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Divide')),
'f1': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F1')),
'f2': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F2')),
'f3': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F3')),
'f4': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F4')),
'f5': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F5')),
'f6': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F6')),
'f7': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F7')),
'f8': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F8')),
'f9': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F9')),
'f10': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F10')),
'f11': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F11')),
'f12': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F12')),
'f13': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F13')),
'f14': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F14')),
'f15': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F15')),
'f16': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F16')),
'f17': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F17')),
'f18': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F18')),
'f19': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F19')),
'f20': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F20')),
'f21': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F21')),
'f22': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F22')),
'f23': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F23')),
'f24': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F24')),
'numlock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Num_Lock')),
'scrolllock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Scroll_Lock')),
'shiftleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')),
'shiftright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_R')),
'ctrlleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')),
'ctrlright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_R')),
'altleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')),
'altright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_R')),
# These are added because unlike a-zA-Z0-9, the single characters do not have a
' ': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('space')),
'space': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('space')),
'\t': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')),
'\n': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), # for some reason this needs to be cr, not lf
'\r': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')),
'\e': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
'!': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('exclam')),
'#': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('numbersign')),
'%': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('percent')),
'$': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('dollar')),
'&': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('ampersand')),
'"': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('quotedbl')),
"'": _display.keysym_to_keycode(Xlib.XK.string_to_keysym('apostrophe')),
'(': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('parenleft')),
')': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('parenright')),
'*': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('asterisk')),
'=': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('equal')),
'+': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('plus')),
',': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('comma')),
'-': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('minus')),
'.': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('period')),
'/': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('slash')),
':': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('colon')),
';': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('semicolon')),
'<': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('less')),
'>': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('greater')),
'?': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('question')),
'@': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('at')),
'[': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('bracketleft')),
']': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('bracketright')),
'\\': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('backslash')),
'^': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('asciicircum')),
'_': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('underscore')),
'`': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('grave')),
'{': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('braceleft')),
'|': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('bar')),
'}': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('braceright')),
'~': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('asciitilde')),
})
# Trading memory for time" populate winKB so we don't have to call VkKeyScanA each time.
for c in """abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890""":
keyboardMapping[c] = _display.keysym_to_keycode(Xlib.XK.string_to_keysym(c))

@ -0,0 +1,117 @@
# Window-handling features of PyAutoGUI for win_32
import ctypes
import ctypes.wintypes
import sys
if sys.platform != 'win32':
raise Exception('The _window_win module should only be loaded on a Windows system.')
SetWindowPos = ctypes.windll.user32.SetWindowPos
# Flags for SetWindowPos:
SWP_NOMOVE = ctypes.c_uint(0x0002)
SWP_NOSIZE = ctypes.c_uint(0x0001)
ShowWindow = ctypes.windll.user32.ShowWindow
# Flags for ShowWindow:
SW_MAXIMIZE = 3
SW_MINIMIZE = 6
SW_RESTORE = 9
SwitchToThisWindow = ctypes.windll.user32.SwitchToThisWindow
SetForegroundWindow = ctypes.windll.user32.SetForegroundWindow
CloseWindow = ctypes.windll.user32.CloseWindow
GetWindowRect = ctypes.windll.user32.GetWindowRect
EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible
class _Rect(ctypes.Structure):
_fields_ = [('left', ctypes.c_long),
('top', ctypes.c_long),
('right', ctypes.c_long),
('bottom', ctypes.c_long)]
class Window(object):
def __init__(self, hwnd):
self._hwnd = hwnd # Window handle
def set_position(self, x, y, width, height):
"""Set window top-left corner position and size"""
SetWindowPos(self._hwnd, None, x, y, width, height, ctypes.c_uint(0))
def move(self, x, y):
"""Move window top-left corner to position"""
SetWindowPos(self._hwnd, None, x, y, 0, 0, SWP_NOSIZE)
def resize(self, width, height):
"""Change window size"""
SetWindowPos(self._hwnd, None, 0, 0, width, height, SWP_NOMOVE)
def maximize(self):
ShowWindow(self._hwnd, SW_MAXIMIZE)
def set_foreground(self):
SetForegroundWindow(self._hwnd)
def minimize(self):
ShowWindow(self._hwnd, SW_MINIMIZE)
def restore(self):
ShowWindow(self._hwnd, SW_RESTORE)
def close(self):
CloseWindow(self._hwnd)
def get_position(self):
"""Returns tuple of 4 numbers: (x, y)s of top-left and bottom-right corners"""
rect = _Rect()
GetWindowRect(self._hwnd, ctypes.pointer(rect))
return rect.left, rect.top, rect.right, rect.bottom
# def moveRel(self, x=0, y=0): # moves relative to the x, y of top-left corner of the window
# pass
# def clickRel(self, x=0, y=0, clicks=1, interval=0.0, button='left'):
# click relative to the x, y of top-left corner of the window
# pass
def getWindows(): #https://sjohannes.wordpress.com/2012/03/23/win32-python-getting-all-window-titles/
"""Return dict: {'window title' : window handle} for all visible windows"""
titles = {}
def foreach_window(hwnd, lparam):
if IsWindowVisible(hwnd):
length = GetWindowTextLength(hwnd)
buff = ctypes.create_unicode_buffer(length + 1)
GetWindowText(hwnd, buff, length + 1)
titles[buff.value] = hwnd
return True
EnumWindows(EnumWindowsProc(foreach_window), 0)
return titles
def getWindow(title, exact=False):
"""Return Window object if 'title' or its part found in visible windows titles, else return None
Return only 1 window found first
Args:
title: unicode string
exact (bool): True if search only exact match
"""
titles = getWindows()
hwnd = titles.get(title, None)
if not hwnd and not exact:
for k, v in titles.items():
if title in k:
hwnd = v
break
if hwnd:
return Window(hwnd)
else:
return None

@ -0,0 +1,217 @@
# Screenshot-related features of PyAutoGUI
"""
So, apparently Pillow support on Ubuntu 64-bit has several additional steps since it doesn't have JPEG/PNG support out of the box. Description here:
https://stackoverflow.com/questions/7648200/pip-install-pil-e-tickets-1-no-jpeg-png-support
http://ubuntuforums.org/showthread.php?t=1751455
"""
import datetime
import os
import subprocess
import sys
from PIL import Image
from PIL import ImageOps
RUNNING_PYTHON_2 = sys.version_info[0] == 2
scrotExists = False
maimExists = False
try:
if sys.platform not in ('java', 'darwin', 'win32'):
whichProc = subprocess.Popen(['which', 'scrot'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
scrotExists = whichProc.wait() == 0
except:
# if there is no "which" program to find scrot, then assume there is no scrot.
pass
try:
if sys.platform not in ('java', 'darwin', 'win32'):
whichProc = subprocess.Popen(['which', 'maim'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
maimExists = whichProc.wait() == 0
except:
# if there is no "which" program to find maim, then assume there is no maim.
pass
def locateAll(needleImage, haystackImage, grayscale=False, limit=None):
needleFileObj = None
haystackFileObj = None
if isinstance(needleImage, str):
# 'image' is a filename, load the Image object
needleFileObj = open(needleImage, 'rb')
needleImage = Image.open(needleFileObj)
if isinstance(haystackImage, str):
# 'image' is a filename, load the Image object
haystackFileObj = open(haystackImage, 'rb')
haystackImage = Image.open(haystackFileObj)
if grayscale:
needleImage = ImageOps.grayscale(needleImage)
haystackImage = ImageOps.grayscale(haystackImage)
needleWidth, needleHeight = needleImage.size
haystackWidth, haystackHeight = haystackImage.size
needleImageData = tuple(needleImage.getdata()) # TODO - rename to needleImageData??
haystackImageData = tuple(haystackImage.getdata())
needleImageRows = [needleImageData[y * needleWidth:(y+1) * needleWidth] for y in range(needleHeight)] # LEFT OFF - check this
needleImageFirstRow = needleImageRows[0]
assert len(needleImageFirstRow) == needleWidth
assert [len(row) for row in needleImageRows] == [needleWidth] * needleHeight
numMatchesFound = 0
for y in range(haystackHeight):
for matchx in _kmp(needleImageFirstRow, haystackImageData[y * haystackWidth:(y+1) * haystackWidth]):
foundMatch = True
for searchy in range(1, needleHeight):
haystackStart = (searchy + y) * haystackWidth + matchx
if needleImageData[searchy * needleWidth:(searchy+1) * needleWidth] != haystackImageData[haystackStart:haystackStart + needleWidth]:
foundMatch = False
break
if foundMatch:
# Match found, report the x, y, width, height of where the matching region is in haystack.
numMatchesFound += 1
yield (matchx, y, needleWidth, needleHeight)
if limit is not None and numMatchesFound >= limit:
# Limit has been reached. Close file handles.
if needleFileObj is not None:
needleFileObj.close()
if haystackFileObj is not None:
haystackFileObj.close()
# There was no limit or the limit wasn't reached, but close the file handles anyway.
if needleFileObj is not None:
needleFileObj.close()
if haystackFileObj is not None:
haystackFileObj.close()
def locate(needleImage, haystackImage, grayscale=False):
# Note: The gymnastics in this function is because we want to make sure to exhaust the iterator so that the needle and haystack files are closed in locateAll.
points = tuple(locateAll(needleImage, haystackImage, grayscale, 1))
if len(points) > 0:
return points[0]
else:
return None
def locateOnScreen(image, grayscale=False,region=None):
screenshotIm = screenshot(region=region)
retVal = locate(image, screenshotIm, grayscale)
if 'fp' in dir(screenshotIm) and screenshotIm.fp is not None:
screenshotIm.fp.close() # Screenshots on Windows won't have an fp since they came from ImageGrab, not a file.
return retVal
def locateAllOnScreen(image, grayscale=False, limit=None, region=None):
screenshotIm = screenshot(region=region)
retVal = locateAll(image, screenshotIm, grayscale, limit)
if 'fp' in dir(screenshotIm) and screenshotIm.fp is not None:
screenshotIm.fp.close() # Screenshots on Windows won't have an fp since they came from ImageGrab, not a file.
return retVal
def locateCenterOnScreen(image, grayscale=False, region=None):
return center(locateOnScreen(image, grayscale, region))
def _screenshot_win32(imageFilename=None):
im = ImageGrab.grab()
if imageFilename is not None:
im.save(imageFilename)
return im
def _screenshot_osx(imageFilename=None):
if imageFilename is None:
tmpFilename = 'screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
else:
tmpFilename = imageFilename
subprocess.call(['screencapture', '-x', tmpFilename])
im = Image.open(tmpFilename)
if imageFilename is None:
os.unlink(tmpFilename)
return im
def _screenshot_linux(imageFilename=None, region=None):
if not scrotExists:
raise NotImplementedError('"scrot" must be installed to use screenshot functions in Linux. Run: sudo apt-get install scrot')
if imageFilename is None:
tmpFilename = '.screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
else:
tmpFilename = imageFilename
if scrotExists:
if not region:
subprocess.call(['scrot', tmpFilename])
else:
if not maimExists:
raise NotImplementedError('"maim" must be installed to use screenshot functions with region in Linux. Run: sudo apt-get install maim')
left,top,width,height = [str(x) for x in region]
subprocess.call(['maim','-x',left,'-y',top,'-w',width,'-h',height, tmpFilename])
im = Image.open(tmpFilename)
if imageFilename is None:
os.unlink(tmpFilename)
return im
else:
raise Exception('The scrot program must be installed to take a screenshot with PyAutoGUI on Linux. Run: sudo apt-get install scrot')
def _kmp(needle, haystack): # Knuth-Morris-Pratt search algorithm implementation (to be used by screen capture)
# build table of shift amounts
shifts = [1] * (len(needle) + 1)
shift = 1
for pos in range(len(needle)):
while shift <= pos and needle[pos] != needle[pos-shift]:
shift += shifts[pos-shift]
shifts[pos+1] = shift
# do the actual search
startPos = 0
matchLen = 0
for c in haystack:
while matchLen == len(needle) or \
matchLen >= 0 and needle[matchLen] != c:
startPos += shifts[matchLen]
matchLen -= shifts[matchLen]
matchLen += 1
if matchLen == len(needle):
yield startPos
def center(coords):
return (coords[0] + int(coords[2] / 2), coords[1] + int(coords[3] / 2))
def pixelMatchesColor(x, y, expectedRGBColor, tolerance=0):
r, g, b = screenshot().getpixel((x, y))
exR, exG, exB = expectedRGBColor
return (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance)
def pixel(x, y):
return screenshot().getpixel((x, y))
# set the screenshot() function based on the platform running this module
if sys.platform.startswith('java'):
raise NotImplementedError('Jython is not yet supported by PyAutoGUI.')
elif sys.platform == 'darwin':
screenshot = _screenshot_osx
elif sys.platform == 'win32':
screenshot = _screenshot_win32
from PIL import ImageGrab
else:
screenshot = _screenshot_linux
grab = screenshot # for compatibility with Pillow/PIL's ImageGrab module.

@ -0,0 +1,9 @@
@property
def foo():
return _foo
@foo.setter
def foo(value):
_foo = value
_foo = 'foo'

@ -0,0 +1,36 @@
import pytweening
# This is just left here for backwards compatibility. I'll be deprecating this in favor of pyautogui.linear, pyautogui.easeInQuad, etc.
getPointOnLine = pytweening.getPointOnLine
linear = pytweening.linear
easeInQuad = pytweening.easeInQuad
easeOutQuad = pytweening.easeOutQuad
easeInOutQuad = pytweening.easeInOutQuad
easeInCubic = pytweening.easeInCubic
easeOutCubic = pytweening.easeOutCubic
easeInOutCubic = pytweening.easeInOutCubic
easeInQuart = pytweening.easeInQuart
easeOutQuart = pytweening.easeOutQuart
easeInOutQuart = pytweening.easeInOutQuart
easeInQuint = pytweening.easeInQuint
easeOutQuint = pytweening.easeOutQuint
easeInOutQuint = pytweening.easeInOutQuint
easeInSine = pytweening.easeInSine
easeOutSine = pytweening.easeOutSine
easeInOutSine = pytweening.easeInOutSine
easeInExpo = pytweening.easeInExpo
easeOutExpo = pytweening.easeOutExpo
easeInOutExpo = pytweening.easeInOutExpo
easeInCirc = pytweening.easeInCirc
easeOutCirc = pytweening.easeOutCirc
easeInOutCirc = pytweening.easeInOutCirc
easeInElastic = pytweening.easeInElastic
easeOutElastic = pytweening.easeOutElastic
easeInOutElastic = pytweening.easeInOutElastic
easeInBack = pytweening.easeInBack
easeOutBack = pytweening.easeOutBack
easeInOutBack = pytweening.easeInOutBack
easeInBounce = pytweening.easeInBounce
easeOutBounce = pytweening.easeOutBounce
easeInOutBounce = pytweening.easeInOutBounce

@ -0,0 +1,50 @@
# PyGetWindow
# A cross-platform module to find information about the windows on the screen.
"""
# Work in progress
# Useful info:
#https://stackoverflow.com/questions/373020/finding-the-current-active-window-in-mac-os-x-using-python
#https://stackoverflow.com/questions/7142342/get-window-position-size-with-python
win32 api and ctypes on Windows
cocoa api and pyobjc on Mac
Xlib on linux
Possible Future Features:
get/click menu (win32: GetMenuItemCount, GetMenuItemInfo, GetMenuItemID, GetMenu, GetMenuItemRect)
"""
__version__ = '0.0.5'
import sys
import collections
class PyGetWindowException(Exception):
pass
def pointInRect(x, y, left, top, width, height):
return left < x < left + width and top < y < top + height
if sys.platform == 'darwin':
raise NotImplementedError('PyGetWindow currently does not support macOS. If you have Appkit/Cocoa knowledge, please contribute! https://github.com/asweigart/pygetwindow') # TODO - implement mac
elif sys.platform == 'win32':
from ._pygetwindow_win import Win32Window, getActiveWindow, getWindowsAt, getWindowsWithTitle, getAllWindows, getAllTitles
Window = Win32Window
else:
raise NotImplementedError('PyGetWindow currently does not support Linux. If you have Xlib knowledge, please contribute! https://github.com/asweigart/pygetwindow')
# NOTE: `Rect` is a named tuple for use in Python, while structs.RECT represents
# the win32 RECT struct. PyRect's Rect class is used for handling changing
# geometry of rectangular areas.
Rect = collections.namedtuple('Rect', 'left top right bottom')
Point = collections.namedtuple('Point', 'x y')
Size = collections.namedtuple('Size', 'width height')

@ -0,0 +1,388 @@
import Quartz
import pygetwindow
def getAllTitles():
"""Returns a list of strings of window titles for all visible windows.
"""
# Source: https://stackoverflow.com/questions/53237278/obtain-list-of-all-window-titles-on-macos-from-a-python-script/53985082#53985082
windows = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListExcludeDesktopElements | Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID)
return ['%s %s' % (win[Quartz.kCGWindowOwnerName], win.get(Quartz.kCGWindowName, '')) for win in windows]
def getFocusedWindow():
"""Returns a Window object of the currently focused Window."""
# Source: https://stackoverflow.com/questions/5286274/front-most-window-using-cgwindowlistcopywindowinfo
windows = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListExcludeDesktopElements | Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID)
for win in windows:
if win['kCGWindowLayer'] == 0:
return '%s %s' % (win[Quartz.kCGWindowOwnerName], win.get(Quartz.kCGWindowName, '')) # Temporary. For now, we'll just return the title of the focused window.
raise Exception('Could not find a focused window.') # Temporary hack.
def getWindowsAt(x, y):
windows = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListExcludeDesktopElements | Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID)
matches = []
for win in windows:
w = win['kCGWindowBounds']
if pygetwindow.pointInRect(x, y, w['X'], w['Y'], w['Width'], w['Height']):
matches.append('%s %s' % (win[Quartz.kCGWindowOwnerName], win.get(Quartz.kCGWindowName, '')))
return matches
def focusWindow():
# TEMP - this is not a real api, I'm just using this name to store these notes for now.
# Source: https://stackoverflow.com/questions/7460092/nswindow-makekeyandorderfront-makes-window-appear-but-not-key-or-front?rq=1
# Source: https://stackoverflow.com/questions/4905024/is-it-possible-to-bring-window-to-front-without-taking-focus?rq=1
pass
def getWindowGeometry(title):
# TEMP - this is not a real api, I'm just using this name to stoe these notes for now.
windows = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListExcludeDesktopElements | Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID)
for win in windows:
if title in '%s %s' % (win[Quartz.kCGWindowOwnerName], win.get(Quartz.kCGWindowName, '')):
w = win['kCGWindowBounds']
return (w['X'], w['Y'], w['Width'], w['Height'])
def isVisible(title):
# TEMP - this is not a real api, I'm just using this name to stoe these notes for now.
windows = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListExcludeDesktopElements | Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID)
for win in windows:
if title in '%s %s' % (win[Quartz.kCGWindowOwnerName], win.get(Quartz.kCGWindowName, '')):
return win['kCGWindowAlpha'] != 0.0
def isMinimized():
# TEMP - this is not a real api, I'm just using this name to stoe these notes for now.
# Source: https://stackoverflow.com/questions/10258676/how-to-know-whether-a-window-is-minimised-or-not
# Use the kCGWindowIsOnscreen to check this. Minimized windows are considered to not be on the screen. (But I'm not sure if there are other situations where a window is "off screen".)
# I'm not sure how kCGWindowListOptionOnScreenOnly interferes with this.
pass
# TODO: This class doesn't work yet. I've copied the Win32Window class and will make adjustments as needed here.
class MacOSWindow():
def __init__(self, hWnd):
self._hWnd = hWnd # TODO fix this, this is a LP_c_long insead of an int.
def _onRead(attrName):
r = _getWindowRect(self._hWnd)
self._rect._left = r.left # Setting _left directly to skip the onRead.
self._rect._top = r.top # Setting _top directly to skip the onRead.
self._rect._width = r.right - r.left # Setting _width directly to skip the onRead.
self._rect._height = r.bottom - r.top # Setting _height directly to skip the onRead.
def _onChange(oldBox, newBox):
self.moveTo(newBox.left, newBox.top)
self.resizeTo(newBox.width, newBox.height)
r = _getWindowRect(self._hWnd)
self._rect = pyrect.Rect(r.left, r.top, r.right - r.left, r.bottom - r.top, onChange=_onChange, onRead=_onRead)
def __str__(self):
r = _getWindowRect(self._hWnd)
width = r.right - r.left
height = r.bottom - r.top
return '<%s left="%s", top="%s", width="%s", height="%s", title="%s">' % (self.__class__.__name__, r.left, r.top, width, height, self.title)
def __repr__(self):
return '%s(hWnd=%s)' % (self.__class__.__name__, self._hWnd)
def __eq__(self, other):
return isinstance(other, Win32Window) and self._hWnd == other._hWnd
def close(self):
"""Closes this window. This may trigger "Are you sure you want to
quit?" dialogs or other actions that prevent the window from
actually closing. This is identical to clicking the X button on the
window."""
result = ctypes.windll.user32.PostMessageA(self._hWnd, WM_CLOSE, 0, 0)
if result == 0:
_raiseWithLastError()
def minimize(self):
"""Minimizes this window."""
ctypes.windll.user32.ShowWindow(self._hWnd, SW_MINIMIZE)
def maximize(self):
"""Maximizes this window."""
ctypes.windll.user32.ShowWindow(self._hWnd, SW_MAXIMIZE)
def restore(self):
"""If maximized or minimized, restores the window to it's normal size."""
ctypes.windll.user32.ShowWindow(self._hWnd, SW_RESTORE)
def focus(self):
"""Focus this window and make it the foreground window."""
result = ctypes.windll.user32.SetForegroundWindow(self._hWnd)
if result == 0:
_raiseWithLastError()
def resizeRel(self, widthOffset, heightOffset):
"""Resizes the window relative to its current size."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, self.left, self.top, self.width + widthOffset, self.height + heightOffset, 0)
if result == 0:
_raiseWithLastError()
def resizeTo(self, newWidth, newHeight):
"""Resizes the window to a new width and height."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, self.left, self.top, newWidth, newHeight, 0)
if result == 0:
_raiseWithLastError()
def moveRel(self, xOffset, yOffset):
"""Moves the window relative to its current position."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, self.left + xOffset, self.top + yOffset, self.width, self.height, 0)
if result == 0:
_raiseWithLastError()
def moveTo(self, newLeft, newTop):
"""Moves the window to new coordinates on the screen."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, newLeft, newTop, self.width, self.height, 0)
if result == 0:
_raiseWithLastError()
@property
def isMinimized(self):
"""Returns True if the window is currently minimized."""
return ctypes.windll.user32.IsIconic(self._hWnd) != 0
@property
def isMaximized(self):
"""Returns True if the window is currently maximized."""
return ctypes.windll.user32.IsZoomed(self._hWnd) != 0
@property
def isFocused(self):
"""Returns True if the window is currently the focused, foreground window."""
return getFocusedWindow() == self
@property
def title(self):
"""Returns the window title as a string."""
return _getWindowText(self._hWnd)
@property
def visible(self):
return isWindowVisible(self._hWnd)
# Wrappers for pyrect.Rect object's properties.
@property
def left(self):
return self._rect.left
@left.setter
def left(self, value):
#import pdb; pdb.set_trace()
self._rect.left # Run rect's onRead to update the Rect object.
self._rect.left = value
@property
def right(self):
return self._rect.right
@right.setter
def right(self, value):
self._rect.right # Run rect's onRead to update the Rect object.
self._rect.right = value
@property
def top(self):
return self._rect.top
@top.setter
def top(self, value):
self._rect.top # Run rect's onRead to update the Rect object.
self._rect.top = value
@property
def bottom(self):
return self._rect.bottom
@bottom.setter
def bottom(self, value):
self._rect.bottom # Run rect's onRead to update the Rect object.
self._rect.bottom = value
@property
def topleft(self):
return self._rect.topleft
@topleft.setter
def topleft(self, value):
self._rect.topleft # Run rect's onRead to update the Rect object.
self._rect.topleft = value
@property
def topright(self):
return self._rect.topright
@topright.setter
def topright(self, value):
self._rect.topright # Run rect's onRead to update the Rect object.
self._rect.topright = value
@property
def bottomleft(self):
return self._rect.bottomleft
@bottomleft.setter
def bottomleft(self, value):
self._rect.bottomleft # Run rect's onRead to update the Rect object.
self._rect.bottomleft = value
@property
def bottomright(self):
return self._rect.bottomright
@bottomright.setter
def bottomright(self, value):
self._rect.bottomright # Run rect's onRead to update the Rect object.
self._rect.bottomright = value
@property
def midleft(self):
return self._rect.midleft
@midleft.setter
def midleft(self, value):
self._rect.midleft # Run rect's onRead to update the Rect object.
self._rect.midleft = value
@property
def midright(self):
return self._rect.midright
@midright.setter
def midright(self, value):
self._rect.midright # Run rect's onRead to update the Rect object.
self._rect.midright = value
@property
def midtop(self):
return self._rect.midtop
@midtop.setter
def midtop(self, value):
self._rect.midtop # Run rect's onRead to update the Rect object.
self._rect.midtop = value
@property
def midbottom(self):
return self._rect.midbottom
@midbottom.setter
def midbottom(self, value):
self._rect.midbottom # Run rect's onRead to update the Rect object.
self._rect.midbottom = value
@property
def center(self):
return self._rect.center
@center.setter
def center(self, value):
self._rect.center # Run rect's onRead to update the Rect object.
self._rect.center = value
@property
def centerx(self):
return self._rect.centerx
@centerx.setter
def centerx(self, value):
self._rect.centerx # Run rect's onRead to update the Rect object.
self._rect.centerx = value
@property
def centery(self):
return self._rect.centery
@centery.setter
def centery(self, value):
self._rect.centery # Run rect's onRead to update the Rect object.
self._rect.centery = value
@property
def width(self):
return self._rect.width
@width.setter
def width(self, value):
self._rect.width # Run rect's onRead to update the Rect object.
self._rect.width = value
@property
def height(self):
return self._rect.height
@height.setter
def height(self, value):
self._rect.height # Run rect's onRead to update the Rect object.
self._rect.height = value
@property
def size(self):
return self._rect.size
@size.setter
def size(self, value):
self._rect.size # Run rect's onRead to update the Rect object.
self._rect.size = value
@property
def area(self):
return self._rect.area
@area.setter
def area(self, value):
self._rect.area # Run rect's onRead to update the Rect object.
self._rect.area = value
@property
def box(self):
return self._rect.box
@box.setter
def box(self, value):
self._rect.box # Run rect's onRead to update the Rect object.
self._rect.box = value

@ -0,0 +1,563 @@
import ctypes
import pyrect
from ctypes import wintypes # We can't use ctypes.wintypes, we must import wintypes this way.
import pygetwindow
NULL = 0 # Used to match the Win32 API value of "null".
# These FORMAT_MESSAGE_ constants are used for FormatMesage() and are
# documented at https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-formatmessage#parameters
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
# These SW_ constants are used for ShowWindow() and are documented at
# https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-showwindow#parameters
SW_MINIMIZE = 6
SW_MAXIMIZE = 3
SW_RESTORE = 9
# SetWindowPos constants:
HWND_TOP = 0
# Window Message constants:
WM_CLOSE = 0x0010
# This ctypes structure is for a Win32 POINT structure,
# which is documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805(v=vs.85).aspx
# The POINT structure is used by GetCursorPos().
class POINT(ctypes.Structure):
_fields_ = [("x", ctypes.c_long),
("y", ctypes.c_long)]
enumWindows = ctypes.windll.user32.EnumWindows
enumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
getWindowText = ctypes.windll.user32.GetWindowTextW
getWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
isWindowVisible = ctypes.windll.user32.IsWindowVisible
class RECT(ctypes.Structure):
"""A nice wrapper of the RECT structure.
Microsoft Documentation:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd162897(v=vs.85).aspx
"""
_fields_ = [('left', ctypes.c_long),
('top', ctypes.c_long),
('right', ctypes.c_long),
('bottom', ctypes.c_long)]
def _getAllTitles():
# This code taken from https://sjohannes.wordpress.com/2012/03/23/win32-python-getting-all-window-titles/
# A correction to this code (for enumWindowsProc) is here: http://makble.com/the-story-of-lpclong
titles = []
def foreach_window(hWnd, lParam):
if isWindowVisible(hWnd):
length = getWindowTextLength(hWnd)
buff = ctypes.create_unicode_buffer(length + 1)
getWindowText(hWnd, buff, length + 1)
titles.append((hWnd, buff.value))
return True
enumWindows(enumWindowsProc(foreach_window), 0)
return titles
def _formatMessage(errorCode):
"""A nice wrapper for FormatMessageW(). TODO
Microsoft Documentation:
https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-formatmessagew
Additional information:
https://stackoverflow.com/questions/18905702/python-ctypes-and-mutable-buffers
https://stackoverflow.com/questions/455434/how-should-i-use-formatmessage-properly-in-c
"""
lpBuffer = wintypes.LPWSTR()
ctypes.windll.kernel32.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorCode,
0, # dwLanguageId
ctypes.cast(ctypes.byref(lpBuffer), wintypes.LPWSTR),
0, # nSize
NULL)
msg = lpBuffer.value.rstrip()
ctypes.windll.kernel32.LocalFree(lpBuffer) # Free the memory allocated for the error message's buffer.
return msg
def _raiseWithLastError():
"""A helper function that raises PyGetWindowException using the error
information from GetLastError() and FormatMessage()."""
errorCode = ctypes.windll.kernel32.GetLastError()
raise pygetwindow.PyGetWindowException('Error code from Windows: %s - %s' % (errorCode, _formatMessage(errorCode)))
def _getWindowRect(hWnd):
"""A nice wrapper for GetWindowRect(). TODO
Syntax:
BOOL GetWindowRect(
HWND hWnd,
LPRECT lpRect
);
Microsoft Documentation:
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowrect
"""
rect = RECT()
result = ctypes.windll.user32.GetWindowRect(hWnd, ctypes.byref(rect))
if result != 0:
return pygetwindow.Rect(rect.left, rect.top, rect.right, rect.bottom)
else:
_raiseWithLastError()
def _getWindowText(hWnd):
"""A wrapper for the GetWindowTextW() win api. TODO
Syntax:
int GetWindowTextW(
HWND hWnd,
LPWSTR lpString,
int nMaxCount
);
int GetWindowTextLengthW(
HWND hWnd
);
Microsoft Documentation:
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowtextw
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowtextlengthw
"""
textLenInCharacters = ctypes.windll.user32.GetWindowTextLengthW(hWnd)
stringBuffer = ctypes.create_unicode_buffer(textLenInCharacters + 1) # +1 for the \0 at the end of the null-terminated string.
ctypes.windll.user32.GetWindowTextW(hWnd, stringBuffer, textLenInCharacters + 1)
# TODO it's ambiguous if an error happened or the title text is just empty. Look into this later.
return stringBuffer.value
def getActiveWindow():
"""Returns a Window object of the currently active Window."""
hWnd = ctypes.windll.user32.GetForegroundWindow()
if hWnd == 0:
# TODO - raise error instead
return None # Note that this function doesn't use GetLastError().
else:
return Win32Window(hWnd)
def getWindowsAt(x, y):
"""Returns a list of Window objects
Args:
x (int, optional): The x position of the window(s).
y (int, optional): The y position of the window(s)."""
windowsAtXY = []
for window in getAllWindows():
if pygetwindow.pointInRect(x, y, window.left, window.top, window.width, window.height):
windowsAtXY.append(window)
return windowsAtXY
def getWindowsWithTitle(title):
"""Returns a list of Window objects that substring match the title.
"""
hWndsAndTitles = _getAllTitles()
windowObjs = []
for hWnd, winTitle in hWndsAndTitles:
if title.upper() in winTitle.upper(): # do a case-insensitive match
windowObjs.append(Win32Window(hWnd))
return windowObjs
def getAllTitles():
"""Returns a list of strings of window titles for all visible windows.
"""
return [window.title for window in getAllWindows()]
def getAllWindows():
"""Returns a list of Window objects for all visible windows.
"""
windowObjs = []
def foreach_window(hWnd, lParam):
if ctypes.windll.user32.IsWindowVisible(hWnd) != 0:
windowObjs.append(Win32Window(hWnd))
return True
enumWindows(enumWindowsProc(foreach_window), 0)
return windowObjs
class Win32Window():
def __init__(self, hWnd):
self._hWnd = hWnd # TODO fix this, this is a LP_c_long insead of an int.
def _onRead(attrName):
r = _getWindowRect(self._hWnd)
self._rect._left = r.left # Setting _left directly to skip the onRead.
self._rect._top = r.top # Setting _top directly to skip the onRead.
self._rect._width = r.right - r.left # Setting _width directly to skip the onRead.
self._rect._height = r.bottom - r.top # Setting _height directly to skip the onRead.
def _onChange(oldBox, newBox):
self.moveTo(newBox.left, newBox.top)
self.resizeTo(newBox.width, newBox.height)
r = _getWindowRect(self._hWnd)
self._rect = pyrect.Rect(r.left, r.top, r.right - r.left, r.bottom - r.top, onChange=_onChange, onRead=_onRead)
def __str__(self):
r = _getWindowRect(self._hWnd)
width = r.right - r.left
height = r.bottom - r.top
return '<%s left="%s", top="%s", width="%s", height="%s", title="%s">' % (self.__class__.__name__, r.left, r.top, width, height, self.title)
def __repr__(self):
return '%s(hWnd=%s)' % (self.__class__.__name__, self._hWnd)
def __eq__(self, other):
return isinstance(other, Win32Window) and self._hWnd == other._hWnd
def close(self):
"""Closes this window. This may trigger "Are you sure you want to
quit?" dialogs or other actions that prevent the window from
actually closing. This is identical to clicking the X button on the
window."""
result = ctypes.windll.user32.PostMessageA(self._hWnd, WM_CLOSE, 0, 0)
if result == 0:
_raiseWithLastError()
def minimize(self):
"""Minimizes this window."""
ctypes.windll.user32.ShowWindow(self._hWnd, SW_MINIMIZE)
def maximize(self):
"""Maximizes this window."""
ctypes.windll.user32.ShowWindow(self._hWnd, SW_MAXIMIZE)
def restore(self):
"""If maximized or minimized, restores the window to it's normal size."""
ctypes.windll.user32.ShowWindow(self._hWnd, SW_RESTORE)
def activate(self):
"""Activate this window and make it the foreground window."""
result = ctypes.windll.user32.SetForegroundWindow(self._hWnd)
if result == 0:
_raiseWithLastError()
def resizeRel(self, widthOffset, heightOffset):
"""Resizes the window relative to its current size."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, self.left, self.top, self.width + widthOffset, self.height + heightOffset, 0)
if result == 0:
_raiseWithLastError()
def resizeTo(self, newWidth, newHeight):
"""Resizes the window to a new width and height."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, self.left, self.top, newWidth, newHeight, 0)
if result == 0:
_raiseWithLastError()
def moveRel(self, xOffset, yOffset):
"""Moves the window relative to its current position."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, self.left + xOffset, self.top + yOffset, self.width, self.height, 0)
if result == 0:
_raiseWithLastError()
def moveTo(self, newLeft, newTop):
"""Moves the window to new coordinates on the screen."""
result = ctypes.windll.user32.SetWindowPos(self._hWnd, HWND_TOP, newLeft, newTop, self.width, self.height, 0)
if result == 0:
_raiseWithLastError()
@property
def isMinimized(self):
"""Returns True if the window is currently minimized."""
return ctypes.windll.user32.IsIconic(self._hWnd) != 0
@property
def isMaximized(self):
"""Returns True if the window is currently maximized."""
return ctypes.windll.user32.IsZoomed(self._hWnd) != 0
@property
def isActive(self):
"""Returns True if the window is currently the active, foreground window."""
return getActiveWindow() == self
@property
def title(self):
"""Returns the window title as a string."""
return _getWindowText(self._hWnd)
@property
def visible(self):
return isWindowVisible(self._hWnd)
# Wrappers for pyrect.Rect object's properties.
@property
def left(self):
return self._rect.left
@left.setter
def left(self, value):
#import pdb; pdb.set_trace()
self._rect.left # Run rect's onRead to update the Rect object.
self._rect.left = value
@property
def right(self):
return self._rect.right
@right.setter
def right(self, value):
self._rect.right # Run rect's onRead to update the Rect object.
self._rect.right = value
@property
def top(self):
return self._rect.top
@top.setter
def top(self, value):
self._rect.top # Run rect's onRead to update the Rect object.
self._rect.top = value
@property
def bottom(self):
return self._rect.bottom
@bottom.setter
def bottom(self, value):
self._rect.bottom # Run rect's onRead to update the Rect object.
self._rect.bottom = value
@property
def topleft(self):
return self._rect.topleft
@topleft.setter
def topleft(self, value):
self._rect.topleft # Run rect's onRead to update the Rect object.
self._rect.topleft = value
@property
def topright(self):
return self._rect.topright
@topright.setter
def topright(self, value):
self._rect.topright # Run rect's onRead to update the Rect object.
self._rect.topright = value
@property
def bottomleft(self):
return self._rect.bottomleft
@bottomleft.setter
def bottomleft(self, value):
self._rect.bottomleft # Run rect's onRead to update the Rect object.
self._rect.bottomleft = value
@property
def bottomright(self):
return self._rect.bottomright
@bottomright.setter
def bottomright(self, value):
self._rect.bottomright # Run rect's onRead to update the Rect object.
self._rect.bottomright = value
@property
def midleft(self):
return self._rect.midleft
@midleft.setter
def midleft(self, value):
self._rect.midleft # Run rect's onRead to update the Rect object.
self._rect.midleft = value
@property
def midright(self):
return self._rect.midright
@midright.setter
def midright(self, value):
self._rect.midright # Run rect's onRead to update the Rect object.
self._rect.midright = value
@property
def midtop(self):
return self._rect.midtop
@midtop.setter
def midtop(self, value):
self._rect.midtop # Run rect's onRead to update the Rect object.
self._rect.midtop = value
@property
def midbottom(self):
return self._rect.midbottom
@midbottom.setter
def midbottom(self, value):
self._rect.midbottom # Run rect's onRead to update the Rect object.
self._rect.midbottom = value
@property
def center(self):
return self._rect.center
@center.setter
def center(self, value):
self._rect.center # Run rect's onRead to update the Rect object.
self._rect.center = value
@property
def centerx(self):
return self._rect.centerx
@centerx.setter
def centerx(self, value):
self._rect.centerx # Run rect's onRead to update the Rect object.
self._rect.centerx = value
@property
def centery(self):
return self._rect.centery
@centery.setter
def centery(self, value):
self._rect.centery # Run rect's onRead to update the Rect object.
self._rect.centery = value
@property
def width(self):
return self._rect.width
@width.setter
def width(self, value):
self._rect.width # Run rect's onRead to update the Rect object.
self._rect.width = value
@property
def height(self):
return self._rect.height
@height.setter
def height(self, value):
self._rect.height # Run rect's onRead to update the Rect object.
self._rect.height = value
@property
def size(self):
return self._rect.size
@size.setter
def size(self, value):
self._rect.size # Run rect's onRead to update the Rect object.
self._rect.size = value
@property
def area(self):
return self._rect.area
@area.setter
def area(self, value):
self._rect.area # Run rect's onRead to update the Rect object.
self._rect.area = value
@property
def box(self):
return self._rect.box
@box.setter
def box(self, value):
self._rect.box # Run rect's onRead to update the Rect object.
self._rect.box = value
def cursor():
"""Returns the current xy coordinates of the mouse cursor as a two-integer
tuple by calling the GetCursorPos() win32 function.
Returns:
(x, y) tuple of the current xy coordinates of the mouse cursor.
"""
cursor = POINT()
ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
return pygetwindow.Point(x=cursor.x, y=cursor.y)
def resolution():
"""Returns the width and height of the screen as a two-integer tuple.
Returns:
(width, height) tuple of the screen size, in pixels.
"""
return pygetwindow.Size(width=ctypes.windll.user32.GetSystemMetrics(0), height=ctypes.windll.user32.GetSystemMetrics(1))
'''
def displayWindowsUnderMouse(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."""
print('Press Ctrl-C to quit.')
if xOffset != 0 or yOffset != 0:
print('xOffset: %s yOffset: %s' % (xOffset, yOffset))
resolution = size()
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)
# TODO - display windows under the mouse
sys.stdout.write(positionStr)
sys.stdout.write('\b' * len(positionStr))
sys.stdout.flush()
except KeyboardInterrupt:
sys.stdout.write('\n')
sys.stdout.flush()
'''

@ -0,0 +1,389 @@
# PyMsgBox - A simple, cross-platform, pure Python module for JavaScript-like message boxes.
# Al Sweigart al@inventwithpython.com
# Modified BSD License
# Derived from Stephen Raymond Ferg's EasyGui http://easygui.sourceforge.net/
"""
The four functions in PyMsgBox:
- 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.
- 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.
- 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.
- 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.
"""
"""
TODO Roadmap:
- Be able to specify a custom icon in the message box.
- Be able to place the message box at an arbitrary position (including on multi screen layouts)
- Add mouse clicks to unit testing.
- progress() function to display a progress bar
- Maybe other types of dialog: open, save, file/folder picker, etc.
"""
__version__ = '1.0.6'
import sys
RUNNING_PYTHON_2 = sys.version_info[0] == 2
# Because PyAutoGUI requires PyMsgBox but might be installed on systems
# without tkinter, we don't want a lack of tkinter to cause installation
# to fail. So exceptions won't be raised until the PyMsgBox functions
# are actually called.
TKINTER_IMPORT_SUCCEEDED = True
try:
if RUNNING_PYTHON_2:
import Tkinter as tk
else:
import tkinter as tk
rootWindowPosition = '+300+200'
if tk.TkVersion < 8.0 :
raise RuntimeError('You are running Tk version: ' + str(tk.TkVersion) + 'You must be using Tk version 8.0 or greater to use PyMsgBox.')
except ImportError:
TKINTER_IMPORT_SUCCEEDED = False
PROPORTIONAL_FONT_FAMILY = ('MS', 'Sans', 'Serif')
MONOSPACE_FONT_FAMILY = ('Courier')
PROPORTIONAL_FONT_SIZE = 10
MONOSPACE_FONT_SIZE = 9 #a little smaller, because it it more legible at a smaller size
TEXT_ENTRY_FONT_SIZE = 12 # a little larger makes it easier to see
STANDARD_SELECTION_EVENTS = ['Return', 'Button-1', 'space']
# constants for strings: (for internationalization, change these)
OK_TEXT = 'OK'
CANCEL_TEXT = 'Cancel'
TIMEOUT_TEXT = 'Timeout'
# Initialize some global variables that will be reset later
__choiceboxMultipleSelect = None
__widgetTexts = None
__replyButtonText = None
__choiceboxResults = None
__firstWidget = None
__enterboxText = None
__enterboxDefaultText=''
__multenterboxText = ''
choiceboxChoices = None
choiceboxWidget = None
entryWidget = None
boxRoot = None
buttonsFrame = None
def alert(text='', title='', button=OK_TEXT, root=None, timeout=None):
"""Displays a simple message box with text and a single OK button. Returns the text of the button clicked on."""
assert TKINTER_IMPORT_SUCCEEDED, 'Tkinter is required for pymsgbox'
return _buttonbox(msg=text, title=title, choices=[str(button)], root=root, timeout=timeout)
def confirm(text='', title='', buttons=[OK_TEXT, CANCEL_TEXT], root=None, timeout=None):
"""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."""
assert TKINTER_IMPORT_SUCCEEDED, 'Tkinter is required for pymsgbox'
return _buttonbox(msg=text, title=title, choices=[str(b) for b in buttons], root=root, timeout=timeout)
def prompt(text='', title='' , default='', root=None, timeout=None):
"""Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked."""
assert TKINTER_IMPORT_SUCCEEDED, 'Tkinter is required for pymsgbox'
return __fillablebox(text, title, default=default, mask=None,root=root, timeout=timeout)
def password(text='', title='', default='', mask='*', root=None, timeout=None):
"""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."""
assert TKINTER_IMPORT_SUCCEEDED, 'Tkinter is required for pymsgbox'
return __fillablebox(text, title, default, mask=mask, root=root, timeout=timeout)
import pymsgbox.native as native # This needs to be after the above functions so that the unimplmeneted native functions can default back to the above functions.
native # dummy line just to make lint stop complaining about the previous line
def timeoutBoxRoot():
global boxRoot, __replyButtonText, __enterboxText
boxRoot.destroy()
__replyButtonText = TIMEOUT_TEXT
__enterboxText = TIMEOUT_TEXT
def _buttonbox(msg, title, choices, root=None, timeout=None):
"""
Display a msg, a title, and a set of buttons.
The buttons are defined by the members of the choices list.
Return the text of the button that the user selected.
@arg msg: the msg to be displayed.
@arg title: the window title
@arg choices: a list or tuple of the choices to be displayed
"""
global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame
# Initialize __replyButtonText to the first choice.
# This is what will be used if the window is closed by the close button.
__replyButtonText = choices[0]
if root:
root.withdraw()
boxRoot = tk.Toplevel(master=root)
boxRoot.withdraw()
else:
boxRoot = tk.Tk()
boxRoot.withdraw()
boxRoot.title(title)
boxRoot.iconname('Dialog')
boxRoot.geometry(rootWindowPosition)
boxRoot.minsize(400, 100)
# ------------- define the messageFrame ---------------------------------
messageFrame = tk.Frame(master=boxRoot)
messageFrame.pack(side=tk.TOP, fill=tk.BOTH)
# ------------- define the buttonsFrame ---------------------------------
buttonsFrame = tk.Frame(master=boxRoot)
buttonsFrame.pack(side=tk.TOP, fill=tk.BOTH)
# -------------------- place the widgets in the frames -----------------------
messageWidget = tk.Message(messageFrame, text=msg, width=400)
messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE))
messageWidget.pack(side=tk.TOP, expand=tk.YES, fill=tk.X, padx='3m', pady='3m')
__put_buttons_in_buttonframe(choices)
# -------------- the action begins -----------
# put the focus on the first button
__firstWidget.focus_force()
boxRoot.deiconify()
if timeout is not None:
boxRoot.after(timeout, timeoutBoxRoot)
boxRoot.mainloop()
try:
boxRoot.destroy()
except tk.TclError:
if __replyButtonText != TIMEOUT_TEXT:
__replyButtonText = None
if root: root.deiconify()
return __replyButtonText
def __put_buttons_in_buttonframe(choices):
"""Put the buttons in the buttons frame"""
global __widgetTexts, __firstWidget, buttonsFrame
__firstWidget = None
__widgetTexts = {}
i = 0
for buttonText in choices:
tempButton = tk.Button(buttonsFrame, takefocus=1, text=buttonText)
_bindArrows(tempButton)
tempButton.pack(expand=tk.YES, side=tk.LEFT, padx='1m', pady='1m', ipadx='2m', ipady='1m')
# remember the text associated with this widget
__widgetTexts[tempButton] = buttonText
# remember the first widget, so we can put the focus there
if i == 0:
__firstWidget = tempButton
i = 1
# for the commandButton, bind activation events to the activation event handler
commandButton = tempButton
handler = __buttonEvent
for selectionEvent in STANDARD_SELECTION_EVENTS:
commandButton.bind('<%s>' % selectionEvent, handler)
if CANCEL_TEXT in choices:
commandButton.bind('<Escape>', __cancelButtonEvent)
def _bindArrows(widget, skipArrowKeys=False):
widget.bind('<Down>', _tabRight)
widget.bind('<Up>' , _tabLeft)
if not skipArrowKeys:
widget.bind('<Right>',_tabRight)
widget.bind('<Left>' , _tabLeft)
def _tabRight(event):
boxRoot.event_generate('<Tab>')
def _tabLeft(event):
boxRoot.event_generate('<Shift-Tab>')
def __buttonEvent(event):
"""
Handle an event that is generated by a person clicking a button.
"""
global boxRoot, __widgetTexts, __replyButtonText
__replyButtonText = __widgetTexts[event.widget]
boxRoot.quit() # quit the main loop
def __cancelButtonEvent(event):
"""Handle pressing Esc by clicking the Cancel button."""
global boxRoot, __widgetTexts, __replyButtonText
__replyButtonText = CANCEL_TEXT
boxRoot.quit()
def __fillablebox(msg, title='', default='', mask=None, root=None, timeout=None):
"""
Show a box in which a user can enter some text.
You may optionally specify some default text, which will appear in the
enterbox when it is displayed.
Returns the text that the user entered, or None if he cancels the operation.
"""
global boxRoot, __enterboxText, __enterboxDefaultText
global cancelButton, entryWidget, okButton
if title == None:
title == ''
if default == None:
default = ''
__enterboxDefaultText = default
__enterboxText = __enterboxDefaultText
if root:
root.withdraw()
boxRoot = tk.Toplevel(master=root)
boxRoot.withdraw()
else:
boxRoot = tk.Tk()
boxRoot.withdraw()
boxRoot.title(title)
boxRoot.iconname('Dialog')
boxRoot.geometry(rootWindowPosition)
boxRoot.bind('<Escape>', __enterboxCancel)
# ------------- define the messageFrame ---------------------------------
messageFrame = tk.Frame(master=boxRoot)
messageFrame.pack(side=tk.TOP, fill=tk.BOTH)
# ------------- define the buttonsFrame ---------------------------------
buttonsFrame = tk.Frame(master=boxRoot)
buttonsFrame.pack(side=tk.TOP, fill=tk.BOTH)
# ------------- define the entryFrame ---------------------------------
entryFrame = tk.Frame(master=boxRoot)
entryFrame.pack(side=tk.TOP, fill=tk.BOTH)
# ------------- define the buttonsFrame ---------------------------------
buttonsFrame = tk.Frame(master=boxRoot)
buttonsFrame.pack(side=tk.TOP, fill=tk.BOTH)
#-------------------- the msg widget ----------------------------
messageWidget = tk.Message(messageFrame, width='4.5i', text=msg)
messageWidget.configure(font=(PROPORTIONAL_FONT_FAMILY, PROPORTIONAL_FONT_SIZE))
messageWidget.pack(side=tk.RIGHT, expand=1, fill=tk.BOTH, padx='3m', pady='3m')
# --------- entryWidget ----------------------------------------------
entryWidget = tk.Entry(entryFrame, width=40)
_bindArrows(entryWidget, skipArrowKeys=True)
entryWidget.configure(font=(PROPORTIONAL_FONT_FAMILY, TEXT_ENTRY_FONT_SIZE))
if mask:
entryWidget.configure(show=mask)
entryWidget.pack(side=tk.LEFT, padx='3m')
entryWidget.bind('<Return>', __enterboxGetText)
entryWidget.bind('<Escape>', __enterboxCancel)
# put text into the entryWidget and have it pre-highlighted
if __enterboxDefaultText != '':
entryWidget.insert(0,__enterboxDefaultText)
entryWidget.select_range(0, tk.END)
# ------------------ ok button -------------------------------
okButton = tk.Button(buttonsFrame, takefocus=1, text=OK_TEXT)
_bindArrows(okButton)
okButton.pack(expand=1, side=tk.LEFT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
# for the commandButton, bind activation events to the activation event handler
commandButton = okButton
handler = __enterboxGetText
for selectionEvent in STANDARD_SELECTION_EVENTS:
commandButton.bind('<%s>' % selectionEvent, handler)
# ------------------ cancel button -------------------------------
cancelButton = tk.Button(buttonsFrame, takefocus=1, text=CANCEL_TEXT)
_bindArrows(cancelButton)
cancelButton.pack(expand=1, side=tk.RIGHT, padx='3m', pady='3m', ipadx='2m', ipady='1m')
# for the commandButton, bind activation events to the activation event handler
commandButton = cancelButton
handler = __enterboxCancel
for selectionEvent in STANDARD_SELECTION_EVENTS:
commandButton.bind('<%s>' % selectionEvent, handler)
# ------------------- time for action! -----------------
entryWidget.focus_force() # put the focus on the entryWidget
boxRoot.deiconify()
if timeout is not None:
boxRoot.after(timeout, timeoutBoxRoot)
boxRoot.mainloop() # run it!
# -------- after the run has completed ----------------------------------
if root: root.deiconify()
try:
boxRoot.destroy() # button_click didn't destroy boxRoot, so we do it now
except tk.TclError:
if __enterboxText != TIMEOUT_TEXT:
return None
return __enterboxText
def __enterboxGetText(event):
global __enterboxText
__enterboxText = entryWidget.get()
boxRoot.quit()
def __enterboxRestore(event):
global entryWidget
entryWidget.delete(0,len(entryWidget.get()))
entryWidget.insert(0, __enterboxDefaultText)
def __enterboxCancel(event):
global __enterboxText
__enterboxText = None
boxRoot.quit()

@ -0,0 +1,65 @@
# The Windows native message box.
import sys
import ctypes # An included library with Python install.
MB_OK = 0x0
MB_OKCANCEL = 0x1
MB_ABORTRETRYIGNORE = 0x2
MB_YESNOCANCEL = 0x3
MB_YESNO = 0x4
MB_RETRYCANCEL = 0x5
MB_ICONHAND = MB_ICONSTOP = MB_ICONERRPR = 0x10
MB_ICONQUESTION = 0x20
MB_ICONEXCLAIMATION = 0x30
MB_ICONASTERISK = MB_ICONINFOMRAITON = 0x40
MB_DEFAULTBUTTON1 = 0x0
MB_DEFAULTBUTTON2 = 0x100
MB_DEFAULTBUTTON3 = 0x200
MB_DEFAULTBUTTON4 = 0x300
MB_SETFOREGROUND = 0x10000
MB_TOPMOST = 0x40000
runningOnPython2 = sys.version_info[0] == 2
if runningOnPython2:
messageBoxFunc = ctypes.windll.user32.MessageBoxA
else: # Python 3 functions.
messageBoxFunc = ctypes.windll.user32.MessageBoxW
def 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."""
messageBoxFunc(0, text, title, MB_OK | MB_SETFOREGROUND | MB_TOPMOST)
return button
def 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."""
retVal = messageBoxFunc(0, text, title, MB_OKCANCEL | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST)
if retVal == 1 or len(buttons) == 1:
return buttons[0]
elif retVal == 2:
return buttons[1]
else:
assert False, 'Unexpected return value from MessageBox: %s' % (retVal)
'''
def 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."""
pass
def 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."""
pass
'''

@ -0,0 +1,27 @@
# These functions use the operating system's native message box calls.
import sys
# default back to the original functions if no native functions exist.
import pymsgbox
alert = pymsgbox.alert
confirm = pymsgbox.confirm
prompt = pymsgbox.prompt
password = pymsgbox.password
# The platformModule is where we reference the platform-specific functions.
if sys.platform.startswith('java'):
import pymsgbox._native_java as platformModule
elif sys.platform == 'darwin':
import pymsgbox._native_osx as platformModule
elif sys.platform == 'win32':
import pymsgbox._native_win as platformModule
alert = platformModule.alert
confirm = platformModule.confirm
else:
import pymsgbox._native_x11 as platformModule
platformModule # this line used to silence the linting tool. Will be removed once implementation is done

@ -0,0 +1,500 @@
# PyScreeze
# by Al Sweigart
# https://github.com/asweigart/pyscreeze
# BSD license
"""
So, apparently Pillow support on Ubuntu 64-bit has several additional steps since it doesn't have JPEG/PNG support out of the box. Description here:
https://stackoverflow.com/questions/7648200/pip-install-pil-e-tickets-1-no-jpeg-png-support
http://ubuntuforums.org/showthread.php?t=1751455
"""
__version__ = '0.1.21'
import collections
import datetime
import os
import subprocess
import sys
import time
import errno
try:
from PIL import Image
from PIL import ImageOps
except ImportError:
pass
from contextlib import contextmanager
try:
import cv2, numpy
useOpenCV = True
RUNNING_CV_2 = cv2.__version__[0] < '3'
except ImportError:
useOpenCV = False
RUNNING_PYTHON_2 = sys.version_info[0] == 2
if useOpenCV:
if RUNNING_CV_2:
LOAD_COLOR = cv2.CV_LOAD_IMAGE_COLOR
LOAD_GRAYSCALE = cv2.CV_LOAD_IMAGE_GRAYSCALE
else:
LOAD_COLOR = cv2.IMREAD_COLOR
LOAD_GRAYSCALE = cv2.IMREAD_GRAYSCALE
GRAYSCALE_DEFAULT = False
# For version 0.1.19 I changed it so that ImageNotFoundException was raised
# instead of returning None. In hindsight, this change came too late, so I'm
# changing it back to returning None. But I'm also including this option for
# folks who would rather have it raise an exception.
USE_IMAGE_NOT_FOUND_EXCEPTION = False
scrotExists = False
try:
if sys.platform not in ('java', 'darwin', 'win32'):
whichProc = subprocess.Popen(
['which', 'scrot'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
scrotExists = whichProc.wait() == 0
except OSError as ex:
if ex.errno == errno.ENOENT:
# if there is no "which" program to find scrot, then assume there
# is no scrot.
pass
else:
raise
if sys.platform == 'win32':
from ctypes import windll
# win32 DC(DeviceContext) Manager
@contextmanager
def __win32_openDC(hWnd):
hDC = windll.user32.GetDC(hWnd)
if hDC == 0: #NULL
raise WindowsError("windll.user32.GetDC failed : return NULL")
try:
yield hDC
finally:
if windll.user32.ReleaseDC(hWnd, hDC) == 0:
raise WindowsError("windll.user32.ReleaseDC failed : return 0")
Box = collections.namedtuple('Box', 'left top width height')
Point = collections.namedtuple('Point', 'x y')
RGB = collections.namedtuple('RGB', 'red green blue')
class ImageNotFoundException(Exception):
pass # This is an exception class raised when the locate functions fail.
def _load_cv2(img, grayscale=None):
# load images if given filename, or convert as needed to opencv
# Alpha layer just causes failures at this point, so flatten to RGB.
# RGBA: load with -1 * cv2.CV_LOAD_IMAGE_COLOR to preserve alpha
# to matchTemplate, need template and image to be the same wrt having alpha
if grayscale is None:
grayscale = GRAYSCALE_DEFAULT
if isinstance(img, str):
# The function imread loads an image from the specified file and
# returns it. If the image cannot be read (because of missing
# file, improper permissions, unsupported or invalid format),
# the function returns an empty matrix
# http://docs.opencv.org/3.0-beta/modules/imgcodecs/doc/reading_and_writing_images.html
if grayscale:
img_cv = cv2.imread(img, LOAD_GRAYSCALE)
else:
img_cv = cv2.imread(img, LOAD_COLOR)
if img_cv is None:
raise IOError("Failed to read %s because file is missing, "
"has improper permissions, or is an "
"unsupported or invalid format" % img)
elif isinstance(img, numpy.ndarray):
# don't try to convert an already-gray image to gray
if grayscale and len(img.shape) == 3: # and img.shape[2] == 3:
img_cv = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
else:
img_cv = img
elif hasattr(img, 'convert'):
# assume its a PIL.Image, convert to cv format
img_array = numpy.array(img.convert('RGB'))
img_cv = img_array[:, :, ::-1].copy() # -1 does RGB -> BGR
if grayscale:
img_cv = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY)
else:
raise TypeError('expected an image filename, OpenCV numpy array, or PIL image')
return img_cv
def _locateAll_opencv(needleImage, haystackImage, grayscale=None, limit=10000, region=None, step=1,
confidence=0.999):
""" faster but more memory-intensive than pure python
step 2 skips every other row and column = ~3x faster but prone to miss;
to compensate, the algorithm automatically reduces the confidence
threshold by 5% (which helps but will not avoid all misses).
limitations:
- OpenCV 3.x & python 3.x not tested
- RGBA images are treated as RBG (ignores alpha channel)
"""
if grayscale is None:
grayscale = GRAYSCALE_DEFAULT
confidence = float(confidence)
needleImage = _load_cv2(needleImage, grayscale)
needleHeight, needleWidth = needleImage.shape[:2]
haystackImage = _load_cv2(haystackImage, grayscale)
if region:
haystackImage = haystackImage[region[1]:region[1]+region[3],
region[0]:region[0]+region[2]]
else:
region = (0, 0) # full image; these values used in the yield statement
if (haystackImage.shape[0] < needleImage.shape[0] or
haystackImage.shape[1] < needleImage.shape[1]):
# avoid semi-cryptic OpenCV error below if bad size
raise ValueError('needle dimension(s) exceed the haystack image or region dimensions')
if step == 2:
confidence *= 0.95
needleImage = needleImage[::step, ::step]
haystackImage = haystackImage[::step, ::step]
else:
step = 1
# get all matches at once, credit: https://stackoverflow.com/questions/7670112/finding-a-subimage-inside-a-numpy-image/9253805#9253805
result = cv2.matchTemplate(haystackImage, needleImage, cv2.TM_CCOEFF_NORMED)
match_indices = numpy.arange(result.size)[(result > confidence).flatten()]
matches = numpy.unravel_index(match_indices[:limit], result.shape)
if len(matches[0]) == 0:
if USE_IMAGE_NOT_FOUND_EXCEPTION:
raise ImageNotFoundException('Could not locate the image (highest confidence = %.3f)' % result.max())
else:
return
# use a generator for API consistency:
matchx = matches[1] * step + region[0] # vectorized
matchy = matches[0] * step + region[1]
for x, y in zip(matchx, matchy):
yield Box(x, y, needleWidth, needleHeight)
def _locateAll_python(needleImage, haystackImage, grayscale=None, limit=None, region=None, step=1):
# setup all the arguments
if grayscale is None:
grayscale = GRAYSCALE_DEFAULT
needleFileObj = None
if isinstance(needleImage, str):
# 'image' is a filename, load the Image object
needleFileObj = open(needleImage, 'rb')
needleImage = Image.open(needleFileObj)
haystackFileObj = None
if isinstance(haystackImage, str):
# 'image' is a filename, load the Image object
haystackFileObj = open(haystackImage, 'rb')
haystackImage = Image.open(haystackFileObj)
if region is not None:
haystackImage = haystackImage.crop((region[0], region[1], region[0] + region[2], region[1] + region[3]))
else:
region = (0, 0) # set to 0 because the code always accounts for a region
if grayscale: # if grayscale mode is on, convert the needle and haystack images to grayscale
needleImage = ImageOps.grayscale(needleImage)
haystackImage = ImageOps.grayscale(haystackImage)
else:
# if not using grayscale, make sure we are comparing RGB images, not RGBA images.
if needleImage.mode == 'RGBA':
needleImage = needleImage.convert('RGB')
if haystackImage.mode == 'RGBA':
haystackImage = haystackImage.convert('RGB')
# setup some constants we'll be using in this function
needleWidth, needleHeight = needleImage.size
haystackWidth, haystackHeight = haystackImage.size
needleImageData = tuple(needleImage.getdata())
haystackImageData = tuple(haystackImage.getdata())
needleImageRows = [needleImageData[y * needleWidth:(y+1) * needleWidth] for y in range(needleHeight)] # LEFT OFF - check this
needleImageFirstRow = needleImageRows[0]
assert len(needleImageFirstRow) == needleWidth, 'For some reason, the calculated width of first row of the needle image is not the same as the width of the image.'
assert [len(row) for row in needleImageRows] == [needleWidth] * needleHeight, 'For some reason, the needleImageRows aren\'t the same size as the original image.'
numMatchesFound = 0
# NOTE: After running tests/benchmarks.py on the following code, it seem that having a step
# value greater than 1 does not give *any* significant performance improvements.
# Since using a step higher than 1 makes for less accurate matches, it will be
# set to 1.
step = 1 # hard-code step as 1 until a way to improve it can be figured out.
if step == 1:
firstFindFunc = _kmp
else:
firstFindFunc = _steppingFind
for y in range(haystackHeight): # start at the leftmost column
for matchx in firstFindFunc(needleImageFirstRow, haystackImageData[y * haystackWidth:(y+1) * haystackWidth], step):
foundMatch = True
for searchy in range(1, needleHeight, step):
haystackStart = (searchy + y) * haystackWidth + matchx
if needleImageData[searchy * needleWidth:(searchy+1) * needleWidth] != haystackImageData[haystackStart:haystackStart + needleWidth]:
foundMatch = False
break
if foundMatch:
# Match found, report the x, y, width, height of where the matching region is in haystack.
numMatchesFound += 1
yield Box(matchx + region[0], y + region[1], needleWidth, needleHeight)
if limit is not None and numMatchesFound >= limit:
# Limit has been reached. Close file handles.
if needleFileObj is not None:
needleFileObj.close()
if haystackFileObj is not None:
haystackFileObj.close()
return
# There was no limit or the limit wasn't reached, but close the file handles anyway.
if needleFileObj is not None:
needleFileObj.close()
if haystackFileObj is not None:
haystackFileObj.close()
if numMatchesFound == 0:
if USE_IMAGE_NOT_FOUND_EXCEPTION:
raise ImageNotFoundException('Could not locate the image.')
else:
return
def locate(needleImage, haystackImage, **kwargs):
# Note: The gymnastics in this function is because we want to make sure to exhaust the iterator so that the needle and haystack files are closed in locateAll.
kwargs['limit'] = 1
points = tuple(locateAll(needleImage, haystackImage, **kwargs))
if len(points) > 0:
return points[0]
else:
if USE_IMAGE_NOT_FOUND_EXCEPTION:
raise ImageNotFoundException('Could not locate the image.')
else:
return None
def locateOnScreen(image, minSearchTime=0, **kwargs):
"""minSearchTime - amount of time in seconds to repeat taking
screenshots and trying to locate a match. The default of 0 performs
a single search.
"""
start = time.time()
while True:
try:
screenshotIm = screenshot(region=None) # the locateAll() function must handle cropping to return accurate coordinates, so don't pass a region here.
retVal = locate(image, screenshotIm, **kwargs)
try:
screenshotIm.fp.close()
except AttributeError:
# Screenshots on Windows won't have an fp since they came from
# ImageGrab, not a file. Screenshots on Linux will have fp set
# to None since the file has been unlinked
pass
if retVal or time.time() - start > minSearchTime:
return retVal
except ImageNotFoundException:
if time.time() - start > minSearchTime:
if USE_IMAGE_NOT_FOUND_EXCEPTION:
raise
else:
return None
def locateAllOnScreen(image, **kwargs):
screenshotIm = screenshot(region=None) # the locateAll() function must handle cropping to return accurate coordinates, so don't pass a region here.
retVal = locateAll(image, screenshotIm, **kwargs)
try:
screenshotIm.fp.close()
except AttributeError:
# Screenshots on Windows won't have an fp since they came from
# ImageGrab, not a file. Screenshots on Linux will have fp set
# to None since the file has been unlinked
pass
return retVal
def locateCenterOnScreen(image, **kwargs):
coords = locateOnScreen(image, **kwargs)
return center(coords)
def showRegionOnScreen(region, outlineColor='red', filename='_showRegionOnScreen.png'):
from PIL import ImageDraw # this is the only function that needs this, and it's rarely called
screenshotIm = screenshot()
draw = ImageDraw.Draw(screenshotIm)
region = (region[0], region[1], region[2] + region[0], region[3] + region[1]) # convert from (left, top, right, bottom) to (left, top, width, height)
draw.rectangle(region, outline=outlineColor)
screenshotIm.save(filename)
def _screenshot_win32(imageFilename=None, region=None):
try:
im = ImageGrab.grab()
except NameError:
raise ImportError('Pillow module must be installed to use screenshot functions on Windows.')
if region is not None:
assert len(region) == 4, 'region argument must be a tuple of four ints'
region = [int(x) for x in region]
im = im.crop((region[0], region[1], region[2] + region[0], region[3] + region[1]))
if imageFilename is not None:
im.save(imageFilename)
return im
def _screenshot_osx(imageFilename=None, region=None):
if imageFilename is None:
tmpFilename = 'screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
else:
tmpFilename = imageFilename
subprocess.call(['screencapture', '-x', tmpFilename])
im = Image.open(tmpFilename)
if region is not None:
assert len(region) == 4, 'region argument must be a tuple of four ints'
region = [int(x) for x in region]
im = im.crop((region[0], region[1], region[2] + region[0], region[3] + region[1]))
os.unlink(tmpFilename) # delete image of entire screen to save cropped version
im.save(tmpFilename)
else:
# force loading before unlinking, Image.open() is lazy
im.load()
if imageFilename is None:
os.unlink(tmpFilename)
return im
def _screenshot_linux(imageFilename=None, region=None):
if not scrotExists:
raise NotImplementedError('"scrot" must be installed to use screenshot functions in Linux. Run: sudo apt-get install scrot')
if imageFilename is None:
tmpFilename = '.screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
else:
tmpFilename = imageFilename
if scrotExists:
subprocess.call(['scrot', tmpFilename])
im = Image.open(tmpFilename)
if region is not None:
assert len(region) == 4, 'region argument must be a tuple of four ints'
region = [int(x) for x in region]
im = im.crop((region[0], region[1], region[2] + region[0], region[3] + region[1]))
os.unlink(tmpFilename) # delete image of entire screen to save cropped version
im.save(tmpFilename)
else:
# force loading before unlinking, Image.open() is lazy
im.load()
if imageFilename is None:
os.unlink(tmpFilename)
return im
else:
raise Exception('The scrot program must be installed to take a screenshot with PyScreeze on Linux. Run: sudo apt-get install scrot')
def _kmp(needle, haystack, _dummy): # Knuth-Morris-Pratt search algorithm implementation (to be used by screen capture)
# build table of shift amounts
shifts = [1] * (len(needle) + 1)
shift = 1
for pos in range(len(needle)):
while shift <= pos and needle[pos] != needle[pos-shift]:
shift += shifts[pos-shift]
shifts[pos+1] = shift
# do the actual search
startPos = 0
matchLen = 0
for c in haystack:
while matchLen == len(needle) or \
matchLen >= 0 and needle[matchLen] != c:
startPos += shifts[matchLen]
matchLen -= shifts[matchLen]
matchLen += 1
if matchLen == len(needle):
yield startPos
def _steppingFind(needle, haystack, step):
for startPos in range(0, len(haystack) - len(needle) + 1):
foundMatch = True
for pos in range(0, len(needle), step):
if haystack[startPos + pos] != needle[pos]:
foundMatch = False
break
if foundMatch:
yield startPos
def center(coords):
return Point(coords[0] + int(coords[2] / 2), coords[1] + int(coords[3] / 2))
def pixelMatchesColor(x, y, expectedRGBColor, tolerance=0):
pix = pixel(x, y)
if len(pix) == 3 or len(expectedRGBColor) == 3: #RGB mode
r, g, b = pix[:3]
exR, exG, exB = expectedRGBColor[:3]
return (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance)
elif len(pix) == 4 and len(expectedRGBColor) == 4: #RGBA mode
r, g, b, a = pix
exR, exG, exB, exA = expectedRGBColor
return (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance) and (abs(a - exA) <= tolerance)
else:
assert False, 'Color mode was expected to be length 3 (RGB) or 4 (RGBA), but pixel is length %s and expectedRGBColor is length %s' % (len(pix), len(expectedRGBColor))
def pixel(x, y):
if sys.platform == 'win32':
# On Windows, calling GetDC() and GetPixel() is twice as fast as using our screenshot() function.
with __win32_openDC(0) as hdc: # handle will be released automatically
color = windll.gdi32.GetPixel(hdc, x, y)
if color < 0:
raise WindowsError("windll.gdi32.GetPixel faild : return {}".format(color))
# color is in the format 0xbbggrr https://msdn.microsoft.com/en-us/library/windows/desktop/dd183449(v=vs.85).aspx
bbggrr = "{:0>6x}".format(color) # bbggrr => 'bbggrr' (hex)
b, g, r = (int(bbggrr[i:i+2], 16) for i in range(0, 6, 2))
return (r, g, b)
else:
# Need to select only the first three values of the color in
# case the returned pixel has an alpha channel
return RGB(*(screenshot().getpixel((x, y))[:3]))
# set the screenshot() function based on the platform running this module
if sys.platform.startswith('java'):
raise NotImplementedError('Jython is not yet supported by PyScreeze.')
elif sys.platform == 'darwin':
screenshot = _screenshot_osx
elif sys.platform == 'win32':
screenshot = _screenshot_win32
try:
from PIL import ImageGrab
except ImportError:
pass
else:
screenshot = _screenshot_linux
grab = screenshot # for compatibility with Pillow/PIL's ImageGrab module.
# set the locateAll function to use opencv if possible; python 3 needs opencv 3.0+
if useOpenCV:
locateAll = _locateAll_opencv
if not RUNNING_PYTHON_2 and cv2.__version__ < '3':
locateAll = _locateAll_python
else:
locateAll = _locateAll_python

@ -0,0 +1,594 @@
from __future__ import division
import math
__version__ = '1.0.3'
# from http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm#Python
def getLine(x1, y1, x2, y2):
"""Returns a list of (x, y) tuples of every point on a line between
(x1, y1) and (x2, y2). The x and y values inside the tuple are integers.
Line generated with the Bresenham algorithm.
Args:
x1 (int, float): The x coordinate of the line's start point.
y1 (int, float): The y coordinate of the line's start point.
x2 (int, float): The x coordinate of the line's end point.
y2 (int, float): The y coordiante of the line's end point.
Returns:
[(x1, y1), (x2, y2), (x3, y3), ...]
Example:
>>> getLine(0, 0, 6, 6)
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
>>> getLine(0, 0, 3, 6)
[(0, 0), (0, 1), (1, 2), (1, 3), (2, 4), (2, 5), (3, 6)]
>>> getLine(3, 3, -3, -3)
[(3, 3), (2, 2), (1, 1), (0, 0), (-1, -1), (-2, -2), (-3, -3)]
"""
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
points = []
issteep = abs(y2-y1) > abs(x2-x1)
if issteep:
x1, y1 = y1, x1
x2, y2 = y2, x2
rev = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
rev = True
deltax = x2 - x1
deltay = abs(y2-y1)
error = int(deltax / 2)
y = y1
ystep = None
if y1 < y2:
ystep = 1
else:
ystep = -1
for x in range(x1, x2 + 1):
if issteep:
points.append((y, x))
else:
points.append((x, y))
error -= deltay
if error < 0:
y += ystep
error += deltax
# Reverse the list if the coordinates were reversed
if rev:
points.reverse()
return points
def getPointOnLine(x1, y1, x2, y2, n):
"""Returns the (x, y) tuple of the point that has progressed a proportion
n along the line defined by the two x, y coordinates.
Args:
x1 (int, float): The x coordinate of the line's start point.
y1 (int, float): The y coordinate of the line's start point.
x2 (int, float): The x coordinate of the line's end point.
y2 (int, float): The y coordiante of the line's end point.
n (float): Progress along the line. 0.0 is the start point, 1.0 is the end point. 0.5 is the midpoint. This value can be less than 0.0 or greater than 1.0.
Returns:
Tuple of floats for the x, y coordinate of the point.
Example:
>>> getPointOnLine(0, 0, 6, 6, 0)
(0, 0)
>>> getPointOnLine(0, 0, 6, 6, 1)
(6, 6)
>>> getPointOnLine(0, 0, 6, 6, 0.5)
(3.0, 3.0)
>>> getPointOnLine(0, 0, 6, 6, 0.75)
(4.5, 4.5)
>>> getPointOnLine(3, 3, -3, -3, 0.5)
(0.0, 0.0)
>>> getPointOnLine(3, 3, -3, -3, 0.25)
(1.5, 1.5)
>>> getPointOnLine(3, 3, -3, -3, 0.75)
(-1.5, -1.5)
"""
x = ((x2 - x1) * n) + x1
y = ((y2 - y1) * n) + y1
return (x, y)
def _checkRange(n):
"""Raises ValueError if the argument is not between 0.0 and 1.0.
"""
if not 0.0 <= n <= 1.0:
raise ValueError('Argument must be between 0.0 and 1.0.')
def linear(n):
"""A linear tween function
Example:
>>> linear(0.0)
0.0
>>> linear(0.2)
0.2
>>> linear(0.4)
0.4
>>> linear(0.6)
0.6
>>> linear(0.8)
0.8
>>> linear(1.0)
1.0
"""
_checkRange(n)
return n
def easeInQuad(n):
"""A quadratic tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return n**2
def easeOutQuad(n):
"""A quadratic tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return -n * (n-2)
def easeInOutQuad(n):
"""A quadratic tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if n < 0.5:
return 2 * n**2
else:
n = n * 2 - 1
return -0.5 * (n*(n-2) - 1)
def easeInCubic(n):
"""A cubic tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return n**3
def easeOutCubic(n):
"""A cubic tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = n - 1
return n**3 + 1
def easeInOutCubic(n):
"""A cubic tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = 2 * n
if n < 1:
return 0.5 * n**3
else:
n = n - 2
return 0.5 * (n**3 + 2)
def easeInQuart(n):
"""A quartic tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return n**4
def easeOutQuart(n):
"""A quartic tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = n - 1
return -(n**4 - 1)
def easeInOutQuart(n):
"""A quartic tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = 2 * n
if n < 1:
return 0.5 * n**4
else:
n = n - 2
return -0.5 * (n**4 - 2)
def easeInQuint(n):
"""A quintic tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return n**5
def easeOutQuint(n):
"""A quintic tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = n - 1
return n**5 + 1
def easeInOutQuint(n):
"""A quintic tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = 2 * n
if n < 1:
return 0.5 * n**5
else:
n = n - 2
return 0.5 * (n**5 + 2)
def easeInSine(n):
"""A sinusoidal tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return -1 * math.cos(n * math.pi / 2) + 1
def easeOutSine(n):
"""A sinusoidal tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return math.sin(n * math.pi / 2)
def easeInOutSine(n):
"""A sinusoidal tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return -0.5 * (math.cos(math.pi * n) - 1)
def easeInExpo(n):
"""An exponential tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if n == 0:
return 0
else:
return 2**(10 * (n - 1))
def easeOutExpo(n):
"""An exponential tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if n == 1:
return 1
else:
return -(2 ** (-10 * n)) + 1
def easeInOutExpo(n):
"""An exponential tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if n == 0:
return 0
elif n == 1:
return 1
else:
n = n * 2
if n < 1:
return 0.5 * 2**(10 * (n - 1))
else:
n -= 1
# 0.5 * (-() + 2)
return 0.5 * (-1 * (2 ** (-10 * n)) + 2)
def easeInCirc(n):
"""A circular tween function that begins slow and then accelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return -1 * (math.sqrt(1 - n * n) - 1)
def easeOutCirc(n):
"""A circular tween function that begins fast and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n -= 1
return math.sqrt(1 - (n * n))
def easeInOutCirc(n):
"""A circular tween function that accelerates, reaches the midpoint, and then decelerates.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = n * 2
if n < 1:
return -0.5 * (math.sqrt(1 - n**2) - 1)
else:
n = n - 2
return 0.5 * (math.sqrt(1 - n**2) + 1)
def easeInElastic(n, amplitude=1, period=0.3):
"""An elastic tween function that begins with an increasing wobble and then snaps into the destination.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return 1 - easeOutElastic(1-n, amplitude=amplitude, period=period)
def easeOutElastic(n, amplitude=1, period=0.3):
"""An elastic tween function that overshoots the destination and then "rubber bands" into the destination.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if amplitude < 1:
amplitude = 1
s = period / 4
else:
s = period / (2 * math.pi) * math.asin(1 / amplitude)
return amplitude * 2**(-10*n) * math.sin((n-s)*(2*math.pi / period)) + 1
def easeInOutElastic(n, amplitude=1, period=0.5):
"""An elastic tween function wobbles towards the midpoint.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n *= 2
if n < 1:
return easeInElastic(n, amplitude=amplitude, period=period) / 2
else:
return easeOutElastic(n-1, amplitude=amplitude, period=period) / 2 + 0.5
def easeInBack(n, s=1.70158):
"""A tween function that backs up first at the start and then goes to the destination.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return n * n * ((s + 1) * n - s)
def easeOutBack(n, s=1.70158):
"""A tween function that overshoots the destination a little and then backs into the destination.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = n - 1
return n * n * ((s + 1) * n + s) + 1
def easeInOutBack(n, s=1.70158):
"""A "back-in" tween function that overshoots both the start and destination.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
n = n * 2
if n < 1:
s *= 1.525
return 0.5 * (n * n * ((s + 1) * n - s))
else:
n -= 2
s *= 1.525
return 0.5 * (n * n * ((s + 1) * n + s) + 2)
def easeInBounce(n):
"""A bouncing tween function that begins bouncing and then jumps to the destination.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
return 1 - easeOutBounce(1 - n)
def easeOutBounce(n):
"""A bouncing tween function that hits the destination and then bounces to rest.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if n < (1/2.75):
return 7.5625 * n * n
elif n < (2/2.75):
n -= (1.5/2.75)
return 7.5625 * n * n + 0.75
elif n < (2.5/2.75):
n -= (2.25/2.75)
return 7.5625 * n * n + 0.9375
else:
n -= (2.65/2.75)
return 7.5625 * n * n + 0.984375
def easeInOutBounce(n):
"""A bouncing tween function that bounces at the start and end.
Args:
n (float): The time progress, starting at 0.0 and ending at 1.0.
Returns:
(float) The line progress, starting at 0.0 and ending at 1.0. Suitable for passing to getPointOnLine().
"""
_checkRange(n)
if n < 0.5:
return easeInBounce(n * 2) * 0.5
else:
return easeOutBounce(n * 2 - 1) * 0.5 + 0.5

@ -0,0 +1,3 @@
from comtypes.gen import _944DE083_8FB8_45CF_BCB7_C477ACB2F897_0_1_0
globals().update(_944DE083_8FB8_45CF_BCB7_C477ACB2F897_0_1_0.__dict__)
__name__ = 'comtypes.gen.UIAutomationClient'

@ -0,0 +1,396 @@
# -*- coding: mbcs -*-
typelib_path = 'C:\\Windows\\System32\\stdole2.tlb'
_lcid = 0 # change this if required
from ctypes import *
from ctypes.wintypes import VARIANT_BOOL
FONTITALIC = VARIANT_BOOL
from comtypes import IUnknown
OLE_COLOR = c_ulong
FONTUNDERSCORE = VARIANT_BOOL
from comtypes.automation import IDispatch
from comtypes import GUID
from comtypes import BSTR
from comtypes import dispid
from comtypes import DISPMETHOD, DISPPROPERTY, helpstring
FONTSTRIKETHROUGH = VARIANT_BOOL
OLE_XPOS_PIXELS = c_int
OLE_HANDLE = c_int
OLE_XSIZE_HIMETRIC = c_int
OLE_YSIZE_HIMETRIC = c_int
OLE_XPOS_HIMETRIC = c_int
OLE_YPOS_HIMETRIC = c_int
from ctypes import HRESULT
from comtypes import helpstring
from comtypes import COMMETHOD
from comtypes import CoClass
FONTNAME = BSTR
from comtypes import GUID
FONTSIZE = c_longlong
OLE_YPOS_PIXELS = c_int
OLE_XSIZE_PIXELS = c_int
from comtypes.automation import DISPPARAMS
OLE_YSIZE_PIXELS = c_int
OLE_XPOS_CONTAINER = c_float
from comtypes.automation import IEnumVARIANT
OLE_YPOS_CONTAINER = c_float
OLE_XSIZE_CONTAINER = c_float
OLE_YSIZE_CONTAINER = c_float
from comtypes.automation import EXCEPINFO
OLE_OPTEXCLUSIVE = VARIANT_BOOL
OLE_CANCELBOOL = VARIANT_BOOL
OLE_ENABLEDEFAULTBOOL = VARIANT_BOOL
FONTBOLD = VARIANT_BOOL
class FontEvents(IDispatch):
_case_insensitive_ = True
'Event interface for the Font object'
_iid_ = GUID('{4EF6100A-AF88-11D0-9846-00C04FC29993}')
_idlflags_ = ['hidden']
_methods_ = []
FontEvents._disp_methods_ = [
DISPMETHOD([dispid(9)], None, 'FontChanged',
( ['in'], BSTR, 'PropertyName' )),
]
# values for enumeration 'LoadPictureConstants'
Default = 0
Monochrome = 1
VgaColor = 2
Color = 4
LoadPictureConstants = c_int # enum
class Picture(IDispatch):
_case_insensitive_ = True
_iid_ = GUID('{7BF80981-BF32-101A-8BBB-00AA00300CAB}')
_idlflags_ = []
_methods_ = []
Picture._disp_methods_ = [
DISPPROPERTY([dispid(0), 'readonly'], OLE_HANDLE, 'Handle'),
DISPPROPERTY([dispid(2)], OLE_HANDLE, 'hPal'),
DISPPROPERTY([dispid(3), 'readonly'], c_short, 'Type'),
DISPPROPERTY([dispid(4), 'readonly'], OLE_XSIZE_HIMETRIC, 'Width'),
DISPPROPERTY([dispid(5), 'readonly'], OLE_YSIZE_HIMETRIC, 'Height'),
DISPMETHOD([dispid(6)], None, 'Render',
( [], c_int, 'hdc' ),
( [], c_int, 'x' ),
( [], c_int, 'y' ),
( [], c_int, 'cx' ),
( [], c_int, 'cy' ),
( [], OLE_XPOS_HIMETRIC, 'xSrc' ),
( [], OLE_YPOS_HIMETRIC, 'ySrc' ),
( [], OLE_XSIZE_HIMETRIC, 'cxSrc' ),
( [], OLE_YSIZE_HIMETRIC, 'cySrc' ),
( [], c_void_p, 'prcWBounds' )),
]
IPictureDisp = Picture
class IFont(IUnknown):
_case_insensitive_ = True
'Font Object'
_iid_ = GUID('{BEF6E002-A874-101A-8BBA-00AA00300CAB}')
_idlflags_ = ['hidden']
IFont._methods_ = [
COMMETHOD(['propget'], HRESULT, 'Name',
( ['out', 'retval'], POINTER(BSTR), 'pname' )),
COMMETHOD(['propput'], HRESULT, 'Name',
( ['in'], BSTR, 'pname' )),
COMMETHOD(['propget'], HRESULT, 'Size',
( ['out', 'retval'], POINTER(c_longlong), 'psize' )),
COMMETHOD(['propput'], HRESULT, 'Size',
( ['in'], c_longlong, 'psize' )),
COMMETHOD(['propget'], HRESULT, 'Bold',
( ['out', 'retval'], POINTER(VARIANT_BOOL), 'pbold' )),
COMMETHOD(['propput'], HRESULT, 'Bold',
( ['in'], VARIANT_BOOL, 'pbold' )),
COMMETHOD(['propget'], HRESULT, 'Italic',
( ['out', 'retval'], POINTER(VARIANT_BOOL), 'pitalic' )),
COMMETHOD(['propput'], HRESULT, 'Italic',
( ['in'], VARIANT_BOOL, 'pitalic' )),
COMMETHOD(['propget'], HRESULT, 'Underline',
( ['out', 'retval'], POINTER(VARIANT_BOOL), 'punderline' )),
COMMETHOD(['propput'], HRESULT, 'Underline',
( ['in'], VARIANT_BOOL, 'punderline' )),
COMMETHOD(['propget'], HRESULT, 'Strikethrough',
( ['out', 'retval'], POINTER(VARIANT_BOOL), 'pstrikethrough' )),
COMMETHOD(['propput'], HRESULT, 'Strikethrough',
( ['in'], VARIANT_BOOL, 'pstrikethrough' )),
COMMETHOD(['propget'], HRESULT, 'Weight',
( ['out', 'retval'], POINTER(c_short), 'pweight' )),
COMMETHOD(['propput'], HRESULT, 'Weight',
( ['in'], c_short, 'pweight' )),
COMMETHOD(['propget'], HRESULT, 'Charset',
( ['out', 'retval'], POINTER(c_short), 'pcharset' )),
COMMETHOD(['propput'], HRESULT, 'Charset',
( ['in'], c_short, 'pcharset' )),
COMMETHOD(['propget'], HRESULT, 'hFont',
( ['out', 'retval'], POINTER(OLE_HANDLE), 'phfont' )),
COMMETHOD([], HRESULT, 'Clone',
( ['out'], POINTER(POINTER(IFont)), 'ppfont' )),
COMMETHOD([], HRESULT, 'IsEqual',
( ['in'], POINTER(IFont), 'pfontOther' )),
COMMETHOD([], HRESULT, 'SetRatio',
( ['in'], c_int, 'cyLogical' ),
( ['in'], c_int, 'cyHimetric' )),
COMMETHOD([], HRESULT, 'AddRefHfont',
( ['in'], OLE_HANDLE, 'hFont' )),
COMMETHOD([], HRESULT, 'ReleaseHfont',
( ['in'], OLE_HANDLE, 'hFont' )),
]
################################################################
## code template for IFont implementation
##class IFont_Impl(object):
## def _get(self):
## '-no docstring-'
## #return pname
## def _set(self, pname):
## '-no docstring-'
## Name = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return psize
## def _set(self, psize):
## '-no docstring-'
## Size = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return pbold
## def _set(self, pbold):
## '-no docstring-'
## Bold = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return pitalic
## def _set(self, pitalic):
## '-no docstring-'
## Italic = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return punderline
## def _set(self, punderline):
## '-no docstring-'
## Underline = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return pstrikethrough
## def _set(self, pstrikethrough):
## '-no docstring-'
## Strikethrough = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return pweight
## def _set(self, pweight):
## '-no docstring-'
## Weight = property(_get, _set, doc = _set.__doc__)
##
## def _get(self):
## '-no docstring-'
## #return pcharset
## def _set(self, pcharset):
## '-no docstring-'
## Charset = property(_get, _set, doc = _set.__doc__)
##
## @property
## def hFont(self):
## '-no docstring-'
## #return phfont
##
## def Clone(self):
## '-no docstring-'
## #return ppfont
##
## def IsEqual(self, pfontOther):
## '-no docstring-'
## #return
##
## def SetRatio(self, cyLogical, cyHimetric):
## '-no docstring-'
## #return
##
## def AddRefHfont(self, hFont):
## '-no docstring-'
## #return
##
## def ReleaseHfont(self, hFont):
## '-no docstring-'
## #return
##
class StdPicture(CoClass):
_reg_clsid_ = GUID('{0BE35204-8F91-11CE-9DE3-00AA004BB851}')
_idlflags_ = []
_typelib_path_ = typelib_path
_reg_typelib_ = ('{00020430-0000-0000-C000-000000000046}', 2, 0)
class IPicture(IUnknown):
_case_insensitive_ = True
'Picture Object'
_iid_ = GUID('{7BF80980-BF32-101A-8BBB-00AA00300CAB}')
_idlflags_ = ['hidden']
StdPicture._com_interfaces_ = [Picture, IPicture]
class Library(object):
'OLE Automation'
name = 'stdole'
_reg_typelib_ = ('{00020430-0000-0000-C000-000000000046}', 2, 0)
IFontEventsDisp = FontEvents
class StdFont(CoClass):
_reg_clsid_ = GUID('{0BE35203-8F91-11CE-9DE3-00AA004BB851}')
_idlflags_ = []
_typelib_path_ = typelib_path
_reg_typelib_ = ('{00020430-0000-0000-C000-000000000046}', 2, 0)
class Font(IDispatch):
_case_insensitive_ = True
_iid_ = GUID('{BEF6E003-A874-101A-8BBA-00AA00300CAB}')
_idlflags_ = []
_methods_ = []
StdFont._com_interfaces_ = [Font, IFont]
StdFont._outgoing_interfaces_ = [FontEvents]
IPicture._methods_ = [
COMMETHOD(['propget'], HRESULT, 'Handle',
( ['out', 'retval'], POINTER(OLE_HANDLE), 'phandle' )),
COMMETHOD(['propget'], HRESULT, 'hPal',
( ['out', 'retval'], POINTER(OLE_HANDLE), 'phpal' )),
COMMETHOD(['propget'], HRESULT, 'Type',
( ['out', 'retval'], POINTER(c_short), 'ptype' )),
COMMETHOD(['propget'], HRESULT, 'Width',
( ['out', 'retval'], POINTER(OLE_XSIZE_HIMETRIC), 'pwidth' )),
COMMETHOD(['propget'], HRESULT, 'Height',
( ['out', 'retval'], POINTER(OLE_YSIZE_HIMETRIC), 'pheight' )),
COMMETHOD([], HRESULT, 'Render',
( ['in'], c_int, 'hdc' ),
( ['in'], c_int, 'x' ),
( ['in'], c_int, 'y' ),
( ['in'], c_int, 'cx' ),
( ['in'], c_int, 'cy' ),
( ['in'], OLE_XPOS_HIMETRIC, 'xSrc' ),
( ['in'], OLE_YPOS_HIMETRIC, 'ySrc' ),
( ['in'], OLE_XSIZE_HIMETRIC, 'cxSrc' ),
( ['in'], OLE_YSIZE_HIMETRIC, 'cySrc' ),
( ['in'], c_void_p, 'prcWBounds' )),
COMMETHOD(['propput'], HRESULT, 'hPal',
( ['in'], OLE_HANDLE, 'phpal' )),
COMMETHOD(['propget'], HRESULT, 'CurDC',
( ['out', 'retval'], POINTER(c_int), 'phdcOut' )),
COMMETHOD([], HRESULT, 'SelectPicture',
( ['in'], c_int, 'hdcIn' ),
( ['out'], POINTER(c_int), 'phdcOut' ),
( ['out'], POINTER(OLE_HANDLE), 'phbmpOut' )),
COMMETHOD(['propget'], HRESULT, 'KeepOriginalFormat',
( ['out', 'retval'], POINTER(VARIANT_BOOL), 'pfkeep' )),
COMMETHOD(['propput'], HRESULT, 'KeepOriginalFormat',
( ['in'], VARIANT_BOOL, 'pfkeep' )),
COMMETHOD([], HRESULT, 'PictureChanged'),
COMMETHOD([], HRESULT, 'SaveAsFile',
( ['in'], c_void_p, 'pstm' ),
( ['in'], VARIANT_BOOL, 'fSaveMemCopy' ),
( ['out'], POINTER(c_int), 'pcbSize' )),
COMMETHOD(['propget'], HRESULT, 'Attributes',
( ['out', 'retval'], POINTER(c_int), 'pdwAttr' )),
COMMETHOD([], HRESULT, 'SetHdc',
( ['in'], OLE_HANDLE, 'hdc' )),
]
################################################################
## code template for IPicture implementation
##class IPicture_Impl(object):
## @property
## def Handle(self):
## '-no docstring-'
## #return phandle
##
## def _get(self):
## '-no docstring-'
## #return phpal
## def _set(self, phpal):
## '-no docstring-'
## hPal = property(_get, _set, doc = _set.__doc__)
##
## @property
## def Type(self):
## '-no docstring-'
## #return ptype
##
## @property
## def Width(self):
## '-no docstring-'
## #return pwidth
##
## @property
## def Height(self):
## '-no docstring-'
## #return pheight
##
## def Render(self, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds):
## '-no docstring-'
## #return
##
## @property
## def CurDC(self):
## '-no docstring-'
## #return phdcOut
##
## def SelectPicture(self, hdcIn):
## '-no docstring-'
## #return phdcOut, phbmpOut
##
## def _get(self):
## '-no docstring-'
## #return pfkeep
## def _set(self, pfkeep):
## '-no docstring-'
## KeepOriginalFormat = property(_get, _set, doc = _set.__doc__)
##
## def PictureChanged(self):
## '-no docstring-'
## #return
##
## def SaveAsFile(self, pstm, fSaveMemCopy):
## '-no docstring-'
## #return pcbSize
##
## @property
## def Attributes(self):
## '-no docstring-'
## #return pdwAttr
##
## def SetHdc(self, hdc):
## '-no docstring-'
## #return
##
# values for enumeration 'OLE_TRISTATE'
Unchecked = 0
Checked = 1
Gray = 2
OLE_TRISTATE = c_int # enum
Font._disp_methods_ = [
DISPPROPERTY([dispid(0)], BSTR, 'Name'),
DISPPROPERTY([dispid(2)], c_longlong, 'Size'),
DISPPROPERTY([dispid(3)], VARIANT_BOOL, 'Bold'),
DISPPROPERTY([dispid(4)], VARIANT_BOOL, 'Italic'),
DISPPROPERTY([dispid(5)], VARIANT_BOOL, 'Underline'),
DISPPROPERTY([dispid(6)], VARIANT_BOOL, 'Strikethrough'),
DISPPROPERTY([dispid(7)], c_short, 'Weight'),
DISPPROPERTY([dispid(8)], c_short, 'Charset'),
]
IFontDisp = Font
__all__ = [ 'OLE_TRISTATE', 'FONTITALIC', 'OLE_OPTEXCLUSIVE', 'Font',
'OLE_ENABLEDEFAULTBOOL', 'OLE_YPOS_CONTAINER',
'OLE_XPOS_HIMETRIC', 'OLE_XSIZE_CONTAINER', 'IPictureDisp',
'OLE_YSIZE_CONTAINER', 'OLE_XPOS_CONTAINER',
'OLE_CANCELBOOL', 'LoadPictureConstants', 'Color',
'FONTBOLD', 'OLE_HANDLE', 'Checked', 'Default', 'FONTSIZE',
'StdPicture', 'StdFont', 'FontEvents', 'FONTSTRIKETHROUGH',
'IPicture', 'Unchecked', 'OLE_XSIZE_HIMETRIC', 'IFont',
'Monochrome', 'OLE_COLOR', 'Gray', 'OLE_YPOS_HIMETRIC',
'OLE_YPOS_PIXELS', 'OLE_YSIZE_PIXELS', 'OLE_XPOS_PIXELS',
'IFontEventsDisp', 'IFontDisp', 'FONTUNDERSCORE',
'OLE_XSIZE_PIXELS', 'VgaColor', 'Picture',
'OLE_YSIZE_HIMETRIC', 'FONTNAME']
from comtypes import _check_version; _check_version('')

@ -0,0 +1 @@
# comtypes.gen package, directory for generated files.

@ -0,0 +1,3 @@
from comtypes.gen import _00020430_0000_0000_C000_000000000046_0_2_0
globals().update(_00020430_0000_0000_C000_000000000046_0_2_0.__dict__)
__name__ = 'comtypes.gen.stdole'
Loading…
Cancel
Save