├── .gbp.conf ├── .gitignore ├── LICENSE.txt ├── MANIFEST.in ├── README.markdown ├── autopy └── __init__.py ├── debian ├── changelog ├── compat ├── control ├── copyright ├── pycompat ├── python-autopy-doc.doc-base ├── python-autopy-doc.install ├── python-autopy.docs ├── pyversions └── rules ├── documentation ├── XMLGen.py ├── api-reference │ ├── alert.html │ ├── bitmap.html │ ├── color.html │ ├── index.html │ ├── key.html │ ├── mouse.html │ ├── screen.html │ └── style.css ├── doc_helper.py ├── doc_helper_helper.py └── mmm! │ ├── alert.mmm │ ├── bitmap.mmm │ ├── color.mmm │ ├── index.mmm │ ├── key.mmm │ ├── mouse.mmm │ └── screen.mmm ├── setup.py ├── src ├── MMBitmap.c ├── MMBitmap.h ├── MMPointArray.c ├── MMPointArray.h ├── UTHashTable.c ├── UTHashTable.h ├── alert.c ├── alert.h ├── autopy-alert-module.c ├── autopy-alert-module.h ├── autopy-bitmap-module.c ├── autopy-bitmap-module.h ├── autopy-color-module.c ├── autopy-color-module.h ├── autopy-key-module.c ├── autopy-key-module.h ├── autopy-mouse-module.c ├── autopy-mouse-module.h ├── autopy-screen-module.c ├── autopy-screen-module.h ├── base64.c ├── base64.h ├── bitmap_find.c ├── bitmap_find.h ├── bmp_io.c ├── bmp_io.h ├── color_find.c ├── color_find.h ├── deadbeef_rand.c ├── deadbeef_rand.h ├── endian.h ├── inline_keywords.h ├── io.c ├── io.h ├── keycode.c ├── keycode.h ├── keypress.c ├── keypress.h ├── microsleep.h ├── mouse.c ├── mouse.h ├── ms_stdbool.h ├── ms_stdint.h ├── os.h ├── pasteboard.c ├── pasteboard.h ├── png_io.c ├── png_io.h ├── py-bitmap-class.c ├── py-bitmap-class.h ├── py-convenience.c ├── py-convenience.h ├── rgb.h ├── screen.c ├── screen.h ├── screengrab.c ├── screengrab.h ├── snprintf.c ├── snprintf.h ├── str_io.c ├── str_io.h ├── types.h ├── uthash.h ├── xdisplay.c ├── xdisplay.h ├── zlib_util.c └── zlib_util.h └── windows ├── README.txt ├── win32 ├── libpng.lib ├── png.h ├── pngconf.h ├── pnglibconf.h ├── zconf.h ├── zlib.h └── zlib.lib └── win64 ├── libpng.lib ├── png.h ├── pngconf.h ├── pnglibconf.h ├── zconf.h ├── zlib.h └── zlib.lib /.gbp.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | upstream-branch = master 3 | debian-branch = debian 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | *.pyc 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | AutoPy (the software) is licensed under the terms of the MIT license. 2 | 3 | The documentation for AutoPy is licensed under the terms of the FreeBSD Documentation License. 4 | 5 | ### MIT License 6 | 7 | Copyright 2010 Michael Sanders. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | ### The FreeBSD Documentation License 16 | 17 | Copyright 2010 Michael Sanders. All rights reserved. 18 | 19 | Redistribution and use in source (Markdown, plaintext, et. al.) and "compiled" forms (HTML, PDF and so forth) with or without modification, are permitted provided that the following conditions are met: 20 | 21 | Redistributions of source code (Markdown, plaintext, et. al.) must retain the above copyright notice, this list of conditions and the following disclaimer as the first lines of this file unmodified. 22 | Redistributions in compiled form (HTML, PDF and so on) 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. 23 | 24 | THIS DOCUMENTATION IS PROVIDED "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 AUTHORS OR COPYRIGHT HOLDERS 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 DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include src/*.c 3 | include src/*.h 4 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # This repository is no longer active. 2 | 3 | ---- 4 | 5 | Please use https://github.com/autopilot-rs/autopy instead. 6 | -------------------------------------------------------------------------------- /autopy/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | AutoPy is a simple, cross-platform GUI automation toolkit for Python. It 3 | includes functions for controlling the keyboard and mouse, finding colors and 4 | bitmaps on-screen, and displaying alerts -- all in a cross-platform, efficient, 5 | and simple manner. 6 | """ 7 | 8 | # Import all sub-modules for convenience 9 | import autopy.alert 10 | import autopy.bitmap 11 | import autopy.color 12 | import autopy.key 13 | import autopy.mouse 14 | import autopy.screen -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | autopy (0.43~b+git20100111.65142bd-0ubuntu1) karmic; urgency=low 2 | 3 | * Initial release 4 | 5 | -- Michael Budde Mon, 11 Jan 2010 11:39:52 +0100 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: autopy 2 | Section: python 3 | Priority: extra 4 | Maintainer: Michael Budde 5 | Build-Depends: cdbs, 6 | debhelper (>= 7), 7 | python-support (>= 0.5.6), 8 | python-all-dev, 9 | libxtst-dev, 10 | libpng-dev, 11 | zlib1g-dev 12 | Standards-Version: 3.8.3 13 | Homepage: http://github.com/msanders/autopy 14 | 15 | Package: python-autopy 16 | Architecture: all 17 | Depends: ${python:Depends}, ${misc:Depends}, 18 | libxtst6, 19 | libpng12-0, 20 | zlib1g 21 | Suggests: python-autopy-doc, doc-base 22 | Description: A simple, cross-platform automation toolkit for Python 23 | AutoPy is a simple toolkit for automating and scripting repetitive tasks, 24 | especially those involving a GUI, with Python. It includes functions for 25 | controlling the mouse and keyboard, finding colors and bitmaps on-screen, as 26 | well as displaying cross-platform alerts. 27 | 28 | Package: python-autopy-doc 29 | Section: doc 30 | Architecture: all 31 | Description: A simple, cross-platform automation toolkit for Python 32 | This package contains the API references for autopy. 33 | 34 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Michael Budde on 2 | Mon, 11 Jan 2010 11:39:52 +0100. 3 | 4 | It was downloaded from http://github.com/msanders/autopy 5 | 6 | Upstream Author(s): 7 | 8 | Michael Sanders 9 | 10 | Copyright: 11 | 12 | Copyright (C) 2010 Michael Sanders 13 | 14 | License: 15 | 16 | AutoPy (the software) is licensed under the terms of the MIT license. 17 | 18 | The documentation for AutoPy is licensed under the terms of the FreeBSD 19 | Documentation License. 20 | 21 | MIT License: 22 | 23 | Permission is hereby granted, free of charge, to any person obtaining a copy of 24 | this software and associated documentation files (the "Software"), to deal in 25 | the Software without restriction, including without limitation the rights to 26 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 27 | of the Software, and to permit persons to whom the Software is furnished to do 28 | so, subject to the following conditions: 29 | 30 | The above copyright notice and this permission notice shall be included in all 31 | copies or substantial portions of the Software. 32 | 33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 39 | SOFTWARE. 40 | 41 | The FreeBSD Documentation License: 42 | 43 | Redistribution and use in source (Markdown, plaintext, et. al.) and "compiled" 44 | forms (HTML, PDF and so forth) with or without modification, are permitted 45 | provided that the following conditions are met: 46 | 47 | Redistributions of source code (Markdown, plaintext, et. al.) must retain the 48 | above copyright notice, this list of conditions and the following disclaimer as 49 | the first lines of this file unmodified. Redistributions in compiled form 50 | (HTML, PDF and so on) must reproduce the above copyright notice, this list of 51 | conditions and the following disclaimer in the documentation and/or other 52 | materials provided with the distribution. 53 | 54 | THIS DOCUMENTATION IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 55 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 56 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 57 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 58 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 59 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 60 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 61 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 62 | IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF ADVISED OF THE 63 | POSSIBILITY OF SUCH DAMAGE. 64 | 65 | The Debian packaging is: 66 | 67 | Copyright (C) 2010 Michael Budde 68 | 69 | and is licensed under the GPL version 3, see `/usr/share/common-licenses/GPL-3'. 70 | -------------------------------------------------------------------------------- /debian/pycompat: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /debian/python-autopy-doc.doc-base: -------------------------------------------------------------------------------- 1 | Document: autopy 2 | Title: Autopy API documentation 3 | Author: Michael Sanders 4 | Abstract: A simple toolkit for automating and scripting repetitive tasks, especially those involving a GUI, with Python. 5 | Section: Programming/Python 6 | 7 | Format: HTML 8 | Index: /usr/share/doc/python-autopy-doc/html/index.html 9 | Files: /usr/share/doc/python-autopy-doc/html/* 10 | -------------------------------------------------------------------------------- /debian/python-autopy-doc.install: -------------------------------------------------------------------------------- 1 | documentation/api-reference/* usr/share/doc/python-autopy-doc/html 2 | -------------------------------------------------------------------------------- /debian/python-autopy.docs: -------------------------------------------------------------------------------- 1 | LICENSE.txt 2 | README.markdown 3 | -------------------------------------------------------------------------------- /debian/pyversions: -------------------------------------------------------------------------------- 1 | 2.5- 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | DEB_PYTHON_SYSTEM=pysupport 4 | 5 | include /usr/share/cdbs/1/rules/debhelper.mk 6 | include /usr/share/cdbs/1/class/python-distutils.mk 7 | 8 | # Add here any variable or target overrides you need. 9 | 10 | DEB_DESTDIR=$(CURDIR)/debian/python-autopy 11 | -------------------------------------------------------------------------------- /documentation/XMLGen.py: -------------------------------------------------------------------------------- 1 | """ 2 | The preferred way to use this module is to first: 3 | from XMLGen import XMLGen, 4 | and then just use the class documented below. 5 | """ 6 | 7 | class XMLGen(object): 8 | """ 9 | Simple class to ease in generating HTML & XML documents. 10 | Knows nothing about HTML, only tags and attributes. 11 | """ 12 | def __init__(self, startstr, is_xml=True): 13 | self.str = startstr 14 | self._tagstack = [] 15 | self.is_xml = is_xml # Determines whether "/" should be included in 16 | # auto-closing tags. 17 | def push_tag(self, tagname, attrs=[]): 18 | """ 19 | Pushes given tag onto stack with given attributes. 20 | 21 | "attrs" should be a list of tuples (attribute, value) to be assigned to 22 | the tag in order, or an empty list [] if none are to be assigned. 23 | 24 | E.g., push_tag("foo", [("id", "baz")]) output ''. 25 | 26 | A list of tuples is used instead of a dict in order for the order to 27 | be preserved. 28 | """ 29 | tag = '<%s%s>' % (tagname, string_for_attrs(attrs)) 30 | self.str += '\n' + indent(tag, self.indent_level()) 31 | self._tagstack.append(tagname) 32 | def pop_tag(self, newline=True): 33 | """Pops tag from stack (and closes it in string).""" 34 | tag = '' % self._tagstack.pop() 35 | if newline: 36 | tag = '\n' + indent(tag, self.indent_level()) 37 | self.str += tag 38 | def insert_tag(self, tagname, attrs=[], text="", 39 | autoclose=False, newline=False): 40 | """Immediately inserts tag, autoclosing it if told to.""" 41 | if autoclose: 42 | self.str += '\n<%s%s%s>' % (tagname, string_for_attrs(attrs), 43 | ' /' if self.is_xml else '') 44 | else: 45 | self.push_tag(tagname, attrs) 46 | if text: 47 | if newline: 48 | self.insert_text('\n' + indent(text, self.indent_level())) 49 | else: 50 | self.insert_text(text) 51 | self.pop_tag(newline=newline) 52 | def insert_text(self, text): 53 | """Inserts (non-indented) text between last pushed tag.""" 54 | self.str += text 55 | def insert_paragraphs(self, str, ignore_pre=True): 56 | """ 57 | Convenience method. 58 | Inserts paragraphs separated by newlines as paragraphs wrapped in 59 |

tags, while silently ignoring content in

 tags if ignore_pre
60 |         is True.
61 |         """
62 |         for block in splittag(str, 'pre'):
63 |             if ignore_pre and '
' in block:
64 |                 self.insert_text(block)
65 |                 if 'Holds down and then' in block:
66 |                     print block
67 |             else:
68 |                 self.insert_text('\n'.join('

%s

' % line 69 | for line in block.splitlines())) 70 | def insert_link(self, text, href): 71 | """ 72 | Convenience method. 73 | Inserts given text wrapped in anchor to the given URL. 74 | """ 75 | self.insert_text('\n%s' % (href, text)) 76 | def indent_level(self): 77 | """Returns current level of indentation inside pushed tags.""" 78 | return len(self._tagstack) - 1 79 | def __str__(self): 80 | return self.str 81 | 82 | def indent(str, level): 83 | """ 84 | Returns string where each line is indented by the given level in tabs. 85 | """ 86 | if level == 0: return str 87 | return "\n".join("\t" * level + line for line in str.splitlines()) 88 | 89 | def string_for_attrs(attrs): 90 | """Returns string describing tag attributes in the order given.""" 91 | if not attrs: return '' 92 | return ''.join(' %s="%s"' % (attr, value) for attr, value in attrs) 93 | 94 | import re 95 | def splittag(str, tagname): 96 | tag = re.escape(tagname) 97 | regex = re.compile('(<%s>.*?)' % (tag, tag), re.DOTALL) 98 | return regex.split(str) 99 | -------------------------------------------------------------------------------- /documentation/api-reference/alert.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | alert — autopy module for displaying alerts 9 | 10 | 11 | 12 | 13 | 19 |
20 | 40 |
41 |

42 | alert — autopy module for displaying alerts 43 |

44 |
45 |

46 | This module contains functions for displaying cross-platform alert dialogs. 47 |

48 |
49 |

50 | Functions 51 |

52 |
53 |
54 | alert.alert(msg, title="AutoPy Alert", default_button="OK", [cancel_button]) 55 |
56 |
57 |

58 | Displays alert with the given attributes. If cancel_button is not given, only the default button is displayed. Returns True if the default button was pressed, or False if cancelled. Note that the arguments are keywords, and can be passed as named parameters (e.g., alert(msg="bar", title="foo")). 59 |

60 |

61 | Due to limitations in the Win32 API, Windows currently replaces default_button with "OK" and cancel_button (if given) with "Cancel". This may be fixed in a later release. 62 |

63 |
64 |
65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /documentation/api-reference/color.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | color — autopy module for converting color formats 9 | 10 | 11 | 12 | 13 | 19 |
20 | 43 |
44 |

45 | color — autopy module for converting color formats 46 |

47 |
48 |

49 | This module provides routines for converting between the color format (hexadecimal) used by autopy methods and other, more readable, formats (e.g., RGB tuples). 50 |

51 |
52 |

53 | Functions 54 |

55 |
56 |
57 | color.rgb_to_hex(r, g, b) 58 |
59 |
60 |

61 | Returns hexadecimal value of given RGB tuple. r, g, and b should be in the range 0 - 255. 62 |

63 |
64 |
65 | color.hex_to_rgb(hex) 66 |
67 |
68 |

69 | Returns a tuple (r, g, b) of the RGB integer values equivalent to the given RGB hexadecimal value. r, g, and b are in the range 0 - 255. 70 |

71 |
72 |
73 |
74 |
75 | 76 | 77 | -------------------------------------------------------------------------------- /documentation/api-reference/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | autopy — API Reference 9 | 10 | 11 | 12 | 13 | 19 |
20 | 55 |
56 |

57 | autopy — API Reference 58 |

59 |
60 |

61 | A simple toolkit for automating and scripting repetitive tasks, especially those involving a GUI, with Python. 62 |

63 |
64 |

65 | Table Of Contents 66 |

67 |
68 |
69 | alert module 70 |
71 |
72 | bitmap module 73 |
74 |
75 | color module 76 |
77 |
78 | key module 79 |
80 |
81 | mouse module 82 |
83 |
84 | screen module 85 |
86 |
87 |
88 |
89 | 90 | 91 | -------------------------------------------------------------------------------- /documentation/api-reference/mouse.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | mouse — autopy module for working with the mouse 9 | 10 | 11 | 12 | 13 | 19 |
20 | 68 |
69 |

70 | mouse — autopy module for working with the mouse 71 |

72 |
73 |

74 | This module contains functions for getting the current state of and controlling the mouse cursor. 75 |

76 |

77 | Unless otherwise stated, coordinates are those of a screen coordinate system, where the origin is at the top left. 78 |

79 |
80 |

81 | Functions 82 |

83 |
84 |
85 | mouse.get_pos() 86 |
87 |
88 |

89 | Returns a tuple (x, y) of the current mouse position. 90 |

91 |
92 |
93 | mouse.toggle(down, button=LEFT_BUTTON) 94 |
95 |
96 |

97 | Holds down or releases the given mouse button in the current position. button can be LEFT_BUTTON, RIGHT_BUTTON, or CENTER_BUTTON. If no button is given, the left button is defaulted to. 98 |

99 |
100 | Exceptions: 101 |
102 |
    103 |
  • 104 | ValueError is thrown if the mouse button is invalid. 105 |
  • 106 |
107 |
108 |
109 | mouse.move(x, y) 110 |
111 |
112 |

113 | Moves the mouse to the given (x, y) coordinate. 114 |

115 |
116 | Exceptions: 117 |
118 |
    119 |
  • 120 | ValueError is thrown if the point is out of index. 121 |
  • 122 |
123 |
124 |
125 | mouse.smooth_move(x, y) 126 |
127 |
128 |

129 | Smoothly moves the mouse to the given (x, y) coordinate in a straight line. 130 |

131 |
132 | Exceptions: 133 |
134 |
    135 |
  • 136 | ValueError is thrown if the point is out of index. 137 |
  • 138 |
139 |
140 |
141 | mouse.click(button=LEFT_BUTTON) 142 |
143 |
144 |

145 | Convenience wrapper around toggle() that holds down and then releases the given mouse button. 146 |

147 |
148 |
149 |

150 | Constants 151 |

152 |
153 |
154 |

155 | The following is a list of constants used by this module in order to specify mouse buttons. 156 |

157 |
158 |
159 | mouse.RIGHT_BUTTON 160 |
161 |
162 |

163 | Right mouse button. 164 |

165 |
166 |
167 | mouse.CENTER_BUTTON 168 |
169 |
170 |

171 | Middle mouse button. 172 |

173 |
174 |
175 | mouse.LEFT_BUTTON 176 |
177 |
178 |

179 | Left mouse button. 180 |

181 |
182 |
183 |
184 |
185 | 186 | 187 | -------------------------------------------------------------------------------- /documentation/api-reference/screen.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | screen — autopy module for working with the screen 9 | 10 | 11 | 12 | 13 | 19 |
20 | 46 |
47 |

48 | screen — autopy module for working with the screen 49 |

50 |
51 |

52 | This module contains functions for obtaining attributes about the screen. 53 |

54 |
55 |

56 | Functions 57 |

58 |
59 |
60 | screen.get_size() 61 |
62 |
63 |

64 | Returns a tuple (width, height) of the size of the main screen. 65 |

66 |
67 |
68 | screen.point_visible(x, y) 69 |
70 |
71 |

72 | Returns True if the given point is inside the main screen boundaries. 73 |

74 |
75 |
76 | screen.get_color(x, y) 77 |
78 |
79 |

80 | Returns hexadecimal value describing the RGB color at the given point. 81 |

82 |

83 | Essentially equivalent to: 84 |

85 |
 86 | rect = ((x, y), (1, 1))
 87 | bitmap.capture_screen_portion(rect).get_color(0, 0)
 88 | 
89 |

90 | only more efficient/convenient. 91 |

92 |
93 | Exceptions: 94 |
95 |
    96 |
  • 97 | OSError is thrown if the system calls were unsuccessful. 98 |
  • 99 |
  • 100 | ValueError is thrown if the rect is out of bounds. 101 |
  • 102 |
103 |
104 |
105 |
106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /documentation/api-reference/style.css: -------------------------------------------------------------------------------- 1 | /* -- Page Layout -- */ 2 | 3 | body, h1, h2, h3, h4, p, blockquote, ol, ul, div, dl, dd, dt, pre { 4 | margin:0; 5 | padding:0; 6 | } 7 | 8 | html, body { 9 | height:100%; 10 | width:100%; 11 | } 12 | 13 | body { 14 | font-family:sans-serif; 15 | background-color:#1c4e63; /* sidebar color */ 16 | color:#000; 17 | } 18 | 19 | div#header { 20 | background-color:#11303d; 21 | color:#fff; 22 | line-height:30px; 23 | font-size:90%; 24 | padding:0 5px; 25 | text-align:left; 26 | } 27 | 28 | div#header div#nav { 29 | float:right; 30 | } 31 | 32 | div#header a { 33 | padding:0 4px 0 4px; 34 | text-decoration:none; 35 | color:#fff; 36 | } 37 | 38 | div#header a:hover { 39 | text-decoration:underline; 40 | color:white; 41 | } 42 | 43 | div#container { 44 | position:absolute; 45 | height:100%; 46 | width:100%; 47 | } 48 | 49 | div#main { 50 | min-height:100%; 51 | background-color:#fff; 52 | color:#000; 53 | margin:0 0 0 230px; 54 | padding:0 20px 10px 20px; 55 | } 56 | 57 | div#sidebar { 58 | position:absolute; 59 | min-height:100%; 60 | left:0; 61 | font-size:90%; 62 | width:230px; 63 | background-color:#1c4e63; 64 | color:#000; 65 | } 66 | 67 | div#sidebar h3 { 68 | font-family:"Trebuchet MS", sans-serif; 69 | color:#fff; 70 | background-color:transparent; 71 | font-size:1.4em; 72 | font-weight:normal; 73 | margin:0; 74 | padding:5px 0 0 10px; 75 | border:none; 76 | } 77 | 78 | div#main ul { 79 | margin-top:1em; 80 | } 81 | 82 | div#sidebar ul { 83 | margin:10px; 84 | color:#fff; 85 | list-style:none; 86 | } 87 | 88 | div#sidebar ul ul { 89 | margin:0 0 0 1em; 90 | list-style:square inside; 91 | } 92 | 93 | div#sidebar a { 94 | color:#98dbcc; 95 | } 96 | 97 | p.note { 98 | margin:10px 0 10px 0; 99 | padding:7px; 100 | background-color:#eee; 101 | border:1px solid #ccc; 102 | } 103 | 104 | .note-title { 105 | font-weight:bold; 106 | padding-right:10px; 107 | } 108 | 109 | .section dd { /* function descriptions */ 110 | margin-bottom:1em; 111 | } 112 | 113 | p { 114 | font-size:1.0em; 115 | margin-top:1em; 116 | /* line-height:1.5em; */ 117 | line-height:130%; 118 | /* margin:1.0em 0 0 0; */ 119 | } 120 | 121 | h1, h2, h3, h4, h5, h6 { 122 | font-family:"Trebuchet MS", sans-serif; 123 | text-align:left; 124 | background-color:#f2f2f2; 125 | font-weight:normal; 126 | color:#20435c; 127 | border-bottom:1px solid #ccc; 128 | margin:20px -20px 10px -20px; 129 | padding:3px 0 3px 10px; 130 | } 131 | 132 | h1 { margin-top:0; font-size:200%; } 133 | h2 { font-size:160%; } 134 | h3 { font-size:140%; } 135 | h4 { font-size:120%; } 136 | h5 { font-size:110%; } 137 | h6 { font-size:100%; } 138 | 139 | pre { 140 | padding:5px; 141 | margin:1em 0 0 0; 142 | background-color:#eeffcc; 143 | color:#333333; 144 | line-height:120%; 145 | border:1px solid #ac9; 146 | border-left:none; 147 | border-right:none; 148 | } 149 | 150 | div.exceptions-header { 151 | margin:1em 0 0 0; 152 | padding:0; 153 | font-style:italic; 154 | } 155 | 156 | div#main ul.exceptions { 157 | padding:0; 158 | margin:0; 159 | /* margin:0.5em 0 0.5em 0; */ 160 | } 161 | 162 | ul.exceptions li { 163 | padding:0; 164 | margin:0.25em 0 0 20px; 165 | list-style:square inside; 166 | } 167 | 168 | h1:target, h2:target, h3:target, h4:target, h5:target, h6:target, 169 | div:target, dt:target, .highlight { 170 | background-color:#fbe54e; 171 | } 172 | 173 | a { 174 | color:#355f7c; 175 | text-decoration:none; 176 | } 177 | 178 | a:hover { 179 | text-decoration:underline; 180 | } 181 | 182 | /* a.headerlink { 183 | visibility:hidden; 184 | } */ 185 | 186 | h1:hover > a.headerlink, 187 | h2:hover > a.headerlink, 188 | h3:hover > a.headerlink, 189 | h4:hover > a.headerlink, 190 | h5:hover > a.headerlink, 191 | h6:hover > a.headerlink, 192 | div:hover > a.headerlink { 193 | visibility:visible; 194 | } 195 | 196 | a.headerlink { 197 | color:#c60f0f; 198 | font-size:0.8em; 199 | padding:0 4px 0 4px; 200 | text-decoration:none; 201 | visibility:hidden; 202 | } 203 | 204 | a.headerlink:hover { 205 | background-color:#c60f0f; 206 | color:white; 207 | } 208 | 209 | /* -- Fonts -- */ 210 | tt, pre, code { 211 | font-family:Menlo, "Panic Sans", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace; 212 | font-size:95%; 213 | } 214 | 215 | dd.constant p { 216 | margin:0.5em 0 0.5em 1.5em; 217 | /* margin:0 0 0 1em; */ 218 | font-size:90%; 219 | line-height:100%; 220 | } 221 | dd.constant { 222 | margin:0; 223 | } 224 | 225 | /* -- Functions -- */ 226 | 227 | .function { 228 | /* margin:0 0 0.5em 0; */ 229 | } 230 | 231 | .function .name { 232 | font-size:16px; 233 | font-weight:bold; 234 | } 235 | 236 | .funcarg { 237 | font-family:sans-serif; 238 | font-style:italic; 239 | font-weight:normal; 240 | font-size:16px; 241 | } 242 | -------------------------------------------------------------------------------- /documentation/mmm!/alert.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | alert 4 | autopy module for displaying alerts 5 | This module contains functions for displaying cross-platform alert dialogs. 6 |
7 | 8 | alert(msg, title="AutoPy Alert", default_button="OK", [cancel_button]) 9 | Displays alert with the given attributes. If cancel_button is not given, only the default button is displayed. Returns True if the default button was pressed, or False if cancelled. Note that the arguments are keywords, and can be passed as named parameters (e.g., alert(msg="bar", title="foo")). 10 | 11 | Due to limitations in the Win32 API, Windows currently replaces default_button with "OK" and cancel_button (if given) with "Cancel". This may be fixed in a later release. 12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /documentation/mmm!/bitmap.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | bitmap 4 | autopy module for working with bitmaps 5 | This module defines the class Bitmap for accessing bitmaps and searching for bitmaps on-screen. 6 | 7 | It also defines functions for taking screenshots of the screen. 8 |
9 | 10 | capture_screen(rect=None) 11 | Returns a screengrab of the given portion of the main display, or the entire display if rect is None. 12 | 13 | the screengrab was unsuccessful 14 | the rect is out of bounds 15 | 16 | 17 |
18 |
19 | 20 | Bitmap.open(filepath, format) 21 | Opens image at absolute filepath in the given format. The image type is determined from the filename if possible, unless format is given. 22 | 23 | the image could not be opened 24 | 25 | 26 | 27 | Bitmap.from_string(string) 28 | Creates bitmap from string created by bmp.to_string(). 29 | 30 | the given string was invalid 31 | 32 | 33 | 34 | bmp.get_portion(origin, size) 35 | Returns new bitmap object created from a portion of another. 36 | 37 | portion was out of bounds 38 | portion could not be copied 39 | 40 | 41 | 42 | bmp.point_in_bounds(x, y) 43 | Returns True if x < bmp.width and y < bmp.height, or False if not. 44 | 45 | 46 | bmp.copy_to_pboard() 47 | Copies image to pasteboard. Currently only supported on Windows and Mac OS X. 48 | 49 | the image could not be copied 50 | 51 | 52 | 53 | bmp.save(filepath, [format]) 54 | Saves image to absolute filepath in the given format. The image type is determined from the filename if possible, unless format is given. Note that if the file already exists, it WILL be overwritten. Check yourself first if you do not desire this. 55 | 56 | the image could not be saved 57 | 58 | 59 | 60 | bmp.to_string() 61 | Returns compressed, printable string representing bitmap, to be used with Bitmap.from_string(). 62 | 63 | the string could not be created 64 | 65 | 66 | 67 | bmp.get_color(x, y) 68 | Returns hexadecimal value describing the RGB color at the given point. 69 | 70 | the point out of bounds 71 | 72 | 73 | 74 | bmp.find_color(color, tolerance=0.0, rect=None) 75 | Attempts to find color inside rect in bmp; returns coordinates if found, or None if not. If rect is None, the entire image is searched. 76 | 77 | 78 | bmp.find_every_color(color, tolerance=0.0, rect=None) 79 | Returns list of all coordinates inside rect in bmp matching color. If rect is None, the entire image is searched. 80 | 81 | 82 | bmp.count_of_color(color, tolerance=0.0, rect=None) 83 | Returns count of color in bitmap. Functionally equivalent to: 84 | len(find_every_color(color, tolerance, rect)) 85 | 86 | 87 | bmp.find_bitmap(needle, tolerance=0.0, rect=None) 88 | Searches for needle in bmp. Returns tuple (x, y) of position if found, or None if not. 89 | 90 | 91 | bmp.find_every_bitmap(needle, tolerance=0.0, rect=None) 92 | Returns list of all (x, y) coordinates where needle occurs in bmp. 93 | 94 | 95 | bmp.count_of_bitmap(needle, tolerance=0.0, rect=None) 96 | Returns count of occurrences of needle in haystack. Functionally equivalent to: 97 | len(bmp.find_every_bitmap(needle, tolerance)) 98 | 99 |
100 |
101 | -------------------------------------------------------------------------------- /documentation/mmm!/color.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | color 4 | autopy module for converting color formats 5 | This module provides routines for converting between the color format (hexadecimal) used by autopy methods and other, more readable, formats (e.g., RGB tuples). 6 |
7 | 8 | hex_to_rgb(hex) 9 | Returns a tuple (r, g, b) of the RGB integer values equivalent to the given RGB hexadecimal value. r, g, and b are in the range 0 - 255. 10 | 11 | 12 | rgb_to_hex(r, g, b) 13 | Returns hexadecimal value of given RGB tuple. r, g, and b should be in the range 0 - 255. 14 | 15 |
16 |
17 | -------------------------------------------------------------------------------- /documentation/mmm!/index.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | autopy 4 | API Reference 5 | 6 | A simple toolkit for automating and scripting repetitive tasks, especially those involving a GUI, with Python. 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | -------------------------------------------------------------------------------- /documentation/mmm!/key.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | key 4 | autopy module for working with the keyboard 5 | This module contains various functions for controlling the keyboard. 6 |
7 | 8 | toggle(key, down_or_up, [modifiers]) 9 | Holds down the given key or keycode if down_or_up is True, or releases it if not. Integer keycodes and modifiers should be taken from module constants (e.g., key.K_DELETE or key.MOD_META). If the given key is a character, it is automatically converted to a keycode corresponding to the current keyboard layout. 10 | 11 | To hold down more than one modifier at a time, bitwise-OR them, e.g.: 12 | toggle('a', True, key.MOD_SHIFT | key.MOD_ALT) 13 | 14 | 15 | tap(key, [modifiers]) 16 | Convenience wrapper around toggle() that holds down and then releases the given key and modifiers. 17 | 18 | 19 | type_string(string, wpm=0) 20 | Attempts to simulate typing a string at the given WPM, or as fast as possible if the WPM is 0. 21 | 22 |
23 |
24 | 25 | The following is an exhaustive list of constants used by this module in order to input non-printable keys across platforms. Most should be self-explanatory. 26 | 27 | 28 | 0 29 | Null modifier (meaning none are to be pressed). 30 | 31 | 32 | Equivalent to the command key modifier on Mac OS X, the Windows key modifier on Windows, or the meta key modifiers on X11. 33 | 34 | 35 | Alt key modifier. 36 | 37 | 38 | Control key modifier. 39 | 40 | 41 | Shift key modifier. 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
73 |
74 | -------------------------------------------------------------------------------- /documentation/mmm!/mouse.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | mouse 4 | autopy module for working with the mouse 5 | This module contains functions for getting the current state of and controlling the mouse cursor. 6 | 7 | Unless otherwise stated, coordinates are those of a screen coordinate system, where the origin is at the top left. 8 |
9 | 10 | move(x, y) 11 | Moves the mouse to the given (x, y) coordinate. 12 | 13 | the point is out of index 14 | 15 | 16 | 17 | smooth_move(x, y) 18 | Smoothly moves the mouse to the given (x, y) coordinate in a straight line. 19 | 20 | the point is out of index 21 | 22 | 23 | 24 | get_pos() 25 | Returns a tuple (x, y) of the current mouse position. 26 | 27 | 28 | toggle(down, button=LEFT_BUTTON) 29 | Holds down or releases the given mouse button in the current position. button can be LEFT_BUTTON, RIGHT_BUTTON, or CENTER_BUTTON. If no button is given, the left button is defaulted to. 30 | 31 | the mouse button is invalid 32 | 33 | 34 | 35 | click(button=LEFT_BUTTON) 36 | Convenience wrapper around toggle() that holds down and then releases the given mouse button. 37 | 38 |
39 |
40 | 41 | The following is a list of constants used by this module in order to specify mouse buttons. 42 | 43 | 44 | Left mouse button. 45 | 46 | 47 | Right mouse button. 48 | 49 | 50 | Middle mouse button. 51 | 52 |
53 |
54 | -------------------------------------------------------------------------------- /documentation/mmm!/screen.mmm: -------------------------------------------------------------------------------- 1 | 2 | 3 | screen 4 | autopy module for working with the screen 5 | This module contains functions for obtaining attributes about the screen. 6 |
7 | 8 | get_size() 9 | Returns a tuple (width, height) of the size of the main screen. 10 | 11 | 12 | point_visible(x, y) 13 | Returns True if the given point is inside the main screen boundaries. 14 | 15 | 16 | get_color(x, y) 17 | Returns hexadecimal value describing the RGB color at the given point. 18 | 19 | Essentially equivalent to: 20 | 21 | rect = ((x, y), (1, 1)) 22 | bitmap.capture_screen_portion(rect).get_color(0, 0) 23 | 24 | 25 | only more efficient/convenient. 26 | 27 | the system calls were unsuccessful 28 | the rect is out of bounds 29 | 30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /src/MMBitmap.c: -------------------------------------------------------------------------------- 1 | #include "MMBitmap.h" 2 | #include 3 | #include 4 | 5 | MMBitmapRef createMMBitmap(uint8_t *buffer, 6 | size_t width, 7 | size_t height, 8 | size_t bytewidth, 9 | uint8_t bitsPerPixel, 10 | uint8_t bytesPerPixel) 11 | { 12 | MMBitmapRef bitmap = malloc(sizeof(MMBitmap)); 13 | if (bitmap == NULL) return NULL; 14 | 15 | bitmap->imageBuffer = buffer; 16 | bitmap->width = width; 17 | bitmap->height = height; 18 | bitmap->bytewidth = bytewidth; 19 | bitmap->bitsPerPixel = bitsPerPixel; 20 | bitmap->bytesPerPixel = bytesPerPixel; 21 | 22 | return bitmap; 23 | } 24 | 25 | void destroyMMBitmap(MMBitmapRef bitmap) 26 | { 27 | assert(bitmap != NULL); 28 | 29 | if (bitmap->imageBuffer != NULL) { 30 | free(bitmap->imageBuffer); 31 | bitmap->imageBuffer = NULL; 32 | } 33 | 34 | free(bitmap); 35 | } 36 | 37 | MMBitmapRef copyMMBitmap(MMBitmapRef bitmap) 38 | { 39 | uint8_t *copiedBuf = NULL; 40 | 41 | assert(bitmap != NULL); 42 | if (bitmap->imageBuffer != NULL) { 43 | const size_t bufsize = bitmap->height * bitmap->bytewidth; 44 | copiedBuf = malloc(bufsize); 45 | if (copiedBuf == NULL) return NULL; 46 | 47 | memcpy(copiedBuf, bitmap->imageBuffer, bufsize); 48 | } 49 | 50 | return createMMBitmap(copiedBuf, 51 | bitmap->width, 52 | bitmap->height, 53 | bitmap->bytewidth, 54 | bitmap->bitsPerPixel, 55 | bitmap->bytesPerPixel); 56 | } 57 | 58 | MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect) 59 | { 60 | assert(source != NULL); 61 | 62 | if (source->imageBuffer == NULL || !MMBitmapRectInBounds(source, rect)) { 63 | return NULL; 64 | } else { 65 | uint8_t *copiedBuf = NULL; 66 | const size_t bufsize = rect.size.height * source->bytewidth; 67 | const size_t offset = (source->bytewidth * rect.origin.y) + 68 | (rect.origin.x * source->bytesPerPixel); 69 | 70 | /* Don't go over the bounds, programmer! */ 71 | assert((bufsize + offset) <= (source->bytewidth * source->height)); 72 | 73 | copiedBuf = malloc(bufsize); 74 | if (copiedBuf == NULL) return NULL; 75 | 76 | memcpy(copiedBuf, source->imageBuffer + offset, bufsize); 77 | 78 | return createMMBitmap(copiedBuf, 79 | rect.size.width, 80 | rect.size.height, 81 | source->bytewidth, 82 | source->bitsPerPixel, 83 | source->bytesPerPixel); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/MMBitmap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MMBITMAP_H 3 | #define MMBITMAP_H 4 | 5 | #include "types.h" 6 | #include "rgb.h" 7 | #include 8 | 9 | #if defined(_MSC_VER) 10 | #include "ms_stdint.h" 11 | #else 12 | #include 13 | #endif 14 | 15 | struct _MMBitmap { 16 | uint8_t *imageBuffer; /* Pixels stored in Quad I format; i.e., origin is in 17 | * top left. Length should be height * bytewidth. */ 18 | size_t width; /* Never 0, unless image is NULL. */ 19 | size_t height; /* Never 0, unless image is NULL. */ 20 | size_t bytewidth; /* The aligned width (width + padding). */ 21 | uint8_t bitsPerPixel; /* Should be either 24 or 32. */ 22 | uint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */ 23 | }; 24 | 25 | typedef struct _MMBitmap MMBitmap; 26 | typedef MMBitmap *MMBitmapRef; 27 | 28 | /* Creates new MMBitmap with the given values. 29 | * Follows the Create Rule (caller is responsible for destroy()'ing object). */ 30 | MMBitmapRef createMMBitmap(uint8_t *buffer, size_t width, size_t height, 31 | size_t bytewidth, uint8_t bitsPerPixel, 32 | uint8_t bytesPerPixel); 33 | 34 | /* Releases memory occupied by MMBitmap. */ 35 | void destroyMMBitmap(MMBitmapRef bitmap); 36 | 37 | /* Returns copy of MMBitmap, to be destroy()'d by caller. */ 38 | MMBitmapRef copyMMBitmap(MMBitmapRef bitmap); 39 | 40 | /* Returns copy of one MMBitmap juxtaposed in another (to be destroy()'d 41 | * by the caller.), or NULL on error. */ 42 | MMBitmapRef copyMMBitmapFromPortion(MMBitmapRef source, MMRect rect); 43 | 44 | #define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && \ 45 | (p).y < (image)->height) 46 | #define MMBitmapRectInBounds(image, r) \ 47 | (((r).origin.x + (r).size.width <= (image)->width) && \ 48 | ((r).origin.y + (r).size.height <= (image)->height)) 49 | 50 | #define MMBitmapGetBounds(image) MMRectMake(0, 0, image->width, image->height) 51 | 52 | /* Get pointer to pixel of MMBitmapRef. No bounds checking is performed (check 53 | * yourself before calling this with MMBitmapPointInBounds(). */ 54 | #define MMRGBColorRefAtPoint(image, x, y) \ 55 | (MMRGBColor *)(assert(MMBitmapPointInBounds(bitmap, MMPointMake(x, y))), \ 56 | ((image)->imageBuffer) + (((image)->bytewidth * (y)) \ 57 | + ((x) * (image)->bytesPerPixel))) 58 | 59 | /* Dereference pixel of MMBitmapRef. Again, no bounds checking is performed. */ 60 | #define MMRGBColorAtPoint(image, x, y) *MMRGBColorRefAtPoint(image, x, y) 61 | 62 | /* Hex/integer value of color at point. */ 63 | #define MMRGBHexAtPoint(image, x, y) \ 64 | hexFromMMRGB(MMRGBColorAtPoint(image, x, y)) 65 | 66 | /* Increment either point.x or point.y depending on the position of point.x. 67 | * That is, if x + 1 is >= width, increment y and start x at the beginning. 68 | * Otherwise, increment x. 69 | * 70 | * This is used as a convenience macro to scan rows when calling functions such 71 | * as findColorInRectAt() and findBitmapInBitmapAt(). */ 72 | #define ITER_NEXT_POINT(pixel, width, start_x) \ 73 | do { \ 74 | if (++(pixel).x >= (width)) { \ 75 | (pixel).x = start_x; \ 76 | ++(point).y; \ 77 | } \ 78 | } while (0); 79 | 80 | #endif /* MMBITMAP_H */ 81 | -------------------------------------------------------------------------------- /src/MMPointArray.c: -------------------------------------------------------------------------------- 1 | #include "MMPointArray.h" 2 | #include 3 | 4 | MMPointArrayRef createMMPointArray(size_t initialCount) 5 | { 6 | MMPointArrayRef pointArray = calloc(1, sizeof(MMPointArray)); 7 | 8 | if (initialCount == 0) initialCount = 1; 9 | 10 | pointArray->_allocedCount = initialCount; 11 | pointArray->array = malloc(pointArray->_allocedCount * sizeof(MMPoint)); 12 | if (pointArray->array == NULL) return NULL; 13 | 14 | return pointArray; 15 | } 16 | 17 | void destroyMMPointArray(MMPointArrayRef pointArray) 18 | { 19 | if (pointArray->array != NULL) { 20 | free(pointArray->array); 21 | pointArray->array = NULL; 22 | } 23 | 24 | free(pointArray); 25 | } 26 | 27 | void MMPointArrayAppendPoint(MMPointArrayRef pointArray, MMPoint point) 28 | { 29 | const size_t newCount = ++(pointArray->count); 30 | if (pointArray->_allocedCount < newCount) { 31 | do { 32 | /* Double size each time to avoid calls to realloc(). */ 33 | pointArray->_allocedCount <<= 1; 34 | } while (pointArray->_allocedCount < newCount); 35 | pointArray->array = realloc(pointArray->array, 36 | sizeof(point) * 37 | pointArray->_allocedCount); 38 | } 39 | 40 | pointArray->array[pointArray->count - 1] = point; 41 | } 42 | -------------------------------------------------------------------------------- /src/MMPointArray.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MMARRAY_H 3 | #define MMARRAY_H 4 | 5 | #include "types.h" 6 | 7 | struct _MMPointArray { 8 | MMPoint *array; /* Pointer to actual data. */ 9 | size_t count; /* Number of elements in array. */ 10 | size_t _allocedCount; /* Private; do not use outside of MMPointArray.c. */ 11 | }; 12 | 13 | typedef struct _MMPointArray MMPointArray; 14 | typedef MMPointArray *MMPointArrayRef; 15 | 16 | /* Creates array of an initial size (the maximum size is still limitless). 17 | * This follows the "Create" Rule; i.e., responsibility for "destroying" the 18 | * array is given to the caller. */ 19 | MMPointArrayRef createMMPointArray(size_t initialCount); 20 | 21 | /* Frees memory occupied by |pointArray|. Does not accept NULL. */ 22 | void destroyMMPointArray(MMPointArrayRef pointArray); 23 | 24 | /* Appends a point to an array, increasing the internal size if necessary. */ 25 | void MMPointArrayAppendPoint(MMPointArrayRef pointArray, MMPoint point); 26 | 27 | /* Retrieve point from array. */ 28 | #define MMPointArrayGetItem(a, i) ((a)->array)[i] 29 | 30 | /* Set point in array. */ 31 | #define MMPointArraySetItem(a, i, item) ((a)->array[i] = item) 32 | 33 | #endif /* MMARRAY_H */ 34 | -------------------------------------------------------------------------------- /src/UTHashTable.c: -------------------------------------------------------------------------------- 1 | #include "UTHashTable.h" 2 | #include 3 | #include 4 | 5 | /* Base struct class (all nodes must contain at least the elements in 6 | * this struct). */ 7 | struct _UTHashNode { 8 | UTHashNode_HEAD 9 | }; 10 | 11 | typedef struct _UTHashNode UTHashNode; 12 | 13 | void initHashTable(UTHashTable *table, size_t initialCount, size_t nodeSize) 14 | { 15 | assert(table != NULL); 16 | assert(nodeSize >= sizeof(UTHashNode)); 17 | 18 | table->uttable = NULL; /* Must be set to NULL for uthash. */ 19 | table->allocedNodeCount = (initialCount == 0) ? 1 : initialCount; 20 | table->nodeCount = 0; 21 | table->nodeSize = nodeSize; 22 | table->nodes = calloc(table->nodeSize, nodeSize * table->allocedNodeCount); 23 | } 24 | 25 | void destroyHashTable(UTHashTable *table) 26 | { 27 | UTHashNode *uttable = table->uttable; 28 | UTHashNode *node; 29 | 30 | /* Let uthash do its magic. */ 31 | while (uttable != NULL) { 32 | node = uttable; /* Grab pointer to first item. */ 33 | HASH_DEL(uttable, node); /* Delete it (table advances to next). */ 34 | } 35 | 36 | /* Only giant malloc'd block containing each node must be freed. */ 37 | if (table->nodes != NULL) free(table->nodes); 38 | table->uttable = table->nodes = NULL; 39 | } 40 | 41 | void *getNewNode(UTHashTable *table) 42 | { 43 | /* Increment node count, resizing table if necessary. */ 44 | const size_t newNodeCount = ++(table->nodeCount); 45 | if (table->allocedNodeCount < newNodeCount) { 46 | do { 47 | /* Double size each time to avoid calls to realloc(). */ 48 | table->allocedNodeCount <<= 1; 49 | } while (table->allocedNodeCount < newNodeCount); 50 | 51 | table->nodes = realloc(table->nodes, table->nodeSize * 52 | table->allocedNodeCount); 53 | } 54 | 55 | return (char *)table->nodes + (table->nodeSize * (table->nodeCount - 1)); 56 | } 57 | -------------------------------------------------------------------------------- /src/UTHashTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef UTHASHTABLE_H 3 | #define UTHASHTABLE_H 4 | 5 | #include 6 | #include "uthash.h" 7 | 8 | /* All node structs must begin with this (note that there is NO semicolon). */ 9 | #define UTHashNode_HEAD UT_hash_handle hh; 10 | 11 | /* This file contains convenience macros and a standard struct for working with 12 | * uthash hash tables. 13 | * 14 | * The main purpose of this is for convenience of creating/freeing nodes. */ 15 | struct _UTHashTable { 16 | void *uttable; /* The uthash table -- must start out as NULL. */ 17 | void *nodes; /* Contiguous array of nodes. */ 18 | size_t allocedNodeCount; /* Node count currently allocated for. */ 19 | size_t nodeCount; /* Current node count. */ 20 | size_t nodeSize; /* Size of each node. */ 21 | }; 22 | 23 | typedef struct _UTHashTable UTHashTable; 24 | 25 | /* Initiates a hash table to the default values. |table| should point to an 26 | * already allocated UTHashTable struct. 27 | * 28 | * If the |initialCount| argument in initHashTable is given, |nodes| is 29 | * allocated immediately to the maximum size and new nodes are simply slices of 30 | * that array. This can save calls to malloc if many nodes are to be added, and 31 | * the a reasonable maximum number is known ahead of time. 32 | * 33 | * If the node count goes over this maximum, or if |initialCount| is 0, the 34 | * array is dynamically reallocated to fit the size. 35 | */ 36 | void initHashTable(UTHashTable *table, size_t initialCount, size_t nodeSize); 37 | 38 | /* Frees memory occupied by a UTHashTable's members. 39 | * 40 | * Note that this does NOT free memory for the UTHashTable pointed to by 41 | * |table| itself; if that was allocated on the heap, you must free() it 42 | * yourself after calling this. */ 43 | void destroyHashTable(UTHashTable *table); 44 | 45 | /* Returns memory allocated for a new node. Responsibility for freeing this is 46 | * up to the destroyHashTable() macro; this should NOT be freed by the caller. 47 | * 48 | * This is intended to be used with a HASH_ADD() macro, e.g.: 49 | * {% 50 | * struct myNode *uttable = utHashTable->uttable; 51 | * struct myNode *node = getNewNode(utHashTable); 52 | * node->key = 42; 53 | * node->value = someValue; 54 | * HASH_ADD_INT(uttable, key, node); 55 | * utHashTable->uttable = uttable; 56 | * %} 57 | * 58 | * Or, use the UTHASHTABLE_ADD_INT or UTHASHTABLE_ADD_STR macros 59 | * for convenience (they are exactly equivalent): 60 | * {% 61 | * struct myNode *node = getNewNode(utHashTable); 62 | * node->key = 42; 63 | * node->value = someValue; 64 | * UTHASHTABLE_ADD_INT(utHashTable, key, node, struct myNode); 65 | * %} 66 | */ 67 | void *getNewNode(UTHashTable *table); 68 | 69 | #define UTHASHTABLE_ADD_INT(tablePtr, keyName, node, nodeType) \ 70 | do { \ 71 | nodeType *uttable = (tablePtr)->uttable; \ 72 | HASH_ADD_INT(uttable, keyName, node); \ 73 | (tablePtr)->uttable = uttable; \ 74 | } while (0) 75 | 76 | #define UTHASHTABLE_ADD_STR(tablePtr, keyName, node, nodeType) \ 77 | do { \ 78 | nodeType *uttable = (tablePtr)->uttable; \ 79 | HASH_ADD_STR(uttable, keyName, node); \ 80 | (tablePtr)->uttable = uttable; \ 81 | } while (0) 82 | 83 | #endif /* MMHASHTABLE_H */ 84 | -------------------------------------------------------------------------------- /src/alert.c: -------------------------------------------------------------------------------- 1 | #include "alert.h" 2 | #include "os.h" 3 | #include 4 | 5 | #if defined(IS_MACOSX) 6 | #include 7 | #elif defined(USE_X11) 8 | #include /* For fputs() */ 9 | #include /* For exit() */ 10 | #include /* For wait() */ 11 | #include /* For fork() */ 12 | #include /* For pid_t */ 13 | #include "snprintf.h" /* For asprintf() */ 14 | #endif 15 | 16 | #if defined(USE_X11) 17 | 18 | enum { 19 | TASK_SUCCESS = 0, 20 | FORK_FAILED = -1, 21 | EXEC_FAILED = -2 22 | }; 23 | 24 | /* 25 | * Unfortunately, X has no standard method of displaying alerts, so instead we 26 | * have to rely on the shell command "xmessage" (or nicer-looking equivalents). 27 | * 28 | * The return value and arguments are the same as those from to runTask() 29 | * (see below). 30 | */ 31 | static int xmessage(char *argv[], int *exit_status); 32 | 33 | #elif defined(IS_MACOSX) 34 | #define CFStringCreateWithUTF8String(string) \ 35 | ((string) == NULL ? NULL : CFStringCreateWithCString(NULL, \ 36 | string, \ 37 | kCFStringEncodingUTF8)) 38 | #endif 39 | 40 | int showAlert(const char *title, const char *msg, const char *defaultButton, 41 | const char *cancelButton) 42 | { 43 | #if defined(IS_MACOSX) 44 | CFStringRef alertHeader = CFStringCreateWithUTF8String(title); 45 | CFStringRef alertMessage = CFStringCreateWithUTF8String(msg); 46 | CFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton); 47 | CFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton); 48 | CFOptionFlags responseFlags; 49 | SInt32 err = CFUserNotificationDisplayAlert(0.0, 50 | kCFUserNotificationNoteAlertLevel, 51 | NULL, 52 | NULL, 53 | NULL, 54 | alertHeader, 55 | alertMessage, 56 | defaultButtonTitle, 57 | cancelButtonTitle, 58 | NULL, 59 | &responseFlags); 60 | if (alertHeader != NULL) CFRelease(alertHeader); 61 | if (alertMessage != NULL) CFRelease(alertMessage); 62 | if (defaultButtonTitle != NULL) CFRelease(defaultButtonTitle); 63 | if (cancelButtonTitle != NULL) CFRelease(cancelButtonTitle); 64 | 65 | if (err != 0) return -1; 66 | return (responseFlags == kCFUserNotificationDefaultResponse) ? 0 : 1; 67 | #elif defined(USE_X11) 68 | /* Note that args[0] is set by the xmessage() function. */ 69 | const char *args[10] = {NULL, msg, "-title", title, "-center"}; 70 | int response, ret; 71 | char *buttonList = NULL; /* To be free()'d. */ 72 | 73 | if (defaultButton == NULL) defaultButton = "OK"; 74 | 75 | if (cancelButton == NULL) { 76 | asprintf(&buttonList, "%s:2", defaultButton); 77 | } else { 78 | asprintf(&buttonList, "%s:2,%s:3", defaultButton, cancelButton); 79 | } 80 | 81 | if (buttonList == NULL) return -1; /* asprintf() failed. */ 82 | args[5] = "-buttons"; 83 | args[6] = buttonList; 84 | args[7] = "-default"; 85 | args[8] = defaultButton; 86 | args[9] = NULL; 87 | 88 | ret = xmessage((char **)args, &response); 89 | if (buttonList != NULL) { 90 | free(buttonList); 91 | buttonList = NULL; 92 | } 93 | 94 | if (ret != TASK_SUCCESS) { 95 | if (ret == EXEC_FAILED) { 96 | fputs("xmessage or equivalent not found.\n", stderr); 97 | } 98 | return -1; 99 | } 100 | 101 | return (response == 2) ? 0 : 1; 102 | #else 103 | /* TODO: Display custom buttons instead of the pre-defined "OK" 104 | * and "Cancel". */ 105 | int response = MessageBox(NULL, msg, title, 106 | (cancelButton == NULL) ? MB_OK : MB_OKCANCEL); 107 | return (response == IDOK) ? 0 : 1; 108 | #endif 109 | } 110 | 111 | #if defined(USE_X11) 112 | 113 | /* 114 | * Attempts to run the given task synchronously with the given arguments. 115 | * 116 | * If |exit_status| is non-NULL and the task ran successfully, |exit_status| is 117 | * set to the exit code of the task on return. 118 | * 119 | * Returns -1 if process could not be forked, -2 if the task could not be run, 120 | * or 0 if the task was ran successfully. 121 | */ 122 | static int runTask(const char *taskname, char * const argv[], int *exit_status); 123 | 124 | static int xmessage(char *argv[], int *exit_status) 125 | { 126 | static const char * const MSG_PROGS[] = {"gmessage", "gxmessage", 127 | "kmessage", "xmessage"}; 128 | static int PREV_MSG_INDEX = -1; 129 | #define MSG_PROGS_LEN (sizeof(MSG_PROGS) / sizeof(MSG_PROGS[0])) 130 | 131 | char *prog = NULL; 132 | int ret; 133 | 134 | /* Save some fork()'ing and attempt to use last program if possible. */ 135 | if (PREV_MSG_INDEX >= 0) { 136 | assert(PREV_MSG_INDEX < MSG_PROGS_LEN); 137 | 138 | prog = argv[0] = (char *)MSG_PROGS[PREV_MSG_INDEX]; 139 | ret = runTask(prog, argv, exit_status); 140 | } else { 141 | /* Otherwise, try running each xmessage alternative until one works or 142 | * we run out of options. */ 143 | size_t i; 144 | for (i = 0; i < MSG_PROGS_LEN; ++i) { 145 | prog = argv[0] = (char *)MSG_PROGS[i]; 146 | ret = runTask(prog, argv, exit_status); 147 | if (ret != EXEC_FAILED) break; 148 | } 149 | 150 | if (ret == TASK_SUCCESS) PREV_MSG_INDEX = i; 151 | } 152 | 153 | return ret; 154 | } 155 | 156 | static int runTask(const char *taskname, char * const argv[], int *exit_status) 157 | { 158 | pid_t pid; 159 | int status; 160 | 161 | switch (pid = fork()) { 162 | case -1: /* Failed to fork */ 163 | perror("fork"); 164 | return FORK_FAILED; /* Failed to fork. */ 165 | case 0: /* Child process */ 166 | execvp(taskname, argv); 167 | exit(42); /* Failed to run task. */ 168 | default: /* Parent process */ 169 | wait(&status); /* Block execution until finished. */ 170 | 171 | if (!WIFEXITED(status) || (status = WEXITSTATUS(status)) == 42) { 172 | return EXEC_FAILED; /* Task failed to run. */ 173 | } 174 | if (exit_status != NULL) *exit_status = status; 175 | return TASK_SUCCESS; /* Success! */ 176 | } 177 | } 178 | 179 | #endif 180 | -------------------------------------------------------------------------------- /src/alert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ALERT_H 3 | #define ALERT_H 4 | 5 | #if defined(_MSC_VER) 6 | #include "ms_stdbool.h" 7 | #else 8 | #include 9 | #endif 10 | 11 | /* Displays alert with given attributes, and blocks execution until the user 12 | * responds. Returns 0 if defaultButton was pressed, 1 if cancelButton was 13 | * pressed, or -1 if an error occurred. */ 14 | int showAlert(const char *title, const char *msg, const char *defaultButton, 15 | const char *cancelButton); 16 | 17 | #endif /* ALERT_H */ 18 | -------------------------------------------------------------------------------- /src/autopy-alert-module.c: -------------------------------------------------------------------------------- 1 | #include "autopy-alert-module.h" 2 | #include "alert.h" 3 | 4 | /* Syntax: alert(msg, title="AutoPy Alert", default_button="OK", 5 | [cancel_button]) */ 6 | /* Arguments: |msg| => string, 7 | |title| => string, 8 | |default_button| => string, 9 | |cancel_button| => string */ 10 | /* Description: Displays alert with the given attributes. If |cancel_button| is 11 | not given, only the default button is displayed. Returns True 12 | if the default button was pressed, or False if cancelled. Note 13 | that the arguments are keywords, and can be passed as named 14 | parameters (e.g., `alert(msg="bar", title="foo")`). 15 | 16 | Due to limitations in the Win32 API, Windows currently replaces 17 | |default_button| with `"OK"` and |cancel_button| (if given) 18 | with `"Cancel"`. This may be fixed in a later release. */ 19 | static PyObject *alert_alert(PyObject *self, PyObject *args, PyObject *kwds); 20 | 21 | static PyMethodDef AlertMethods[] = { 22 | {"alert", (PyCFunction)alert_alert, METH_VARARGS | METH_KEYWORDS, 23 | "alert(msg, title='AutoPy Alert', default_button='OK', " 24 | "[cancel_button]) => Boolean\n" 25 | "Displays alert with the given attributes.\n" 26 | "Returns True if the default button was pressed, or False if cancelled."}, 27 | {NULL, NULL, 0, NULL} /* Sentinel */ 28 | }; 29 | 30 | #ifdef PYTHREE 31 | static struct PyModuleDef alertmodule = { 32 | PyModuleDef_HEAD_INIT, 33 | "alert", 34 | "autopy module for displaying alerts", 35 | -1, 36 | AlertMethods 37 | }; 38 | #endif 39 | 40 | PyMODINIT_FUNC initalert(void) 41 | { 42 | #ifdef PYTHREE 43 | PyObject *mod = PyModule_Create(&alertmodule); 44 | return mod; 45 | #else 46 | Py_InitModule3("alert", AlertMethods, 47 | "autopy module for displaying alerts"); 48 | #endif 49 | } 50 | 51 | #ifdef PYTHREE 52 | PyMODINIT_FUNC PyInit_alert(void) { return initalert(); } 53 | #endif 54 | 55 | static PyObject *alert_alert(PyObject *self, PyObject *args, PyObject *kwds) 56 | { 57 | char *msg = NULL, *title = "AutoPy Alert"; 58 | char *default_button = "OK", *cancel_button = NULL; 59 | 60 | static char *kwdlist[] = {"title", "msg", "default_button", 61 | "cancel_button", NULL}; 62 | int button; 63 | 64 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|szz", kwdlist, 65 | &msg, 66 | &title, 67 | &default_button, 68 | &cancel_button)) { 69 | return NULL; 70 | } 71 | 72 | button = showAlert(title, msg, default_button, cancel_button); 73 | if (button == 0) { 74 | Py_RETURN_TRUE; 75 | } else if (button == 1) { 76 | Py_RETURN_FALSE; 77 | } else { 78 | PyErr_SetString(PyExc_OSError, "Could not display alert"); 79 | return NULL; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/autopy-alert-module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AUTOPY_ALERT_MODULE_H 3 | #define AUTOPY_ALERT_MODULE_H 4 | 5 | #include 6 | 7 | #if PY_MAJOR_VERSION >= 3 8 | #define PYTHREE 9 | #endif 10 | 11 | /* Summary: autopy module for displaying alerts */ 12 | /* Description: This module contains functions for displaying cross-platform 13 | alert dialogs. */ 14 | PyMODINIT_FUNC initalert(void); 15 | 16 | #endif /* AUTOPY_ALERT_MODULE_H */ 17 | -------------------------------------------------------------------------------- /src/autopy-bitmap-module.c: -------------------------------------------------------------------------------- 1 | #include "autopy-bitmap-module.h" 2 | #include "py-bitmap-class.h" 3 | #include "screen.h" 4 | #include "screengrab.h" 5 | #include "py-convenience.h" 6 | 7 | /* Syntax: capture_screen(rect=None) => Bitmap object */ 8 | /* Arguments: |rect| => ((|x|, |y|), (|width|, |height|)) rect of ints */ 9 | /* Description: Returns a screengrab of the given portion of the main display, 10 | or the entire display if |rect| is None. */ 11 | /* Raises: |ValueError| if the rect is out of bounds, 12 | |OSError| if the screengrab was unsuccessful. */ 13 | static PyObject *bitmap_capture_screen(PyObject *self, PyObject *args); 14 | 15 | static PyMethodDef BitmapMethods[] = { 16 | {"capture_screen", bitmap_capture_screen, METH_NOARGS | METH_O, 17 | "capture_screen(rect=None) -> Bitmap object\n" 18 | "Returns a screengrab of the given portion of the main display,\n" 19 | "or the entire display if rect is None."}, 20 | {NULL, NULL, 0, NULL} /* Sentinel */ 21 | }; 22 | 23 | #ifdef PYTHREE 24 | static struct PyModuleDef bitmapmodule = { 25 | PyModuleDef_HEAD_INIT, 26 | "bitmap", 27 | "autopy module for working with bitmaps", 28 | -1, 29 | BitmapMethods 30 | }; 31 | #endif 32 | 33 | 34 | PyMODINIT_FUNC initbitmap(void) 35 | { 36 | PyObject *mod; 37 | #ifdef PYTHREE 38 | mod = PyModule_Create(&bitmapmodule); 39 | if (mod == NULL) return NULL; /* Error */ 40 | #else 41 | mod = Py_InitModule3("bitmap", BitmapMethods, 42 | "autopy module for working with bitmaps"); 43 | if (mod == NULL) return; /* Error */ 44 | #endif 45 | 46 | /* Instantiate new "Bitmap" class so that it is available in the module. */ 47 | if (Py_AddClassToModule(mod, &Bitmap_Type) < 0) { 48 | #ifdef PYTHREE 49 | return NULL; /* Error */ 50 | #else 51 | return; /* Error */ 52 | #endif 53 | } 54 | #ifdef PYTHREE 55 | return mod; 56 | #endif 57 | } 58 | 59 | #ifdef PYTHREE 60 | PyMODINIT_FUNC PyInit_bitmap(void) { return initbitmap(); } 61 | #endif 62 | 63 | static PyObject *bitmap_capture_screen(PyObject *self, PyObject *arg) 64 | { 65 | MMRect rect; 66 | MMBitmapRef bitmap = NULL; 67 | MMSize displaySize = getMainDisplaySize(); 68 | 69 | if (arg == NULL || arg == Py_None) { 70 | rect = MMRectMake(0, 0, displaySize.width, displaySize.height); 71 | } else { 72 | if (!PyArg_ParseTuple(arg, "(kk)(kk)", &rect.origin.x, 73 | &rect.origin.y, 74 | &rect.size.width, 75 | &rect.size.height)) { 76 | PyErr_SetString(PyExc_TypeError, "Argument is not a rect"); 77 | return NULL; 78 | } 79 | 80 | if (rect.origin.x >= displaySize.width || 81 | rect.origin.y >= displaySize.height || 82 | rect.origin.x + rect.size.width > displaySize.width || 83 | rect.origin.y + rect.size.height > displaySize.height) { 84 | PyErr_SetString(PyExc_ValueError, "Rect out of bounds"); 85 | return NULL; 86 | } 87 | } 88 | 89 | bitmap = copyMMBitmapFromDisplayInRect(rect); 90 | if (bitmap == NULL || bitmap->imageBuffer == NULL) { 91 | PyErr_SetString(PyExc_OSError, 92 | "Could not copy RGB data from display"); 93 | return NULL; 94 | } 95 | 96 | return BitmapObject_FromMMBitmap(bitmap); 97 | } 98 | -------------------------------------------------------------------------------- /src/autopy-bitmap-module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AUTOPY_BITMAP_MODULE_H 3 | #define AUTOPY_BITMAP_MODULE_H 4 | 5 | #include 6 | 7 | #if PY_MAJOR_VERSION >= 3 8 | #define PYTHREE 9 | #endif 10 | 11 | /* Summary: autopy module for working with bitmaps */ 12 | /* Description: This module defines the class `Bitmap` for accessing 13 | bitmaps and searching for bitmaps on-screen. 14 | 15 | It also defines functions for taking screenshots of the screen. */ 16 | PyMODINIT_FUNC initbitmap(void); 17 | 18 | #endif /* AUTOPY_BITMAP_MODULE_H */ 19 | -------------------------------------------------------------------------------- /src/autopy-color-module.c: -------------------------------------------------------------------------------- 1 | #include "autopy-color-module.h" 2 | #include "MMBitmap.h" 3 | 4 | /* Syntax: hex_to_rgb(hex) => tuple (r, g, b) */ 5 | /* Arguments: |hex| => integer (in range 0x000000 - 0xFFFFFF) */ 6 | /* Description: Returns a tuple `(r, g, b)` of the RGB integer values equivalent 7 | to the given RGB hexadecimal value. |r|, |g|, and |b| are in 8 | the range 0 - 255. */ 9 | static PyObject *color_hex_to_rgb(PyObject *self, PyObject *args); 10 | 11 | /* Syntax: rgb_to_hex(r, g, b) => integer (in the range 0x000000 - 0xFFFFFF) */ 12 | /* Arguments: |r| => integer (0 - 255), 13 | |b| => integer (0 - 255), 14 | |g| => integer (0 - 255) */ 15 | /* Description: Returns hexadecimal value of given RGB tuple. |r|, |g|, and |b| 16 | should be in the range 0 - 255. */ 17 | static PyObject *color_rgb_to_hex(PyObject *self, PyObject *args); 18 | 19 | static PyMethodDef ColorMethods[] = { 20 | {"hex_to_rgb", color_hex_to_rgb, METH_VARARGS, 21 | "hex_to_rgb(hex) -> tuple (r, g, b)\n" 22 | "Returns a tuple (r, g, b) of the RGB integer values equivalent to the\n" 23 | "given RGB hex value."}, 24 | {"rgb_to_hex", color_rgb_to_hex, METH_VARARGS, 25 | "rgb_to_hex(r, g, b) -> integer\n" 26 | "Returns hexadecimal value of given RGB tuple, where |r|, |g|, and\n" 27 | "|b| in the range 0 - 255, and the returned value is in the\n" 28 | "range 0x000000 - 0xFFFFFF."}, 29 | {NULL, NULL, 0, NULL} /* Sentinel */ 30 | }; 31 | 32 | #ifdef PYTHREE 33 | static struct PyModuleDef colormodule = { 34 | PyModuleDef_HEAD_INIT, 35 | "color", 36 | "autopy module for converting between colour formats", 37 | -1, 38 | ColorMethods 39 | }; 40 | #endif 41 | 42 | PyMODINIT_FUNC initcolor(void) 43 | { 44 | #ifdef PYTHREE 45 | return PyModule_Create(&colormodule); 46 | #else 47 | Py_InitModule3("color", ColorMethods, 48 | "autopy module for converting between color formats"); 49 | #endif 50 | } 51 | 52 | #ifdef PYTHREE 53 | PyMODINIT_FUNC PyInit_color(void) { return initcolor(); } 54 | #endif 55 | 56 | static PyObject *color_hex_to_rgb(PyObject *self, PyObject *args) 57 | { 58 | MMRGBHex hex; 59 | if (!PyArg_ParseTuple(args, "I", &hex)) return NULL; 60 | 61 | return Py_BuildValue("(bbb)", RED_FROM_HEX(hex), 62 | GREEN_FROM_HEX(hex), 63 | BLUE_FROM_HEX(hex)); 64 | } 65 | 66 | static PyObject *color_rgb_to_hex(PyObject *self, PyObject *args) 67 | { 68 | MMRGBColor color; 69 | if (!PyArg_ParseTuple(args, "bbb", &color.red, 70 | &color.green, 71 | &color.blue)) { 72 | return NULL; 73 | } 74 | 75 | return Py_BuildValue("I", hexFromMMRGB(color)); 76 | } 77 | -------------------------------------------------------------------------------- /src/autopy-color-module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AUTOPY_COLOR_MODULE_H 3 | #define AUTOPY_COLOR_MODULE_H 4 | 5 | #include 6 | 7 | #if PY_MAJOR_VERSION >= 3 8 | #define PYTHREE 9 | #endif 10 | 11 | /* Summary: autopy module for converting color formats */ 12 | /* Description: This module provides routines for converting between the color 13 | format (hexadecimal) used by autopy methods and other, more 14 | readable, formats (e.g., RGB tuples). */ 15 | PyMODINIT_FUNC initcolor(void); 16 | 17 | #endif /* AUTOPY_COLOR_MODULE_H */ 18 | -------------------------------------------------------------------------------- /src/autopy-key-module.c: -------------------------------------------------------------------------------- 1 | #include "autopy-key-module.h" 2 | #include "keypress.h" 3 | #include "py-convenience.h" 4 | #include "deadbeef_rand.h" 5 | #include 6 | 7 | #if defined(_MSC_VER) 8 | #include "ms_stdbool.h" 9 | #else 10 | #include 11 | #endif 12 | 13 | /* Syntax: toggle(key, down_or_up, [modifiers]) */ 14 | /* Arguments: |key| => character or integer describing the key or keycode, 15 | |down_or_up| => Boolean describing whether to hold down or 16 | release the key, 17 | |modifiers| => integer (bitwise-OR of |MOD_*| constants) */ 18 | /* Description: Holds down the given key or keycode if |down_or_up| is True, 19 | or releases it if not. Integer keycodes and modifiers should 20 | be taken from module constants (e.g., |key.K_DELETE| or 21 | |key.MOD_META|). If the given key is a character, it is 22 | automatically converted to a keycode corresponding to the 23 | current keyboard layout. 24 | 25 | To hold down more than one modifier at a time, bitwise-OR them, 26 | e.g.: 27 | {% toggle('a', True, key.MOD_SHIFT | key.MOD_ALT) %} */ 28 | static PyObject *key_toggle(PyObject *self, PyObject *args); 29 | 30 | /* Syntax: tap(key, [modifiers]) */ 31 | /* Arguments: |key| => character or integer, 32 | |modifiers| => integer (bitise-OR of |MOD_*| constants) */ 33 | /* Description: Convenience wrapper around `toggle()` that holds down and then 34 | releases the given key and modifiers. */ 35 | static PyObject *key_tap(PyObject *self, PyObject *args); 36 | 37 | /* Syntax: type_string(string, wpm=0) */ 38 | /* Arguments: |string| => ASCII string, 39 | |wpm| => double (Words per minute to type string, 40 | or unlimited if 0) */ 41 | /* Description: Attempts to simulate typing a string at the given WPM, or as 42 | fast as possible if the WPM is 0. */ 43 | static PyObject *key_type_string(PyObject *self, PyObject *args); 44 | 45 | static PyMethodDef KeyMethods[] = { 46 | {"toggle", key_toggle, METH_VARARGS, 47 | "toggle(key, down_or_up, [modifiers]) -> None\n" 48 | "Holds down given key if down_or_up is True, releases if not."}, 49 | {"tap", key_tap, METH_VARARGS, 50 | "tap(key, [modifiers]) -> None\n" 51 | "Holds down and then releases the given key."}, 52 | {"type_string", key_type_string, METH_VARARGS, 53 | "type_string(string, wpm=0) -> None\n" 54 | "Attempts to type a string at the given WPM, or as fast as possible if\n" 55 | "wpm is 0."}, 56 | {NULL, NULL, 0, NULL} /* Sentinel */ 57 | }; 58 | 59 | #ifdef PYTHREE 60 | static struct PyModuleDef keymodule = { 61 | PyModuleDef_HEAD_INIT, 62 | "key", 63 | "autopy module for working with the keyboard", 64 | -1, 65 | KeyMethods 66 | }; 67 | #endif 68 | 69 | PyMODINIT_FUNC initkey(void) 70 | { 71 | PyObject *mod; 72 | #ifdef PYTHREE 73 | mod = PyModule_Create(&keymodule); 74 | #else 75 | mod = Py_InitModule3("key", KeyMethods, 76 | "autopy module for working with the " 77 | "keyboard"); 78 | #endif 79 | if (mod == NULL) return; /* Error */ 80 | 81 | /* Needed for type_string(). */ 82 | deadbeef_srand_time(); 83 | 84 | /* Add keycode constants for toggle() and tap(). */ 85 | if (PyModule_AddIntMacro(mod, MOD_NONE) < 0 || 86 | PyModule_AddIntMacro(mod, MOD_META) < 0 || 87 | PyModule_AddIntMacro(mod, MOD_ALT) < 0 || 88 | PyModule_AddIntMacro(mod, MOD_CONTROL) < 0 || 89 | PyModule_AddIntMacro(mod, MOD_SHIFT) < 0 || 90 | PyModule_AddIntMacro(mod, K_BACKSPACE) < 0 || 91 | PyModule_AddIntMacro(mod, K_DELETE) < 0 || 92 | PyModule_AddIntMacro(mod, K_RETURN) < 0 || 93 | PyModule_AddIntMacro(mod, K_ESCAPE) < 0 || 94 | PyModule_AddIntMacro(mod, K_UP) < 0 || 95 | PyModule_AddIntMacro(mod, K_DOWN) < 0 || 96 | PyModule_AddIntMacro(mod, K_RIGHT) < 0 || 97 | PyModule_AddIntMacro(mod, K_LEFT) < 0 || 98 | PyModule_AddIntMacro(mod, K_HOME) < 0 || 99 | PyModule_AddIntMacro(mod, K_END) < 0 || 100 | PyModule_AddIntMacro(mod, K_PAGEUP) < 0 || 101 | PyModule_AddIntMacro(mod, K_PAGEDOWN) < 0 || 102 | PyModule_AddIntMacro(mod, K_F1) < 0 || 103 | PyModule_AddIntMacro(mod, K_F2) < 0 || 104 | PyModule_AddIntMacro(mod, K_F3) < 0 || 105 | PyModule_AddIntMacro(mod, K_F4) < 0 || 106 | PyModule_AddIntMacro(mod, K_F5) < 0 || 107 | PyModule_AddIntMacro(mod, K_F6) < 0 || 108 | PyModule_AddIntMacro(mod, K_F7) < 0 || 109 | PyModule_AddIntMacro(mod, K_F8) < 0 || 110 | PyModule_AddIntMacro(mod, K_F9) < 0 || 111 | PyModule_AddIntMacro(mod, K_F10) < 0 || 112 | PyModule_AddIntMacro(mod, K_F11) < 0 || 113 | PyModule_AddIntMacro(mod, K_F12) < 0 || 114 | PyModule_AddIntMacro(mod, K_META) < 0 || 115 | PyModule_AddIntMacro(mod, K_ALT) < 0 || 116 | PyModule_AddIntMacro(mod, K_CONTROL) < 0 || 117 | PyModule_AddIntMacro(mod, K_SHIFT) < 0 || 118 | PyModule_AddIntMacro(mod, K_CAPSLOCK) < 0) { 119 | PyErr_SetString(PyExc_ValueError, "Error adding keycode constants"); 120 | return; 121 | } 122 | #ifdef PYTHREE 123 | return mod; 124 | #endif 125 | } 126 | 127 | #ifdef PYTHREE 128 | PyMODINIT_FUNC PyInit_key(void) { return initkey(); } 129 | #endif 130 | 131 | /* Attempts to extract MMKeyCode from PyInt. Returns false and sets error if 132 | * MMKeyCode could not be converted, or returns true if it could. */ 133 | static bool MMKeyCodeFromPyInt(PyObject *num, MMKeyCode *val); 134 | 135 | /* Attempts to extract char from PyString. Returns false and sets error if 136 | * MMKeyCode could not be converted, or returns true if it could. */ 137 | static bool charFromPyString(PyObject *str, char *val); 138 | 139 | static PyObject *key_toggle(PyObject *self, PyObject *args) 140 | { 141 | PyObject *key; 142 | PyObject *downBool; 143 | MMKeyFlags flags = MOD_NONE; 144 | 145 | if (!PyArg_ParseTuple(args, "OO!|K", &key, &PyBool_Type, &downBool, &flags)) { 146 | return NULL; 147 | } 148 | 149 | if (PyNumber_Check(key)) { /* Check for key code */ 150 | MMKeyCode code; 151 | if (!MMKeyCodeFromPyInt(key, &code)) return NULL; 152 | toggleKeyCode(code, downBool == Py_True, flags); 153 | } else if (PyUnicode_Check(key)) { /* Check for single-character string */ 154 | char c; 155 | if (!charFromPyString(key, &c)) return NULL; 156 | toggleKey(c, downBool == Py_True, flags); 157 | } else { 158 | return Py_SetArgConvertErr("integer or char", 1, key); 159 | } 160 | 161 | Py_RETURN_NONE; 162 | } 163 | 164 | static PyObject *key_tap(PyObject *self, PyObject *args) 165 | { 166 | PyObject *key; 167 | MMKeyFlags flags = MOD_NONE; 168 | 169 | if (!PyArg_ParseTuple(args, "O|I", &key, &flags)) return NULL; 170 | 171 | if (PyNumber_Check(key)) { /* Check for key code */ 172 | MMKeyCode code; 173 | if (!MMKeyCodeFromPyInt(key, &code)) return NULL; 174 | tapKeyCode(code, flags); 175 | } else if (PyUnicode_Check(key)) { /* Check for single-character string */ 176 | char c; 177 | if (!charFromPyString(key, &c)) return NULL; 178 | tapKey(c, flags); 179 | } else { 180 | return Py_SetArgConvertErr("integer or char", 1, key); 181 | } 182 | 183 | Py_RETURN_NONE; 184 | } 185 | 186 | static PyObject *key_type_string(PyObject *self, PyObject *args) 187 | { 188 | char *str = NULL; 189 | double wpm = 0.0; 190 | if (!PyArg_ParseTuple(args, "s|d", &str, &wpm)) return NULL; 191 | 192 | if (wpm == 0.0) { 193 | typeString(str); 194 | } else { 195 | typeStringDelayed(str, WPM_TO_CPM(wpm)); 196 | } 197 | 198 | Py_RETURN_NONE; 199 | } 200 | 201 | /* -- Helper functions -- */ 202 | 203 | static bool MMKeyCodeFromPyInt(PyObject *num, MMKeyCode *val) 204 | { 205 | long ival; 206 | assert(val != NULL); 207 | 208 | if (!PyLong_Check(num) || PyFloat_Check(num)) { 209 | Py_SetConvertErr("integer", num); 210 | return false; 211 | } 212 | 213 | ival = PyLong_AsLong(num); 214 | if (ival == -1 && PyErr_Occurred()) { 215 | Py_SetConvertErr("integer", num); 216 | return false; 217 | } 218 | 219 | *val = (MMKeyCode)ival; 220 | return true; 221 | } 222 | 223 | #ifdef PYTHREE 224 | static bool charFromPyString(PyObject *str, char *val) 225 | { 226 | assert(val != NULL); 227 | if (PyUnicode_GetLength(str) != 1) { 228 | Py_SetConvertErr("char", str); 229 | return false; 230 | } else { 231 | *val = PyUnicode_AsUTF8(str)[0]; 232 | return true; 233 | } 234 | } 235 | #else 236 | static bool charFromPyString(PyObject *str, char *val) 237 | { 238 | assert(val != NULL); 239 | if (PyString_Size(str) != 1) { 240 | Py_SetConvertErr("char", str); 241 | return false; 242 | } else { 243 | *val = PyString_AsString(str)[0]; 244 | return true; 245 | } 246 | } 247 | #endif 248 | -------------------------------------------------------------------------------- /src/autopy-key-module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AUTOPY_KEY_MODULE_H 3 | #define AUTOPY_KEY_MODULE_H 4 | 5 | #include 6 | 7 | #if PY_MAJOR_VERSION >= 3 8 | #define PYTHREE 9 | #endif 10 | 11 | /* Summary: autopy module for working with the keyboard */ 12 | /* Description: This module contains various functions for controlling the 13 | keyboard. */ 14 | PyMODINIT_FUNC initkey(void); 15 | 16 | #endif /* AUTOPY_KEY_MODULE_H */ 17 | -------------------------------------------------------------------------------- /src/autopy-mouse-module.c: -------------------------------------------------------------------------------- 1 | #include "autopy-mouse-module.h" 2 | #include "mouse.h" 3 | #include "py-convenience.h" 4 | #include "deadbeef_rand.h" 5 | #include "screen.h" 6 | 7 | /* Syntax: move(x, y) */ 8 | /* Arguments: |x| => int, 9 | |y| => int */ 10 | /* Description: Moves the mouse to the given `(x, y)` coordinate. */ 11 | /* Raises: |ValueError| if the point is out of index. */ 12 | static PyObject *mouse_move(PyObject *self, PyObject *args); 13 | 14 | /* Syntax: smooth_move(x, y) */ 15 | /* Arguments: |x| => int, 16 | |y| => int */ 17 | /* Description: Smoothly moves the mouse to the given `(x, y)` coordinate in a 18 | straight line. */ 19 | /* Raises: |ValueError| if the point is out of index. */ 20 | static PyObject *mouse_smooth_move(PyObject *self, PyObject *args); 21 | 22 | /* Syntax: get_pos() => tuple (x, y) */ 23 | /* Description: Returns a tuple `(x, y)` of the current mouse position. */ 24 | static PyObject *mouse_get_pos(PyObject *self, PyObject *args); 25 | 26 | /* Syntax: toggle(down, button=LEFT_BUTTON) */ 27 | /* Arguments: |down| => Boolean 28 | |button| => int */ 29 | /* Description: Holds down or releases the given mouse button in the current 30 | position. |button| can be |LEFT_BUTTON|, |RIGHT_BUTTON|, or 31 | |CENTER_BUTTON|. If no button is given, the left button is 32 | defaulted to. */ 33 | /* Raises: |ValueError| if the mouse button is invalid. */ 34 | static PyObject *mouse_toggle(PyObject *self, PyObject *args); 35 | 36 | /* Syntax: click(button=LEFT_BUTTON) */ 37 | /* Arguments: |button| => int */ 38 | /* Description: Convenience wrapper around `toggle()` that holds down and then 39 | releases the given mouse button. */ 40 | static PyObject *mouse_click(PyObject *self, PyObject *args); 41 | 42 | static PyMethodDef MouseMethods[] = { 43 | {"move", mouse_move, METH_VARARGS, 44 | "move(x, y) -> None\n" 45 | "Moves cursor to given (x, y) coordinate."}, 46 | {"smooth_move", mouse_smooth_move, METH_VARARGS, 47 | "smooth_move(x, y) -> None\n" 48 | "Smoothly moves cursor to given (x, y) coordinate in a straight line."}, 49 | {"get_pos", mouse_get_pos, METH_NOARGS, 50 | "get_pos() -> tuple\n" 51 | "Returns a tuple (x, y) of the current mouse position."}, 52 | {"toggle", mouse_toggle, METH_VARARGS, 53 | "toggle(down, button=LEFT_BUTTON) -> None\n" 54 | "Holds down or releases the mouse with the given button."}, 55 | {"click", mouse_click, METH_VARARGS, 56 | "click(button=LEFT_BUTTON) -> None\n" 57 | "Clicks the mouse with the given button."}, 58 | {NULL, NULL, 0, NULL} /* Sentinel */ 59 | }; 60 | 61 | #ifdef PYTHREE 62 | static struct PyModuleDef mousemodule = { 63 | PyModuleDef_HEAD_INIT, 64 | "mouse", 65 | "autopy module for working with the mouse", 66 | -1, 67 | MouseMethods 68 | }; 69 | #endif 70 | 71 | PyMODINIT_FUNC initmouse(void) 72 | { 73 | PyObject *mod; 74 | #ifdef PYTHREE 75 | mod = PyModule_Create(&mousemodule); 76 | #else 77 | mod = Py_InitModule3("mouse", MouseMethods, 78 | "autopy module for working with the mouse"); 79 | #endif 80 | if (mod == NULL) return; /* Error */ 81 | 82 | /* Add mouse button constants for click_mouse(). */ 83 | if (PyModule_AddIntMacro(mod, LEFT_BUTTON) < 0 || 84 | PyModule_AddIntMacro(mod, RIGHT_BUTTON) < 0 || 85 | PyModule_AddIntMacro(mod, CENTER_BUTTON) < 0) { 86 | PyErr_SetString(PyExc_ValueError, "Error adding constants to mouse module"); 87 | return; 88 | } 89 | 90 | deadbeef_srand_time(); 91 | #ifdef PYTHREE 92 | return mod; 93 | #endif 94 | } 95 | 96 | #ifdef PYTHREE 97 | PyMODINIT_FUNC PyInit_mouse(void) { return initmouse(); } 98 | #endif 99 | 100 | static PyObject *mouse_move(PyObject *self, PyObject *args) 101 | { 102 | MMPoint point; 103 | if (!PyArg_ParseTuple(args, "kk", &point.x, &point.y)) return NULL; 104 | 105 | if (!pointVisibleOnMainDisplay(point)) { 106 | PyErr_SetString(PyExc_ValueError, "Point out of bounds"); 107 | return NULL; 108 | } 109 | 110 | moveMouse(point); 111 | 112 | Py_RETURN_NONE; 113 | } 114 | 115 | static PyObject *mouse_smooth_move(PyObject *self, PyObject *args) 116 | { 117 | MMPoint point; 118 | if (!PyArg_ParseTuple(args, "kk", &point.x, &point.y)) return NULL; 119 | 120 | if (!pointVisibleOnMainDisplay(point) || !smoothlyMoveMouse(point)) { 121 | PyErr_SetString(PyExc_ValueError, "Point out of bounds"); 122 | return NULL; 123 | } 124 | 125 | Py_RETURN_NONE; 126 | } 127 | 128 | static PyObject *mouse_get_pos(PyObject *self, PyObject *args) 129 | { 130 | MMPoint pos = getMousePos(); 131 | return Py_BuildValue("kk", pos.x, pos.y); 132 | } 133 | 134 | static PyObject *mouse_toggle(PyObject *self, PyObject *args) 135 | { 136 | PyObject *downBool; 137 | MMMouseButton button = LEFT_BUTTON; 138 | 139 | if (!PyArg_ParseTuple(args, "O!|I", &PyBool_Type, &downBool, &button)) { 140 | return NULL; 141 | } 142 | 143 | if (!MMMouseButtonIsValid(button)) { 144 | PyErr_SetString(PyExc_ValueError, "Invalid mouse button"); 145 | return NULL; 146 | } 147 | 148 | toggleMouse(downBool == Py_True, button); 149 | 150 | Py_RETURN_NONE; 151 | } 152 | 153 | static PyObject *mouse_click(PyObject *self, PyObject *args) 154 | { 155 | MMMouseButton button = LEFT_BUTTON; 156 | 157 | if (!PyArg_ParseTuple(args, "|I", &button)) return NULL; 158 | 159 | if (!MMMouseButtonIsValid(button)) { 160 | PyErr_SetString(PyExc_ValueError, "Invalid mouse button"); 161 | return NULL; 162 | } 163 | 164 | clickMouse(button); 165 | 166 | Py_RETURN_NONE; 167 | } 168 | -------------------------------------------------------------------------------- /src/autopy-mouse-module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AUTOPY_MOUSE_MODULE_H 3 | #define AUTOPY_MOUSE_MODULE_H 4 | 5 | #include 6 | 7 | #if PY_MAJOR_VERSION >= 3 8 | #define PYTHREE 9 | #endif 10 | 11 | /* Summary: autopy module for working with the mouse */ 12 | /* Description: This module contains functions for getting the current state of 13 | and controlling the mouse cursor. 14 | 15 | Unless otherwise stated, coordinates are those of a screen 16 | coordinate system, where the origin is at the top left. */ 17 | PyMODINIT_FUNC initmouse(void); 18 | 19 | #endif /* AUTOPY_MOUSE_MODULE_H */ 20 | -------------------------------------------------------------------------------- /src/autopy-screen-module.c: -------------------------------------------------------------------------------- 1 | #include "autopy-screen-module.h" 2 | #include "screen.h" 3 | #include "screengrab.h" 4 | 5 | /* Syntax: get_size() => tuple (width, height) */ 6 | /* Description: Returns a tuple `(width, height)` of the size of the 7 | main screen. */ 8 | static PyObject *screen_get_size(PyObject *self, PyObject *args); 9 | 10 | /* Syntax: point_visible(x, y) => Boolean */ 11 | /* Arguments: |x| => integer, 12 | |y| => integer */ 13 | /* Description: Returns True if the given point is inside the main 14 | screen boundaries. */ 15 | static PyObject *screen_point_visible(PyObject *self, PyObject *args); 16 | 17 | /* Syntax: get_color(x, y) => hexadecimal integer */ 18 | /* Arguments: |x| => integer, 19 | |y| => integer */ 20 | /* Description: Returns hexadecimal value describing the RGB color at the 21 | given point. 22 | 23 | Essentially equivalent to: 24 | {% 25 | rect = ((x, y), (1, 1)) 26 | bitmap.capture_screen_portion(rect).get_color(0, 0) 27 | %} 28 | only more efficient/convenient. */ 29 | /* Raises: |ValueError| if the rect is out of bounds, 30 | |OSError| if the system calls were unsuccessful. */ 31 | static PyObject *screen_get_color(PyObject *self, PyObject *args); 32 | 33 | static PyMethodDef ScreenMethods[] = { 34 | {"get_size", screen_get_size, METH_NOARGS, 35 | "get_size() -> tuple (width, height)\n" 36 | "Returns a tuple (width, height) of the size of the main screen."}, 37 | {"point_visible", screen_point_visible, METH_VARARGS, 38 | "point_visible(x, y) -> Boolean\n" 39 | "Returns whether given (x, y) coordinate is inside the main screen."}, 40 | {"get_color", screen_get_color, METH_VARARGS, 41 | "get_color(x, y) -> integer\n" 42 | "Returns hexadecimal value describing the RGB color at the given point."}, 43 | {NULL, NULL, 0, NULL} /* Sentinel */ 44 | }; 45 | 46 | #ifdef PYTHREE 47 | static struct PyModuleDef screenmodule = { 48 | PyModuleDef_HEAD_INIT, 49 | "screen", 50 | "autopy module for working with the screen", 51 | -1, 52 | ScreenMethods 53 | }; 54 | #endif 55 | 56 | PyMODINIT_FUNC initscreen(void) 57 | { 58 | #ifdef PYTHREE 59 | return PyModule_Create(&screenmodule); 60 | #else 61 | Py_InitModule3("screen", ScreenMethods, "autopy module for working with " 62 | "the screen"); 63 | #endif 64 | } 65 | 66 | #ifdef PYTHREE 67 | PyMODINIT_FUNC PyInit_screen(void) { return initscreen(); } 68 | #endif 69 | 70 | static PyObject *screen_get_size(PyObject *self, PyObject *args) 71 | { 72 | MMSize screenSize = getMainDisplaySize(); 73 | return Py_BuildValue("(kk)", screenSize.width, screenSize.height); 74 | } 75 | 76 | static PyObject *screen_point_visible(PyObject *self, PyObject *args) 77 | { 78 | MMPoint point; 79 | if (!PyArg_ParseTuple(args, "kk", &point.x, &point.y)) { 80 | return NULL; 81 | } 82 | 83 | if (!pointVisibleOnMainDisplay(point)) { 84 | Py_RETURN_FALSE; 85 | } 86 | 87 | Py_RETURN_TRUE; 88 | } 89 | 90 | static PyObject *screen_get_color(PyObject *self, PyObject *args) 91 | { 92 | MMPoint point; 93 | 94 | MMBitmapRef bitmap; 95 | MMRGBHex color; 96 | 97 | if (!PyArg_ParseTuple(args, "kk", &point.x, &point.y)) { 98 | return NULL; 99 | } 100 | 101 | if (!pointVisibleOnMainDisplay(point)) { 102 | PyErr_SetString(PyExc_ValueError, "Point out of bounds"); 103 | return NULL; 104 | } 105 | 106 | bitmap = copyMMBitmapFromDisplayInRect(MMRectMake(point.x, point.y, 1, 1)); 107 | if (bitmap == NULL || bitmap->imageBuffer == NULL) { 108 | PyErr_SetString(PyExc_OSError, 109 | "Could not copy RGB data from display."); 110 | return NULL; 111 | } 112 | 113 | color = MMRGBHexAtPoint(bitmap, 0, 0); 114 | destroyMMBitmap(bitmap); 115 | return Py_BuildValue("I", color); 116 | } 117 | -------------------------------------------------------------------------------- /src/autopy-screen-module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef AUTOPY_SCREEN_MODULE_H 3 | #define AUTOPY_SCREEN_MODULE_H 4 | 5 | #include 6 | 7 | #if PY_MAJOR_VERSION >= 3 8 | #define PYTHREE 9 | #endif 10 | 11 | /* Summary: autopy module for working with the screen */ 12 | /* Description: This module contains functions for obtaining attributes 13 | about the screen. */ 14 | PyMODINIT_FUNC initscreen(void); 15 | 16 | #endif /* AUTOPY_SCREEN_MODULE_H */ 17 | -------------------------------------------------------------------------------- /src/base64.c: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* Encoding table as described in RFC1113. */ 8 | const static uint8_t b64_encode_table[] = 9 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 10 | "abcdefghijklmnopqrstuvwxyz0123456789+/"; 11 | 12 | /* Decoding table. */ 13 | const static int8_t b64_decode_table[256] = { 14 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00-0F */ 15 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10-1F */ 16 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20-2F */ 17 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 30-3F */ 18 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40-4F */ 19 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50-5F */ 20 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60-6F */ 21 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 70-7F */ 22 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80-8F */ 23 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90-9F */ 24 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0-AF */ 25 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0-BF */ 26 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0-CF */ 27 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0-DF */ 28 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0-EF */ 29 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* F0-FF */ 30 | }; 31 | 32 | uint8_t *base64decode(const uint8_t *src, const size_t buflen, size_t *retlen) 33 | { 34 | int8_t digit, lastdigit; 35 | size_t i, j; 36 | uint8_t *decoded; 37 | const size_t maxlen = ((buflen + 3) / 4) * 3; 38 | 39 | /* Sanity check */ 40 | assert(src != NULL); 41 | 42 | digit = lastdigit = j = 0; 43 | decoded = malloc(maxlen + 1); 44 | if (decoded == NULL) return NULL; 45 | for (i = 0; i < buflen; ++i) { 46 | if ((digit = b64_decode_table[src[i]]) != -1) { 47 | /* Decode block */ 48 | switch (i % 4) { 49 | case 1: 50 | decoded[j++] = ((lastdigit << 2) | ((digit & 0x30) >> 4)); 51 | break; 52 | case 2: 53 | decoded[j++] = (((lastdigit & 0xF) << 4) | ((digit & 0x3C) >> 2)); 54 | break; 55 | case 3: 56 | decoded[j++] = (((lastdigit & 0x03) << 6) | digit); 57 | break; 58 | } 59 | lastdigit = digit; 60 | } 61 | } 62 | 63 | if (retlen != NULL) *retlen = j; 64 | decoded[j] = '\0'; 65 | return decoded; /* Must be free()'d by caller */ 66 | } 67 | 68 | uint8_t *base64encode(const uint8_t *src, const size_t buflen, size_t *retlen) 69 | { 70 | size_t i, j; 71 | const size_t maxlen = (((buflen + 3) & ~3)) * 4; 72 | uint8_t *encoded = malloc(maxlen + 1); 73 | if (encoded == NULL) return NULL; 74 | 75 | /* Sanity check */ 76 | assert(src != NULL); 77 | assert(buflen > 0); 78 | 79 | j = 0; 80 | for (i = 0; i < buflen + 1; ++i) { 81 | /* Encode block */ 82 | switch (i % 3) { 83 | case 0: 84 | encoded[j++] = b64_encode_table[src[i] >> 2]; 85 | encoded[j++] = b64_encode_table[((src[i] & 0x03) << 4) | 86 | ((src[i + 1] & 0xF0) >> 4)]; 87 | break; 88 | case 1: 89 | encoded[j++] = b64_encode_table[((src[i] & 0x0F) << 2) | 90 | ((src[i + 1] & 0xC0) >> 6)]; 91 | break; 92 | case 2: 93 | encoded[j++] = b64_encode_table[(src[i] & 0x3F)]; 94 | break; 95 | } 96 | } 97 | 98 | /* Add padding if necessary */ 99 | if ((j % 4) != 0) { 100 | const size_t with_padding = ((j + 3) & ~3); /* Align to 4 bytes */ 101 | do { 102 | encoded[j++] = '='; 103 | } while (j < with_padding); 104 | } 105 | 106 | assert(j <= maxlen); 107 | 108 | if (retlen != NULL) *retlen = j; 109 | encoded[j] = '\0'; 110 | return encoded; /* Must be free()'d by caller */ 111 | } 112 | -------------------------------------------------------------------------------- /src/base64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef BASE64_H 3 | #define BASE64_H 4 | 5 | #include 6 | 7 | #if defined(_MSC_VER) 8 | #include "ms_stdint.h" 9 | #else 10 | #include 11 | #endif 12 | 13 | /* Decode a base64 encoded string discarding line breaks and noise. 14 | * 15 | * Returns a new string to be free()'d by caller, or NULL on error. 16 | * Returned string is guaranteed to be NUL-terminated. 17 | * 18 | * If |retlen| is not NULL, it is set to the length of the returned string 19 | * (minus the NUL-terminator) on successful return. */ 20 | uint8_t *base64decode(const uint8_t *buf, const size_t buflen, size_t *retlen); 21 | 22 | /* Encode a base64 encoded string without line breaks or noise. 23 | * 24 | * Returns a new string to be free()'d by caller, or NULL on error. 25 | * Returned string is guaranteed to be NUL-terminated with the correct padding. 26 | * 27 | * If |retlen| is not NULL, it is set to the length of the returned string 28 | * (minus the NUL-terminator) on successful return. */ 29 | uint8_t *base64encode(const uint8_t *buf, const size_t buflen, size_t *retlen); 30 | 31 | #endif /* BASE64_H */ 32 | -------------------------------------------------------------------------------- /src/bitmap_find.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef BITMAP_H 3 | #define BITMAP_H 4 | 5 | #include "types.h" 6 | #include "MMBitmap.h" 7 | #include "MMPointArray.h" 8 | 9 | /* Convenience wrapper around findBitmapInRect(), where |rect| is the bounds 10 | * of |haystack|. */ 11 | #define findBitmapInBitmap(needle, haystack, pointPtr, tol) \ 12 | findBitmapInRect(needle, haystack, pointPtr, MMBitmapGetBounds(haystack), tol) 13 | 14 | /* Returns 0 and sets |point| to the origin of |needle| in |haystack| if 15 | * |needle| was found in |haystack| inside of |rect|, or returns -1 if not. 16 | * 17 | * |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the 18 | * colors in the bitmaps need to match, with 0 being exact and 1 being any. 19 | */ 20 | int findBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, 21 | MMPoint *point, MMRect rect, float tolerance); 22 | 23 | /* Convenience wrapper around findAllBitmapInRect(), where |rect| is the bounds 24 | * of |haystack|. */ 25 | #define findAllBitmapInBitmap(needle, haystack, tolerance) \ 26 | findAllBitmapInRect(needle, haystack, \ 27 | MMBitmapGetBounds(haystack), tolerance) 28 | 29 | /* Returns MMPointArray of all occurrences of |needle| in |haystack| inside of 30 | * |rect|. Note that an is returned regardless of whether |needle| was found; 31 | * check array->count to see if it actually was. 32 | * 33 | * |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the 34 | * colors in the bitmaps need to match, with 0 being exact and 1 being any. 35 | * 36 | * Responsibility for freeing the MMPointArray with destroyMMPointArray() is 37 | * given to the caller. 38 | */ 39 | MMPointArrayRef findAllBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, 40 | MMRect rect, float tolerance); 41 | 42 | /* Convenience wrapper around countOfBitmapInRect(), where |rect| is the bounds 43 | * of |haystack|. */ 44 | #define countOfBitmapInBitmap(needle, haystack, tolerance) \ 45 | countOfBitmapInRect(needle, haystack, MMBitmapGetBounds(haystack), tolerance) 46 | 47 | /* Returns the number of occurences of |needle| in |haystack| inside 48 | * of |rect|. */ 49 | size_t countOfBitmapInRect(MMBitmapRef needle, MMBitmapRef haystack, 50 | MMRect rect, float tolerance); 51 | 52 | #endif /* BITMAP_H */ 53 | -------------------------------------------------------------------------------- /src/bmp_io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef BMP_IO_H 3 | #define BMP_IO_H 4 | 5 | #include "MMBitmap.h" 6 | #include "io.h" 7 | 8 | enum _BMPReadError { 9 | kBMPGenericError = 0, 10 | kBMPAccessError, 11 | kBMPInvalidKeyError, 12 | kBMPUnsupportedHeaderError, 13 | kBMPInvalidColorPanesError, 14 | kBMPUnsupportedColorDepthError, 15 | kBMPUnsupportedCompressionError, 16 | kBMPInvalidPixelDataError 17 | }; 18 | 19 | typedef MMIOError MMBMPReadError; 20 | 21 | /* Returns description of given MMBMPReadError. 22 | * Returned string is constant and hence should not be freed. */ 23 | const char *MMBMPReadErrorString(MMIOError error); 24 | 25 | /* Attempts to read bitmap file at path; returns new MMBitmap on success, or 26 | * NULL on error. If |error| is non-NULL, it will be set to the error code 27 | * on return. 28 | * 29 | * Currently supports: 30 | * - Uncompressed Windows v3/v4/v5 24-bit or 32-bit BMP. 31 | * - OS/2 v1 or v2 24-bit BMP. 32 | * - Does NOT yet support: 1-bit, 4-bit, 8-bit, 16-bit, compressed bitmaps, 33 | * or PNGs/JPEGs disguised as BMPs (and returns NULL if those are given). 34 | * 35 | * Responsibility for destroy()'ing returned MMBitmap is left up to caller. */ 36 | MMBitmapRef newMMBitmapFromBMP(const char *path, MMBMPReadError *error); 37 | 38 | /* Returns a buffer containing the raw BMP file data in Windows v3 BMP format, 39 | * ready to be saved to a file. If |len| is not NULL, it will be set to the 40 | * number of bytes allocated in the returned buffer. 41 | * 42 | * Responsibility for free()'ing data is left up to the caller. */ 43 | uint8_t *createBitmapData(MMBitmapRef bitmap, size_t *len); 44 | 45 | /* Saves bitmap to file in Windows v3 BMP format. 46 | * Returns 0 on success, -1 on error. */ 47 | int saveMMBitmapAsBMP(MMBitmapRef bitmap, const char *path); 48 | 49 | /* Swaps bitmap from Quadrant 1 to Quadran III format, or vice versa 50 | * (upside-down Cartesian/PostScript/GL <-> right side up QD/CG raster format). 51 | */ 52 | void flipBitmapData(void *data, size_t width, size_t height, size_t bytewidth); 53 | 54 | #endif /* BMP_IO_H */ 55 | -------------------------------------------------------------------------------- /src/color_find.c: -------------------------------------------------------------------------------- 1 | #include "color_find.h" 2 | #include "screen.h" 3 | #include 4 | 5 | /* Abstracted, general function to avoid repeated code. */ 6 | static int findColorInRectAt(MMBitmapRef image, MMRGBHex color, MMPoint *point, 7 | MMRect rect, float tolerance, MMPoint startPoint) 8 | { 9 | MMPoint scan = startPoint; 10 | if (!MMBitmapRectInBounds(image, rect)) return -1; 11 | 12 | for (; scan.y < rect.size.height; ++scan.y) { 13 | for (; scan.x < rect.size.width; ++scan.x) { 14 | MMRGBHex found = MMRGBHexAtPoint(image, scan.x, scan.y); 15 | if (MMRGBHexSimilarToColor(color, found, tolerance)) { 16 | if (point != NULL) *point = scan; 17 | return 0; 18 | } 19 | } 20 | scan.x = rect.origin.x; 21 | } 22 | 23 | return -1; 24 | } 25 | 26 | int findColorInRect(MMBitmapRef image, MMRGBHex color, 27 | MMPoint *point, MMRect rect, float tolerance) 28 | { 29 | return findColorInRectAt(image, color, point, rect, tolerance, rect.origin); 30 | } 31 | 32 | MMPointArrayRef findAllColorInRect(MMBitmapRef image, MMRGBHex color, 33 | MMRect rect, float tolerance) 34 | { 35 | MMPointArrayRef pointArray = createMMPointArray(0); 36 | MMPoint point = MMPointZero; 37 | 38 | while (findColorInRectAt(image, color, &point, rect, tolerance, point) == 0) { 39 | MMPointArrayAppendPoint(pointArray, point); 40 | ITER_NEXT_POINT(point, rect.size.width, rect.origin.x); 41 | } 42 | 43 | return pointArray; 44 | } 45 | 46 | size_t countOfColorsInRect(MMBitmapRef image, MMRGBHex color, MMRect rect, 47 | float tolerance) 48 | { 49 | size_t count = 0; 50 | MMPoint point = MMPointZero; 51 | 52 | while (findColorInRectAt(image, color, &point, rect, tolerance, point) == 0) { 53 | ITER_NEXT_POINT(point, rect.size.width, rect.origin.x); 54 | ++count; 55 | } 56 | 57 | return count; 58 | } 59 | -------------------------------------------------------------------------------- /src/color_find.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef COLOR_FIND_H 3 | #define COLOR_FIND_H 4 | 5 | #include "MMBitmap.h" 6 | #include "MMPointArray.h" 7 | 8 | /* Convenience wrapper around findColorInRect(), where |rect| is the bounds of 9 | * the image. */ 10 | #define findColorInImage(image, color, pointPtr, tolerance) \ 11 | findColorInRect(image, color, pointPtr, MMBitmapGetBounds(image), tolerance) 12 | 13 | /* Attempt to find a pixel with the given color in |image| inside |rect|. 14 | * Returns 0 on success, non-zero on failure. If the color was found and 15 | * |point| is not NULL, it will be initialized to the (x, y) coordinates the 16 | * RGB color. 17 | * 18 | * |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the 19 | * colors need to match, with 0 being exact and 1 being any. */ 20 | int findColorInRect(MMBitmapRef image, MMRGBHex color, MMPoint *point, 21 | MMRect rect, float tolerance); 22 | 23 | /* Convenience wrapper around findAllRGBInRect(), where |rect| is the bounds of 24 | * the image. */ 25 | #define findAllColorInImage(image, color, tolerance) \ 26 | findAllColorInRect(image, color, MMBitmapGetBounds(image), tolerance) 27 | 28 | /* Returns MMPointArray of all pixels of given color in |image| inside of 29 | * |rect|. Note that an array is returned regardless of whether the color was 30 | * found; check array->count to see if it actually was. 31 | * 32 | * Responsibility for freeing the MMPointArray with destroyMMPointArray() is 33 | * given to the caller. 34 | * 35 | * |tolerance| should be in the range 0.0f - 1.0f, denoting how closely the 36 | * colors need to match, with 0 being exact and 1 being any. */ 37 | MMPointArrayRef findAllColorInRect(MMBitmapRef image, MMRGBHex color, 38 | MMRect rect, float tolerance); 39 | 40 | /* Convenience wrapper around countOfColorsInRect, where |rect| is the bounds 41 | * of the image. */ 42 | #define countOfColorsInImage(image, color, tolerance) \ 43 | countOfColorsInRect(image, color, MMBitmapGetBounds(image), tolerance) 44 | 45 | /* Returns the count of the given color in |rect| inside of |image|. */ 46 | size_t countOfColorsInRect(MMBitmapRef image, MMRGBHex color, MMRect rect, 47 | float tolerance); 48 | 49 | #endif /* COLOR_FIND_H */ 50 | -------------------------------------------------------------------------------- /src/deadbeef_rand.c: -------------------------------------------------------------------------------- 1 | #include "deadbeef_rand.h" 2 | #include 3 | 4 | static uint32_t deadbeef_seed; 5 | static uint32_t deadbeef_beef = 0xdeadbeef; 6 | 7 | uint32_t deadbeef_rand(void) 8 | { 9 | deadbeef_seed = (deadbeef_seed << 7) ^ ((deadbeef_seed >> 25) + deadbeef_beef); 10 | deadbeef_beef = (deadbeef_beef << 7) ^ ((deadbeef_beef >> 25) + 0xdeadbeef); 11 | return deadbeef_seed; 12 | } 13 | 14 | void deadbeef_srand(uint32_t x) 15 | { 16 | deadbeef_seed = x; 17 | deadbeef_beef = 0xdeadbeef; 18 | } 19 | 20 | /* Taken directly from the documentation: 21 | * http://inglorion.net/software/cstuff/deadbeef_rand/ */ 22 | uint32_t deadbeef_generate_seed(void) 23 | { 24 | uint32_t t = (uint32_t)time(NULL); 25 | uint32_t c = (uint32_t)clock(); 26 | return (t << 24) ^ (c << 11) ^ t ^ (size_t) &c; 27 | } 28 | -------------------------------------------------------------------------------- /src/deadbeef_rand.h: -------------------------------------------------------------------------------- 1 | #ifndef DEADBEEF_RAND_H 2 | #define DEADBEEF_RAND_H 3 | 4 | #if defined(_MSC_VER) 5 | #include "ms_stdint.h" 6 | #else 7 | #include 8 | #endif 9 | 10 | #define DEADBEEF_MAX UINT32_MAX 11 | 12 | /* Dead Beef Random Number Generator 13 | * From: http://inglorion.net/software/deadbeef_rand 14 | * A fast, portable psuedo-random number generator by BJ Amsterdam Zuidoost. 15 | * Stated in license terms: "Feel free to use the code in your own software." */ 16 | 17 | /* Generates a random number between 0 and DEADBEEF_MAX. */ 18 | uint32_t deadbeef_rand(void); 19 | 20 | /* Seeds with the given integer. */ 21 | void deadbeef_srand(uint32_t x); 22 | 23 | /* Generates seed from the current time. */ 24 | uint32_t deadbeef_generate_seed(void); 25 | 26 | /* Seeds with the above function. */ 27 | #define deadbeef_srand_time() deadbeef_srand(deadbeef_generate_seed()) 28 | 29 | /* Returns random double in the range [a, b). 30 | * Taken directly from the rand() man page. */ 31 | #define DEADBEEF_UNIFORM(a, b) \ 32 | ((a) + (deadbeef_rand() / (((double)DEADBEEF_MAX / (b - a) + 1)))) 33 | 34 | /* Returns random integer in the range [a, b). 35 | * Also taken from the rand() man page. */ 36 | #define DEADBEEF_RANDRANGE(a, b) \ 37 | (uint32_t)DEADBEEF_UNIFORM(a, b) 38 | 39 | #endif /* DEADBEEF_RAND_H */ 40 | -------------------------------------------------------------------------------- /src/endian.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ENDIAN_H 3 | #define ENDIAN_H 4 | 5 | #include "os.h" 6 | 7 | /* 8 | * (Mostly) cross-platform endian definitions and bit swapping macros. 9 | * Unfortunately, there is no standard C header for this, so we just 10 | * include the most common ones and fallback to our own custom macros. 11 | */ 12 | 13 | #if defined(__linux__) /* Linux */ 14 | #include 15 | #include 16 | #elif (defined(__FreeBSD__) && __FreeBSD_version >= 470000) || \ 17 | defined(__OpenBSD__) || defined(__NetBSD__) /* (Free|Open|Net)BSD */ 18 | #include 19 | #define __BIG_ENDIAN BIG_ENDIAN 20 | #define __LITTLE_ENDIAN LITTLE_ENDIAN 21 | #define __BYTE_ORDER BYTE_ORDER 22 | #elif defined(IS_MACOSX) || (defined(BSD) && (BSD >= 199103)) /* Other BSD */ 23 | #include 24 | #define __BIG_ENDIAN BIG_ENDIAN 25 | #define __LITTLE_ENDIAN LITTLE_ENDIAN 26 | #define __BYTE_ORDER BYTE_ORDER 27 | #elif defined(IS_WINDOWS) /* Windows is assumed to be little endian only. */ 28 | #define __BIG_ENDIAN 4321 29 | #define __LITTLE_ENDIAN 1234 30 | #define __BYTE_ORDER __LITTLE_ENDIAN 31 | #endif 32 | 33 | /* Fallback to custom constants. */ 34 | #if !defined(__BIG_ENDIAN) 35 | #define __BIG_ENDIAN 4321 36 | #endif 37 | 38 | #if !defined(__LITTLE_ENDIAN) 39 | #define __LITTLE_ENDIAN 1234 40 | #endif 41 | 42 | /* Prefer compiler flag settings if given. */ 43 | #if defined(MM_BIG_ENDIAN) 44 | #undef __BYTE_ORDER /* Avoid redefined macro compiler warning. */ 45 | #define __BYTE_ORDER __BIG_ENDIAN 46 | #elif defined(MM_LITTLE_ENDIAN) 47 | #undef __BYTE_ORDER /* Avoid redefined macro compiler warning. */ 48 | #define __BYTE_ORDER __LITTLE_ENDIAN 49 | #endif 50 | 51 | /* Define default endian-ness. */ 52 | #ifndef __LITTLE_ENDIAN 53 | #define __LITTLE_ENDIAN 1234 54 | #endif /* __LITTLE_ENDIAN */ 55 | 56 | #ifndef __BIG_ENDIAN 57 | #define __BIG_ENDIAN 4321 58 | #endif /* __BIG_ENDIAN */ 59 | 60 | #ifndef __BYTE_ORDER 61 | #warning "Byte order not defined on your system; assuming little endian" 62 | #define __BYTE_ORDER __LITTLE_ENDIAN 63 | #endif /* __BYTE_ORDER */ 64 | 65 | #if __BYTE_ORDER != __BIG_ENDIAN && __BYTE_ORDER != __LITTLE_ENDIAN 66 | #error "__BYTE_ORDER set to unknown byte order" 67 | #endif 68 | 69 | #if defined(IS_MACOSX) 70 | #include 71 | 72 | /* OS X system functions. */ 73 | #define bitswap16(i) OSSwapInt16(i) 74 | #define bitswap32(i) OSSwapInt32(i) 75 | #define swapLittleAndHost32(i) OSSwapLittleToHostInt32(i) 76 | #define swapLittleAndHost16(i) OSSwapLittleToHostInt16(i) 77 | #else 78 | #ifndef bitswap16 79 | #if defined(bswap16) 80 | #define bitswap16(i) bswap16(i) /* FreeBSD system function */ 81 | #elif defined(bswap_16) 82 | #define bitswap16(i) bswap_16(i) /* Linux system function */ 83 | #else /* Default macro */ 84 | #define bitswap16(i) (((uint16_t)(i) & 0xFF00) >> 8) | \ 85 | (((uint16_t)(i) & 0x00FF) << 8) 86 | #endif 87 | #endif /* bitswap16 */ 88 | 89 | #ifndef bitswap32 90 | #if defined(bswap32) 91 | #define bitswap32(i) bswap32(i) /* FreeBSD system function. */ 92 | #elif defined(bswap_32) 93 | #define bitswap32(i) bswap_32(i) /* Linux system function. */ 94 | #else /* Default macro */ 95 | #define bitswap32(i) (((uint32_t)(i) & 0xFF000000) >> 24) | \ 96 | ((uint32_t)((i) & 0x00FF0000) >> 8) | \ 97 | ((uint32_t)((i) & 0x0000FF00) << 8) | \ 98 | ((uint32_t)((i) & 0x000000FF) << 24) 99 | #endif 100 | #endif /* bitswap32 */ 101 | #endif 102 | 103 | #if __BYTE_ORDER == __BIG_ENDIAN 104 | /* Little endian to/from host byte order (big endian). */ 105 | #ifndef swapLittleAndHost16 106 | #define swapLittleAndHost16(i) bitswap16(i) 107 | #endif /* swapLittleAndHost16 */ 108 | 109 | #ifndef swapLittleAndHost32 110 | #define swapLittleAndHost32(i) bitswap32(i) 111 | #endif /* swapLittleAndHost32 */ 112 | #elif __BYTE_ORDER == __LITTLE_ENDIAN 113 | /* We are already little endian, so no conversion is needed. */ 114 | #ifndef swapLittleAndHost16 115 | #define swapLittleAndHost16(i) i 116 | #endif /* swapLittleAndHost16 */ 117 | 118 | #ifndef swapLittleAndHost32 119 | #define swapLittleAndHost32(i) i 120 | #endif /* swapLittleAndHost32 */ 121 | #endif 122 | 123 | #endif /* ENDIAN_H */ 124 | -------------------------------------------------------------------------------- /src/inline_keywords.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* A complicated, portable model for declaring inline functions in 4 | * header files. */ 5 | #if !defined(H_INLINE) 6 | #if defined(__GNUC__) 7 | #define H_INLINE static __inline__ __attribute__((always_inline)) 8 | #elif defined(__MWERKS__) || defined(__cplusplus) 9 | #define H_INLINE static inline 10 | #elif defined(_MSC_VER) 11 | #define H_INLINE static __inline 12 | #elif TARGET_OS_WIN32 13 | #define H_INLINE static __inline__ 14 | #endif 15 | #endif /* H_INLINE */ 16 | -------------------------------------------------------------------------------- /src/io.c: -------------------------------------------------------------------------------- 1 | #include "io.h" 2 | #include "os.h" 3 | #include "bmp_io.h" 4 | #include "png_io.h" 5 | #include /* For fputs() */ 6 | #include /* For strcmp() */ 7 | #include /* For tolower() */ 8 | 9 | const char *getExtension(const char *fname, size_t len) 10 | { 11 | if (fname == NULL || len <= 0) return NULL; 12 | 13 | while (--len > 0 && fname[len] != '.' && fname[len] != '\0') 14 | ; 15 | 16 | return fname + len + 1; 17 | } 18 | 19 | MMImageType imageTypeFromExtension(const char *extension) 20 | { 21 | char ext[4]; 22 | const size_t maxlen = sizeof(ext) / sizeof(ext[0]); 23 | size_t i; 24 | 25 | for (i = 0; extension[i] != '\0'; ++i) { 26 | if (i >= maxlen) return kInvalidImageType; 27 | ext[i] = tolower(extension[i]); 28 | } 29 | ext[i] = '\0'; 30 | 31 | if (strcmp(ext, "png") == 0) { 32 | return kPNGImageType; 33 | } else if (strcmp(ext, "bmp") == 0) { 34 | return kBMPImageType; 35 | } else { 36 | return kInvalidImageType; 37 | } 38 | } 39 | 40 | MMBitmapRef newMMBitmapFromFile(const char *path, 41 | MMImageType type, 42 | MMIOError *err) 43 | { 44 | switch (type) { 45 | case kBMPImageType: 46 | return newMMBitmapFromBMP(path, err); 47 | case kPNGImageType: 48 | return newMMBitmapFromPNG(path, err); 49 | default: 50 | if (err != NULL) *err = kMMIOUnsupportedTypeError; 51 | return NULL; 52 | } 53 | } 54 | 55 | int saveMMBitmapToFile(MMBitmapRef bitmap, 56 | const char *path, 57 | MMImageType type) 58 | { 59 | switch (type) { 60 | case kBMPImageType: 61 | return saveMMBitmapAsBMP(bitmap, path); 62 | case kPNGImageType: 63 | return saveMMBitmapAsPNG(bitmap, path); 64 | default: 65 | return -1; 66 | } 67 | } 68 | 69 | const char *MMIOErrorString(MMImageType type, MMIOError error) 70 | { 71 | switch (type) { 72 | case kBMPImageType: 73 | return MMBMPReadErrorString(error); 74 | case kPNGImageType: 75 | return MMPNGReadErrorString(error); 76 | default: 77 | return "Unsupported image type"; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef IO_H 3 | #define IO_H 4 | 5 | #include "MMBitmap.h" 6 | #include 7 | 8 | #if defined(_MSC_VER) 9 | #include "ms_stdint.h" 10 | #else 11 | #include 12 | #endif 13 | 14 | enum _MMImageType { 15 | kInvalidImageType = 0, 16 | kPNGImageType, 17 | kBMPImageType /* Currently only PNG and BMP are supported. */ 18 | }; 19 | 20 | typedef uint16_t MMImageType; 21 | 22 | enum _MMIOError { 23 | kMMIOUnsupportedTypeError = 0 24 | }; 25 | 26 | typedef uint16_t MMIOError; 27 | 28 | const char *getExtension(const char *fname, size_t len); 29 | 30 | /* Returns best guess at the MMImageType based on a file extension, or 31 | * |kInvalidImageType| if no matching type was found. */ 32 | MMImageType imageTypeFromExtension(const char *ext); 33 | 34 | /* Attempts to parse the file of the given type at the given path. 35 | * |filepath| is an ASCII string describing the absolute POSIX path. 36 | * Returns new bitmap (to be destroy()'d by caller) on success, NULL on error. 37 | * If |error| is non-NULL, it will be set to the error code on return. 38 | */ 39 | MMBitmapRef newMMBitmapFromFile(const char *path, MMImageType type, MMIOError *err); 40 | 41 | /* Saves |bitmap| to a file of the given type at the given path. 42 | * |filepath| is an ASCII string describing the absolute POSIX path. 43 | * Returns 0 on success, -1 on error. */ 44 | int saveMMBitmapToFile(MMBitmapRef bitmap, const char *path, MMImageType type); 45 | 46 | /* Returns description of given error code. 47 | * Returned string is constant and hence should not be freed. */ 48 | const char *MMIOErrorString(MMImageType type, MMIOError error); 49 | 50 | #endif /* IO_H */ 51 | -------------------------------------------------------------------------------- /src/keycode.c: -------------------------------------------------------------------------------- 1 | #include "keycode.h" 2 | 3 | #if defined(IS_MACOSX) 4 | 5 | #include 6 | #include /* For kVK_ constants, and TIS functions. */ 7 | 8 | /* Returns string representation of key, if it is printable. 9 | * Ownership follows the Create Rule; that is, it is the caller's 10 | * responsibility to release the returned object. */ 11 | CFStringRef createStringForKey(CGKeyCode keyCode); 12 | 13 | #elif defined(USE_X11) 14 | 15 | /* 16 | * Structs to store key mappings not handled by XStringToKeysym() on some 17 | * Linux systems. 18 | */ 19 | 20 | struct XSpecialCharacterMapping { 21 | char name; 22 | MMKeyCode code; 23 | }; 24 | 25 | struct XSpecialCharacterMapping XSpecialCharacterTable[] = { 26 | {'~', XK_asciitilde}, 27 | {'_', XK_underscore}, 28 | {'[', XK_bracketleft}, 29 | {']', XK_bracketright}, 30 | {'!', XK_exclam}, 31 | {'\'', XK_quotedbl}, 32 | {'#', XK_numbersign}, 33 | {'$', XK_dollar}, 34 | {'%', XK_percent}, 35 | {'&', XK_ampersand}, 36 | {'\'', XK_quoteright}, 37 | {'*', XK_asterisk}, 38 | {'+', XK_plus}, 39 | {',', XK_comma}, 40 | {'-', XK_minus}, 41 | {'.', XK_period}, 42 | {'?', XK_question}, 43 | {'<', XK_less}, 44 | {'>', XK_greater}, 45 | {'=', XK_equal}, 46 | {'@', XK_at}, 47 | {':', XK_colon}, 48 | {';', XK_semicolon}, 49 | {'\\', XK_backslash}, 50 | {'`', XK_grave}, 51 | {'{', XK_braceleft}, 52 | {'}', XK_braceright}, 53 | {'|', XK_bar}, 54 | {'^', XK_asciicircum}, 55 | {'(', XK_parenleft}, 56 | {')', XK_parenright}, 57 | {' ', XK_space}, 58 | {'/', XK_slash}, 59 | {'\t', XK_Tab}, 60 | {'\n', XK_Return} 61 | }; 62 | 63 | #endif 64 | 65 | MMKeyCode keyCodeForChar(const char c) 66 | { 67 | #if defined(IS_MACOSX) 68 | /* OS X does not appear to have a built-in function for this, so instead we 69 | * have to write our own. */ 70 | static CFMutableDictionaryRef charToCodeDict = NULL; 71 | CGKeyCode code; 72 | UniChar character = c; 73 | CFStringRef charStr = NULL; 74 | 75 | /* Generate table of keycodes and characters. */ 76 | if (charToCodeDict == NULL) { 77 | size_t i; 78 | charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 79 | 128, 80 | &kCFCopyStringDictionaryKeyCallBacks, 81 | NULL); 82 | if (charToCodeDict == NULL) return UINT16_MAX; 83 | 84 | /* Loop through every keycode (0 - 127) to find its current mapping. */ 85 | for (i = 0; i < 128; ++i) { 86 | CFStringRef string = createStringForKey((CGKeyCode)i); 87 | if (string != NULL) { 88 | CFDictionaryAddValue(charToCodeDict, string, (const void *)i); 89 | CFRelease(string); 90 | } 91 | } 92 | } 93 | 94 | charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1); 95 | 96 | /* Our values may be NULL (0), so we need to use this function. */ 97 | if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr, 98 | (const void **)&code)) { 99 | code = UINT16_MAX; /* Error */ 100 | } 101 | 102 | CFRelease(charStr); 103 | return (MMKeyCode)code; 104 | #elif defined(IS_WINDOWS) 105 | return VkKeyScan(c); 106 | #elif defined(USE_X11) 107 | MMKeyCode code; 108 | 109 | char buf[2]; 110 | buf[0] = c; 111 | buf[1] = '\0'; 112 | 113 | code = XStringToKeysym(buf); 114 | if (code == NoSymbol) { 115 | /* Some special keys are apparently not handled properly by 116 | * XStringToKeysym() on some systems, so search for them instead in our 117 | * mapping table. */ 118 | size_t i; 119 | const size_t specialCharacterCount = 120 | sizeof(XSpecialCharacterTable) / sizeof(XSpecialCharacterTable[0]); 121 | for (i = 0; i < specialCharacterCount; ++i) { 122 | if (c == XSpecialCharacterTable[i].name) { 123 | code = XSpecialCharacterTable[i].code; 124 | break; 125 | } 126 | } 127 | } 128 | 129 | return code; 130 | #endif 131 | } 132 | 133 | #if defined(IS_MACOSX) 134 | 135 | CFStringRef createStringForKey(CGKeyCode keyCode) 136 | { 137 | TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); 138 | CFDataRef layoutData = 139 | TISGetInputSourceProperty(currentKeyboard, 140 | kTISPropertyUnicodeKeyLayoutData); 141 | const UCKeyboardLayout *keyboardLayout = 142 | (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); 143 | 144 | UInt32 keysDown = 0; 145 | UniChar chars[4]; 146 | UniCharCount realLength; 147 | 148 | UCKeyTranslate(keyboardLayout, 149 | keyCode, 150 | kUCKeyActionDisplay, 151 | 0, 152 | LMGetKbdType(), 153 | kUCKeyTranslateNoDeadKeysBit, 154 | &keysDown, 155 | sizeof(chars) / sizeof(chars[0]), 156 | &realLength, 157 | chars); 158 | CFRelease(currentKeyboard); 159 | 160 | return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); 161 | } 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /src/keycode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef KEYCODE_H 3 | #define KEYCODE_H 4 | 5 | #include "os.h" 6 | 7 | #if defined(IS_MACOSX) 8 | 9 | #include /* Really only need */ 10 | #include 11 | 12 | enum _MMKeyCode { 13 | K_BACKSPACE = kVK_Delete, 14 | K_DELETE = kVK_ForwardDelete, 15 | K_RETURN = kVK_Return, 16 | K_ESCAPE = kVK_Escape, 17 | K_UP = kVK_UpArrow, 18 | K_DOWN = kVK_DownArrow, 19 | K_RIGHT = kVK_RightArrow, 20 | K_LEFT = kVK_LeftArrow, 21 | K_HOME = kVK_Home, 22 | K_END = kVK_End, 23 | K_PAGEUP = kVK_PageUp, 24 | K_PAGEDOWN = kVK_PageDown, 25 | K_F1 = kVK_F1, 26 | K_F2 = kVK_F2, 27 | K_F3 = kVK_F3, 28 | K_F4 = kVK_F4, 29 | K_F5 = kVK_F5, 30 | K_F6 = kVK_F6, 31 | K_F7 = kVK_F7, 32 | K_F8 = kVK_F8, 33 | K_F9 = kVK_F9, 34 | K_F10 = kVK_F10, 35 | K_F11 = kVK_F11, 36 | K_F12 = kVK_F12, 37 | K_META = kVK_Command, 38 | K_ALT = kVK_Option, 39 | K_CONTROL = kVK_Control, 40 | K_SHIFT = kVK_Shift, 41 | K_CAPSLOCK = kVK_CapsLock 42 | }; 43 | 44 | typedef CGKeyCode MMKeyCode; 45 | 46 | #elif defined(USE_X11) 47 | 48 | #include 49 | 50 | enum _MMKeyCode { 51 | K_BACKSPACE = XK_BackSpace, 52 | K_DELETE = XK_Delete, 53 | K_RETURN = XK_Return, 54 | K_ESCAPE = XK_Escape, 55 | K_UP = XK_Up, 56 | K_DOWN = XK_Down, 57 | K_RIGHT = XK_Right, 58 | K_LEFT = XK_Left, 59 | K_HOME = XK_Home, 60 | K_END = XK_End, 61 | K_PAGEUP = XK_Page_Up, 62 | K_PAGEDOWN = XK_Page_Down, 63 | K_F1 = XK_F1, 64 | K_F2 = XK_F2, 65 | K_F3 = XK_F3, 66 | K_F4 = XK_F4, 67 | K_F5 = XK_F5, 68 | K_F6 = XK_F6, 69 | K_F7 = XK_F7, 70 | K_F8 = XK_F8, 71 | K_F9 = XK_F9, 72 | K_F10 = XK_F10, 73 | K_F11 = XK_F11, 74 | K_F12 = XK_F12, 75 | K_META = XK_Super_L, 76 | K_ALT = XK_Alt_L, 77 | K_CONTROL = XK_Control_L, 78 | K_SHIFT = XK_Shift_L, 79 | K_CAPSLOCK = XK_Shift_Lock 80 | }; 81 | 82 | typedef KeySym MMKeyCode; 83 | 84 | #elif defined(IS_WINDOWS) 85 | 86 | enum _MMKeyCode { 87 | K_BACKSPACE = VK_BACK, 88 | K_DELETE = VK_DELETE, 89 | K_RETURN = VK_RETURN, 90 | K_ESCAPE = VK_ESCAPE, 91 | K_UP = VK_UP, 92 | K_DOWN = VK_DOWN, 93 | K_RIGHT = VK_RIGHT, 94 | K_LEFT = VK_LEFT, 95 | K_HOME = VK_HOME, 96 | K_END = VK_END, 97 | K_PAGEUP = VK_PRIOR, 98 | K_PAGEDOWN = VK_NEXT, 99 | K_F1 = VK_F1, 100 | K_F2 = VK_F2, 101 | K_F3 = VK_F3, 102 | K_F4 = VK_F4, 103 | K_F5 = VK_F5, 104 | K_F6 = VK_F6, 105 | K_F7 = VK_F7, 106 | K_F8 = VK_F8, 107 | K_F9 = VK_F9, 108 | K_F10 = VK_F10, 109 | K_F11 = VK_F11, 110 | K_F12 = VK_F12, 111 | K_META = VK_LWIN, 112 | K_CONTROL = VK_CONTROL, 113 | K_SHIFT = VK_SHIFT, 114 | K_ALT = VK_MENU, 115 | K_CAPSLOCK = VK_CAPITAL 116 | }; 117 | 118 | typedef int MMKeyCode; 119 | 120 | #endif 121 | 122 | /* Returns the keyCode corresponding to the current keyboard layout for the 123 | * given ASCII character. */ 124 | MMKeyCode keyCodeForChar(const char c); 125 | 126 | #endif /* KEYCODE_H */ 127 | -------------------------------------------------------------------------------- /src/keypress.c: -------------------------------------------------------------------------------- 1 | #include "keypress.h" 2 | #include "deadbeef_rand.h" 3 | #include "microsleep.h" 4 | 5 | #include /* For isupper() */ 6 | 7 | #if defined(IS_MACOSX) 8 | #include 9 | #elif defined(USE_X11) 10 | #include 11 | #include "xdisplay.h" 12 | #endif 13 | 14 | /* Convenience wrappers around ugly APIs. */ 15 | #if defined(IS_WINDOWS) 16 | #define WIN32_KEY_EVENT(key, flags) keybd_event(key, 0, flags, 0) 17 | #define WIN32_KEY_EVENT_WAIT(key, flags) \ 18 | (WIN32_KEY_EVENT(key, flags), Sleep(DEADBEEF_RANDRANGE(0, 63))) 19 | #elif defined(USE_X11) 20 | #define X_KEY_EVENT(display, key, is_press) \ 21 | (XTestFakeKeyEvent(display, \ 22 | XKeysymToKeycode(display, key), \ 23 | is_press, CurrentTime), \ 24 | XFlush(display)) 25 | #define X_KEY_EVENT_WAIT(display, key, is_press) \ 26 | (X_KEY_EVENT(display, key, is_press), \ 27 | microsleep(DEADBEEF_UNIFORM(0.0, 62.5))) 28 | #endif 29 | 30 | void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) 31 | { 32 | #if defined(IS_MACOSX) 33 | CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 34 | (CGKeyCode)code, down); 35 | assert(keyEvent != NULL); 36 | 37 | CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp); 38 | CGEventSetFlags(keyEvent, flags); 39 | CGEventPost(kCGSessionEventTap, keyEvent); 40 | CFRelease(keyEvent); 41 | #elif defined(IS_WINDOWS) 42 | const DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP; 43 | 44 | /* Parse modifier keys. */ 45 | if (flags & MOD_META) WIN32_KEY_EVENT_WAIT(K_META, dwFlags); 46 | if (flags & MOD_ALT) WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags); 47 | if (flags & MOD_CONTROL) WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags); 48 | if (flags & MOD_SHIFT) WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags); 49 | 50 | WIN32_KEY_EVENT(code, dwFlags); 51 | #elif defined(USE_X11) 52 | Display *display = XGetMainDisplay(); 53 | const Bool is_press = down ? True : False; /* Just to be safe. */ 54 | 55 | /* Parse modifier keys. */ 56 | if (flags & MOD_META) X_KEY_EVENT_WAIT(display, K_META, is_press); 57 | if (flags & MOD_ALT) X_KEY_EVENT_WAIT(display, K_ALT, is_press); 58 | if (flags & MOD_CONTROL) X_KEY_EVENT_WAIT(display, K_CONTROL, is_press); 59 | if (flags & MOD_SHIFT) X_KEY_EVENT_WAIT(display, K_SHIFT, is_press); 60 | 61 | X_KEY_EVENT(display, code, is_press); 62 | #endif 63 | } 64 | 65 | void tapKeyCode(MMKeyCode code, MMKeyFlags flags) 66 | { 67 | toggleKeyCode(code, true, flags); 68 | toggleKeyCode(code, false, flags); 69 | } 70 | 71 | void toggleKey(char c, const bool down, MMKeyFlags flags) 72 | { 73 | if (isupper(c) && !(flags & MOD_SHIFT)) { 74 | flags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */ 75 | } 76 | toggleKeyCode(keyCodeForChar(c), down, flags); 77 | } 78 | 79 | void tapKey(char c, MMKeyFlags flags) 80 | { 81 | toggleKey(c, true, flags); 82 | toggleKey(c, false, flags); 83 | } 84 | 85 | #if defined(IS_MACOSX) 86 | void toggleUniKey(char c, const bool down) 87 | { 88 | /* This function relies on the convenient 89 | * CGEventKeyboardSetUnicodeString(), which allows us to not have to 90 | * convert characters to a keycode, but does not support adding modifier 91 | * flags. It is therefore only used in typeString() and typeStringDelayed() 92 | * -- if you need modifier keys, use the above functions instead. */ 93 | UniChar ch = (UniChar)c; /* Convert to unsigned char */ 94 | 95 | CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down); 96 | if (keyEvent == NULL) { 97 | fputs("Could not create keyboard event.\n", stderr); 98 | return; 99 | } 100 | 101 | CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch); 102 | 103 | CGEventPost(kCGSessionEventTap, keyEvent); 104 | CFRelease(keyEvent); 105 | } 106 | #else 107 | #define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE) 108 | #endif 109 | 110 | static void tapUniKey(char c) 111 | { 112 | toggleUniKey(c, true); 113 | toggleUniKey(c, false); 114 | } 115 | 116 | void typeString(const char *str) 117 | { 118 | while (*str != '\0') { 119 | tapUniKey(*str++); 120 | } 121 | } 122 | 123 | void typeStringDelayed(const char *str, const unsigned cpm) 124 | { 125 | /* Characters per second */ 126 | const double cps = (double)cpm / 60.0; 127 | 128 | /* Average milli-seconds per character */ 129 | const double mspc = (cps == 0.0) ? 0.0 : 1000.0 / cps; 130 | 131 | while (*str != '\0') { 132 | tapUniKey(*str++); 133 | microsleep(mspc + (DEADBEEF_UNIFORM(0.0, 62.5))); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/keypress.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef KEYPRESS_H 3 | #define KEYPRESS_H 4 | 5 | #include "os.h" 6 | #include "keycode.h" 7 | 8 | #if defined(_MSC_VER) 9 | #include "ms_stdbool.h" 10 | #else 11 | #include 12 | #endif 13 | 14 | #if defined(IS_MACOSX) 15 | 16 | enum _MMKeyFlags { 17 | MOD_NONE = 0, 18 | MOD_META = kCGEventFlagMaskCommand, 19 | MOD_ALT = kCGEventFlagMaskAlternate, 20 | MOD_CONTROL = kCGEventFlagMaskControl, 21 | MOD_SHIFT = kCGEventFlagMaskShift 22 | }; 23 | 24 | typedef CGEventFlags MMKeyFlags; 25 | 26 | #elif defined(USE_X11) 27 | 28 | enum _MMKeyFlags { 29 | MOD_NONE = 0, 30 | MOD_META = Mod4Mask, 31 | MOD_ALT = Mod1Mask, 32 | MOD_CONTROL = ControlMask, 33 | MOD_SHIFT = ShiftMask 34 | }; 35 | 36 | typedef unsigned int MMKeyFlags; 37 | 38 | #elif defined(IS_WINDOWS) 39 | 40 | enum _MMKeyFlags { 41 | MOD_NONE = 0, 42 | /* These are already defined by the Win32 API */ 43 | /* MOD_ALT = 0, 44 | MOD_CONTROL = 0, 45 | MOD_SHIFT = 0, */ 46 | MOD_META = MOD_WIN 47 | }; 48 | 49 | typedef unsigned int MMKeyFlags; 50 | 51 | #endif 52 | 53 | /* Toggles the given key down or up. */ 54 | void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags); 55 | 56 | /* Toggles the key down and then up. */ 57 | void tapKeyCode(MMKeyCode code, MMKeyFlags flags); 58 | 59 | /* Toggles the key corresponding to the given UTF character up or down. */ 60 | void toggleKey(char c, const bool down, MMKeyFlags flags); 61 | void tapKey(char c, MMKeyFlags flags); 62 | 63 | /* Sends a UTF-8 string without modifiers. */ 64 | void typeString(const char *str); 65 | 66 | /* Macro to convert WPM to CPM integers. 67 | * (the average English word length is 5.1 characters.) */ 68 | #define WPM_TO_CPM(WPM) (unsigned)(5.1 * WPM) 69 | 70 | /* Sends a string with partially random delays between each letter. Note that 71 | * deadbeef_srand() must be called before this function if you actually want 72 | * randomness. */ 73 | void typeStringDelayed(const char *str, const unsigned cpm); 74 | 75 | #endif /* KEYPRESS_H */ 76 | -------------------------------------------------------------------------------- /src/microsleep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MICROSLEEP_H 3 | #define MICROSLEEP_H 4 | 5 | #include "os.h" 6 | #include "inline_keywords.h" 7 | 8 | #if !defined(IS_WINDOWS) 9 | /* Make sure nanosleep gets defined even when using C89. */ 10 | #if !defined(__USE_POSIX199309) || !__USE_POSIX199309 11 | #define __USE_POSIX199309 1 12 | #endif 13 | 14 | #include /* For nanosleep() */ 15 | #endif 16 | 17 | /* 18 | * A more widely supported alternative to usleep(), based on Sleep() in Windows 19 | * and nanosleep() everywhere else. 20 | * 21 | * Pauses execution for the given amount of milliseconds. 22 | */ 23 | H_INLINE void microsleep(double milliseconds) 24 | { 25 | #if defined(IS_WINDOWS) 26 | Sleep((DWORD)milliseconds); /* (Unfortunately truncated to a 32-bit integer.) */ 27 | #else 28 | /* Technically, nanosleep() is not an ANSI function, but it is the most 29 | * supported precise sleeping function I can find. 30 | * 31 | * If it is really necessary, it may be possible to emulate this with some 32 | * hack using select() in the future if we really have to. */ 33 | struct timespec sleepytime; 34 | sleepytime.tv_sec = milliseconds / 1000; 35 | sleepytime.tv_nsec = (milliseconds - (sleepytime.tv_sec * 1000)) * 1000000; 36 | nanosleep(&sleepytime, NULL); 37 | #endif 38 | } 39 | 40 | #endif /* MICROSLEEP_H */ 41 | -------------------------------------------------------------------------------- /src/mouse.c: -------------------------------------------------------------------------------- 1 | #include "mouse.h" 2 | #include "screen.h" 3 | #include "deadbeef_rand.h" 4 | #include "microsleep.h" 5 | 6 | #include /* For floor() */ 7 | 8 | #if defined(IS_MACOSX) 9 | #include 10 | #elif defined(USE_X11) 11 | #include 12 | #include 13 | #include "xdisplay.h" 14 | #endif 15 | 16 | #if !defined(M_SQRT2) 17 | #define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */ 18 | #endif 19 | 20 | void moveMouse(MMPoint point) 21 | { 22 | #if defined(IS_MACOSX) 23 | CGEventRef move = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, 24 | CGPointFromMMPoint(point), 25 | 0); 26 | CGEventPost(kCGSessionEventTap, move); 27 | CFRelease(move); 28 | #elif defined(USE_X11) 29 | Display *display = XGetMainDisplay(); 30 | XWarpPointer(display, None, DefaultRootWindow(display), 31 | 0, 0, 0, 0, point.x, point.y); 32 | XFlush(display); 33 | #elif defined(IS_WINDOWS) 34 | point.x *= 0xFFFF / GetSystemMetrics(SM_CXSCREEN); 35 | point.y *= 0xFFFF / GetSystemMetrics(SM_CYSCREEN); 36 | mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, 37 | (DWORD)point.x, (DWORD)point.y, 0, 0); 38 | #endif 39 | } 40 | 41 | MMPoint getMousePos() 42 | { 43 | #if defined(IS_MACOSX) 44 | CGEventRef event = CGEventCreate(NULL); 45 | CGPoint point = CGEventGetLocation(event); 46 | CFRelease(event); 47 | 48 | return MMPointFromCGPoint(point); 49 | #elif defined(USE_X11) 50 | int x, y; /* This is all we care about. Seriously. */ 51 | Window garb1, garb2; /* Why you can't specify NULL as a parameter */ 52 | int garb_x, garb_y; /* is beyond me. */ 53 | unsigned int more_garbage; 54 | 55 | Display *display = XGetMainDisplay(); 56 | XQueryPointer(display, XDefaultRootWindow(display), &garb1, &garb2, 57 | &x, &y, &garb_x, &garb_y, &more_garbage); 58 | 59 | return MMPointMake(x, y); 60 | #elif defined(IS_WINDOWS) 61 | POINT point; 62 | GetCursorPos(&point); 63 | 64 | return MMPointFromPOINT(point); 65 | #endif 66 | } 67 | 68 | /* Some convenience macros for converting our enums to the system API types. */ 69 | #if defined(IS_MACOSX) 70 | 71 | #define MMMouseToCGEventType(down, button) \ 72 | (down ? MMMouseDownToCGEventType(button) : MMMouseUpToCGEventType(button)) 73 | 74 | #define MMMouseDownToCGEventType(button) \ 75 | ((button) == (LEFT_BUTTON) ? kCGEventLeftMouseDown \ 76 | : ((button) == RIGHT_BUTTON ? kCGEventRightMouseDown \ 77 | : kCGEventOtherMouseDown)) 78 | 79 | #define MMMouseUpToCGEventType(button) \ 80 | ((button) == LEFT_BUTTON ? kCGEventLeftMouseUp \ 81 | : ((button) == RIGHT_BUTTON ? kCGEventRightMouseUp \ 82 | : kCGEventOtherMouseUp)) 83 | 84 | #elif defined(IS_WINDOWS) 85 | 86 | #define MMMouseToMEventF(down, button) \ 87 | (down ? MMMouseDownToMEventF(button) : MMMouseUpToMEventF(button)) 88 | 89 | #define MMMouseUpToMEventF(button) \ 90 | ((button) == LEFT_BUTTON ? MOUSEEVENTF_LEFTUP \ 91 | : ((button) == RIGHT_BUTTON ? MOUSEEVENTF_RIGHTUP \ 92 | : MOUSEEVENTF_MIDDLEUP)) 93 | 94 | #define MMMouseDownToMEventF(button) \ 95 | ((button) == LEFT_BUTTON ? MOUSEEVENTF_LEFTDOWN \ 96 | : ((button) == RIGHT_BUTTON ? MOUSEEVENTF_RIGHTDOWN \ 97 | : MOUSEEVENTF_MIDDLEDOWN)) 98 | 99 | #endif 100 | 101 | void toggleMouse(bool down, MMMouseButton button) 102 | { 103 | #if defined(IS_MACOSX) 104 | const CGPoint currentPos = CGPointFromMMPoint(getMousePos()); 105 | const CGEventType mouseType = MMMouseToCGEventType(down, button); 106 | CGEventRef event = CGEventCreateMouseEvent(NULL, 107 | mouseType, 108 | currentPos, 109 | (CGMouseButton)button); 110 | CGEventPost(kCGSessionEventTap, event); 111 | CFRelease(event); 112 | #elif defined(USE_X11) 113 | Display *display = XGetMainDisplay(); 114 | XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime); 115 | XFlush(display); 116 | #elif defined(IS_WINDOWS) 117 | mouse_event(MMMouseToMEventF(down, button), 0, 0, 0, 0); 118 | #endif 119 | } 120 | 121 | void clickMouse(MMMouseButton button) 122 | { 123 | toggleMouse(true, button); 124 | toggleMouse(false, button); 125 | } 126 | 127 | /* 128 | * A crude, fast hypot() approximation to get around the fact that hypot() is 129 | * not a standard ANSI C function. 130 | * 131 | * It is not particularly accurate but that does not matter for our use case. 132 | * 133 | * Taken from this StackOverflow answer: 134 | * http://stackoverflow.com/questions/3506404/fast-hypotenuse-algorithm-for-embedded-processor#3507882 135 | * 136 | */ 137 | static double crude_hypot(double x, double y) 138 | { 139 | double big = fabs(x); /* max(|x|, |y|) */ 140 | double small = fabs(y); /* min(|x|, |y|) */ 141 | 142 | if (big > small) { 143 | double temp = big; 144 | big = small; 145 | small = temp; 146 | } 147 | 148 | return ((M_SQRT2 - 1.0) * small) + big; 149 | } 150 | 151 | bool smoothlyMoveMouse(MMPoint endPoint) 152 | { 153 | MMPoint pos = getMousePos(); 154 | MMSize screenSize = getMainDisplaySize(); 155 | double velo_x = 0.0, velo_y = 0.0; 156 | double distance; 157 | 158 | while ((distance = crude_hypot((double)pos.x - endPoint.x, 159 | (double)pos.y - endPoint.y)) > 1.0) { 160 | double gravity = DEADBEEF_UNIFORM(5.0, 500.0); 161 | double veloDistance; 162 | velo_x += (gravity * ((double)endPoint.x - pos.x)) / distance; 163 | velo_y += (gravity * ((double)endPoint.y - pos.y)) / distance; 164 | 165 | /* Normalize velocity to get a unit vector of length 1. */ 166 | veloDistance = crude_hypot(velo_x, velo_y); 167 | velo_x /= veloDistance; 168 | velo_y /= veloDistance; 169 | 170 | pos.x += floor(velo_x + 0.5); 171 | pos.y += floor(velo_y + 0.5); 172 | 173 | /* Make sure we are in the screen boundaries! 174 | * (Strange things will happen if we are not.) */ 175 | if (pos.x >= screenSize.width || pos.y >= screenSize.height) { 176 | return false; 177 | } 178 | 179 | moveMouse(pos); 180 | 181 | /* Wait 1 - 3 milliseconds. */ 182 | microsleep(DEADBEEF_UNIFORM(1.0, 3.0)); 183 | } 184 | 185 | return true; 186 | } 187 | -------------------------------------------------------------------------------- /src/mouse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef MOUSE_H 3 | #define MOUSE_H 4 | 5 | #include "os.h" 6 | #include "types.h" 7 | 8 | #if defined(_MSC_VER) 9 | #include "ms_stdbool.h" 10 | #else 11 | #include 12 | #endif 13 | 14 | #if defined(IS_MACOSX) 15 | 16 | #include 17 | 18 | enum _MMMouseButton { 19 | LEFT_BUTTON = kCGMouseButtonLeft, 20 | RIGHT_BUTTON = kCGMouseButtonRight, 21 | CENTER_BUTTON = kCGMouseButtonCenter 22 | }; 23 | typedef CGMouseButton MMMouseButton; 24 | 25 | #elif defined(USE_X11) 26 | 27 | enum _MMMouseButton { 28 | LEFT_BUTTON = 1, 29 | CENTER_BUTTON = 2, 30 | RIGHT_BUTTON = 3 31 | }; 32 | typedef unsigned int MMMouseButton; 33 | 34 | #elif defined(IS_WINDOWS) 35 | 36 | enum _MMMouseButton { 37 | LEFT_BUTTON = 1, 38 | CENTER_BUTTON = 2, 39 | RIGHT_BUTTON = 3 40 | }; 41 | typedef unsigned int MMMouseButton; 42 | 43 | #else 44 | #error "No mouse button constants set for platform" 45 | #endif 46 | 47 | #define MMMouseButtonIsValid(button) \ 48 | (button == LEFT_BUTTON || button == RIGHT_BUTTON || \ 49 | button == CENTER_BUTTON) 50 | 51 | /* Immediately moves the mouse to the given point on-screen. 52 | * It is up to the caller to ensure that this point is within the 53 | * screen boundaries. */ 54 | void moveMouse(MMPoint point); 55 | 56 | /* Smoothly moves the mouse from the current position to the given point. 57 | * deadbeef_srand() should be called before using this function. 58 | * 59 | * Returns false if unsuccessful (i.e. a point was hit that is outside of the 60 | * screen boundaries), or true if successful. */ 61 | bool smoothlyMoveMouse(MMPoint point); 62 | 63 | /* Returns the coordinates of the mouse on the current screen. */ 64 | MMPoint getMousePos(void); 65 | 66 | /* Holds down or releases the mouse with the given button in the current 67 | * position. */ 68 | void toggleMouse(bool down, MMMouseButton button); 69 | 70 | /* Clicks the mouse with the given button in the current position. */ 71 | void clickMouse(MMMouseButton button); 72 | 73 | #endif /* MOUSE_H */ 74 | -------------------------------------------------------------------------------- /src/ms_stdbool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #if !defined(MS_STDBOOL_H) && \ 3 | (!defined(__bool_true_false_are_defined) || __bool_true_false_are_defined) 4 | #define MS_STDBOOL_H 5 | 6 | #ifndef _MSC_VER 7 | #error "Use this header only with Microsoft Visual C++ compilers!" 8 | #endif /* _MSC_VER */ 9 | 10 | #define __bool_true_false_are_defined 1 11 | 12 | #ifndef __cplusplus 13 | 14 | #if defined(true) || defined(false) || defined(bool) 15 | #error "Boolean type already defined" 16 | #endif 17 | 18 | enum { 19 | false = 0, 20 | true = 1 21 | }; 22 | 23 | typedef unsigned char bool; 24 | 25 | #endif /* !__cplusplus */ 26 | 27 | #endif /* MS_STDBOOL_H */ 28 | -------------------------------------------------------------------------------- /src/ms_stdint.h: -------------------------------------------------------------------------------- 1 | /* ISO C9x compliant stdint.h for Microsoft Visual Studio 2 | * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 3 | * 4 | * Copyright (c) 2006-2008 Alexander Chemeris 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * 3. The name of the author may be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef _MSC_VER 32 | #error "Use this header only with Microsoft Visual C++ compilers!" 33 | #endif /* _MSC_VER */ 34 | 35 | #ifndef MSC_STDINT_H 36 | #define MSC_STDINT_H 37 | 38 | #if _MSC_VER > 1000 39 | #pragma once 40 | #endif 41 | 42 | #include 43 | 44 | /* For Visual Studio 6 in C++ mode and for many Visual Studio versions when 45 | * compiling for ARM we should wrap include with 'extern "C++" {}' 46 | * or compiler give many errors like this: */ 47 | #if defined(__cplusplus) 48 | extern "C" { 49 | #endif /* __cplusplus */ 50 | #include 51 | #if defined(__cplusplus) 52 | } 53 | #endif /* __cplusplus */ 54 | 55 | /* Define _W64 macros to mark types changing their size, like intptr_t. */ 56 | #ifndef _W64 57 | #if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 58 | #define _W64 __w64 59 | #else 60 | #define _W64 61 | #endif 62 | #endif 63 | 64 | 65 | /* 7.18.1 Integer types */ 66 | 67 | /* 7.18.1.1 Exact-width integer types */ 68 | 69 | /* Visual Studio 6 and Embedded Visual C++ 4 doesn't 70 | * realize that, e.g. char has the same size as __int8 71 | * so we give up on __intX for them. */ 72 | #if _MSC_VER < 1300 73 | typedef signed char int8_t; 74 | typedef signed short int16_t; 75 | typedef signed int int32_t; 76 | typedef unsigned char uint8_t; 77 | typedef unsigned short uint16_t; 78 | typedef unsigned int uint32_t; 79 | #else 80 | typedef signed __int8 int8_t; 81 | typedef signed __int16 int16_t; 82 | typedef signed __int32 int32_t; 83 | typedef unsigned __int8 uint8_t; 84 | typedef unsigned __int16 uint16_t; 85 | typedef unsigned __int32 uint32_t; 86 | #endif 87 | typedef signed __int64 int64_t; 88 | typedef unsigned __int64 uint64_t; 89 | 90 | /* 7.18.1.2 Minimum-width integer types */ 91 | typedef int8_t int_least8_t; 92 | typedef int16_t int_least16_t; 93 | typedef int32_t int_least32_t; 94 | typedef int64_t int_least64_t; 95 | typedef uint8_t uint_least8_t; 96 | typedef uint16_t uint_least16_t; 97 | typedef uint32_t uint_least32_t; 98 | typedef uint64_t uint_least64_t; 99 | 100 | /* 7.18.1.3 Fastest minimum-width integer types */ 101 | typedef int8_t int_fast8_t; 102 | typedef int16_t int_fast16_t; 103 | typedef int32_t int_fast32_t; 104 | typedef int64_t int_fast64_t; 105 | typedef uint8_t uint_fast8_t; 106 | typedef uint16_t uint_fast16_t; 107 | typedef uint32_t uint_fast32_t; 108 | typedef uint64_t uint_fast64_t; 109 | 110 | /* 7.18.1.4 Integer types capable of holding object pointers */ 111 | #if defined(_WIN64) 112 | typedef signed __int64 intptr_t; 113 | typedef unsigned __int64 uintptr_t; 114 | #else 115 | typedef _W64 signed int intptr_t; 116 | typedef _W64 unsigned int uintptr_t; 117 | #endif /* _WIN64 ] */ 118 | 119 | /* 7.18.1.5 Greatest-width integer types */ 120 | typedef int64_t intmax_t; 121 | typedef uint64_t uintmax_t; 122 | 123 | /* 7.18.2 Limits of specified-width integer types */ 124 | 125 | /* See footnote 220 at page 257 and footnote 221 at page 259 */ 126 | #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) 127 | 128 | /* 7.18.2.1 Limits of exact-width integer types */ 129 | #define INT8_MIN ((int8_t)_I8_MIN) 130 | #define INT8_MAX _I8_MAX 131 | #define INT16_MIN ((int16_t)_I16_MIN) 132 | #define INT16_MAX _I16_MAX 133 | #define INT32_MIN ((int32_t)_I32_MIN) 134 | #define INT32_MAX _I32_MAX 135 | #define INT64_MIN ((int64_t)_I64_MIN) 136 | #define INT64_MAX _I64_MAX 137 | #define UINT8_MAX _UI8_MAX 138 | #define UINT16_MAX _UI16_MAX 139 | #define UINT32_MAX _UI32_MAX 140 | #define UINT64_MAX _UI64_MAX 141 | 142 | /* 7.18.2.2 Limits of minimum-width integer types */ 143 | #define INT_LEAST8_MIN INT8_MIN 144 | #define INT_LEAST8_MAX INT8_MAX 145 | #define INT_LEAST16_MIN INT16_MIN 146 | #define INT_LEAST16_MAX INT16_MAX 147 | #define INT_LEAST32_MIN INT32_MIN 148 | #define INT_LEAST32_MAX INT32_MAX 149 | #define INT_LEAST64_MIN INT64_MIN 150 | #define INT_LEAST64_MAX INT64_MAX 151 | #define UINT_LEAST8_MAX UINT8_MAX 152 | #define UINT_LEAST16_MAX UINT16_MAX 153 | #define UINT_LEAST32_MAX UINT32_MAX 154 | #define UINT_LEAST64_MAX UINT64_MAX 155 | 156 | /* 7.18.2.4 Limits of integer types capable of holding object pointers */ 157 | #if defined(_WIN64) 158 | #define INTPTR_MIN INT64_MIN 159 | #define INTPTR_MAX INT64_MAX 160 | #define UINTPTR_MAX UINT64_MAX 161 | #else 162 | #define INTPTR_MIN INT32_MIN 163 | #define INTPTR_MAX INT32_MAX 164 | #define UINTPTR_MAX UINT32_MAX 165 | #endif 166 | 167 | /* 7.18.3 Limits of other integer types */ 168 | 169 | #if defined(_WIN64) 170 | #define PTRDIFF_MIN _I64_MIN 171 | #define PTRDIFF_MAX _I64_MAX 172 | #else 173 | #define PTRDIFF_MIN _I32_MIN 174 | #define PTRDIFF_MAX _I32_MAX 175 | #endif /* _WIN64 */ 176 | 177 | #define SIG_ATOMIC_MIN INT_MIN 178 | #define SIG_ATOMIC_MAX INT_MAX 179 | 180 | #ifndef SIZE_MAX 181 | #if defined(_WIN64) 182 | #define SIZE_MAX _UI64_MAX 183 | #else 184 | #define SIZE_MAX _UI32_MAX 185 | #endif 186 | #endif 187 | 188 | /* WCHAR_MIN and WCHAR_MAX are also defined in */ 189 | #ifndef WCHAR_MIN 190 | #define WCHAR_MIN 0 191 | #endif /* WCHAR_MIN */ 192 | 193 | #ifndef WCHAR_MAX 194 | #define WCHAR_MAX _UI16_MAX 195 | #endif /* WCHAR_MAX */ 196 | 197 | #define WINT_MIN 0 198 | #define WINT_MAX _UI16_MAX 199 | #endif /* __STDC_LIMIT_MACROS */ 200 | 201 | 202 | /* 7.18.4 Limits of other integer types */ 203 | 204 | #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* See footnote 224 at page 260 */ 205 | 206 | /* 7.18.4.1 Macros for minimum-width integer constants */ 207 | 208 | #define INT8_C(val) val##i8 209 | #define INT16_C(val) val##i16 210 | #define INT32_C(val) val##i32 211 | #define INT64_C(val) val##i64 212 | 213 | #define UINT8_C(val) val##ui8 214 | #define UINT16_C(val) val##ui16 215 | #define UINT32_C(val) val##ui32 216 | #define UINT64_C(val) val##ui64 217 | 218 | /* 7.18.4.2 Macros for greatest-width integer constants */ 219 | #define INTMAX_C INT64_C 220 | #define UINTMAX_C UINT64_C 221 | 222 | #endif /* __STDC_CONSTANT_MACROS */ 223 | 224 | #endif /* MSC_STDINT_H */ 225 | -------------------------------------------------------------------------------- /src/os.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef OS_H 3 | #define OS_H 4 | 5 | /* Python versions under 2.5 don't support this macro, but it's not 6 | * terribly difficult to replicate: */ 7 | #ifndef PyModule_AddIntMacro 8 | #define PyModule_AddIntMacro(module, macro) \ 9 | PyModule_AddIntConstant(module, #macro, macro) 10 | #endif /* PyModule_AddIntMacro */ 11 | 12 | #if !defined(IS_MACOSX) && defined(__APPLE__) && defined(__MACH__) 13 | #define IS_MACOSX 14 | #endif /* IS_MACOSX */ 15 | 16 | #if !defined(IS_WINDOWS) && (defined(WIN32) || defined(_WIN32) || \ 17 | defined(__WIN32__) || defined(__WINDOWS__)) 18 | #define IS_WINDOWS 19 | #endif /* IS_WINDOWS */ 20 | 21 | #if !defined(USE_X11) && !defined(NUSE_X11) && !defined(IS_MACOSX) && !defined(IS_WINDOWS) 22 | #define USE_X11 23 | #endif /* USE_X11 */ 24 | 25 | #if defined(IS_WINDOWS) 26 | #define STRICT /* Require use of exact types. */ 27 | #define WIN32_LEAN_AND_MEAN 1 /* Speed up compilation. */ 28 | #include 29 | #elif !defined(IS_MACOSX) && !defined(USE_X11) 30 | #error "Sorry, this platform isn't supported yet!" 31 | #endif 32 | 33 | /* Interval to align by for large buffers (e.g. bitmaps). */ 34 | /* Must be a power of 2. */ 35 | #ifndef BYTE_ALIGN 36 | #define BYTE_ALIGN 4 /* Bytes to align pixel buffers to. */ 37 | /* #include */ 38 | /* #define BYTE_ALIGN (sizeof(size_t)) */ 39 | #endif /* BYTE_ALIGN */ 40 | 41 | #if BYTE_ALIGN == 0 42 | /* No alignment needed. */ 43 | #define ADD_PADDING(width) (width) 44 | #else 45 | /* Aligns given width to padding. */ 46 | #define ADD_PADDING(width) (BYTE_ALIGN + (((width) - 1) & ~(BYTE_ALIGN - 1))) 47 | #endif 48 | 49 | #endif /* OS_H */ 50 | -------------------------------------------------------------------------------- /src/pasteboard.c: -------------------------------------------------------------------------------- 1 | #include "pasteboard.h" 2 | #include "os.h" 3 | 4 | #if defined(IS_MACOSX) 5 | #include "png_io.h" 6 | #include 7 | #elif defined(IS_WINDOWS) 8 | #include "bmp_io.h" 9 | #endif 10 | 11 | MMPasteError copyMMBitmapToPasteboard(MMBitmapRef bitmap) 12 | { 13 | #if defined(IS_MACOSX) 14 | PasteboardRef clipboard; 15 | 16 | size_t len; 17 | uint8_t *pngbuf; 18 | CFDataRef data; 19 | OSStatus err; 20 | 21 | if (PasteboardCreate(kPasteboardClipboard, &clipboard) != noErr) { 22 | return kMMPasteOpenError; 23 | } 24 | 25 | if (PasteboardClear(clipboard) != noErr) { 26 | CFRelease(clipboard); 27 | return kMMPasteClearError; 28 | } 29 | 30 | pngbuf = createPNGData(bitmap, &len); 31 | if (pngbuf == NULL) { 32 | CFRelease(clipboard); 33 | return kMMPasteDataError; 34 | } 35 | 36 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pngbuf, len, 37 | kCFAllocatorNull); 38 | if (data == NULL) { 39 | CFRelease(clipboard); 40 | free(pngbuf); 41 | return kMMPasteDataError; 42 | } 43 | 44 | err = PasteboardPutItemFlavor(clipboard, bitmap, kUTTypePNG, data, 0); 45 | CFRelease(data); 46 | CFRelease(clipboard); 47 | free(pngbuf); 48 | return (err == noErr) ? kMMPasteNoError : kMMPastePasteError; 49 | #elif defined(IS_WINDOWS) 50 | MMPasteError ret = kMMPasteNoError; 51 | uint8_t *bmpData; 52 | size_t len; 53 | HGLOBAL handle; 54 | 55 | if (!OpenClipboard(NULL)) return kMMPasteOpenError; 56 | if (!EmptyClipboard()) return kMMPasteClearError; 57 | 58 | bmpData = createBitmapData(bitmap, &len); 59 | if (bmpData == NULL) return kMMPasteDataError; 60 | 61 | /* CF_DIB does not include the BITMAPFILEHEADER struct (and displays a 62 | * cryptic error if it is included). */ 63 | len -= sizeof(BITMAPFILEHEADER); 64 | 65 | /* SetClipboardData() needs a "handle", not just a buffer, so we have to 66 | * allocate one with GlobalAlloc(). */ 67 | if ((handle = GlobalAlloc(GMEM_MOVEABLE, len)) == NULL) { 68 | CloseClipboard(); 69 | free(bmpData); 70 | return kMMPasteDataError; 71 | } 72 | 73 | memcpy(GlobalLock(handle), bmpData + sizeof(BITMAPFILEHEADER), len); 74 | GlobalUnlock(handle); 75 | free(bmpData); 76 | 77 | if (SetClipboardData(CF_DIB, handle) == NULL) { 78 | ret = kMMPastePasteError; 79 | } 80 | 81 | CloseClipboard(); 82 | GlobalFree(handle); 83 | return ret; 84 | #elif defined(USE_X11) 85 | /* TODO (X11's clipboard is _weird_.) */ 86 | return kMMPasteUnsupportedError; 87 | #endif 88 | } 89 | 90 | const char *MMPasteErrorString(MMPasteError err) 91 | { 92 | switch (err) { 93 | case kMMPasteOpenError: 94 | return "Could not open pasteboard"; 95 | case kMMPasteClearError: 96 | return "Could not clear pasteboard"; 97 | case kMMPasteDataError: 98 | return "Could not create image data from bitmap"; 99 | case kMMPastePasteError: 100 | return "Could not paste data"; 101 | case kMMPasteUnsupportedError: 102 | return "Unsupported platform"; 103 | default: 104 | return NULL; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/pasteboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PASTEBOARD_H 3 | #define PASTEBOARD_H 4 | 5 | #include "MMBitmap.h" 6 | #include "io.h" 7 | 8 | enum _MMBitmapPasteError { 9 | kMMPasteNoError = 0, 10 | kMMPasteGenericError, 11 | kMMPasteOpenError, 12 | kMMPasteClearError, 13 | kMMPasteDataError, 14 | kMMPastePasteError, 15 | kMMPasteUnsupportedError 16 | }; 17 | 18 | typedef MMIOError MMPasteError; 19 | 20 | /* Copies |bitmap| to the pasteboard as a PNG. 21 | * Returns 0 on success, non-zero on error. */ 22 | MMPasteError copyMMBitmapToPasteboard(MMBitmapRef bitmap); 23 | 24 | /* Returns description of given MMPasteError. 25 | * Returned string is constant and hence should not be freed. */ 26 | const char *MMPasteErrorString(MMPasteError error); 27 | 28 | #endif /* PASTEBOARD_H */ 29 | -------------------------------------------------------------------------------- /src/png_io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PNG_IO_H 3 | #define PNG_IO_H 4 | 5 | #include "MMBitmap.h" 6 | #include "io.h" 7 | 8 | enum _PNGReadError { 9 | kPNGGenericError = 0, 10 | kPNGReadError, 11 | kPNGAccessError, 12 | kPNGInvalidHeaderError 13 | }; 14 | 15 | typedef MMIOError MMPNGReadError; 16 | 17 | /* Returns description of given MMPNGReadError. 18 | * Returned string is constant and hence should not be freed. */ 19 | const char *MMPNGReadErrorString(MMIOError error); 20 | 21 | /* Attempts to read PNG file at path; returns new MMBitmap on success, or 22 | * NULL on error. If |error| is non-NULL, it will be set to the error code 23 | * on return. 24 | * Responsibility for destroy()'ing returned MMBitmap is left up to caller. */ 25 | MMBitmapRef newMMBitmapFromPNG(const char *path, MMPNGReadError *error); 26 | 27 | /* Attempts to write PNG at path; returns 0 on success, -1 on error. */ 28 | int saveMMBitmapAsPNG(MMBitmapRef bitmap, const char *path); 29 | 30 | /* Returns a buffer containing the raw PNG file data, ready to be saved to a 31 | * file. |len| will be set to the number of bytes allocated in the returned 32 | * buffer (it cannot be NULL). 33 | * 34 | * Responsibility for free()'ing data is left up to the caller. */ 35 | uint8_t *createPNGData(MMBitmapRef bitmap, size_t *len); 36 | 37 | #endif /* PNG_IO_H */ 38 | -------------------------------------------------------------------------------- /src/py-bitmap-class.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PY_BITMAP_CLASS_H 3 | #define PY_BITMAP_CLASS_H 4 | 5 | #include 6 | #include /* For PyObject_HEAD, etc. */ 7 | #include "MMBitmap.h" 8 | 9 | /* This file defines the class "Bitmap" for dealing with raw bitmaps. */ 10 | struct _BitmapObject { 11 | PyObject_HEAD 12 | MMBitmapRef bitmap; 13 | MMPoint point; /* For iterator */ 14 | }; 15 | 16 | typedef struct _BitmapObject BitmapObject; 17 | 18 | extern PyTypeObject Bitmap_Type; 19 | 20 | /* Returns a newly-initialized BitmapObject from the given MMBitmap. 21 | * The reference to |bitmap| is "stolen"; i.e., only the pointer is copied, and 22 | * the reponsibility for free()'ing the buffer is given to the |BitmapObject|. 23 | * 24 | * Remember to call PyType_Ready() before using this for the first time! */ 25 | PyObject *BitmapObject_FromMMBitmap(MMBitmapRef bitmap); 26 | 27 | #endif /* PY_BITMAP_CLASS_H */ 28 | -------------------------------------------------------------------------------- /src/py-convenience.c: -------------------------------------------------------------------------------- 1 | #include "py-convenience.h" 2 | 3 | int Py_AddClassToModule(PyObject *mod, PyTypeObject *classType) 4 | { 5 | if (PyType_Ready(classType) < 0) return -1; 6 | 7 | Py_INCREF(classType); 8 | return PyModule_AddObject(mod, classType->tp_name, (PyObject *)classType); 9 | } 10 | 11 | void PyErr_SetFormatString(PyObject *type, size_t size, 12 | const char *format, ...) 13 | { 14 | char *str = malloc(sizeof(char) * (size + 1)); 15 | va_list va; 16 | if (str == NULL) return; 17 | 18 | va_start(va, format); 19 | PyOS_vsnprintf(str, size, format, va); 20 | va_end(va); 21 | 22 | PyErr_SetString(type, str); 23 | free(str); 24 | } 25 | 26 | PyObject *Py_SetArgConvertErr(const char *expected, unsigned arg_count, 27 | PyObject *obj) 28 | { 29 | PyErr_SetFormatString(PyExc_TypeError, 130, 30 | "argument %u must be %.50s, not %.50s", 31 | arg_count, expected, obj->ob_type->tp_name); 32 | return NULL; 33 | } 34 | 35 | PyObject *Py_SetConvertErr(const char *expected, PyObject *obj) 36 | { 37 | PyErr_SetFormatString(PyExc_TypeError, 123, 38 | "argument must be %.50s, not %.50s", 39 | expected, obj->ob_type->tp_name); 40 | return NULL; 41 | } 42 | -------------------------------------------------------------------------------- /src/py-convenience.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PYCONVENIENCE_H 3 | #define PYCONVENIENCE_H 4 | 5 | #include 6 | 7 | /* Checks class is ready and adds it to module. 8 | * 0 is returned on success, -1 on failure. */ 9 | int Py_AddClassToModule(PyObject *mod, PyTypeObject *classType); 10 | 11 | /* Convenience wrapper around PyOS_snprintf() and PyErr_SetString(). */ 12 | void PyErr_SetFormatString(PyObject *type, size_t size, 13 | const char *format, ...); 14 | 15 | /* Throws a convert error just as PyArg_ParseTuple() would. */ 16 | /* Always returns NULL for convenience. */ 17 | PyObject *Py_SetArgConvertErr(const char *expected, unsigned arg_count, 18 | PyObject *obj); 19 | 20 | PyObject *Py_SetConvertErr(const char *expected, PyObject *obj); 21 | 22 | #endif /* PYCONVENIENCE_H */ 23 | -------------------------------------------------------------------------------- /src/rgb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef RGB_H 3 | #define RGB_H 4 | 5 | #include /* For abs() */ 6 | #include 7 | #include "inline_keywords.h" /* For H_INLINE */ 8 | 9 | #if defined(_MSC_VER) 10 | #include "ms_stdint.h" 11 | #else 12 | #include 13 | #endif 14 | 15 | /* RGB colors in MMBitmaps are stored as BGR for convenience in converting 16 | * to/from certain formats (mainly OpenGL). 17 | * 18 | * It is best not to rely on the order (simply use rgb.{blue,green,red} to 19 | * access values), but some situations (e.g., glReadPixels) require one to 20 | * do so. In that case, check to make sure to use MMRGB_IS_BGR for future 21 | * compatibility. */ 22 | 23 | /* #define MMRGB_IS_BGR (offsetof(MMRGBColor, red) > offsetof(MMRGBColor, blue)) */ 24 | #define MMRGB_IS_BGR 1 25 | 26 | struct _MMRGBColor { 27 | uint8_t blue; 28 | uint8_t green; 29 | uint8_t red; 30 | }; 31 | 32 | typedef struct _MMRGBColor MMRGBColor; 33 | 34 | /* MMRGBHex is a hexadecimal color value, akin to HTML's, in the form 0xRRGGBB 35 | * where RR is the red value expressed as hexadecimal, GG is the green value, 36 | * and BB is the blue value. */ 37 | typedef uint32_t MMRGBHex; 38 | 39 | #define MMRGBHEX_MIN 0x000000 40 | #define MMRGBHEX_MAX 0xFFFFFF 41 | 42 | /* Converts rgb color to hexadecimal value. 43 | * |red|, |green|, and |blue| should each be of the type |uint8_t|, where the 44 | * range is 0 - 255. */ 45 | #define RGB_TO_HEX(red, green, blue) (((red) << 16) | ((green) << 8) | (blue)) 46 | 47 | /* Convenience wrapper for MMRGBColors. */ 48 | H_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb) 49 | { 50 | return RGB_TO_HEX(rgb.red, rgb.green, rgb.blue); 51 | } 52 | 53 | #define RED_FROM_HEX(hex) ((hex >> 16) & 0xFF) 54 | #define GREEN_FROM_HEX(hex) ((hex >> 8) & 0xFF) 55 | #define BLUE_FROM_HEX(hex) (hex & 0xFF) 56 | 57 | /* Converts hexadecimal color to MMRGBColor. */ 58 | H_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex) 59 | { 60 | MMRGBColor color; 61 | color.red = RED_FROM_HEX(hex); 62 | color.green = GREEN_FROM_HEX(hex); 63 | color.blue = BLUE_FROM_HEX(hex); 64 | return color; 65 | } 66 | 67 | /* Check absolute equality of two RGB colors. */ 68 | #define MMRGBColorEqualToColor(c1, c2) ((c1).red == (c2).red && \ 69 | (c1).blue == (c2).blue && \ 70 | (c1).green == (c2).green) 71 | 72 | /* Returns whether two colors are similar within the given range, |tolerance|. 73 | * Tolerance can be in the range 0.0f - 1.0f, where 0 denotes the exact 74 | * color and 1 denotes any color. */ 75 | H_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2, 76 | float tolerance) 77 | { 78 | /* Speedy case */ 79 | if (tolerance <= 0.0f) { 80 | return MMRGBColorEqualToColor(c1, c2); 81 | } else { /* Otherwise, use a Euclidean space to determine similarity */ 82 | uint8_t d1 = c1.red - c2.red; 83 | uint8_t d2 = c1.green - c2.green; 84 | uint8_t d3 = c1.blue - c2.blue; 85 | return sqrt((d1 * d1) + 86 | (d2 * d2) + 87 | (d3 * d3)) <= (tolerance * 442.0f); 88 | } 89 | 90 | } 91 | 92 | /* Identical to MMRGBColorSimilarToColor, only for hex values. */ 93 | H_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance) 94 | { 95 | if (tolerance <= 0.0f) { 96 | return h1 == h2; 97 | } else { 98 | uint8_t d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2); 99 | uint8_t d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2); 100 | uint8_t d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2); 101 | return sqrt((d1 * d1) + 102 | (d2 * d2) + 103 | (d3 * d3)) <= (tolerance * 442.0f); 104 | } 105 | } 106 | 107 | #endif /* RGB_H */ 108 | -------------------------------------------------------------------------------- /src/screen.c: -------------------------------------------------------------------------------- 1 | #include "screen.h" 2 | #include "os.h" 3 | 4 | #if defined(IS_MACOSX) 5 | #include 6 | #elif defined(USE_X11) 7 | #include 8 | #include "xdisplay.h" 9 | #endif 10 | 11 | MMSize getMainDisplaySize(void) 12 | { 13 | #if defined(IS_MACOSX) 14 | CGDirectDisplayID displayID = CGMainDisplayID(); 15 | return MMSizeMake(CGDisplayPixelsWide(displayID), 16 | CGDisplayPixelsHigh(displayID)); 17 | #elif defined(USE_X11) 18 | Display *display = XGetMainDisplay(); 19 | const int screen = DefaultScreen(display); 20 | 21 | return MMSizeMake((size_t)DisplayWidth(display, screen), 22 | (size_t)DisplayHeight(display, screen)); 23 | #elif defined(IS_WINDOWS) 24 | return MMSizeMake((size_t)GetSystemMetrics(SM_CXSCREEN), 25 | (size_t)GetSystemMetrics(SM_CYSCREEN)); 26 | #endif 27 | } 28 | 29 | bool pointVisibleOnMainDisplay(MMPoint point) 30 | { 31 | MMSize displaySize = getMainDisplaySize(); 32 | return point.x < displaySize.width && point.y < displaySize.height; 33 | } 34 | -------------------------------------------------------------------------------- /src/screen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SCREEN_H 3 | #define SCREEN_H 4 | 5 | #include "types.h" 6 | 7 | #if defined(_MSC_VER) 8 | #include "ms_stdbool.h" 9 | #else 10 | #include 11 | #endif 12 | 13 | /* Returns the size of the main display. */ 14 | MMSize getMainDisplaySize(void); 15 | 16 | /* Convenience function that returns whether the given point is in the bounds 17 | * of the main screen. */ 18 | bool pointVisibleOnMainDisplay(MMPoint point); 19 | 20 | #endif /* SCREEN_H */ 21 | -------------------------------------------------------------------------------- /src/screengrab.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef SCREENGRAB_H 3 | #define SCREENGRAB_H 4 | 5 | #include "types.h" 6 | #include "MMBitmap.h" 7 | 8 | /* Returns a raw bitmap of screengrab of the display (to be destroyed()'d by 9 | * caller), or NULL on error. */ 10 | MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect); 11 | 12 | #endif /* SCREENGRAB_H */ 13 | -------------------------------------------------------------------------------- /src/snprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef _PORTABLE_SNPRINTF_H_ 2 | #define _PORTABLE_SNPRINTF_H_ 3 | 4 | #define PORTABLE_SNPRINTF_VERSION_MAJOR 2 5 | #define PORTABLE_SNPRINTF_VERSION_MINOR 2 6 | 7 | #include "os.h" 8 | #if defined(IS_MACOSX) 9 | #define HAVE_SNPRINTF 10 | #else 11 | #define HAVE_SNPRINTF 12 | #define PREFER_PORTABLE_SNPRINTF 13 | #endif 14 | 15 | #include 16 | #include 17 | 18 | #ifdef HAVE_SNPRINTF 19 | #include 20 | #else 21 | extern int snprintf(char *, size_t, const char *, /*args*/ ...); 22 | extern int vsnprintf(char *, size_t, const char *, va_list); 23 | #endif 24 | 25 | #if defined(HAVE_SNPRINTF) && defined(PREFER_PORTABLE_SNPRINTF) 26 | extern int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); 27 | extern int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap); 28 | #define snprintf portable_snprintf 29 | #define vsnprintf portable_vsnprintf 30 | #endif 31 | 32 | extern int asprintf (char **ptr, const char *fmt, /*args*/ ...); 33 | extern int vasprintf (char **ptr, const char *fmt, va_list ap); 34 | extern int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); 35 | extern int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/str_io.c: -------------------------------------------------------------------------------- 1 | #include "str_io.h" 2 | #include "zlib_util.h" 3 | #include "base64.h" 4 | #include "snprintf.h" /* snprintf() */ 5 | #include /* fputs() */ 6 | #include /* isdigit() */ 7 | #include /* atoi() */ 8 | #include /* strlen() */ 9 | #include 10 | 11 | #if defined(_MSC_VER) 12 | #include "ms_stdbool.h" 13 | #else 14 | #include 15 | #endif 16 | 17 | #define STR_BITS_PER_PIXEL 24 18 | #define STR_BYTES_PER_PIXEL ((STR_BITS_PER_PIXEL) / 8) 19 | 20 | #define MAX_DIMENSION_LEN 5 /* Maximum length for [width] or [height] 21 | * in string. */ 22 | 23 | const char *MMBitmapStringErrorString(MMBMPStringError err) 24 | { 25 | switch (err) { 26 | case kMMBMPStringInvalidHeaderError: 27 | return "Invalid header for string"; 28 | case kMMBMPStringDecodeError: 29 | return "Error decoding string"; 30 | case kMMBMPStringDecompressError: 31 | return "Error decompressing string"; 32 | case kMMBMPStringSizeError: 33 | return "String not of expected size"; 34 | case MMMBMPStringEncodeError: 35 | return "Error encoding string"; 36 | case kMMBMPStringCompressError: 37 | return "Error compressing string"; 38 | default: 39 | return NULL; 40 | } 41 | } 42 | 43 | /* Parses beginning of string in the form of "[width],[height],*". 44 | * 45 | * If successful, |width| and |height| are set to the appropropriate values, 46 | * |len| is set to the length of [width] + the length of [height] + 2, 47 | * and true is returned; otherwise, false is returned. 48 | */ 49 | static bool getSizeFromString(const uint8_t *buf, size_t buflen, 50 | size_t *width, size_t *height, 51 | size_t *len); 52 | 53 | MMBitmapRef createMMBitmapFromString(const uint8_t *buffer, size_t buflen, 54 | MMBMPStringError *err) 55 | { 56 | uint8_t *decoded, *decompressed; 57 | size_t width, height; 58 | size_t len, bytewidth; 59 | 60 | if (*buffer++ != 'b' || !getSizeFromString(buffer, --buflen, 61 | &width, &height, &len)) { 62 | if (err != NULL) *err = kMMBMPStringInvalidHeaderError; 63 | return NULL; 64 | } 65 | buffer += len; 66 | buflen -= len; 67 | 68 | decoded = base64decode(buffer, buflen, NULL); 69 | if (decoded == NULL) { 70 | if (err != NULL) *err = kMMBMPStringDecodeError; 71 | return NULL; 72 | } 73 | 74 | decompressed = zlib_decompress(decoded, &len); 75 | free(decoded); 76 | 77 | if (decompressed == NULL) { 78 | if (err != NULL) *err = kMMBMPStringDecompressError; 79 | return NULL; 80 | } 81 | 82 | bytewidth = width * STR_BYTES_PER_PIXEL; /* Note that bytewidth is NOT 83 | * aligned to a padding. */ 84 | if (height * bytewidth != len) { 85 | if (err != NULL) *err = kMMBMPStringSizeError; 86 | return NULL; 87 | } 88 | 89 | return createMMBitmap(decompressed, width, height, 90 | bytewidth, STR_BITS_PER_PIXEL, STR_BYTES_PER_PIXEL); 91 | } 92 | 93 | /* Returns bitmap data suitable for encoding to a string; that is, 24-bit BGR 94 | * bitmap with no padding and 3 bytes per pixel. 95 | * 96 | * Caller is responsible for free()'ing returned buffer. */ 97 | static uint8_t *createRawBitmapData(MMBitmapRef bitmap); 98 | 99 | uint8_t *createStringFromMMBitmap(MMBitmapRef bitmap, MMBMPStringError *err) 100 | { 101 | uint8_t *raw, *compressed; 102 | uint8_t *ret, *encoded; 103 | size_t len, retlen; 104 | 105 | assert(bitmap != NULL); 106 | 107 | raw = createRawBitmapData(bitmap); 108 | if (raw == NULL) { 109 | if (err != NULL) *err = kMMBMPStringGenericError; 110 | return NULL; 111 | } 112 | 113 | compressed = zlib_compress(raw, 114 | bitmap->width * bitmap->height * 115 | STR_BYTES_PER_PIXEL, 116 | 9, &len); 117 | free(raw); 118 | if (compressed == NULL) { 119 | if (err != NULL) *err = kMMBMPStringCompressError; 120 | return NULL; 121 | } 122 | 123 | encoded = base64encode(compressed, len - 1, &retlen); 124 | free(compressed); 125 | if (encoded == NULL) { 126 | if (err != NULL) *err = MMMBMPStringEncodeError; 127 | return NULL; 128 | } 129 | 130 | retlen += 3 + (MAX_DIMENSION_LEN * 2); 131 | ret = calloc(sizeof(char), (retlen + 1)); 132 | snprintf((char *)ret, retlen, "b%lu,%lu,%s", (unsigned long)bitmap->width, 133 | (unsigned long)bitmap->height, 134 | encoded); 135 | ret[retlen] = '\0'; 136 | free(encoded); 137 | return ret; 138 | } 139 | 140 | static uint32_t parseDimension(const uint8_t *buf, size_t buflen, 141 | size_t *numlen); 142 | 143 | static bool getSizeFromString(const uint8_t *buf, size_t buflen, 144 | size_t *width, size_t *height, 145 | size_t *len) 146 | { 147 | size_t numlen; 148 | assert(buf != NULL); 149 | assert(width != NULL); 150 | assert(height != NULL); 151 | 152 | if ((*width = parseDimension(buf, buflen, &numlen)) == 0) { 153 | return false; 154 | } 155 | *len = numlen + 1; 156 | 157 | if ((*height = parseDimension(buf + *len, buflen, &numlen)) == 0) { 158 | return false; 159 | } 160 | *len += numlen + 1; 161 | 162 | return true; 163 | } 164 | 165 | /* Parses one dimension from string as described in getSizeFromString(). 166 | * Returns dimension on success, or 0 on error. */ 167 | static uint32_t parseDimension(const uint8_t *buf, size_t buflen, 168 | size_t *numlen) 169 | { 170 | char num[MAX_DIMENSION_LEN + 1]; 171 | size_t i; 172 | 173 | assert(buf != NULL); 174 | assert(len != NULL); 175 | for (i = 0; i < buflen && buf[i] != ',' && buf[i] != '\0'; ++i) { 176 | if (!isdigit(buf[i]) || i > MAX_DIMENSION_LEN) return 0; 177 | num[i] = buf[i]; 178 | } 179 | num[i] = '\0'; 180 | *numlen = i; 181 | 182 | return (uint32_t)atoi(num); 183 | } 184 | 185 | static uint8_t *createRawBitmapData(MMBitmapRef bitmap) 186 | { 187 | uint8_t *raw = calloc(STR_BYTES_PER_PIXEL, bitmap->width * bitmap->height); 188 | size_t y; 189 | 190 | for (y = 0; y < bitmap->height; ++y) { 191 | /* No padding is added to string bitmaps. */ 192 | const size_t rowOffset = y * bitmap->width * STR_BYTES_PER_PIXEL; 193 | size_t x; 194 | for (x = 0; x < bitmap->width; ++x) { 195 | /* Copy in BGR format. */ 196 | const size_t colOffset = x * STR_BYTES_PER_PIXEL; 197 | uint8_t *dest = raw + rowOffset + colOffset; 198 | MMRGBColor *srcColor = MMRGBColorRefAtPoint(bitmap, x, y); 199 | dest[0] = srcColor->blue; 200 | dest[1] = srcColor->green; 201 | dest[2] = srcColor->red; 202 | } 203 | } 204 | 205 | return raw; 206 | } 207 | -------------------------------------------------------------------------------- /src/str_io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef STR_IO_H 3 | #define STR_IO_H 4 | 5 | #include "MMBitmap.h" 6 | #include "io.h" 7 | 8 | #if defined(_MSC_VER) 9 | #include "ms_stdint.h" 10 | #else 11 | #include 12 | #endif 13 | 14 | enum _MMBMPStringError { 15 | kMMBMPStringGenericError = 0, 16 | kMMBMPStringInvalidHeaderError, 17 | kMMBMPStringDecodeError, 18 | kMMBMPStringDecompressError, 19 | kMMBMPStringSizeError, /* Size does not match header. */ 20 | MMMBMPStringEncodeError, 21 | kMMBMPStringCompressError 22 | }; 23 | 24 | typedef MMIOError MMBMPStringError; 25 | 26 | /* Creates a 24-bit bitmap from a compressed, printable string. 27 | * 28 | * String should be in the format: "b[width],[height],[data]", 29 | * where [width] and [height] are the image width & height, and [data] 30 | * is the raw image data run through zlib_compress() and base64_encode(). 31 | * 32 | * Returns NULL on error; follows the Create Rule (that is, the caller is 33 | * responsible for destroy'()ing object). 34 | * If |error| is non-NULL, it will be set to the error code on return. 35 | */ 36 | MMBitmapRef createMMBitmapFromString(const uint8_t *buffer, size_t buflen, 37 | MMBMPStringError *error); 38 | 39 | /* Inverse of createMMBitmapFromString(). 40 | * 41 | * Creates string in the format: "b[width],[height],[data]", where [width] and 42 | * [height] are the image width & height, and [data] is the raw image data run 43 | * through zlib_compress() and base64_encode(). 44 | * 45 | * Returns NULL on error, or new string on success (to be free'()d by caller). 46 | * If |error| is non-NULL, it will be set to the error code on return. 47 | */ 48 | uint8_t *createStringFromMMBitmap(MMBitmapRef bitmap, MMBMPStringError *error); 49 | 50 | /* Returns description of given error code. 51 | * Returned string is constant and hence should not be freed. */ 52 | const char *MMBitmapStringErrorString(MMBMPStringError err); 53 | 54 | #endif /* STR_IO_H */ 55 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef TYPES_H 3 | #define TYPES_H 4 | 5 | #include "os.h" 6 | #include "inline_keywords.h" /* For H_INLINE */ 7 | #include 8 | 9 | /* Some generic, cross-platform types. */ 10 | 11 | struct _MMPoint { 12 | size_t x; 13 | size_t y; 14 | }; 15 | 16 | typedef struct _MMPoint MMPoint; 17 | 18 | struct _MMSize { 19 | size_t width; 20 | size_t height; 21 | }; 22 | 23 | typedef struct _MMSize MMSize; 24 | 25 | struct _MMRect { 26 | MMPoint origin; 27 | MMSize size; 28 | }; 29 | 30 | typedef struct _MMRect MMRect; 31 | 32 | H_INLINE MMPoint MMPointMake(size_t x, size_t y) 33 | { 34 | MMPoint point; 35 | point.x = x; 36 | point.y = y; 37 | return point; 38 | } 39 | 40 | H_INLINE MMSize MMSizeMake(size_t width, size_t height) 41 | { 42 | MMSize size; 43 | size.width = width; 44 | size.height = height; 45 | return size; 46 | } 47 | 48 | H_INLINE MMRect MMRectMake(size_t x, size_t y, size_t width, size_t height) 49 | { 50 | MMRect rect; 51 | rect.origin = MMPointMake(x, y); 52 | rect.size = MMSizeMake(width, height); 53 | return rect; 54 | } 55 | 56 | #define MMPointZero MMPointMake(0, 0) 57 | 58 | #if defined(IS_MACOSX) 59 | 60 | #define CGPointFromMMPoint(p) CGPointMake((CGFloat)(p).x, (CGFloat)(p).y) 61 | #define MMPointFromCGPoint(p) MMPointMake((size_t)(p).x, (size_t)(p).y) 62 | 63 | #elif defined(IS_WINDOWS) 64 | 65 | #define MMPointFromPOINT(p) MMPointMake((size_t)p.x, (size_t)p.y) 66 | 67 | #endif 68 | 69 | #endif /* TYPES_H */ 70 | -------------------------------------------------------------------------------- /src/xdisplay.c: -------------------------------------------------------------------------------- 1 | #include "xdisplay.h" 2 | #include /* For fputs() */ 3 | #include /* For atexit() */ 4 | 5 | static Display *mainDisplay = NULL; 6 | static int registered = 0; 7 | 8 | Display *XGetMainDisplay(void) 9 | { 10 | if (mainDisplay == NULL) { 11 | mainDisplay = XOpenDisplay(NULL); 12 | 13 | if (mainDisplay == NULL) { 14 | fputs("Could not open main display\n", stderr); 15 | } else if (!registered) { 16 | atexit(&XCloseMainDisplay); 17 | registered = 1; 18 | } 19 | } 20 | 21 | return mainDisplay; 22 | } 23 | 24 | void XCloseMainDisplay(void) 25 | { 26 | if (mainDisplay != NULL) { 27 | XCloseDisplay(mainDisplay); 28 | mainDisplay = NULL; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/xdisplay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef XDISPLAY_H 3 | #define XDISPLAY_H 4 | 5 | #include 6 | 7 | /* Returns the main display, closed either on exit or when closeMainDisplay() 8 | * is invoked. This removes a bit of the overhead of calling XOpenDisplay() & 9 | * XCloseDisplay() everytime the main display needs to be used. 10 | * 11 | * Note that this is almost certainly not thread safe. */ 12 | Display *XGetMainDisplay(void); 13 | 14 | /* Closes the main display if it is open, or does nothing if not. */ 15 | void XCloseMainDisplay(void); 16 | 17 | #endif /* XDISPLAY_H */ 18 | -------------------------------------------------------------------------------- /src/zlib_util.c: -------------------------------------------------------------------------------- 1 | #include "zlib_util.h" 2 | #include 3 | #include /* fprintf() */ 4 | #include /* malloc() */ 5 | #include 6 | 7 | #define ZLIB_CHUNK (16 * 1024) 8 | 9 | uint8_t *zlib_decompress(const uint8_t *buf, size_t *len) 10 | { 11 | size_t output_size = ZLIB_CHUNK; 12 | uint8_t *output = malloc(output_size); 13 | int err; 14 | z_stream zst; 15 | 16 | /* Sanity check */ 17 | if (output == NULL) return NULL; 18 | assert(buf != NULL); 19 | 20 | /* Set inflate state */ 21 | zst.zalloc = Z_NULL; 22 | zst.zfree = Z_NULL; 23 | zst.opaque = Z_NULL; 24 | zst.next_out = (Byte *)output; 25 | zst.next_in = (Byte *)buf; 26 | zst.avail_out = ZLIB_CHUNK; 27 | 28 | if (inflateInit(&zst) != Z_OK) goto error; 29 | 30 | /* Decompress input buffer */ 31 | do { 32 | if ((err = inflate(&zst, Z_NO_FLUSH)) == Z_OK) { /* Need more memory */ 33 | zst.avail_out = (uInt)output_size; 34 | 35 | /* Double size each time to avoid calls to realloc() */ 36 | output_size <<= 1; 37 | output = realloc(output, output_size + 1); 38 | if (output == NULL) return NULL; 39 | 40 | zst.next_out = (Byte *)(output + zst.avail_out); 41 | } else if (err != Z_STREAM_END) { /* Error decompressing */ 42 | if (zst.msg != NULL) { 43 | fprintf(stderr, "Could not decompress data: %s\n", zst.msg); 44 | } 45 | inflateEnd(&zst); 46 | goto error; 47 | } 48 | } while (err != Z_STREAM_END); 49 | 50 | if (len != NULL) *len = zst.total_out; 51 | if (inflateEnd(&zst) != Z_OK) goto error; 52 | return output; /* To be free()'d by caller */ 53 | 54 | error: 55 | if (output != NULL) free(output); 56 | return NULL; 57 | } 58 | 59 | uint8_t *zlib_compress(const uint8_t *buf, const size_t buflen, int level, 60 | size_t *len) 61 | { 62 | z_stream zst; 63 | uint8_t *output = NULL; 64 | 65 | /* Sanity check */ 66 | assert(buf != NULL); 67 | assert(len != NULL); 68 | assert(level <= 9 && level >= 0); 69 | 70 | zst.avail_out = (uInt)((buflen + (buflen / 10)) + 12); 71 | output = malloc(zst.avail_out); 72 | if (output == NULL) return NULL; 73 | 74 | /* Set deflate state */ 75 | zst.zalloc = Z_NULL; 76 | zst.zfree = Z_NULL; 77 | zst.next_out = (Byte *)output; 78 | zst.next_in = (Byte *)buf; 79 | zst.avail_in = (uInt)buflen; 80 | 81 | if (deflateInit(&zst, level) != Z_OK) goto error; 82 | 83 | /* Compress input buffer */ 84 | if (deflate(&zst, Z_FINISH) != Z_STREAM_END) { 85 | if (zst.msg != NULL) { 86 | fprintf(stderr, "Could not compress data: %s\n", zst.msg); 87 | } 88 | deflateEnd(&zst); 89 | goto error; 90 | } 91 | 92 | if (len != NULL) *len = zst.total_out; 93 | if (deflateEnd(&zst) != Z_OK) goto error; 94 | return output; /* To be free()'d by caller */ 95 | 96 | error: 97 | if (output != NULL) free(output); 98 | return NULL; 99 | } 100 | -------------------------------------------------------------------------------- /src/zlib_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef ZLIB_UTIL_H 3 | #define ZLIB_UTIL_H 4 | 5 | #include 6 | 7 | #if defined(_MSC_VER) 8 | #include "ms_stdint.h" 9 | #else 10 | #include 11 | #endif 12 | 13 | /* Attempts to decompress given deflated NUL-terminated buffer. 14 | * 15 | * If successful and |len| is not NULL, |len| will be set to the number of 16 | * bytes in the returned buffer. 17 | * Returns new string to be free()'d by caller, or NULL on error. */ 18 | uint8_t *zlib_decompress(const uint8_t *buf, size_t *len); 19 | 20 | /* Attempt to compress given buffer. 21 | * 22 | * The compression level is passed directly to zlib: it must between 0 and 9, 23 | * where 1 gives best speed, 9 gives best compression, and 0 gives no 24 | * compression at all. 25 | * 26 | * If successful and |len| is not NULL, |len| will be set to the number of 27 | * bytes in the returned buffer. 28 | * Returns new string to be free()'d by caller, or NULL on error. */ 29 | uint8_t *zlib_compress(const uint8_t *buf, const size_t buflen, int level, 30 | size_t *len); 31 | 32 | #endif /* ZLIB_UTIL_H */ 33 | -------------------------------------------------------------------------------- /windows/README.txt: -------------------------------------------------------------------------------- 1 | This directory contains statically compiled binaries of libpng 1.5.2 and zlib 2 | 1.2.5. They were compiled using the "visualc71" project in the libpng 1.5.2 3 | source[1] on Microsoft Visual Studio 2008. 4 | 5 | The following settings were used: 6 | 7 | 1.) The instructions stated in README.txt in the visual71 directory were 8 | followed. 9 | 10 | 2.) The "Lib Release" Configuration was set for both libpng and zlib (pngtest 11 | was not built). 12 | 13 | 3.) For both libpng and zlib, on the Property Pages dialog under Configuration 14 | Properties > Library > General, "uuid.lib" was set under "Ignore Specific 15 | Library" in order to avoid a linking error. 16 | 17 | 4.) In addition, under Configuration Properties > C/C++ > Optimization, "Favor 18 | Small Code" was selected in order to produce smaller binaries. 19 | 20 | Using this approach, no external libraries or DLLs should be required for the 21 | user to install (outside of those already installed by Python). 22 | 23 | [1]: (Download: http://prdownloads.sourceforge.net/libpng/lpng152.zip?download 24 | Path: "projects/visualc71") 25 | -------------------------------------------------------------------------------- /windows/win32/libpng.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/autopilot-rs/autopy-legacy/1cbf4e842c4d43f706a16ac6106f77031ab00163/windows/win32/libpng.lib -------------------------------------------------------------------------------- /windows/win32/pnglibconf.h: -------------------------------------------------------------------------------- 1 | 2 | /* libpng STANDARD API DEFINITION */ 3 | 4 | /* pnglibconf.h - library build configuration */ 5 | 6 | /* libpng version 1.5.0 - last changed on February 11, 2011 */ 7 | 8 | /* Copyright (c) 1998-2011 Glenn Randers-Pehrson */ 9 | 10 | /* This code is released under the libpng license. */ 11 | /* For conditions of distribution and use, see the disclaimer */ 12 | /* and license in png.h */ 13 | 14 | /* pnglibconf.h */ 15 | /* Derived from: scripts/pnglibconf.dfa */ 16 | /* If you edit this file by hand you must obey the rules expressed in */ 17 | /* pnglibconf.dfa with respect to the dependencies between the following */ 18 | /* symbols. It is much better to generate a new file using */ 19 | /* scripts/libpngconf.mak */ 20 | 21 | #ifndef PNGLCONF_H 22 | #define PNGLCONF_H 23 | /* settings */ 24 | #define PNG_API_RULE 0 25 | #define PNG_CALLOC_SUPPORTED 26 | #define PNG_COST_SHIFT 3 27 | #define PNG_DEFAULT_READ_MACROS 1 28 | #define PNG_GAMMA_THRESHOLD_FIXED 5000 29 | #define PNG_MAX_GAMMA_8 11 30 | #define PNG_QUANTIZE_BLUE_BITS 5 31 | #define PNG_QUANTIZE_GREEN_BITS 5 32 | #define PNG_QUANTIZE_RED_BITS 5 33 | #define PNG_sCAL_PRECISION 5 34 | #define PNG_USER_CHUNK_CACHE_MAX 0 35 | #define PNG_USER_CHUNK_MALLOC_MAX 0 36 | #define PNG_USER_HEIGHT_MAX 1000000L 37 | #define PNG_USER_WIDTH_MAX 1000000L 38 | #define PNG_WEIGHT_SHIFT 8 39 | #define PNG_ZBUF_SIZE 8192 40 | /* end of settings */ 41 | /* options */ 42 | #define PNG_16BIT_SUPPORTED 43 | #define PNG_ALIGN_MEMORY_SUPPORTED 44 | #define PNG_BENIGN_ERRORS_SUPPORTED 45 | #define PNG_bKGD_SUPPORTED 46 | #define PNG_CHECK_cHRM_SUPPORTED 47 | #define PNG_cHRM_SUPPORTED 48 | #define PNG_CONSOLE_IO_SUPPORTED 49 | #define PNG_CONVERT_tIME_SUPPORTED 50 | #define PNG_EASY_ACCESS_SUPPORTED 51 | #define PNG_ERROR_TEXT_SUPPORTED 52 | #define PNG_FIXED_POINT_SUPPORTED 53 | #define PNG_FLOATING_ARITHMETIC_SUPPORTED 54 | #define PNG_FLOATING_POINT_SUPPORTED 55 | #define PNG_gAMA_SUPPORTED 56 | #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED 57 | #define PNG_hIST_SUPPORTED 58 | #define PNG_iCCP_SUPPORTED 59 | #define PNG_INCH_CONVERSIONS_SUPPORTED 60 | #define PNG_INFO_IMAGE_SUPPORTED 61 | #define PNG_IO_STATE_SUPPORTED 62 | #define PNG_iTXt_SUPPORTED 63 | #define PNG_MNG_FEATURES_SUPPORTED 64 | #define PNG_oFFs_SUPPORTED 65 | #define PNG_pCAL_SUPPORTED 66 | #define PNG_pHYs_SUPPORTED 67 | #define PNG_POINTER_INDEXING_SUPPORTED 68 | #define PNG_PROGRESSIVE_READ_SUPPORTED 69 | #define PNG_READ_16BIT_SUPPORTED 70 | #define PNG_READ_16_TO_8_SUPPORTED 71 | #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED 72 | #define PNG_READ_BACKGROUND_SUPPORTED 73 | #define PNG_READ_BGR_SUPPORTED 74 | #define PNG_READ_bKGD_SUPPORTED 75 | #define PNG_READ_cHRM_SUPPORTED 76 | #define PNG_READ_COMPOSITE_NODIV_SUPPORTED 77 | #define PNG_READ_EXPAND_16_SUPPORTED 78 | #define PNG_READ_EXPAND_SUPPORTED 79 | #define PNG_READ_FILLER_SUPPORTED 80 | #define PNG_READ_gAMA_SUPPORTED 81 | #define PNG_READ_GAMMA_SUPPORTED 82 | #define PNG_READ_GRAY_TO_RGB_SUPPORTED 83 | #define PNG_READ_hIST_SUPPORTED 84 | #define PNG_READ_iCCP_SUPPORTED 85 | #define PNG_READ_INTERLACING_SUPPORTED 86 | #define PNG_READ_INT_FUNCTIONS_SUPPORTED 87 | #define PNG_READ_INVERT_ALPHA_SUPPORTED 88 | #define PNG_READ_INVERT_SUPPORTED 89 | #define PNG_READ_iTXt_SUPPORTED 90 | #define PNG_READ_oFFs_SUPPORTED 91 | #define PNG_READ_OPT_PLTE_SUPPORTED 92 | #define PNG_READ_PACK_SUPPORTED 93 | #define PNG_READ_PACKSWAP_SUPPORTED 94 | #define PNG_READ_pCAL_SUPPORTED 95 | #define PNG_READ_pHYs_SUPPORTED 96 | #define PNG_READ_QUANTIZE_SUPPORTED 97 | #define PNG_READ_RGB_TO_GRAY_SUPPORTED 98 | #define PNG_READ_sBIT_SUPPORTED 99 | #define PNG_READ_sCAL_SUPPORTED 100 | #define PNG_READ_SHIFT_SUPPORTED 101 | #define PNG_READ_sPLT_SUPPORTED 102 | #define PNG_READ_sRGB_SUPPORTED 103 | #define PNG_READ_STRIP_ALPHA_SUPPORTED 104 | #define PNG_READ_SUPPORTED 105 | #define PNG_READ_SWAP_ALPHA_SUPPORTED 106 | #define PNG_READ_SWAP_SUPPORTED 107 | #define PNG_READ_tEXt_SUPPORTED 108 | #define PNG_READ_TEXT_SUPPORTED 109 | #define PNG_READ_tIME_SUPPORTED 110 | #define PNG_READ_TRANSFORMS_SUPPORTED 111 | #define PNG_READ_tRNS_SUPPORTED 112 | #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 113 | #define PNG_READ_USER_CHUNKS_SUPPORTED 114 | #define PNG_READ_USER_TRANSFORM_SUPPORTED 115 | #define PNG_READ_zTXt_SUPPORTED 116 | #define PNG_SAVE_INT_32_SUPPORTED 117 | #define PNG_sBIT_SUPPORTED 118 | #define PNG_sCAL_SUPPORTED 119 | #define PNG_SEQUENTIAL_READ_SUPPORTED 120 | #define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED 121 | #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED 122 | #define PNG_SETJMP_SUPPORTED 123 | #define PNG_SET_USER_LIMITS_SUPPORTED 124 | #define PNG_sPLT_SUPPORTED 125 | #define PNG_sRGB_SUPPORTED 126 | #define PNG_STDIO_SUPPORTED 127 | #define PNG_tEXt_SUPPORTED 128 | #define PNG_TEXT_SUPPORTED 129 | #define PNG_TIME_RFC1123_SUPPORTED 130 | #define PNG_tIME_SUPPORTED 131 | #define PNG_tRNS_SUPPORTED 132 | #define PNG_UNKNOWN_CHUNKS_SUPPORTED 133 | #define PNG_USER_CHUNKS_SUPPORTED 134 | #define PNG_USER_LIMITS_SUPPORTED 135 | #define PNG_USER_MEM_SUPPORTED 136 | #define PNG_USER_TRANSFORM_INFO_SUPPORTED 137 | #define PNG_USER_TRANSFORM_PTR_SUPPORTED 138 | #define PNG_WARNINGS_SUPPORTED 139 | #define PNG_WRITE_16BIT_SUPPORTED 140 | #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED 141 | #define PNG_WRITE_BGR_SUPPORTED 142 | #define PNG_WRITE_bKGD_SUPPORTED 143 | #define PNG_WRITE_cHRM_SUPPORTED 144 | #define PNG_WRITE_FILLER_SUPPORTED 145 | #define PNG_WRITE_FILTER_SUPPORTED 146 | #define PNG_WRITE_FLUSH_SUPPORTED 147 | #define PNG_WRITE_gAMA_SUPPORTED 148 | #define PNG_WRITE_hIST_SUPPORTED 149 | #define PNG_WRITE_iCCP_SUPPORTED 150 | #define PNG_WRITE_INTERLACING_SUPPORTED 151 | #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED 152 | #define PNG_WRITE_INVERT_ALPHA_SUPPORTED 153 | #define PNG_WRITE_INVERT_SUPPORTED 154 | #define PNG_WRITE_iTXt_SUPPORTED 155 | #define PNG_WRITE_oFFs_SUPPORTED 156 | #define PNG_WRITE_PACK_SUPPORTED 157 | #define PNG_WRITE_PACKSWAP_SUPPORTED 158 | #define PNG_WRITE_pCAL_SUPPORTED 159 | #define PNG_WRITE_pHYs_SUPPORTED 160 | #define PNG_WRITE_sBIT_SUPPORTED 161 | #define PNG_WRITE_sCAL_SUPPORTED 162 | #define PNG_WRITE_SHIFT_SUPPORTED 163 | #define PNG_WRITE_sPLT_SUPPORTED 164 | #define PNG_WRITE_sRGB_SUPPORTED 165 | #define PNG_WRITE_SUPPORTED 166 | #define PNG_WRITE_SWAP_ALPHA_SUPPORTED 167 | #define PNG_WRITE_SWAP_SUPPORTED 168 | #define PNG_WRITE_tEXt_SUPPORTED 169 | #define PNG_WRITE_TEXT_SUPPORTED 170 | #define PNG_WRITE_tIME_SUPPORTED 171 | #define PNG_WRITE_TRANSFORMS_SUPPORTED 172 | #define PNG_WRITE_tRNS_SUPPORTED 173 | #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 174 | #define PNG_WRITE_USER_TRANSFORM_SUPPORTED 175 | #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED 176 | #define PNG_WRITE_zTXt_SUPPORTED 177 | #define PNG_zTXt_SUPPORTED 178 | /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ 179 | /*#undef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED*/ 180 | /* end of options */ 181 | #endif /* PNGLCONF_H */ 182 | -------------------------------------------------------------------------------- /windows/win32/zlib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/autopilot-rs/autopy-legacy/1cbf4e842c4d43f706a16ac6106f77031ab00163/windows/win32/zlib.lib -------------------------------------------------------------------------------- /windows/win64/libpng.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/autopilot-rs/autopy-legacy/1cbf4e842c4d43f706a16ac6106f77031ab00163/windows/win64/libpng.lib -------------------------------------------------------------------------------- /windows/win64/pnglibconf.h: -------------------------------------------------------------------------------- 1 | 2 | /* libpng STANDARD API DEFINITION */ 3 | 4 | /* pnglibconf.h - library build configuration */ 5 | 6 | /* libpng version 1.5.0 - last changed on February 11, 2011 */ 7 | 8 | /* Copyright (c) 1998-2011 Glenn Randers-Pehrson */ 9 | 10 | /* This code is released under the libpng license. */ 11 | /* For conditions of distribution and use, see the disclaimer */ 12 | /* and license in png.h */ 13 | 14 | /* pnglibconf.h */ 15 | /* Derived from: scripts/pnglibconf.dfa */ 16 | /* If you edit this file by hand you must obey the rules expressed in */ 17 | /* pnglibconf.dfa with respect to the dependencies between the following */ 18 | /* symbols. It is much better to generate a new file using */ 19 | /* scripts/libpngconf.mak */ 20 | 21 | #ifndef PNGLCONF_H 22 | #define PNGLCONF_H 23 | /* settings */ 24 | #define PNG_API_RULE 0 25 | #define PNG_CALLOC_SUPPORTED 26 | #define PNG_COST_SHIFT 3 27 | #define PNG_DEFAULT_READ_MACROS 1 28 | #define PNG_GAMMA_THRESHOLD_FIXED 5000 29 | #define PNG_MAX_GAMMA_8 11 30 | #define PNG_QUANTIZE_BLUE_BITS 5 31 | #define PNG_QUANTIZE_GREEN_BITS 5 32 | #define PNG_QUANTIZE_RED_BITS 5 33 | #define PNG_sCAL_PRECISION 5 34 | #define PNG_USER_CHUNK_CACHE_MAX 0 35 | #define PNG_USER_CHUNK_MALLOC_MAX 0 36 | #define PNG_USER_HEIGHT_MAX 1000000L 37 | #define PNG_USER_WIDTH_MAX 1000000L 38 | #define PNG_WEIGHT_SHIFT 8 39 | #define PNG_ZBUF_SIZE 8192 40 | /* end of settings */ 41 | /* options */ 42 | #define PNG_16BIT_SUPPORTED 43 | #define PNG_ALIGN_MEMORY_SUPPORTED 44 | #define PNG_BENIGN_ERRORS_SUPPORTED 45 | #define PNG_bKGD_SUPPORTED 46 | #define PNG_CHECK_cHRM_SUPPORTED 47 | #define PNG_cHRM_SUPPORTED 48 | #define PNG_CONSOLE_IO_SUPPORTED 49 | #define PNG_CONVERT_tIME_SUPPORTED 50 | #define PNG_EASY_ACCESS_SUPPORTED 51 | #define PNG_ERROR_TEXT_SUPPORTED 52 | #define PNG_FIXED_POINT_SUPPORTED 53 | #define PNG_FLOATING_ARITHMETIC_SUPPORTED 54 | #define PNG_FLOATING_POINT_SUPPORTED 55 | #define PNG_gAMA_SUPPORTED 56 | #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED 57 | #define PNG_hIST_SUPPORTED 58 | #define PNG_iCCP_SUPPORTED 59 | #define PNG_INCH_CONVERSIONS_SUPPORTED 60 | #define PNG_INFO_IMAGE_SUPPORTED 61 | #define PNG_IO_STATE_SUPPORTED 62 | #define PNG_iTXt_SUPPORTED 63 | #define PNG_MNG_FEATURES_SUPPORTED 64 | #define PNG_oFFs_SUPPORTED 65 | #define PNG_pCAL_SUPPORTED 66 | #define PNG_pHYs_SUPPORTED 67 | #define PNG_POINTER_INDEXING_SUPPORTED 68 | #define PNG_PROGRESSIVE_READ_SUPPORTED 69 | #define PNG_READ_16BIT_SUPPORTED 70 | #define PNG_READ_16_TO_8_SUPPORTED 71 | #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED 72 | #define PNG_READ_BACKGROUND_SUPPORTED 73 | #define PNG_READ_BGR_SUPPORTED 74 | #define PNG_READ_bKGD_SUPPORTED 75 | #define PNG_READ_cHRM_SUPPORTED 76 | #define PNG_READ_COMPOSITE_NODIV_SUPPORTED 77 | #define PNG_READ_EXPAND_16_SUPPORTED 78 | #define PNG_READ_EXPAND_SUPPORTED 79 | #define PNG_READ_FILLER_SUPPORTED 80 | #define PNG_READ_gAMA_SUPPORTED 81 | #define PNG_READ_GAMMA_SUPPORTED 82 | #define PNG_READ_GRAY_TO_RGB_SUPPORTED 83 | #define PNG_READ_hIST_SUPPORTED 84 | #define PNG_READ_iCCP_SUPPORTED 85 | #define PNG_READ_INTERLACING_SUPPORTED 86 | #define PNG_READ_INT_FUNCTIONS_SUPPORTED 87 | #define PNG_READ_INVERT_ALPHA_SUPPORTED 88 | #define PNG_READ_INVERT_SUPPORTED 89 | #define PNG_READ_iTXt_SUPPORTED 90 | #define PNG_READ_oFFs_SUPPORTED 91 | #define PNG_READ_OPT_PLTE_SUPPORTED 92 | #define PNG_READ_PACK_SUPPORTED 93 | #define PNG_READ_PACKSWAP_SUPPORTED 94 | #define PNG_READ_pCAL_SUPPORTED 95 | #define PNG_READ_pHYs_SUPPORTED 96 | #define PNG_READ_QUANTIZE_SUPPORTED 97 | #define PNG_READ_RGB_TO_GRAY_SUPPORTED 98 | #define PNG_READ_sBIT_SUPPORTED 99 | #define PNG_READ_sCAL_SUPPORTED 100 | #define PNG_READ_SHIFT_SUPPORTED 101 | #define PNG_READ_sPLT_SUPPORTED 102 | #define PNG_READ_sRGB_SUPPORTED 103 | #define PNG_READ_STRIP_ALPHA_SUPPORTED 104 | #define PNG_READ_SUPPORTED 105 | #define PNG_READ_SWAP_ALPHA_SUPPORTED 106 | #define PNG_READ_SWAP_SUPPORTED 107 | #define PNG_READ_tEXt_SUPPORTED 108 | #define PNG_READ_TEXT_SUPPORTED 109 | #define PNG_READ_tIME_SUPPORTED 110 | #define PNG_READ_TRANSFORMS_SUPPORTED 111 | #define PNG_READ_tRNS_SUPPORTED 112 | #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 113 | #define PNG_READ_USER_CHUNKS_SUPPORTED 114 | #define PNG_READ_USER_TRANSFORM_SUPPORTED 115 | #define PNG_READ_zTXt_SUPPORTED 116 | #define PNG_SAVE_INT_32_SUPPORTED 117 | #define PNG_sBIT_SUPPORTED 118 | #define PNG_sCAL_SUPPORTED 119 | #define PNG_SEQUENTIAL_READ_SUPPORTED 120 | #define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED 121 | #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED 122 | #define PNG_SETJMP_SUPPORTED 123 | #define PNG_SET_USER_LIMITS_SUPPORTED 124 | #define PNG_sPLT_SUPPORTED 125 | #define PNG_sRGB_SUPPORTED 126 | #define PNG_STDIO_SUPPORTED 127 | #define PNG_tEXt_SUPPORTED 128 | #define PNG_TEXT_SUPPORTED 129 | #define PNG_TIME_RFC1123_SUPPORTED 130 | #define PNG_tIME_SUPPORTED 131 | #define PNG_tRNS_SUPPORTED 132 | #define PNG_UNKNOWN_CHUNKS_SUPPORTED 133 | #define PNG_USER_CHUNKS_SUPPORTED 134 | #define PNG_USER_LIMITS_SUPPORTED 135 | #define PNG_USER_MEM_SUPPORTED 136 | #define PNG_USER_TRANSFORM_INFO_SUPPORTED 137 | #define PNG_USER_TRANSFORM_PTR_SUPPORTED 138 | #define PNG_WARNINGS_SUPPORTED 139 | #define PNG_WRITE_16BIT_SUPPORTED 140 | #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED 141 | #define PNG_WRITE_BGR_SUPPORTED 142 | #define PNG_WRITE_bKGD_SUPPORTED 143 | #define PNG_WRITE_cHRM_SUPPORTED 144 | #define PNG_WRITE_FILLER_SUPPORTED 145 | #define PNG_WRITE_FILTER_SUPPORTED 146 | #define PNG_WRITE_FLUSH_SUPPORTED 147 | #define PNG_WRITE_gAMA_SUPPORTED 148 | #define PNG_WRITE_hIST_SUPPORTED 149 | #define PNG_WRITE_iCCP_SUPPORTED 150 | #define PNG_WRITE_INTERLACING_SUPPORTED 151 | #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED 152 | #define PNG_WRITE_INVERT_ALPHA_SUPPORTED 153 | #define PNG_WRITE_INVERT_SUPPORTED 154 | #define PNG_WRITE_iTXt_SUPPORTED 155 | #define PNG_WRITE_oFFs_SUPPORTED 156 | #define PNG_WRITE_PACK_SUPPORTED 157 | #define PNG_WRITE_PACKSWAP_SUPPORTED 158 | #define PNG_WRITE_pCAL_SUPPORTED 159 | #define PNG_WRITE_pHYs_SUPPORTED 160 | #define PNG_WRITE_sBIT_SUPPORTED 161 | #define PNG_WRITE_sCAL_SUPPORTED 162 | #define PNG_WRITE_SHIFT_SUPPORTED 163 | #define PNG_WRITE_sPLT_SUPPORTED 164 | #define PNG_WRITE_sRGB_SUPPORTED 165 | #define PNG_WRITE_SUPPORTED 166 | #define PNG_WRITE_SWAP_ALPHA_SUPPORTED 167 | #define PNG_WRITE_SWAP_SUPPORTED 168 | #define PNG_WRITE_tEXt_SUPPORTED 169 | #define PNG_WRITE_TEXT_SUPPORTED 170 | #define PNG_WRITE_tIME_SUPPORTED 171 | #define PNG_WRITE_TRANSFORMS_SUPPORTED 172 | #define PNG_WRITE_tRNS_SUPPORTED 173 | #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED 174 | #define PNG_WRITE_USER_TRANSFORM_SUPPORTED 175 | #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED 176 | #define PNG_WRITE_zTXt_SUPPORTED 177 | #define PNG_zTXt_SUPPORTED 178 | /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ 179 | /*#undef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED*/ 180 | /* end of options */ 181 | #endif /* PNGLCONF_H */ 182 | -------------------------------------------------------------------------------- /windows/win64/zlib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/autopilot-rs/autopy-legacy/1cbf4e842c4d43f706a16ac6106f77031ab00163/windows/win64/zlib.lib --------------------------------------------------------------------------------