├── .gitignore ├── LICENSE ├── README.md ├── aris.ahk ├── assets ├── 7za-license.txt ├── 7za-x32.exe ├── 7za-x64.exe ├── index.json ├── main.ico └── sort_index.ahk ├── lib ├── Aris │ ├── FanaticGuru │ │ ├── GuiReSizer.ahk │ │ └── GuiReSizer@2ba5b65 │ │ │ └── GuiResizer.ahk │ ├── G33kDude │ │ ├── cJson.ahk │ │ └── cJson@2.0.0 │ │ │ └── JSON.ahk │ └── packages.ahk ├── env.ahk ├── hash.ahk ├── ui-main.ahk ├── utils.ahk ├── version.ahk └── web.ahk └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | assets/config.json 2 | assets/user-path-backup.txt 3 | .vscode 4 | cache -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Descolada 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ARIS 2 | AutoHotkey Repository Install System 3 | 4 | ## Why use Aris 5 | Compared to other package managers Aris is able to install from more sources: GitHub repositories, Gists, archives (zip, tar files), and AutoHotkey forums posts. There is also a central index of packages which helps to find and install useful packages. 6 | 7 | Additionally, package.json isn't required to install a package, which greatly increases the number of places from where packages may be installed. 8 | 9 | Furthermore, Aris doesn't require admin access nor does it use any other executables than AutoHotkey. For command line use there needs to be privileges to execute .bat files, this requirement might be removed in the future if it turns out to be an issue. 10 | 11 | Most of the following examples will use the command line interface, but most packages can be installed via the GUI as well. Run Aris.ahk, select your project folder by pressing "Load package", then press "Add" in the "Current package" tab to install from a custom source. 12 | 13 | ## Introductory example 14 | For example, to install my (Descolada) OCR package: 15 | 1. Run Aris.ahk, select your project folder, choose the Index tab, and double-click "Descolada/OCR" 16 | 2. Alternatively open command prompt or Powershell, navigate to your project folder, run `aris i Descolada/OCR`. Note: the Aris GUI needs to be started at least once before this, otherwise Aris isn't added to PATH. 17 | 18 | Then either use the generated #include directive (in this case `#include `) or include all installed packages with `#include ` 19 | 20 | ## Aris command arguments 21 | ### Install 22 | `aris install package` installs the specified package from the specified source, see examples further down. 23 | Command aliases: `i` 24 | `aris install Author/Name` will install either from the index, or the corresponding GitHub repo. 25 | `aris i package@version` installs the specified version. If the package is already installed then it's forcibly uninstalled and then reinstalled with the specific version. Use @latest to install the latest version. 26 | ### Remove 27 | `aris remove package` removes the package. Specify either the full package name, or only the name without the author. 28 | Command aliases: `uninstall`, `r`, `rm` 29 | ### Update 30 | `aris update package` updates to the latest allowed version specified in the package.json file. If the version is a hash then update to the latest version with `aris install package@latest` 31 | 32 | `aris update` without specifying a package tries to update the package in the working directory. For example, this could be used to update Aris itself. 33 | ### List 34 | `aris list` lists all installed packages. 35 | ### Clean 36 | `aris clean` removes unused entries from package.json dependencies and packages.ahk 37 | 38 | # Examples 39 | 40 | ## Index install 41 | Open the Aris GUI, then in the Index tab select a package and press "Install" (or double-click the package). Specific versions of packages can be installed by pressing the "Query versions" button. 42 | 43 | Install via the command line by specifying the full package name, or if there is only one package with the package name then only that may be used. 44 | 45 | For example, install UIA-v2 with 46 | ``` 47 | aris i UIA 48 | ``` 49 | or 50 | ``` 51 | aris i Descolada/UIA 52 | ``` 53 | 54 | ## GitHub install 55 | GitHub installs first checks for releases and downloads the latest one, and if no releases are found then falls back to the latest commit. 56 | Use the full URL: 57 | ``` 58 | aris i https://github.com/Descolada/OCR 59 | ``` 60 | Or short forms: 61 | ``` 62 | aris i github:Descolada/OCR 63 | ``` 64 | A specific branch may be requested: 65 | ``` 66 | aris i gh:Descolada/OCR/main 67 | ``` 68 | A specific release version may be requested: 69 | ``` 70 | aris i gh:Descolada/UIA-v2@v1.0.0 71 | ``` 72 | A specific commit short-hash may be requested: 73 | ``` 74 | aris i gh:Descolada/OCR@1ef23ba 75 | ``` 76 | If the package isn't in the package index, then by default it's assumed a GitHub repo: 77 | ``` 78 | aris i Descolada/OCR 79 | ``` 80 | It's also possible to create separate packages for specific files in a repository by using `-m`/`--main` and `--files` flags. The following example installs a single file and creates a package named "thqby/MCode": 81 | ``` 82 | aris i thqby/ahk2_lib as MCode --files MCode.ahk 83 | ``` 84 | Or include a folder (creates a package named "thqby/RapidOcr.ahk"): 85 | ``` 86 | aris i thqby/ahk2_lib as RapidOcr -m RapidOcr/RapidOcr.ahk --files RapidOcr/*.* 87 | ``` 88 | If a release has multiple assets then the fallback is the source zip file. However, if a specific asset is required then it can be specified in the version metadata (wildcards are supported): 89 | ``` 90 | aris i Descolada/OCR@latest+OCR.7z 91 | ``` 92 | ## Gist install 93 | Install a specific file from a Gist: 94 | ``` 95 | aris i https://gist.github.com/anonymous1184/7cce378c9dfdaf733cb3ca6df345b140/GetUrl.ahk 96 | ``` 97 | Short form can be used: 98 | ``` 99 | aris i gist:7cce378c9dfdaf733cb3ca6df345b140/GetUrl.ahk 100 | ``` 101 | If the file name is omitted, then the first available file is used: 102 | ``` 103 | aris i gist:7cce378c9dfdaf733cb3ca6df345b140 104 | ``` 105 | 106 | ## Forums install 107 | Forums install queries the webpage from Wayback Archive, which might not have the latest page content and is usually also quite slow to respond (installs may take tens of seconds). However, it allows for versioning in the form of the date the web page was crawled. 108 | 109 | To install from a forums post, use the URL of the thread. Required URL field is "t=123456" (the thread id), optional are "codebox=1" (the code box number on the page, by default is 1), "p=123456" (post id) and "start=123" (is related to the page in the thread). Note that the Wayback Machine reliably only has the main page of the thread. 110 | ``` 111 | aris i https://www.autohotkey.com/boards/viewtopic.php?f=83&t=116471 112 | ``` 113 | To install directly from the AutoHotkey forums use @latest. This does not work if the forums has Cloudflare attack mode activated (which causes the "verify you are human" page to appear). 114 | ``` 115 | aris i https://www.autohotkey.com/boards/viewtopic.php?f=83&t=116471@latest 116 | ``` 117 | 118 | ## Archive install 119 | For archive installs use the download URL. A version can't be specified in this case. 120 | ``` 121 | aris i https://github.com/Descolada/UIA-v2/archive/refs/heads/main.zip 122 | ``` 123 | 124 | # Developer info 125 | 126 | ## Adding packages to index 127 | The minimum information for an index.json entry is "description", "main", and "repository". If the package consists of more than a single file and not all files in the package are needed, then the "files" array should be filled with the appropriate file names or wildcard patterns. In that case "main" also needs to be specified with the relative path to the file, but doesn't need to be duplicated in the "files" array. 128 | Including a GitHub repo branch name is optional and will default to the default branch. 129 | 130 | Example minimal entry, which downloads all files in the repository and sets main.ahk as the entry-point. "files" is implicitly ["*.*"] in this case. 131 | ``` 132 | "Author/Name": { 133 | "description": "A short package description", 134 | "main": "main.ahk", 135 | "repository": "Author/repo[/branch]" 136 | } 137 | ``` 138 | Example multiple files minimal entry, which downloads the assets folder, include.ahk and main.ahk: 139 | ``` 140 | "Author/Name": { 141 | "description": "A short package description", 142 | "main": "subfolder/main.ahk", 143 | "files": ["subfolder/include.ahk", "subfolder/assets/*.*"] 144 | "repository": "Author/repo/branch" 145 | } 146 | ``` 147 | 148 | # Roadmap 149 | Not in order of priority: 150 | 1. Updating a main package (eg Aris itself) is currently untested, most likely needs fixing. 151 | 2. Improve GUI experience (beautify, search packages by tags etc) 152 | 3. Create automated tests 153 | 4. Support GitHub installs by tags 154 | 5. Support installs from local files/folders 155 | 6. Fix nested dependency installs in the case where specific versions are required -------------------------------------------------------------------------------- /assets/7za-license.txt: -------------------------------------------------------------------------------- 1 | 7-Zip 2 | ~~~~~ 3 | License for use and distribution 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | 7-Zip Copyright (C) 1999-2023 Igor Pavlov. 7 | 8 | The licenses for files are: 9 | 10 | 1) 7z.dll: 11 | - The "GNU LGPL" as main license for most of the code 12 | - The "GNU LGPL" with "unRAR license restriction" for some code 13 | - The "BSD 3-clause License" for some code 14 | 2) All other files: the "GNU LGPL". 15 | 16 | Redistributions in binary form must reproduce related license information from this file. 17 | 18 | Note: 19 | You can use 7-Zip on any computer, including a computer in a commercial 20 | organization. You don't need to register or pay for 7-Zip. 21 | 22 | 23 | GNU LGPL information 24 | -------------------- 25 | 26 | This library is free software; you can redistribute it and/or 27 | modify it under the terms of the GNU Lesser General Public 28 | License as published by the Free Software Foundation; either 29 | version 2.1 of the License, or (at your option) any later version. 30 | 31 | This library is distributed in the hope that it will be useful, 32 | but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 34 | Lesser General Public License for more details. 35 | 36 | You can receive a copy of the GNU Lesser General Public License from 37 | http://www.gnu.org/ 38 | 39 | 40 | 41 | 42 | BSD 3-clause License 43 | -------------------- 44 | 45 | The "BSD 3-clause License" is used for the code in 7z.dll that implements LZFSE data decompression. 46 | That code was derived from the code in the "LZFSE compression library" developed by Apple Inc, 47 | that also uses the "BSD 3-clause License": 48 | 49 | ---- 50 | Copyright (c) 2015-2016, Apple Inc. All rights reserved. 51 | 52 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 53 | 54 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 55 | 56 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 57 | in the documentation and/or other materials provided with the distribution. 58 | 59 | 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived 60 | from this software without specific prior written permission. 61 | 62 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 63 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 64 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 65 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 67 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 | ---- 69 | 70 | 71 | 72 | 73 | unRAR license restriction 74 | ------------------------- 75 | 76 | The decompression engine for RAR archives was developed using source 77 | code of unRAR program. 78 | All copyrights to original unRAR code are owned by Alexander Roshal. 79 | 80 | The license for original unRAR code has the following restriction: 81 | 82 | The unRAR sources cannot be used to re-create the RAR compression algorithm, 83 | which is proprietary. Distribution of modified unRAR sources in separate form 84 | or as a part of other software is permitted, provided that it is clearly 85 | stated in the documentation and source comments that the code may 86 | not be used to develop a RAR (WinRAR) compatible archiver. 87 | 88 | 89 | -- 90 | Igor Pavlov -------------------------------------------------------------------------------- /assets/7za-x32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Descolada/Aris/b2728cf89b899ce07e2dd28ee9141e25ca52c072/assets/7za-x32.exe -------------------------------------------------------------------------------- /assets/7za-x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Descolada/Aris/b2728cf89b899ce07e2dd28ee9141e25ca52c072/assets/7za-x64.exe -------------------------------------------------------------------------------- /assets/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "v2.0": { 3 | "0w0Demonic/AquaHotkey": { 4 | "description": "Class prototyping library for AutoHotkey v2.", 5 | "files": "src/*.*", 6 | "license": "MIT", 7 | "main": "src/AquaHotkey.ahk", 8 | "repository": "0w0Demonic/AquaHotkey/main" 9 | }, 10 | "AstraVista/ScriptSock": { 11 | "description": "Communicate easily between scripts", 12 | "files": "v2/AstraVista/ScriptSock.ahk", 13 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=126320", 14 | "keywords": "IPC, inter-process, communication", 15 | "repository": "ahkscript/ScriptHub/main" 16 | }, 17 | "AstraVista/ScriptVar": { 18 | "description": "Deep clone an object, convert a user class object to a string packet, convert a compiled packet back to object", 19 | "files": "v2/AstraVista/ScriptVar.ahk", 20 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=127205", 21 | "repository": "ahkscript/ScriptHub/main" 22 | }, 23 | "Cebolla/Array": { 24 | "description": "An AutoHotkey library implementing common array methods", 25 | "files": "Array.ahk", 26 | "repository": "Nich-Cebolla/AutoHotkey-Array/main" 27 | }, 28 | "Cebolla/DeepClone": { 29 | "description": "Deep clones an object, with an option to specify a maximum depth.", 30 | "files": [ 31 | "Object.Prototype.DeepClone.ahk", 32 | "GetObjectFromString.ahk" 33 | ], 34 | "license": "MIT", 35 | "main": "Object.Prototype.DeepClone.ahk", 36 | "repository": "Nich-Cebolla/AutoHotkey-Object.Prototype.DeepClone/main" 37 | }, 38 | "Cebolla/Monitor": { 39 | "description": "This class provides methods for obtaining information about monitor size, dimensions, position, and DPI.", 40 | "files": "cMonitor.ahk", 41 | "license": "MIT", 42 | "repository": "Nich-Cebolla/Monitor.ahk/main" 43 | }, 44 | "Chunjee/adash": { 45 | "author": "Shawn Brooker", 46 | "bugs": { 47 | "url": "https://github.com/adash-ahk/adash.ahk/issues" 48 | }, 49 | "description": "A modern utility library for AutoHotkey", 50 | "homepage": "https://adash.app", 51 | "keywords": [ 52 | "autohotkey", 53 | "ahk", 54 | "utility", 55 | "lodash" 56 | ], 57 | "license": "MIT", 58 | "main": "adash.ahk", 59 | "repository": "adash-ahk/adash.ahk/main" 60 | }, 61 | "DaveT1/Expect": { 62 | "description": "Rapid units testing class", 63 | "files": "v2/DaveT1/Expect.ahk", 64 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=130093", 65 | "repository": "ahkscript/ScriptHub/main" 66 | }, 67 | "Delta Pythagorean/Lua": { 68 | "description": "Extend your AHK script with Lua", 69 | "files": "v2/Delta Pythagorean/Lua.ahk", 70 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?t=122655", 71 | "repository": "ahkscript/ScriptHub/main" 72 | }, 73 | "Descolada/Acc": { 74 | "description": "Acc library for AHK v2 (note: use of UIA is preferred over Acc)", 75 | "files": "Lib/Acc.ahk", 76 | "homepage": "https://github.com/Descolada/Acc-v2", 77 | "license": "MIT", 78 | "repository": "Descolada/Acc-v2/main" 79 | }, 80 | "Descolada/Array": { 81 | "description": "Adds useful methods to arrays", 82 | "files": "Lib/Array.ahk", 83 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 84 | "license": "MIT", 85 | "repository": "Descolada/AHK-v2-libraries/main" 86 | }, 87 | "Descolada/DUnit": { 88 | "description": "Alternative unit testing framework to YUnit", 89 | "files": "Lib/DUnit.ahk", 90 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 91 | "license": "MIT", 92 | "repository": "Descolada/AHK-v2-libraries/main" 93 | }, 94 | "Descolada/FileReadLine": { 95 | "description": "Read a single line from a file", 96 | "files": "v2/Descolada/FileReadLine.ahk", 97 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=117999", 98 | "repository": "ahkscript/ScriptHub/main" 99 | }, 100 | "Descolada/JAB": { 101 | "description": "Java Access Bridge library to automate Java applications interfaces", 102 | "files": "Lib/JAB.ahk", 103 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 104 | "license": "MIT", 105 | "repository": "Descolada/AHK-v2-libraries/main" 106 | }, 107 | "Descolada/Map": { 108 | "description": "Adds useful methods to maps", 109 | "files": "Lib/Map.ahk", 110 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 111 | "license": "MIT", 112 | "repository": "Descolada/AHK-v2-libraries/main" 113 | }, 114 | "Descolada/Media": { 115 | "description": "Implements UWP Media Control, allowing access and control of the playing media (but not any media, only UWP ones that are notified by a tray tip with the play-pause buttons and playing song title)", 116 | "files": "Lib/Media.ahk", 117 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 118 | "license": "MIT", 119 | "repository": "Descolada/AHK-v2-libraries/main" 120 | }, 121 | "Descolada/Misc": { 122 | "description": "Miscallaneous useful functions such as Range, RegExMatchAll, Highlight, WinGetInfo, GetCaretPos, ConvertWinPos, etc", 123 | "files": "Lib/Misc.ahk", 124 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 125 | "license": "MIT", 126 | "repository": "Descolada/AHK-v2-libraries/main" 127 | }, 128 | "Descolada/OCR": { 129 | "description": "OCR library using Windows' built-in UWP OCR capabilities", 130 | "files": "Lib/OCR.ahk", 131 | "homepage": "https://github.com/Descolada/OCR", 132 | "keywords": [ 133 | "OCR", 134 | "optical character recognition", 135 | "image search" 136 | ], 137 | "license": "MIT", 138 | "repository": "Descolada/OCR/main" 139 | }, 140 | "Descolada/String": { 141 | "description": "Adds useful methods to strings", 142 | "files": "Lib/String.ahk", 143 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 144 | "license": "MIT", 145 | "repository": "Descolada/AHK-v2-libraries/main" 146 | }, 147 | "Descolada/UIA": { 148 | "description": "An AutoHotkey v2 wrapper for the UIAutomation framework, which can be used to automate windows that normally might be difficult or impossible to automate with AHK", 149 | "files": "Lib/UIA.ahk", 150 | "homepage": "https://github.com/Descolada/UIA-v2", 151 | "keywords": [ 152 | "UIA", 153 | "UI automation" 154 | ], 155 | "license": "MIT", 156 | "repository": "Descolada/UIA-v2/main" 157 | }, 158 | "Descolada/UIA_Browser": { 159 | "dependencies": { 160 | "Descolada/UIA": "*" 161 | }, 162 | "description": "An addon for Descolada/UIA library to simplify automating browsers via UIA", 163 | "files": "Lib/UIA_Browser.ahk", 164 | "repository": "Descolada/UIA-v2/main" 165 | }, 166 | "Descolada/WinEvent": { 167 | "description": "Can be used to monitor for window events such as close, open, minimize etc", 168 | "files": "Lib/WinEvent.ahk", 169 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 170 | "license": "MIT", 171 | "repository": "Descolada/AHK-v2-libraries/main" 172 | }, 173 | "Descolada/XHotstring": { 174 | "description": "Implements regular expression hotstrings", 175 | "files": "Lib/XHotstring.ahk", 176 | "homepage": "https://github.com/Descolada/AHK-v2-libraries", 177 | "keywords": [ 178 | "RegEx", 179 | "hotstrings" 180 | ], 181 | "license": "MIT", 182 | "repository": "Descolada/AHK-v2-libraries/main" 183 | }, 184 | "FanaticGuru/GuiButtonIcon": { 185 | "description": "A function that allows an icon to be assigned to a Gui Button using the button's hwnd to identify the button", 186 | "files": "v2/FanaticGuru/GuiButtonIcon.ahk", 187 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=115871", 188 | "repository": "ahkscript/ScriptHub/main" 189 | }, 190 | "FanaticGuru/GuiResizer": { 191 | "description": "A class to simplify adjusting GUI controls to GUI resizing", 192 | "files": "v2/FanaticGuru/GuiResizer.ahk", 193 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?t=113921", 194 | "repository": "ahkscript/ScriptHub/main" 195 | }, 196 | "FanaticGuru/SpellCurrency": { 197 | "description": "A function to convert a number to currency words", 198 | "files": "v2/FanaticGuru/SpellCurrency.ahk", 199 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=133138", 200 | "repository": "ahkscript/ScriptHub/main" 201 | }, 202 | "Flipeador/WinCloseEx": { 203 | "description": "Close a window with different methods", 204 | "files": "v2/Ruevil2/ADOSQL.ahk", 205 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=126579", 206 | "repository": "ahkscript/ScriptHub/main" 207 | }, 208 | "G33kDude/HashMap": { 209 | "description": "Provides a hash map based alternative implementation of AutoHotkey's Map class, with the goal of allowing drop-in replacement for situations where the native Map's performance limitations have been reached", 210 | "files": "Dist/HashMap.ahk", 211 | "homepage": "https://github.com/G33kDude/HashMap.ahk", 212 | "license": "MIT", 213 | "repository": "G33kDude/HashMap.ahk/main" 214 | }, 215 | "G33kDude/Neutron": { 216 | "description": "Neutron provides a powerful set of tools for build HTML-based user interfaces with AutoHotkey. It leverages the Trident engine, known for its use in Internet Explorer, because of its deep integration with the Microsoft Windows operating system and its wide availability across systems.", 217 | "files": "Neutron.ahk", 218 | "homepage": "https://github.com/G33kDude/Neutron.ahk", 219 | "license": "MIT", 220 | "repository": "G33kDude/Neutron.ahk/v2" 221 | }, 222 | "G33kDude/cJson": { 223 | "description": "A high-performance JSON parsing library", 224 | "files": "Dist/JSON.ahk", 225 | "homepage": "https://github.com/G33kDude/cJson.ahk", 226 | "keywords": [ 227 | "JSON", 228 | "parser" 229 | ], 230 | "license": "MIT", 231 | "repository": "G33kDude/cJson.ahk/v2" 232 | }, 233 | "GroggyOtter/AHK-v2-AutoUpdater": { 234 | "description": "Class object that will notify you of AHKv2 updates and ask if you'd like to download the new version.", 235 | "license": "GPL-3.0", 236 | "main": "src/AHK_v2_Auto_Updater.v2.ahk", 237 | "repository": "GroggyOtter/AHK_v2_Auto_Updater/main" 238 | }, 239 | "GroggyOtter/JavaScriptStrings": { 240 | "description": "Adds JavaScript-style string functionality to AHK v2 strings.", 241 | "license": "MIT", 242 | "main": "src/javascript_strings.ahk", 243 | "repository": "GroggyOtter/AHK-JavaScript-Strings/main" 244 | }, 245 | "GroggyOtter/Peep": { 246 | "description": "Easily get information from nested objects.", 247 | "license": "MIT", 248 | "main": "script/Peep.v2.ahk", 249 | "repository": "GroggyOtter/PeepAHK/main" 250 | }, 251 | "GroggyOtter/jsongo": { 252 | "description": "Full JSON support for AHKv2 written natively in AHK.", 253 | "license": "GPL-3.0", 254 | "main": "src/jsongo.v2.ahk", 255 | "repository": "GroggyOtter/jsongo_AHKv2/main" 256 | }, 257 | "Hellbent/PopupWindow": { 258 | "dependencies": { 259 | "buliasz/Gdip": "*" 260 | }, 261 | "description": "Simplifies the process of working with layered windows", 262 | "files": "v2/Hellbent/PopupWindow.ahk", 263 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=132744", 264 | "repository": "ahkscript/ScriptHub/main" 265 | }, 266 | "Hellbent/Vector": { 267 | "description": "Vector math class", 268 | "files": "v2/Hellbent/Vector.ahk", 269 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=132770", 270 | "repository": "ahkscript/ScriptHub/main" 271 | }, 272 | "Komrad Toast/DLLManager": { 273 | "description": "Simplifies DLL file management. Loads your requested DLLs, keeps track of which DLLs are loaded and how many times that DLL has been referenced, and if the reference count on a DLL drops to 0 it is automatically unloaded.", 274 | "files": "v2/Komrad Toast/DLLManager.ahk", 275 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=134661", 276 | "keywords": "DLL, win32", 277 | "repository": "ahkscript/ScriptHub/main" 278 | }, 279 | "MrDoge/MemoryModule": { 280 | "description": "Include a .dll into a compiled .exe and then load the .dll and use it without having to extract the .dll", 281 | "files": "v2/MrDoge/MemoryModule.ahk", 282 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=128846", 283 | "repository": "ahkscript/ScriptHub/main" 284 | }, 285 | "MrDoge/SH_Watcher": { 286 | "description": "Monitors for folder changes based on an event-driven method.", 287 | "files": "SH_Watcher.ah2", 288 | "repository": "FuPeiJiang/SH_Watcher.ah2/main" 289 | }, 290 | "MrDoge/VD": { 291 | "description": "Control and move windows between virtual desktops. Warning: this library uses an undocumented Windows API, which has a real chance of breaking in the future. In such a case the library will need to be updated to accommodate.", 292 | "files": "VD.ah2", 293 | "license": "MIT", 294 | "repository": "FuPeiJiang/VD.ahk/v2_port" 295 | }, 296 | "MrDoge/sqlite": { 297 | "description": "Wrapper for SQLite, which implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine", 298 | "files": "v2/MrDoge/sqlite.ahk", 299 | "repository": "ahkscript/ScriptHub/main" 300 | }, 301 | "Qriist/LibQurl": { 302 | "author": { 303 | "email": "Qriist+LibQurl@gmail.com", 304 | "name": "Qriist" 305 | }, 306 | "bugs": { 307 | "url": "https://github.com/Qriist/LibQurl/issues" 308 | }, 309 | "dependencies": { 310 | "G33kDude/cJson": "^2.0.0" 311 | }, 312 | "description": "A full libcurl wrapper for AHKv2", 313 | "keywords": "curl, libcurl, internet, transfers", 314 | "license": "" 315 | }, 316 | "RaptorX/SQLite": { 317 | "description": "Wrapper for SQLite, which implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine", 318 | "files": [ 319 | "License.txt", 320 | "SQLite.ahk", 321 | "lib/*.*" 322 | ], 323 | "license": "MIT", 324 | "repository": "RaptorX/SQLite/main" 325 | }, 326 | "Ruevil2/ADOSQL": { 327 | "description": "Wraps the utility of ADODB to connect to a database, submit a query, and read the resulting recordset", 328 | "files": "v2/Ruevil2/ADOSQL.ahk", 329 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=125462", 330 | "repository": "ahkscript/ScriptHub/main" 331 | }, 332 | "SKAN/InBuf": { 333 | "description": "Find values from a buffer", 334 | "files": "v2/SKAN/InBuf.ahk", 335 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=132507", 336 | "repository": "ahkscript/ScriptHub/main" 337 | }, 338 | "SKAN/ListBuffer": { 339 | "description": "UI as a function to view/search binary content, up to few MB's", 340 | "files": "v2/SKAN/ListBuffer.ahk", 341 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=101121", 342 | "repository": "ahkscript/ScriptHub/main" 343 | }, 344 | "SKAN/MapFile": { 345 | "description": "Maps a view of a file object (Parameter FileObj) into the address space of AutoHotkey process", 346 | "files": "v2/SKAN/MapFile.ahk", 347 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=132507", 348 | "repository": "ahkscript/ScriptHub/main" 349 | }, 350 | "SKAN/MonitorFind": { 351 | "description": "Enumerates a list (database) of plugged-in monitors", 352 | "files": "v2/SKAN/MonitorFind.ahk", 353 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=133259", 354 | "repository": "ahkscript/ScriptHub/main" 355 | }, 356 | "SKAN/PathX": { 357 | "description": "PathX() is an alternative solution for SplitPath(). It breaks down a fullpath to individual parts and returns them as an object.", 358 | "files": "v2/SKAN/PathX.ahk", 359 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=120582", 360 | "repository": "ahkscript/ScriptHub/main" 361 | }, 362 | "SKAN/RunAsTask": { 363 | "description": "Auto-elevates script without UAC prompt", 364 | "files": "v2/SKAN/RunAsTask.ahk", 365 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=119710", 366 | "repository": "ahkscript/ScriptHub/main" 367 | }, 368 | "SKAN/RunCMD": { 369 | "description": "Run a program in windowless mode and capture its output", 370 | "files": "v2/SKAN/RunCMD.ahk", 371 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=133668", 372 | "repository": "ahkscript/ScriptHub/main" 373 | }, 374 | "SKAN/ToggleSound": { 375 | "description": "Toggle between audio devices using their names or IDs", 376 | "files": "v2/SKAN/ToggleSound.ahk", 377 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=131731", 378 | "repository": "ahkscript/ScriptHub/main" 379 | }, 380 | "SKAN/WiseGui": { 381 | "description": "Create highly customizable notifications", 382 | "files": "v2/SKAN/WiseGui.ahk", 383 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=94044", 384 | "repository": "ahkscript/ScriptHub/main" 385 | }, 386 | "Spawnova/ShinsImageScanClass": { 387 | "description": "Search for images and pixels extremely fast and also with background window support", 388 | "files": "AHK V2/ShinsImageScanClass.ahk", 389 | "repository": "Spawnova/ShinsImageScanClass/main" 390 | }, 391 | "Spawnova/ShinsOverlayClass": { 392 | "description": "A Direct2D overlay, made to be user friendly and fast.", 393 | "files": "AHK V2/ShinsOverlayClass.ahk", 394 | "repository": "Spawnova/ShinsOverlayClass/main" 395 | }, 396 | "Tebayaki/HotGestures": { 397 | "description": "This is a light Autohotkey library for mouse gestures creating and recognizing. It helps you to customize any one-stroke pattern and bind it to any function.", 398 | "files": [ 399 | "HotGestures.ahk", 400 | "GestureRecorder.ahk" 401 | ], 402 | "license": "MIT", 403 | "main": "HotGestures.ahk", 404 | "repository": "Tebayaki/HotGestures/main" 405 | }, 406 | "The-CoDingman/WebViewToo": { 407 | "description": "Allows for use of the WebView2 Framework within AHK to create Web-based GUIs", 408 | "files": [ 409 | "AHK Resources/*.*" 410 | ], 411 | "license": "MIT", 412 | "main": "AHK Resources/WebViewToo.ahk", 413 | "repository": "The-CoDingman/WebViewToo/main" 414 | }, 415 | "The-CoDingman/gToolTip": { 416 | "description": "Class for creating ToolTips that can be clicked, dragged, and customized by font and color", 417 | "files": "gTooltip.ahk", 418 | "license": "MIT", 419 | "repository": "The-CoDingman/gToolTip.ahk/main" 420 | }, 421 | "TheArkive/CliSAK": { 422 | "description": "CLI class: easy one-time and streaming output that collects stdOut and stdErr, and allows writing to stdIn", 423 | "files": "AHK2/TheArkive_CliSAK.ahk", 424 | "license": "MIT", 425 | "repository": "TheArkive/CLSAK_AHK/master" 426 | }, 427 | "TheArkive/JXON": { 428 | "description": "JSON serializer for AHK v2", 429 | "files": "_JXON.ahk", 430 | "license": "MIT", 431 | "repository": "TheArkive/JXON_ahk2/master" 432 | }, 433 | "TheArkive/WinClip": { 434 | "dependencies": { 435 | "TheArkive/WinClipAPI": "*" 436 | }, 437 | "description": "Manipulate clipboard contents", 438 | "files": [ 439 | "WinClip.ahk" 440 | ], 441 | "license": "MIT", 442 | "repository": "TheArkive/WinClip_ahk2/master" 443 | }, 444 | "TheArkive/WinClipAPI": { 445 | "description": "Base class for the WinClip library", 446 | "files": [ 447 | "WinClipAPI.ahk" 448 | ], 449 | "license": "MIT", 450 | "repository": "TheArkive/WinClip_ahk2/master" 451 | }, 452 | "Tigerlily/MonitorFind": { 453 | "description": "Wrapper for monitor configuration WinAPI functions, get and set monitor properties (brightness etc)", 454 | "files": "v2/Tigerlily/MonitorFind.ahk", 455 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=79220", 456 | "repository": "ahkscript/ScriptHub/main" 457 | }, 458 | "Uberi/Yunit": { 459 | "description": "Super simple unit testing framework", 460 | "homepage": "https://github.com/Uberi/Yunit/tree/v2", 461 | "license": "AGPL-3.0", 462 | "main": "Yunit.ahk", 463 | "repository": "Uberi/Yunit/v2", 464 | "scripts": { 465 | "postdownload": "A_WorkingDir := A_Args[1]\nFileAppend('`n#include JUnit.ahk`n#include OutputDebug.ahk`n#include Stdout.ahk`n#include Window.ahk', 'Yunit.ahk')" 466 | } 467 | }, 468 | "XMCQCX/Notify": { 469 | "description": "Create and display notification GUIs", 470 | "files": "Notify.ahk", 471 | "homepage": "https://github.com/XMCQCX/Notify_Class", 472 | "license": "MIT", 473 | "repository": "XMCQCX/Notify_Class/main" 474 | }, 475 | "anonymous1184/GetUrl": { 476 | "description": "Get the current URL from a browser window", 477 | "main": "GetUrl.ahk", 478 | "repository": "gist:7cce378c9dfdaf733cb3ca6df345b140/GetUrl.ahk" 479 | }, 480 | "buliasz/Gdip": { 481 | "description": "GDI+ library (Gdip_All.ahk) for graphics manipulation", 482 | "files": "Gdip_All.ahk", 483 | "repository": "buliasz/AHKv2-Gdip/master" 484 | }, 485 | "burque505/JartePlus": { 486 | "description": "A library to automate Jarte Plus", 487 | "files": "v2/burque505/JartePlus.ahk", 488 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=135720", 489 | "license": "MIT", 490 | "repository": "ahkscript/ScriptHub/main" 491 | }, 492 | "cyruz/ConfMan": { 493 | "description": "Ini files management class, implementing an object central storage and an interface dealing with the underlined classes", 494 | "files": "v2/cyruz/ConfMan.ahk", 495 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=112809", 496 | "repository": "ahkscript/ScriptHub/main" 497 | }, 498 | "cyruz/StdoutToVar": { 499 | "description": "Runs a command line program and returns its output", 500 | "files": "v2/cyruz/StdoutToVar.ahk", 501 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=109148", 502 | "repository": "ahkscript/ScriptHub/main" 503 | }, 504 | "devPnal/AhkSoup": { 505 | "description": "HTML Parsing library for Autohotkey (v2)", 506 | "files": "AhkSoup.ahk", 507 | "license": "MIT", 508 | "repository": "devPnal/ahksoup/main" 509 | }, 510 | "devPnal/EveryHangul": { 511 | "description": "Library for processing the Korean alphabet, \"Hangul\".", 512 | "files": "EveryHangul.ahk", 513 | "license": "MIT", 514 | "repository": "devPnal/every-hangul-v2" 515 | }, 516 | "emliberace/MIDI": { 517 | "description": "The MIDIv2 library grants MIDI functionality to AutoHotKey v2. Send and receive MIDI in your AHK scripts with ease.", 518 | "files": "MIDIv2.ahk", 519 | "license": "GPL-3.0", 520 | "repository": "emliberace/MIDIv2.ahk/main" 521 | }, 522 | "evilC/AutoHotInterception": { 523 | "description": "AutoHotInterception (AHI) allows you to execute AutoHotkey code in response to events from a specific keyboard or mouse, whilst (optionally) blocking the native functionality (i.e. stopping Windows from seeing that keyboard or mouse event).", 524 | "files": [ 525 | "AHK v2/Lib/*.*" 526 | ], 527 | "homepage": "https://github.com/evilC/AutoHotInterception", 528 | "license": "MIT; Interception driver: LGPL for non-commercial, custom license for commercial use", 529 | "main": "AHK v2/Lib/AutoHotInterception.ahk", 530 | "repository": "evilC/AutoHotInterception/master", 531 | "scripts": { 532 | "postdownload": "A_WorkingDir := A_Args[1]\nDownload(\"https://github.com/oblitum/Interception/releases/latest/download/Interception.zip\", \"Interception.zip\")\nDirCopy \"Interception.zip\", \"Interception\", true\nFileCopy('Interception\\Interception\\library\\x64\\interception.dll', 'AHK v2\\Lib\\x64\\interception.dll', true)\nFileCopy('Interception\\Interception\\library\\x86\\interception.dll', 'AHK v2\\Lib\\x86\\interception.dll', true)\nFileMove('Common\\Lib\\AutoHotInterception.dll', 'AHK v2\\Lib\\AutoHotInterception.dll', true)\nFileMove('Interception\\Interception\\command line installer\\install-interception.exe', 'AHK v2\\Lib\\install-interception.exe')\nif !(FileExist('C:\\Windows\\System32\\drivers\\mouse.sys') && FileExist('C:\\Windows\\System32\\drivers\\keyboard.sys')) {\nMsgBox('Preparing to run the Interception driver installer.`nReboot your computer after installation.`n`nPress OK to continue', 'Notice', 'Iconi')\nRunWait '*RunAs \"AHK v2\\Lib\\install-interception.exe\" /install',, 'Hide'\n}\nDirDelete('Interception', true)\nDirDelete('Common', true)\nRunWait 'powershell.exe -windowstyle hidden -ExecutionPolicy Bypass -File \"' A_WorkingDir '\\AHK v2\\Lib\\Unblocker.ps1\"',, 'Hide'\nExitApp", 533 | "preinstall": "ExitApp((FileExist('C:\\Windows\\System32\\drivers\\mouse.sys') && FileExist('C:\\Windows\\System32\\drivers\\keyboard.sys')) ? 0 : (MsgBox('This package requires installing the Interception driver, which requires administrator access and must be used cautiously as not to disable certain key combinations such as Ctrl+Alt+Delete. Are you sure you want to continue?', 'Warning', 'YesNo Icon!') = 'Yes') ? 0 : 1)", 534 | "preremove": "A_WorkingDir := A_Args[1]\nif !(FileExist('C:\\Windows\\System32\\drivers\\mouse.sys') && FileExist('C:\\Windows\\System32\\drivers\\keyboard.sys')) || !FileExist('AHK v2\\Lib\\install-interception.exe')\nExitApp\nif MsgBox('Do you wish to uninstall the Interception driver?`nThis requires Administator privileges and a reboot after uninstalling.', 'Uninstall Interception', 'YesNo Icon?') = 'Yes'\nRunWait('*RunAs \"AHK v2\\Lib\\install-interception.exe\" /uninstall',,'Hide')\nExitApp" 535 | } 536 | }, 537 | "evilC/InterceptionTapHoldManager": { 538 | "dependencies": { 539 | "evilC/AutoHotInterception": "*", 540 | "evilC/TapHoldManager": "*" 541 | }, 542 | "description": "A patch for TapHoldManager that allows it to be used with the Interception driver. See main description under evilC/TapHoldManager", 543 | "files": "AHK v2/Lib/InterceptionTapHold.ahk", 544 | "homepage": "https://github.com/evilC/TapHoldManager", 545 | "license": "MIT", 546 | "repository": "evilC/TapHoldManager/master" 547 | }, 548 | "evilC/TapHoldManager": { 549 | "description": "An AutoHotkey library that allows you to map multiple actions to one key using a tap-and hold system. Long press / Tap / Multi Tap / Tap and Hold / Multi Tap and Hold etc are all supported.", 550 | "files": "AHK v2/Lib/TapHoldManager.ahk", 551 | "homepage": "https://github.com/evilC/TapHoldManager", 552 | "license": "MIT", 553 | "repository": "evilC/TapHoldManager/master" 554 | }, 555 | "feiyue/FindText": { 556 | "description": "A high-performance image search library, which can use images in text form", 557 | "files": "v2/feiyue/FindText.ahk", 558 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=116471", 559 | "keywords": [ 560 | "image" 561 | ], 562 | "repository": "ahkscript/ScriptHub/main" 563 | }, 564 | "iseahound/ImagePut": { 565 | "description": "A core library for images in AutoHotkey", 566 | "files": "ImagePut.ahk", 567 | "homepage": "https://github.com/iseahound/ImagePut", 568 | "license": "MIT", 569 | "repository": "iseahound/ImagePut/master" 570 | }, 571 | "iseahound/TextRender": { 572 | "description": "Draw images and text on the screen, configure its background color, text outline, and drop shadow, make the text clickable and more", 573 | "files": "TextRender.ahk", 574 | "homepage": "https://github.com/iseahound/TextRender", 575 | "license": "MIT", 576 | "repository": "iseahound/TextRender/main" 577 | }, 578 | "jNizM/DNSQuery": { 579 | "description": "Retrieves the Resource Record (RR) depends on DNS Record Type", 580 | "files": "src/Network/DNSQuery.ahk", 581 | "license": "MIT", 582 | "repository": "jNizM/ahk-scripts-v2/main", 583 | "scripts": { 584 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\DNSQuery.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 585 | } 586 | }, 587 | "jNizM/DnsServerList": { 588 | "description": "Gets a list of DNS servers for the local computer", 589 | "files": "src/Network/DnsServerList.ahk", 590 | "license": "MIT", 591 | "repository": "jNizM/ahk-scripts-v2/main", 592 | "scripts": { 593 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\DnsServerList.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 594 | } 595 | }, 596 | "jNizM/EnumInstalledApps": { 597 | "description": "Gets general information about an application (from the Add/Remove Programs Application)", 598 | "files": "src/ComObject/EnumInstalledApps.ahk", 599 | "license": "MIT", 600 | "repository": "jNizM/ahk-scripts-v2/main", 601 | "scripts": { 602 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\EnumInstalledApps.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 603 | } 604 | }, 605 | "jNizM/FileCountLines": { 606 | "description": "Count the number of lines in a file", 607 | "files": "src/FileObject/FileCountLines.ahk", 608 | "license": "MIT", 609 | "repository": "jNizM/ahk-scripts-v2/main", 610 | "scripts": { 611 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\FileCountLines.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 612 | } 613 | }, 614 | "jNizM/FileFindString": { 615 | "description": "Finds a specific word / string in a text file", 616 | "files": "src/FileObject/FileFindString.ahk", 617 | "license": "MIT", 618 | "repository": "jNizM/ahk-scripts-v2/main", 619 | "scripts": { 620 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\FileFindString.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 621 | } 622 | }, 623 | "jNizM/FileReadLastLines": { 624 | "description": "Read last x lines of a text file", 625 | "files": "src/FileObject/FileReadLastLines.ahk", 626 | "license": "MIT", 627 | "repository": "jNizM/ahk-scripts-v2/main", 628 | "scripts": { 629 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\FileReadLastLines.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 630 | } 631 | }, 632 | "jNizM/GetAdaptersInfo": { 633 | "description": "Gets network adapter information for the local computer", 634 | "files": "src/Network/GetAdaptersInfo.ahk", 635 | "license": "MIT", 636 | "repository": "jNizM/ahk-scripts-v2/main", 637 | "scripts": { 638 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\GetAdaptersInfo.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 639 | } 640 | }, 641 | "jNizM/GetFilePEHeader": { 642 | "description": "Get the PE File Header information (Machine Type)", 643 | "files": "src/FileObject/GetFilePEHeader.ahk", 644 | "license": "MIT", 645 | "repository": "jNizM/ahk-scripts-v2/main", 646 | "scripts": { 647 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\GetFilePEHeader.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 648 | } 649 | }, 650 | "jNizM/Hash": { 651 | "description": "Calculate hash (MD2, MD4, MD5, SHA-1, SHA-256, SHA-384, SHA-512, HMAC, PBKDF2) from string, hex or file", 652 | "files": "src/HashCalc.ahk", 653 | "license": "MIT", 654 | "repository": "jNizM/HashCalc/master", 655 | "scripts": { 656 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\src\\HashCalc.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; COMPILER DIRECTIVES ===[\\w\\W]+?; INCLUDES ====+\\r?\\n\\r?\\n\"))" 657 | } 658 | }, 659 | "jNizM/IsProcessElevated": { 660 | "description": "Retrieves whether a process has elevated privileges", 661 | "files": "src/ProcessThreadModule/IsProcessElevated.ahk", 662 | "license": "MIT", 663 | "repository": "jNizM/ahk-scripts-v2/main", 664 | "scripts": { 665 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\IsProcessElevated.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 666 | } 667 | }, 668 | "jNizM/NVML": { 669 | "description": "Wrapper for NVIDIA NVML: retrieve info about NVIDIA graphics cards", 670 | "files": "src/Class_NVML.ahk", 671 | "license": "MIT, NVML", 672 | "repository": "jNizM/NVIDIA_NVML/main" 673 | }, 674 | "jNizM/ResolveHostname": { 675 | "description": "Gets the IP Address from a Hostname (Resolve Hostname to IP Address) like nslookup", 676 | "files": "src/Network/ResolveHostname.ahk", 677 | "license": "MIT", 678 | "repository": "jNizM/ahk-scripts-v2/main", 679 | "scripts": { 680 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\ResolveHostname.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 681 | } 682 | }, 683 | "jNizM/ReverseLookup": { 684 | "description": "Gets the Hostname by the IP Address (Reverse Lookup) like nslookup", 685 | "files": "src/Network/ReverseLookup.ahk", 686 | "repository": "jNizM/ahk-scripts-v2/main", 687 | "scripts": { 688 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\ReverseLookup.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"; ======+\\r?\\n; Example[\\w\\W]+$\"))" 689 | } 690 | }, 691 | "just me/GuiCtrlTips": { 692 | "description": "Add tooltips to your Gui.Controls", 693 | "files": "GuiCtrlTips.ahk", 694 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=116218", 695 | "repository": "AHK-just-me/AHKv2_GuiCtrlTips/main" 696 | }, 697 | "just me/ListViewExtensions": { 698 | "description": "Additional functions for GUI ListView controls", 699 | "files": "v2/just me/ListViewExtensions.ahk", 700 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=95019", 701 | "repository": "ahkscript/ScriptHub/main" 702 | }, 703 | "just me/SQLiteDB": { 704 | "description": "Class definitions as wrappers for SQLite3.dll to work with SQLite DBs", 705 | "files": "v2/just me/SQLiteDB.ahk", 706 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=95389", 707 | "repository": "ahkscript/ScriptHub/main" 708 | }, 709 | "just me/ToolTipOptions": { 710 | "description": "Can set font, color and title options for subsequent calls to the ToolTip command", 711 | "files": "v2/just me/ToolTipOptions.ahk", 712 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=113308", 713 | "repository": "ahkscript/ScriptHub/main" 714 | }, 715 | "just me/WatchFolder": { 716 | "description": "Notifies about changes within folders, a rewrite of HotKeyIt's WatchDirectory()", 717 | "files": "v2/just me/WatchFolder.ahk", 718 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=95659", 719 | "repository": "ahkscript/ScriptHub/main" 720 | }, 721 | "lexikos/CLR": { 722 | "description": "Load the Common Language Runtime into the script's process, load .NET assemblies, instantiate objects and call instance methods or properties, compile C# or VB code on the fly or to file", 723 | "files": "CLR.ahk", 724 | "repository": "Lexikos/CLR.ahk/v2.0" 725 | }, 726 | "lexikos/ObjRegisterActive": { 727 | "description": "Registers an object as the active object for a given class ID.", 728 | "files": "v2/lexikos/ObjRegisterActive.ahk", 729 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=6&t=6148", 730 | "repository": "ahkscript/ScriptHub/main" 731 | }, 732 | "lexikos/OnProcessClose": { 733 | "description": "Monitor for process close event efficiently", 734 | "files": [ 735 | "v2/lexikos/OnProcessClose.ahk", 736 | "v2/lexikos/RegisterWaitCallback.ahk" 737 | ], 738 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=110691", 739 | "main": "v2/lexikos/OnProcessClose.ahk", 740 | "repository": "ahkscript/ScriptHub/main" 741 | }, 742 | "lexikos/RegisterWaitCallback": { 743 | "description": "Monitor for a handle signal event", 744 | "files": "v2/lexikos/RegisterWaitCallback.ahk", 745 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=110691", 746 | "repository": "ahkscript/ScriptHub/main" 747 | }, 748 | "lexikos/XInput": { 749 | "description": "Wraps a few key functions of XInput: get XBox controller information (read L/R triggers), set level of vibration", 750 | "files": "v2/lexikos/XInput.ahk", 751 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=106254", 752 | "repository": "ahkscript/ScriptHub/main" 753 | }, 754 | "neogna2/GetOpenedFiles": { 755 | "description": "Gets an array of files currently in use by a process", 756 | "files": "v2/neogna2/GetOpenedFiles.ahk", 757 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=110405", 758 | "repository": "ahkscript/ScriptHub/main" 759 | }, 760 | "nperovic/ColorButton": { 761 | "description": "An extended method for changing a button's background color", 762 | "files": "ColorButton.ahk", 763 | "license": "MIT", 764 | "repository": "nperovic/ColorButton.ahk/main" 765 | }, 766 | "nperovic/GuiEnhancerKit": { 767 | "description": "Provides a set of extended methods and properties to enhance your AutoHotkey Gui development experience", 768 | "files": "GuiEnhancerKit.ahk", 769 | "license": "MIT", 770 | "repository": "nperovic/GuiEnhancerKit/main" 771 | }, 772 | "nperovic/ToolTipEx": { 773 | "description": "Creates a pop-up tooltip that follows the mouse movement, can be switched between dark and light themes, and be clicked and dragged", 774 | "files": "ToolTipEx (for v2.0+).ahk", 775 | "license": "MIT", 776 | "repository": "nperovic/ToolTipEx/main" 777 | }, 778 | "prasad383/HotKeyChain": { 779 | "description": "This class creates an interactive hotkey system with a GUI menu, supporting nested hotkeys and customizable appearance", 780 | "files": "v2/prasad383/HotKeyChain.ahk", 781 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=135125", 782 | "repository": "ahkscript/ScriptHub/main" 783 | }, 784 | "prasad383/SettingsManager": { 785 | "description": "A simple class to manage settings for any script using ini files.", 786 | "files": "v2/prasad383/SettingsManager.ahk", 787 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=135324", 788 | "repository": "ahkscript/ScriptHub/main", 789 | "scripts": { 790 | "postdownload": "A_FileEncoding := \"UTF-8\", Path := A_Args[1] \"\\DNSQuery.ahk\", Content := FileRead(Path), FileOpen(Path, \"w\").Write(RegExReplace(Content, \"[\\w\\W]*;========+\\r?\\n\"))" 791 | } 792 | }, 793 | "rockitdontstopit/ImageActions": { 794 | "dependencies": { 795 | "feiyue/FindText": "*" 796 | }, 797 | "description": "A helper class for FindText, simplifying FindText image searches and clicking", 798 | "files": "v2/rockitdontstopit/ImageActions.ahk", 799 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=135206", 800 | "repository": "ahkscript/ScriptHub/main" 801 | }, 802 | "sxzxs/redis": { 803 | "description": "Redis wrapper for AutoHotkey, provides a set of functions to interact with Redis", 804 | "files": [ 805 | "lib/*.*" 806 | ], 807 | "license": "MIT", 808 | "main": "lib/redisclient.ahk", 809 | "repository": "sxzxs/redis/main" 810 | }, 811 | "thqby/Audio": { 812 | "description": "Core Audio APIs", 813 | "files": "Audio.ahk", 814 | "license": "MIT", 815 | "repository": "thqby/ahk2_lib/master" 816 | }, 817 | "thqby/Base64": { 818 | "description": "Encode a buffer to a base64 string, or decode a base64 string.", 819 | "files": "Base64.ahk", 820 | "license": "MIT", 821 | "repository": "thqby/ahk2_lib/master" 822 | }, 823 | "thqby/CGdip": { 824 | "description": "Gdip implemented as a class instead of seperate functions", 825 | "files": "CGdip.ahk", 826 | "license": "MIT", 827 | "repository": "thqby/ahk2_lib/master" 828 | }, 829 | "thqby/Chrome": { 830 | "dependencies": { 831 | "thqby/WebSocket": "*" 832 | }, 833 | "description": "Automate Google Chrome using native AutoHotkey\nNOTICE: this also requires a JSON library, for example G33kDude/cJson or thqby/JSON", 834 | "files": "Chrome.ahk", 835 | "license": "MIT", 836 | "repository": "thqby/ahk2_lib/master", 837 | "scripts": { 838 | "postdownload": "A_WorkingDir := A_Args[1]\nA_FileEncoding := 'UTF-8'\nContent := FileRead('Chrome.ahk')\nFileOpen('Chrome.ahk', 'w').Write(StrReplace(Content, \"#Include 'WebSocket.ahk'\", \"; #Include 'WebSocket.ahk'\"))" 839 | } 840 | }, 841 | "thqby/ComObjDll": { 842 | "description": "Create a COM object from an unregistered DLL", 843 | "files": "ComObjDll.ahk", 844 | "license": "MIT", 845 | "repository": "thqby/ahk2_lib/master" 846 | }, 847 | "thqby/Crypt": { 848 | "description": "Cryptograhic functions for MD5, SHA, and AES hashes", 849 | "files": "Crypt.ahk", 850 | "license": "MIT", 851 | "repository": "thqby/ahk2_lib/master" 852 | }, 853 | "thqby/Detours": { 854 | "description": "Detours is a software package for monitoring and instrumenting API calls on Windows.", 855 | "files": [ 856 | "Detours/*.*" 857 | ], 858 | "license": "MIT", 859 | "main": "Detours.ahk", 860 | "repository": "thqby/ahk2_lib/master" 861 | }, 862 | "thqby/DirectoryWatcher": { 863 | "description": "Call the notification function when the specified directory changes", 864 | "files": "DirectoryWatcher.ahk", 865 | "license": "MIT", 866 | "repository": "thqby/ahk2_lib/master" 867 | }, 868 | "thqby/DownloadAsync": { 869 | "dependencies": { 870 | "thqby/WinHttpRequest": "*" 871 | }, 872 | "description": "Asynchronous download, you can get the download progress, and call the specified function after the download is complete.", 873 | "files": "DownloadAsync.ahk", 874 | "license": "MIT", 875 | "repository": "thqby/ahk2_lib/master", 876 | "scripts": { 877 | "postdownload": "A_WorkingDir := A_Args[1]\nA_FileEncoding := 'UTF-8'\nContent := FileRead('DownloadAsync.ahk')\nFileOpen('DownloadAsync.ahk', 'w').Write(Trim(StrReplace(Content, '#Include WinHttpRequest.ahk'), '`r`n'))" 878 | } 879 | }, 880 | "thqby/JSON": { 881 | "description": "A basic JSON library", 882 | "files": "JSON.ahk", 883 | "license": "MIT", 884 | "repository": "thqby/ahk2_lib/master" 885 | }, 886 | "thqby/LoadScript": { 887 | "description": "Loads a script file or script code as a subprocess and returns an object that can be used to call functions or get/set global variables.", 888 | "files": "LoadScript.ahk", 889 | "license": "MIT", 890 | "repository": "thqby/ahk2_lib/master" 891 | }, 892 | "thqby/NTL": { 893 | "description": "NTL is a high-performance, portable C++ library providing data structures and algorithms for manipulating signed, arbitrary length integers, and for vectors, matrices, and polynomials over the integers and over finite fields.", 894 | "files": [ 895 | "NTLCalc/*.*" 896 | ], 897 | "license": "MIT", 898 | "main": "NTLCalc.ahk", 899 | "repository": "thqby/ahk2_lib/master" 900 | }, 901 | "thqby/Native": { 902 | "description": "Create native functions or methods from MCode, load modules written in C/C++ as native classes or functions.", 903 | "files": "Native/Native.ahk", 904 | "license": "MIT", 905 | "repository": "thqby/ahk2_lib/master" 906 | }, 907 | "thqby/Promise": { 908 | "description": "Implements a Javascript-like Promise", 909 | "files": "Promise.ahk", 910 | "license": "MIT", 911 | "repository": "thqby/ahk2_lib/master" 912 | }, 913 | "thqby/RapidOcr": { 914 | "description": "A cross platform OCR Library based on PaddleOCR & OnnxRuntime", 915 | "files": [ 916 | "RapidOcr/*.*" 917 | ], 918 | "license": "MIT", 919 | "main": "RapidOcr/RapidOcr.ahk", 920 | "repository": "thqby/ahk2_lib/master" 921 | }, 922 | "thqby/Socket": { 923 | "description": "Simple implementation of a socket Server and Client.", 924 | "files": "Socket.ahk", 925 | "license": "MIT", 926 | "repository": "thqby/ahk2_lib/master" 927 | }, 928 | "thqby/WebSocket": { 929 | "description": "The websocket client implemented through winhttp", 930 | "files": "WebSocket.ahk", 931 | "license": "MIT", 932 | "repository": "thqby/ahk2_lib/master" 933 | }, 934 | "thqby/WebView2": { 935 | "description": "The Microsoft Edge WebView2 control enables you to host web content in your application using Microsoft Edge (Chromium) as the rendering engine", 936 | "files": [ 937 | "WebView2/*.*" 938 | ], 939 | "license": "MIT", 940 | "main": "WebView2/WebView2.ahk", 941 | "repository": "thqby/ahk2_lib/master" 942 | }, 943 | "thqby/WinHttpRequest": { 944 | "description": "Wrapper for WinHttp.WinHttpRequest.5.1 to make web requests.", 945 | "files": "WinHttpRequest.ahk", 946 | "license": "MIT", 947 | "repository": "thqby/ahk2_lib/master" 948 | }, 949 | "thqby/YAML": { 950 | "description": "Converts a AutoHotkey Object Notation (YAML/JSON) string into an object.", 951 | "files": "YAML.ahk", 952 | "license": "MIT", 953 | "repository": "thqby/ahk2_lib/master" 954 | }, 955 | "thqby/archive": { 956 | "description": "Read and write archives in many formats.", 957 | "files": "archive.ahk", 958 | "license": "MIT", 959 | "repository": "thqby/ahk2_lib/master" 960 | }, 961 | "thqby/child_process": { 962 | "description": "Create a child process, and read stdout/stderr asynchronously, supporting multiple stdin inputs", 963 | "files": "child_process.ahk", 964 | "license": "MIT", 965 | "repository": "thqby/ahk2_lib/master" 966 | }, 967 | "thqby/ctypes": { 968 | "description": "Create struct, union, array and pointer bindings, and use it like an AHK object", 969 | "files": "ctypes.ahk", 970 | "license": "MIT", 971 | "repository": "thqby/ahk2_lib/master" 972 | }, 973 | "thqby/import_v1lib": { 974 | "description": "Import AHK v1 library to v2: call v1 functions and classes, read and modify global variables.", 975 | "license": "MIT", 976 | "main": "import_v1lib.ahk", 977 | "repository": "thqby/ahk2_lib/master" 978 | }, 979 | "thqby/wincapture": { 980 | "description": "wincapture contains 3 types of windows capture, as well as waiting for screen changes, bitmap grayscale, binarization, colors search and picture search.", 981 | "files": [ 982 | "wincapture/*.*" 983 | ], 984 | "license": "MIT", 985 | "main": "wincapture/wincapture.ahk", 986 | "repository": "thqby/ahk2_lib/master" 987 | }, 988 | "thqby/windows": { 989 | "description": "Alternative to thqby/winrt (provides an alternative entry point for the system-defined WinRT classes). Provides an AutoHotkey v2 \"language projection\" for the Windows Runtime (WinRT). In other words, it hides the details of interop between AutoHotkey and WinRT, allowing WinRT objects to be used like native AutoHotkey objects.", 990 | "license": "Unlicense", 991 | "main": "windows.ahk", 992 | "repository": "thqby/winrt.ahk/main" 993 | }, 994 | "thqby/winrt": { 995 | "description": "Provides an AutoHotkey v2 \"language projection\" for the Windows Runtime (WinRT). In other words, it hides the details of interop between AutoHotkey and WinRT, allowing WinRT objects to be used like native AutoHotkey objects.", 996 | "license": "Unlicense", 997 | "main": "winrt.ahk", 998 | "repository": "thqby/winrt.ahk/main" 999 | }, 1000 | "xroot/Array2Buffer": { 1001 | "description": "A simple way to create a buffer (eg Win32 data structure) from a 2D-array containing the data and type.", 1002 | "files": "v2/xroot/Array2Buffer.ahk", 1003 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=135564", 1004 | "repository": "ahkscript/ScriptHub/main" 1005 | } 1006 | }, 1007 | "v2.1": { 1008 | "Komrad Toast/Cursor": { 1009 | "description": "Setting cursors, loading cursors from file (.bmp / .ico / .cur / .ani), programmatically creating custom cursors, turning on trails and shadows, setting the cursor bounding rectangle, and more can be accomplished with this class", 1010 | "files": "v2/Komrad Toast/Cursor.ahk", 1011 | "homepage": "https://www.autohotkey.com/boards/viewtopic.php?f=83&t=135044", 1012 | "license": "MIT", 1013 | "repository": "ahkscript/ScriptHub/main" 1014 | } 1015 | }, 1016 | "version": "2.0.0" 1017 | } -------------------------------------------------------------------------------- /assets/main.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Descolada/Aris/b2728cf89b899ce07e2dd28ee9141e25ca52c072/assets/main.ico -------------------------------------------------------------------------------- /assets/sort_index.ahk: -------------------------------------------------------------------------------- 1 | ; Run this to load and then resave index.json to sort it and make visually uniform 2 | 3 | #Requires AutoHotkey v2 4 | #include ..\Lib\Aris\packages.ahk 5 | #include ..\Lib\utils.ahk 6 | 7 | A_FileEncoding := "UTF-8" 8 | if (Content := FileRead("index.json")) && (IndexJson := JSON.Load(Content)) && IndexJson.Count { 9 | CaseInsensitiveIndex := Mapi() 10 | for key, value in IndexJson 11 | CaseInsensitiveIndex[key] := value 12 | if (Result := JSON.Dump(CaseInsensitiveIndex, true)) 13 | FileOpen("index.json", "w").Write(Result) 14 | } 15 | -------------------------------------------------------------------------------- /lib/Aris/FanaticGuru/GuiReSizer.ahk: -------------------------------------------------------------------------------- 1 | #include .\GuiReSizer@2ba5b65\GuiResizer.ahk -------------------------------------------------------------------------------- /lib/Aris/FanaticGuru/GuiReSizer@2ba5b65/GuiResizer.ahk: -------------------------------------------------------------------------------- 1 | ; Source: https://www.autohotkey.com/boards/viewtopic.php?t=113921 2 | ; Author: FanaticGuru 3 | 4 | ;{ [Class] GuiReSizer 5 | ; Fanatic Guru 6 | ; Version 2023 03 13 7 | ; 8 | ; Update 2023 02 15: Add more Min Max properties and renamed some Properties 9 | ; Update 2023 03 13: Major rewrite. Converted to Class to allow for Methods 10 | ; 11 | ; #Requires AutoHotkey v2.0.2+ 12 | ; 13 | ; Class to Handle the Resizing of Gui and 14 | ; Move and Resize Controls 15 | ; 16 | ;------------------------------------------------ 17 | ; 18 | ; Class GuiReSizer 19 | ; 20 | ; Call: GuiReSizer(GuiObj, WindowMinMax, Width, Height) 21 | ; 22 | ; Parameters: 23 | ; 1) {GuiObj} Gui Object 24 | ; 2) {WindowMinMax} Window status, 0 = neither minimized nor maximized, 1 = maximized, -1 = minimized 25 | ; 3) {Width} Width of GuiObj 26 | ; 4) {Height} Height of GuiObj 27 | ; 28 | ; Normally parameters are passed by a callback from {gui}.OnEvent("Size", GuiReSizer) 29 | ; 30 | ; Properties: Abbr Description 31 | ; X X positional offset from margins 32 | ; Y Y positional offset from margins 33 | ; XP X positional offset from margins as percentage of Gui width 34 | ; YP Y positional offset from margins as percentage of Gui height 35 | ; OriginX OX control origin X defaults to 0 or left side of control, this relocates the origin 36 | ; OriginXP OXP control origin X as percentage of Gui width defaults to 0 or left side of control, this relocates the origin 37 | ; OriginY OY control origin Y defaults to 0 or top side of control, this relocates the origin 38 | ; OriginYP OYP control origin Y as percentage of Gui height defaults to 0 or top side of control, this relocates the origin 39 | ; Width W width of control 40 | ; WidthP WP width of control as percentage of Gui width 41 | ; Height H height of control 42 | ; HeightP HP height of control as percentage of Gui height 43 | ; MinX mininum X offset 44 | ; MaxX maximum X offset 45 | ; MinY minimum Y offset 46 | ; MaxY maximum Y offset 47 | ; MinWidth MinW minimum control width 48 | ; MaxWidth MaxW maximum control width 49 | ; MinHeight MinH minimum control height 50 | ; MaxHeight MaxH maximum control height 51 | ; Cleanup C {true/false} when set to true will redraw this control each time to cleanup artifacts, normally not required and causes flickering 52 | ; Function F {function} custom function that will be called for this control 53 | ; Anchor A {contol object} anchor control so that size and position commands are in relation to another control 54 | ; AnchorIn AI {true/false} controls where the control is restricted to the inside of another control 55 | ; 56 | ; Methods: 57 | ; Now(GuiObj) will force a manual Call now for {GuiObj} 58 | ; Opt({switches}) same as Options method 59 | ; Options({switches}) all options are set as a string with each switch separated by a space "x10 yp50 oCM" 60 | ; Flags: 61 | ; x{number} X 62 | ; y{number} Y 63 | ; xp{number} XP 64 | ; yp{number} YP 65 | ; wp{number} WidthP 66 | ; hp{number} HeightP 67 | ; w{number} Width 68 | ; h{number} Height 69 | ; minx{number} MinX 70 | ; maxx{number} MaxX 71 | ; miny{number} MinY 72 | ; maxy{number} MaxY 73 | ; minw{number} MinWidth 74 | ; maxw{number} MaxWidth 75 | ; minh{number} MinHeight 76 | ; maxh{number} MaxHeight 77 | ; oxp{number} OriginXP 78 | ; oyp{number} OriginYP 79 | ; ox{number} OriginX 80 | ; oy{number} OriginY 81 | ; o{letters} Origin: "L" left, "C" center, "R" right, "T" top, "M" middle, "B" bottom; may use 1 or 2 letters 82 | ; 83 | ; Gui Properties: 84 | ; Init {Gui}.Init := 1, will cause all controls of the Gui to be redrawn on next function call 85 | ; {Gui}.Init := 2, will also reinitialize abbreviations 86 | ; 87 | Class GuiReSizer 88 | { 89 | ;{ Call GuiReSizer 90 | Static Call(GuiObj, WindowMinMax, GuiW, GuiH) 91 | { 92 | ; On Initial display of Gui use redraw to cleanup first positioning 93 | Try 94 | (GuiObj.Init) 95 | Catch 96 | GuiObj.Init := 2 ; Redraw Twice on Initial Call(called on initial Show) 97 | 98 | If WindowMinMax = -1 ; Do nothing if window minimized 99 | Return 100 | 101 | ;{ Loop through all Controls of Gui 102 | For Hwnd, CtrlObj in GuiObj 103 | { 104 | ;{ Initializations on First Call 105 | If GuiObj.Init = 2 106 | { 107 | Try CtrlObj.OriginX := CtrlObj.OX 108 | Try CtrlObj.OriginXP := CtrlObj.OXP 109 | Try CtrlObj.OriginY := CtrlObj.OY 110 | Try CtrlObj.OriginYP := CtrlObj.OYP 111 | Try CtrlObj.Width := CtrlObj.W 112 | Try CtrlObj.WidthP := CtrlObj.WP 113 | Try CtrlObj.Height := CtrlObj.H 114 | Try CtrlObj.HeightP := CtrlObj.HP 115 | Try CtrlObj.MinWidth := CtrlObj.MinW 116 | Try CtrlObj.MaxWidth := CtrlObj.MaxW 117 | Try CtrlObj.MinHeight := CtrlObj.MinH 118 | Try CtrlObj.MaxHeight := CtrlObj.MaxH 119 | Try CtrlObj.Function := CtrlObj.F 120 | Try CtrlObj.Cleanup := CtrlObj.C 121 | Try CtrlObj.Anchor := CtrlObj.A 122 | Try CtrlObj.AnchorIn := CtrlObj.AI 123 | If !CtrlObj.HasProp("AnchorIn") 124 | CtrlObj.AnchorIn := true 125 | } 126 | ;} 127 | ;{ Initialize Current Positions and Sizes 128 | CtrlObj.GetPos(&CtrlX, &CtrlY, &CtrlW, &CtrlH) 129 | LimitX := AnchorW := GuiW, LimitY := AnchorH := GuiH, OffsetX := OffsetY := 0 130 | ;} 131 | ;{ Check for Anchor 132 | If CtrlObj.HasProp("Anchor") 133 | { 134 | If Type(CtrlObj.Anchor) = "Gui.Tab" 135 | { 136 | CtrlObj.Anchor.GetPos(&AnchorX, &AnchorY, &AnchorW, &AnchorH) 137 | Offset(CtrlObj, &TabX, &TabY) 138 | CtrlX := CtrlX - TabX, CtrlY := CtrlY - TabY 139 | AnchorW := AnchorW + AnchorX - TabX, AnchorH := AnchorH + AnchorY - TabY 140 | } 141 | Else 142 | { 143 | CtrlObj.Anchor.GetPos(&AnchorX, &AnchorY, &AnchorW, &AnchorH) 144 | If CtrlObj.HasProp("X") or CtrlObj.HasProp("XP") 145 | OffsetX := AnchorX 146 | If CtrlObj.HasProp("Y") or CtrlObj.HasProp("YP") 147 | OffsetY := AnchorY 148 | } 149 | If CtrlObj.AnchorIn 150 | LimitX := AnchorW, LimitY := AnchorH 151 | } 152 | ;} 153 | ;{ OriginX 154 | If CtrlObj.HasProp("OriginX") and CtrlObj.HasProp("OriginXP") 155 | OriginX := CtrlObj.OriginX + (CtrlW * CtrlObj.OriginXP) 156 | Else If CtrlObj.HasProp("OriginX") and !CtrlObj.HasProp("OriginXP") 157 | OriginX := CtrlObj.OriginX 158 | Else If !CtrlObj.HasProp("OriginX") and CtrlObj.HasProp("OriginXP") 159 | OriginX := CtrlW * CtrlObj.OriginXP 160 | Else 161 | OriginX := 0 162 | ;} 163 | ;{ OriginY 164 | If CtrlObj.HasProp("OriginY") and CtrlObj.HasProp("OriginYP") 165 | OriginY := CtrlObj.OriginY + (CtrlH * CtrlObj.OriginYP) 166 | Else If CtrlObj.HasProp("OriginY") and !CtrlObj.HasProp("OriginYP") 167 | OriginY := CtrlObj.OriginY 168 | Else If !CtrlObj.HasProp("OriginY") and CtrlObj.HasProp("OriginYP") 169 | OriginY := CtrlH * CtrlObj.OriginYP 170 | Else 171 | OriginY := 0 172 | ;} 173 | ;{ X 174 | If CtrlObj.HasProp("X") and CtrlObj.HasProp("XP") 175 | CtrlX := Mod(LimitX + CtrlObj.X + (AnchorW * CtrlObj.XP) - OriginX, LimitX) 176 | Else If CtrlObj.HasProp("X") and !CtrlObj.HasProp("XP") 177 | CtrlX := Mod(LimitX + CtrlObj.X - OriginX, LimitX) 178 | Else If !CtrlObj.HasProp("X") and CtrlObj.HasProp("XP") 179 | CtrlX := Mod(LimitX + (AnchorW * CtrlObj.XP) - OriginX, LimitX) 180 | ;} 181 | ;{ Y 182 | If CtrlObj.HasProp("Y") and CtrlObj.HasProp("YP") 183 | CtrlY := Mod(LimitY + CtrlObj.Y + (AnchorH * CtrlObj.YP) - OriginY, LimitY) 184 | Else If CtrlObj.HasProp("Y") and !CtrlObj.HasProp("YP") 185 | CtrlY := Mod(LimitY + CtrlObj.Y - OriginY, LimitY) 186 | Else If !CtrlObj.HasProp("Y") and CtrlObj.HasProp("YP") 187 | CtrlY := Mod(LimitY + AnchorH * CtrlObj.YP - OriginY, LimitY) 188 | ;} 189 | ;{ Width 190 | If CtrlObj.HasProp("Width") and CtrlObj.HasProp("WidthP") 191 | (CtrlObj.Width > 0 and CtrlObj.WidthP > 0 ? CtrlW := CtrlObj.Width + AnchorW * CtrlObj.WidthP : CtrlW := CtrlObj.Width + AnchorW + AnchorW * CtrlObj.WidthP - CtrlX) 192 | Else If CtrlObj.HasProp("Width") and !CtrlObj.HasProp("WidthP") 193 | (CtrlObj.Width > 0 ? CtrlW := CtrlObj.Width : CtrlW := AnchorW + CtrlObj.Width - CtrlX) 194 | Else If !CtrlObj.HasProp("Width") and CtrlObj.HasProp("WidthP") 195 | (CtrlObj.WidthP > 0 ? CtrlW := AnchorW * CtrlObj.WidthP : CtrlW := AnchorW + AnchorW * CtrlObj.WidthP - CtrlX) 196 | ;} 197 | ;{ Height 198 | If CtrlObj.HasProp("Height") and CtrlObj.HasProp("HeightP") 199 | (CtrlObj.Height > 0 and CtrlObj.HeightP > 0 ? CtrlH := CtrlObj.Height + AnchorH * CtrlObj.HeightP : CtrlH := CtrlObj.Height + AnchorH + AnchorH * CtrlObj.HeightP - CtrlY) 200 | Else If CtrlObj.HasProp("Height") and !CtrlObj.HasProp("HeightP") 201 | (CtrlObj.Height > 0 ? CtrlH := CtrlObj.Height : CtrlH := AnchorH + CtrlObj.Height - CtrlY) 202 | Else If !CtrlObj.HasProp("Height") and CtrlObj.HasProp("HeightP") 203 | (CtrlObj.HeightP > 0 ? CtrlH := AnchorH * CtrlObj.HeightP : CtrlH := AnchorH + AnchorH * CtrlObj.HeightP - CtrlY) 204 | ;} 205 | ;{ Min Max 206 | (CtrlObj.HasProp("MinX") ? MinX := CtrlObj.MinX : MinX := -999999) 207 | (CtrlObj.HasProp("MaxX") ? MaxX := CtrlObj.MaxX : MaxX := 999999) 208 | (CtrlObj.HasProp("MinY") ? MinY := CtrlObj.MinY : MinY := -999999) 209 | (CtrlObj.HasProp("MaxY") ? MaxY := CtrlObj.MaxY : MaxY := 999999) 210 | (CtrlObj.HasProp("MinWidth") ? MinW := CtrlObj.MinWidth : MinW := 0) 211 | (CtrlObj.HasProp("MaxWidth") ? MaxW := CtrlObj.MaxWidth : MaxW := 999999) 212 | (CtrlObj.HasProp("MinHeight") ? MinH := CtrlObj.MinHeight : MinH := 0) 213 | (CtrlObj.HasProp("MaxHeight") ? MaxH := CtrlObj.MaxHeight : MaxH := 999999) 214 | CtrlX := MinMax(CtrlX, MinX, MaxX) 215 | CtrlY := MinMax(CtrlY, MinY, MaxY) 216 | CtrlW := MinMax(CtrlW, MinW, MaxW) 217 | CtrlH := MinMax(CtrlH, MinH, MaxH) 218 | ;} 219 | ;{ Move and Size 220 | CtrlObj.Move(CtrlX + OffsetX, CtrlY + OffsetY, CtrlW, CtrlH) 221 | ;} 222 | ;{ Redraw on Cleanup or GuiObj.Init 223 | If GuiObj.Init or (CtrlObj.HasProp("Cleanup") and CtrlObj.Cleanup = true) 224 | CtrlObj.Redraw() 225 | ;} 226 | ;{ Custom Function Call 227 | If CtrlObj.HasProp("Function") 228 | CtrlObj.Function(GuiObj) ; CtrlObj is hidden 'this' first parameter 229 | ;} 230 | } 231 | ;} 232 | ;{ Reduce GuiObj.Init Counter and Check for Call again 233 | If (GuiObj.Init := Max(GuiObj.Init - 1, 0)) 234 | { 235 | GuiObj.GetClientPos(, , &AnchorW, &AnchorH) 236 | GuiReSizer(GuiObj, WindowMinMax, AnchorW, AnchorH) 237 | } 238 | ;} 239 | ;{ Functions: Helpers 240 | MinMax(Num, MinNum, MaxNum) => Min(Max(Num, MinNum), MaxNum) 241 | Offset(CtrlObj, &OffsetX, &OffsetY) 242 | { 243 | Hwnd := CtrlObj.Hwnd 244 | hParentWnd := DllCall("GetParent", "Ptr", Hwnd, "Ptr") 245 | RECT := Buffer(16, 0) 246 | DllCall("GetWindowRect", "Ptr", hParentWnd, "Ptr", RECT) 247 | DllCall("MapWindowPoints", "Ptr", 0, "Ptr", DllCall("GetParent", "Ptr", hParentWnd, "Ptr"), "Ptr", RECT, "UInt", 1) 248 | OffsetX := NumGet(RECT, 0, "Int"), OffsetY := NumGet(RECT, 4, "Int") 249 | } 250 | ;} 251 | } 252 | ;} 253 | ;{ Methods: 254 | ;{ Options 255 | Static Opt(CtrlObj, Options) => GuiReSizer.Options(CtrlObj, Options) 256 | Static Options(CtrlObj, Options) 257 | { 258 | For Option in StrSplit(Options, " ") 259 | { 260 | For Abbr, Cmd in Map( 261 | "xp", "XP", "yp", "YP", "x", "X", "y", "Y", 262 | "wp", "WidthP", "hp", "HeightP", "w", "Width", "h", "Height", 263 | "minx", "MinX", "maxx", "MaxX", "miny", "MinY", "maxy", "MaxY", 264 | "minw", "MinWidth", "maxw", "MaxWidth", "minh", "MinHeight", "maxh", "MaxHeight", 265 | "oxp", "OriginXP", "oyp", "OriginYP", "ox", "OriginX", "oy", "OriginY") 266 | If RegExMatch(Option, "i)^" Abbr "([\d.-]*$)", &Match) 267 | { 268 | CtrlObj.%Cmd% := Match.1 269 | Break 270 | } 271 | ; Origin letters 272 | If SubStr(Option, 1, 1) = "o" 273 | { 274 | Flags := SubStr(Option, 2) 275 | If Flags ~= "i)l" ; left 276 | CtrlObj.OriginXP := 0 277 | If Flags ~= "i)c" ; center (left to right) 278 | CtrlObj.OriginXP := 0.5 279 | If Flags ~= "i)r" ; right 280 | CtrlObj.OriginXP := 1 281 | If Flags ~= "i)t" ; top 282 | CtrlObj.OriginYP := 0 283 | If Flags ~= "i)m" ; middle (top to bottom) 284 | CtrlObj.OriginYP := 0.5 285 | If Flags ~= "i)b" ; bottom 286 | CtrlObj.OriginYP := 1 287 | } 288 | } 289 | } 290 | ;} 291 | ;{ Now 292 | Static Now(GuiObj, Redraw := true, Init := 2) 293 | { 294 | If Redraw 295 | GuiObj.Init := Init 296 | GuiObj.GetClientPos(, , &Width, &Height) 297 | GuiReSizer(GuiObj, WindowMinMax := 1, Width, Height) 298 | } 299 | ;} 300 | ;} 301 | } 302 | ;} -------------------------------------------------------------------------------- /lib/Aris/G33kDude/cJson.ahk: -------------------------------------------------------------------------------- 1 | #include .\cJson@2.0.0\JSON.ahk -------------------------------------------------------------------------------- /lib/Aris/G33kDude/cJson@2.0.0/JSON.ahk: -------------------------------------------------------------------------------- 1 | ; 2 | ; cJson.ahk 2.0.0 3 | ; Copyright (c) 2023 Philip Taylor (known also as GeekDude, G33kDude) 4 | ; https://github.com/G33kDude/cJson.ahk 5 | ; 6 | ; MIT License 7 | ; 8 | ; Permission is hereby granted, free of charge, to any person obtaining a copy 9 | ; of this software and associated documentation files (the "Software"), to deal 10 | ; in the Software without restriction, including without limitation the rights 11 | ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | ; copies of the Software, and to permit persons to whom the Software is 13 | ; furnished to do so, subject to the following conditions: 14 | ; 15 | ; The above copyright notice and this permission notice shall be included in all 16 | ; copies or substantial portions of the Software. 17 | ; 18 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | ; SOFTWARE. 25 | ; 26 | #Requires AutoHotkey v2.0 27 | 28 | class JSON 29 | { 30 | static version := "2.0.0" 31 | 32 | static BoolsAsInts { 33 | get => this.lib.bBoolsAsInts 34 | set => this.lib.bBoolsAsInts := value 35 | } 36 | 37 | static NullsAsStrings { 38 | get => this.lib.bNullsAsStrings 39 | set => this.lib.bNullsAsStrings := value 40 | } 41 | 42 | static EscapeUnicode { 43 | get => this.lib.bEscapeUnicode 44 | set => this.lib.bEscapeUnicode := value 45 | } 46 | 47 | static fnCastString := Format.Bind('{}') 48 | 49 | static __New() { 50 | this.lib := this._LoadLib() 51 | 52 | ; Populate globals 53 | this.lib.objTrue := ObjPtr(this.True) 54 | this.lib.objFalse := ObjPtr(this.False) 55 | this.lib.objNull := ObjPtr(this.Null) 56 | 57 | this.lib.fnGetMap := ObjPtr(Map) 58 | this.lib.fnGetArray := ObjPtr(Array) 59 | 60 | this.lib.fnCastString := ObjPtr(this.fnCastString) 61 | } 62 | 63 | 64 | static _LoadLib32Bit() { 65 | static lib, code := Buffer(6624), codeB64 := "" 66 | . "ubgAVYnlV1aNlbAA/v//U4HsnAEAAACLRRSLdQhIx4W0AJD2FAB4XVAMiYWcADCKAhSIBIWjABSLBolUJBgUjZUBkAASCMdE2CQQAAAAAA4MAIYB" 67 | . "DgAE3BMAAIk0JBD/UBSLAr6D7BgAg/r/dSm6ChUAAABmD74ChMAAD4TzAwAAhdsAdAyLC415AokAO2aJAesFi0UAEP8AQuvcMcBIjb24ADi5BABR" 68 | . "8yCrjX2cuQAtAGY0x4UBFQgBEgIJjb0CyAUliUWYMcDzIKuLBo2NARONfYCYiUwkGIl8AKuEvdgDqwTHhcAACaIcAITHRaAErCAEXqochAMQhAsM" 69 | . "hAcIgQMRAmYYMcCCNI2V6EeAIgFBgSuD7CSFP43uvQEMg0IANxiAQYN/g0JO+IAEgGABGggAA0fgzYAFJgFHs0MI/4NDgSw/ikMBDJBDBTOAQgEZ" 70 | . "CADox4UAQAouQyBCHoEqT1YfwCxDIAAbZoPCXgMgdQmDvdAAAgB1rlmABAFAggTwggRSgASBwSIDdRODvRAAApVAHKRABgJAE3U/ioOe5EAclYMD" 71 | . "DYEg6wrDAouBJwGJGMAUjVWoxIkQiwaDvYIXi0AUCA+Fr4MsFI1VuBkCqkW4BDrWq9CLVZqo0qpHGCeAIX3IBaoyjQEkiwYFWoGgjU1KyAZXTBdX" 72 | . "6aeGK4ikjX1ELIhAwqqoxYS7DS7FhNCGhMEfAczMAsyjADMAA0W4ZgA/A4CGMsiAJkXAQV/ChVXIuMdF0PVg4QcwQBRgJI8HQaIko0EhDwl0XUMm" 73 | . "lHQY1CXg4ACJXMAHQHXIwf4fieAKjQBFyIkEJIl1zAjo5hGiLA6LA40AUAKJE2bHACKCAAQHMf/pHgeiAwIbQzwBixMZwIMA4OCNSgKDwHsgiQtm" 74 | . "iQJEBYC9kYGVALpOIBN1boFExiggE8Ijx4WY5EigIqy9OMUCgQFIiQFYiQESaIcBD7ZCoImFlFmgAOm5YAIAEhWgHHEoAokzoBxCgx916WTriEIR" 75 | . "6+7gIuEHA5APhV8FACW9cGFgGA+EUoIBghEPhGGxgksPhC9BsEYfLAAZY4ENAxkPhSqhA2JfSMCD+AEPhmniAWEYKGaD+OAL0qA6i4UGQOABwitF" 76 | . "uMH4H1iJRbzBLYIsuIAs6OqEIEj/giCNQgcgV2CBQcEdDECJhWDgALglwki1QQKNlQEnicEIiZVQgUqljX3YQ4AFASUMQI214QCJG+ReQAOs4k2B" 77 | . "TciNjRFBHsdFsOJMRaiL1IUggWIQg2GobU2ZYqFmXAQk/1KhjolAuGgPhKbBLw5gKKIs6TbTwAEVMS4EMYQpD4QVwcbroVMk0AVHO32QGA+PlUAE" 78 | . "ulGgLsTr56MH34uFQSEBLZR1HEAHESlU6YEAFMXjBHogBBR1SXRYJV+ZwTGFMMEnIDLyDoM/lsKBCKkKvAACulNhkOCD+Al1KMxqBBfIaiEiCutN" 79 | . "ulxDBgh1TiroDaMD4Q3eD8AaX+W1JQfUEg+/Ag9aJKULXZMkOnILfA7kAy2AASksiwMkF/UBOsAXS/0JYCVQBPEAQAIgAAzpO/AAMAOLdRCLBXEC" 80 | . "QFUaRcKJBuk2HsABAhUWmhMhLukvYbMBCQ+FxYETQgG6ImugDzsF2MBcdSSdlVsOgAI/E5NbunACA7LQCgPd/A8DBgN2AgMa1AoDrA8DBgOLdRgB" 81 | . "ggsEJI1WAYu1g2FDsFMQiXQkDDAPoWAACOh19uAMaDAEXUIbHkob0jzAFinAFukSRDACunvTHQUPhRLGE3B9vII38g8QQ9ICATiIjY14AjiIIaIz" 82 | . "RbihxAALx0VOjOEAZTghYYgFUAHAD/9fPzk/OTI58g8RRRKQgDkxwKA5i1WAAGaLFAJmhdIPKISY+zwRETARdRCA/waDwALr1t8nZ9sn7h4xEMkL" 83 | . "AierNzDbcAYzQCaRAFU6CfAkEi/j0A6RQwjrFdIVVAExAfQV3ACuUQZUEgOhBh8DOwQIEwNSxkxSArlmUHVKLvAJdu9pwH3jaWADfw97DzHJO00Y" 84 | . "fbK6okeKAuO2MD8gcAMAFIszjUYCiQMjMANiAWaJBlYm1EEE68eiAI1l9In4IFteX13Dsb2/EzAAgABWob1hH3UMAItdCGbHBhQAFMdGYxxGUh2L" 85 | . "A2YBwAxFpI1K92aDIPkXD4f2MB+J+ADT6InBgOEBdBAKi0WkMBuJA+sA1maD+lsPhbWdcsKkJY+yAZGmocgwJntgJfUlyCQkb60vJWxei6BFwI1V" 86 | . "tPBjjLOFCMdFtIMspIsAi3R9pDOSsO2QtMhzBDyPscfAj9INpA13E7oREYDT6oDiAXQaQw3C30ANXQ+EvzGxcSuKtsEDdKAnHCTogWKJwGaFhtAF" 87 | . "jX3cYjY4jVXYUKaACGAIddiox0XgkQeLZJG07w48JBhvD/y0oQrztD4JaUAaRgi1JVICHBoMEFSJ+uMLEeML4uALLEQPhJIuE4PIgCw6kF0PhdDB" 88 | . "hcICYArBYTIGCQDpwFARoALYIg+F0R3hG1BgKWBYhIlWMSEIAOnVERDAg/p7D4UVMd4BHurYDB7MCx7YP0M/Qw8eVQIeffJCAxAdZnBfSAmTJ4Y8" 89 | . "Ugr4fQ+EFo2RAIF+hCMBIg+EJj6QABAO6fOiAcl0CPONepGlg/lcD0KFEZ1mi0oC0AAi5HUhoGX+IgAQ4A3ACwCLE414/maLChGyAcbp3XIO+Vx1" 90 | . "gXAPQP5cAOvX0ABCL9MALwDrydAAYqHTAAgA67vQAGbTAFAMAOut0ABu0wAKKADrn9AActMADQAU65HQAHTTAAkA68KD0AB1D4VNYBlgCFjHRZhy" 91 | . "2TFv/oEKUAD+izvB4gSJfRCkZolQsAkPjXkA0GaD/wl3BAFA+usgjXm/wAAFAHcGjVQKyesRBI15kAb/BQ+H/zFBm1QKqaAnYQODxwAC/02YiTt1" 92 | . "rwTpFiFMiUj+6Q0hcSBGCIn50B8pwSCJSPxmxzCziRNk6duQmI1CQAYAc5YCwXAeLQ+UwLS2AAjBiE2kD4TLAAEAAGbHBhQAwr8AQADHRggAKAAw" 93 | . "AgwBMIsDZoM4LQB1CIPAAoPP/wSJAwA8iwBmg/gIMHUTC6CDAwLrEFiD6DEANggPhwBU/v//iwtmiwABZolFooPoMAEAKgl3OWtGDAoAg8ECiUWU" 94 | . "uAoBAGT3ZgiJC4lVAJyJRZiLRZQBAEWcD79FopkDAEWYE1Wcg8DQAIPS/4lGCIlWiAzrtQKFLnQTAX0AEIPi32aD+kUQdEXpygF3wAK5QQG2iQPf" 95 | . "bggAxQUAAN1eCIsTZosCAgV2ymvJCoPCAAKJE4lNmNtFApgAkZjefZjcRlIIACjr1YAfiYAuPjgUdQsJIAE0gDItdBAKxkWkAHj6K3UOBQIVAoAE" 96 | . "LQ+HbP0Q//8xwIF0EYPqgYAJ+gl3D2vAAXIAD7/SiQsB0OsQ4zHJuoFPOch0AAZr0gpB6/aAUH2kAN0AbFWBRnSABN756wLeyYE5AhaAHxR1I4n4" 97 | . "iwBODJmLRggPrwDPD6/CAcGJ+EmAlAHKA4bpEYAmMcLAABUFD4XogAUBJSB9pNpNpAAh6dcRAAi5axWA54P6dAB1QWYPvgGEwAGAmxNBZjsCD4UQ" 98 | . "vfz//wKF6+WASD24EwBLdA6APAMTAX0BKetKQAMJAKGS2IAG6ZwABLlwwxKoZnVFzRJxzxIVxRIpyIXrZIMU0EAI60yEuXbDE24PhTHAD1XNFB3J" 99 | . "FMDCFA+ADwgQAKHgFIB4RgjrGhZDE9TABoADixCJAAQk/1IEUDHABOncQAu6EwCAAADT6onRgOEBD0iExfsAoVWkAhTpApAAA41FyIkcJACJRCQE" 100 | . "6N34/8D/hcAPhavBCAF7AI1K92aD+Rd30jHEEIDiQBCNQAdCfQDr24sTg8j/ZmCDOn11dgIUwiGJEH4I64SAMzoPhUJihQqJdCQEQBnoSntEGElB" 101 | . "GEXQgAUIZIk8Ax8cAgLWBx0TGQcddJYDHMG4LHWJEQID6dP6AC9l9FuAXl9dw5CQkIFq/8UAPwAfAB8AHwAfAB8AHwABDwAwMTIzNDU2ADc4OUFC" 102 | . "Q0RFAEYAAEgAYQBzAABNAGUAdABoEABvAGSgBCJVbgBrbm93bl9PYgBqZWN0XwAAUFQAdaAEaGADUyIFAEAATwB3AG7gAnJFYAZwYAMAAF8gAEUR" 103 | . "YAJ1AG2gAQ0KABgJACIFCCYKVHlwAGVfAHRydWUAAGZhbHNlAG51hGxsxwNWYWx14AMB6A0AAFWJ5VdWAI1VtI19vFODAOx8i3UIi10QCMdFtAKy" 104 | . "BolUJBAUjVUMwAAIx0TEJBBibUQkDGK3oEsB4QGJNCT/UBSLCAO5AyEGUwyD7IAYZsdF2AgAgJ8IyItDYI/UjVW4AIlF0ItFDIlFIOAxwPOrYGPH" 105 | . "RQLAAFMAiUW4iwbVIAkgJAsc5AAYIguADz+hDsEMoQ5kAyN+qQ8YgwDsJGaDOwl1DDPgDeR0CFCHWGIcU4GU7KwhFEUAr0XmAAEBoAVQBIsAicGJ" 106 | . "CNOBwSADgIPTAECD+wAPhq0CE6BgjX2wMcCiGiEWmACJVaSNTYiJRYisocQAgsdFmCIkABCJTCQYjU2sjMdFQZhA20WYFIAD/rQkJOoaQAXiGWQD" 107 | . "8xlhFwgYMcAgGotVkGYAixQCZoXSD4QCi0ADhfZ0DIsOAI1ZAokeZokRgOsFi30Q/wdgdkjr1rkAlgC7wdyFEMB5K78BAZm7MAGhCU2ESff/KdMA" 108 | . "ZolcTb6FwHUA6YtNhIPpAmYAx0RNvi0A6xAAmUn3+4PCMGYEiVTCA/AByY1EhA2+wdGF0nQaFg4y3kArMcCDK2Mrg+wADItdDIt9CIsAdRCF23QO" 109 | . "iwMEjVAClwAiAOsjEP8G6x9g2CJ1K5WwASKxAQSQAVwAAQIAQAIiAIPHAmaIiwdmEAjZ6TrQESCDBgLr6wADXHUKGAAD8Q0DXADrzQuhf9IB090B" 110 | . "YgDrrx3QAQzSAdB82wFmAOuikdABCnUb0AGX3QEgbgDpcP+gYoP4AA11H4XbD4RyQ9AATQJyAOlLQwIJBUMCTU8CAnQA6SYRYAGAPbySZQuNUALg" 111 | . "QFZedxHrQo1EUIGgACF2BhAEHxx3M3AI0DPbA3UA6wYDQBByXFwkBA+3kgdwIeg9kATp0NCOASADD4sTjUoCiUALZokC6b0gAf8YBum2kwG7FwL/" 112 | . "BgiDxAx1MDHAieURwRoQi1XwGhCLTQAIic5mwekEgyTmD+BxtuRwJGaJAHRF8ECD+AR1DOS4sS+AIBGLCo1AcQKJMmaLoAFmBIkxQAUDg+gBczDk" 113 | . "g8QQYSByYg==" 114 | if (32 != A_PtrSize * 8) 115 | throw Error("$Name does not support " (A_PtrSize * 8) " bit AHK, please run using 32 bit AHK") 116 | ; MCL standalone loader https://github.com/G33kDude/MCLib.ahk 117 | ; Copyright (c) 2023 G33kDude, CloakerSmoker (CC-BY-4.0) 118 | ; https://creativecommons.org/licenses/by/4.0/ 119 | if IsSet(lib) 120 | return lib 121 | if !DllCall("Crypt32\CryptStringToBinary", "Str", codeB64, "UInt", 0, "UInt", 1, "Ptr", buf := Buffer(3955), "UInt*", buf.Size, "Ptr", 0, "Ptr", 0, "UInt") 122 | throw Error("Failed to convert MCL b64 to binary") 123 | if (r := DllCall("ntdll\RtlDecompressBuffer", "UShort", 0x102, "Ptr", code, "UInt", 6624, "Ptr", buf, "UInt", buf.Size, "UInt*", &DecompressedSize := 0, "UInt")) 124 | throw Error("Error calling RtlDecompressBuffer",, Format("0x{:08x}", r)) 125 | for import, offset in Map(['OleAut32', 'SysFreeString'], 5340) { 126 | if !(hDll := DllCall("GetModuleHandle", "Str", import[1], "Ptr")) 127 | throw Error("Could not load dll " import[1] ": " OsError().Message) 128 | if !(pFunction := DllCall("GetProcAddress", "Ptr", hDll, "AStr", import[2], "Ptr")) 129 | throw Error("Could not find function " import[2] " from " import[1] ".dll: " OsError().Message) 130 | NumPut("Ptr", pFunction, code, offset) 131 | } 132 | for offset in [30, 91, 116, 249, 392, 522, 643, 755, 779, 800, 933, 1094, 1248, 1449, 1823, 1956, 2007, 2258, 2264, 2307, 2313, 2356, 2362, 2485, 2539, 2815, 2865, 2892, 2970, 3151, 3234, 3632, 4567, 4606, 4633, 4643, 4682, 4716, 4723, 4766, 4779, 4794, 5835, 6392, 6564] 133 | NumPut("Ptr", NumGet(code, offset, "Ptr") + code.Ptr, code, offset) 134 | if !DllCall("VirtualProtect", "Ptr", code, "Ptr", code.Size, "UInt", 0x40, "UInt*", &old := 0, "UInt") 135 | throw Error("Failed to mark MCL memory as executable") 136 | lib := { 137 | code: code, 138 | dumps: (this, pObjIn, ppszString, pcchString, bPretty, iLevel) => 139 | DllCall(this.code.Ptr + 0, "Ptr", pObjIn, "Ptr", ppszString, "IntP", pcchString, "Int", bPretty, "Int", iLevel, "CDecl Ptr"), 140 | loads: (this, ppJson, pResult) => 141 | DllCall(this.code.Ptr + 3036, "Ptr", ppJson, "Ptr", pResult, "CDecl Int") 142 | } 143 | lib.DefineProp("bBoolsAsInts", { 144 | get: (this) => NumGet(this.code.Ptr + 5048, "Int"), 145 | set: (this, value) => NumPut("Int", value, this.code.Ptr + 5048) 146 | }) 147 | lib.DefineProp("bEscapeUnicode", { 148 | get: (this) => NumGet(this.code.Ptr + 5052, "Int"), 149 | set: (this, value) => NumPut("Int", value, this.code.Ptr + 5052) 150 | }) 151 | lib.DefineProp("bNullsAsStrings", { 152 | get: (this) => NumGet(this.code.Ptr + 5056, "Int"), 153 | set: (this, value) => NumPut("Int", value, this.code.Ptr + 5056) 154 | }) 155 | lib.DefineProp("fnCastString", { 156 | get: (this) => NumGet(this.code.Ptr + 5060, "Ptr"), 157 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5060) 158 | }) 159 | lib.DefineProp("fnGetArray", { 160 | get: (this) => NumGet(this.code.Ptr + 5064, "Ptr"), 161 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5064) 162 | }) 163 | lib.DefineProp("fnGetMap", { 164 | get: (this) => NumGet(this.code.Ptr + 5068, "Ptr"), 165 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5068) 166 | }) 167 | lib.DefineProp("objFalse", { 168 | get: (this) => NumGet(this.code.Ptr + 5072, "Ptr"), 169 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5072) 170 | }) 171 | lib.DefineProp("objNull", { 172 | get: (this) => NumGet(this.code.Ptr + 5076, "Ptr"), 173 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5076) 174 | }) 175 | lib.DefineProp("objTrue", { 176 | get: (this) => NumGet(this.code.Ptr + 5080, "Ptr"), 177 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5080) 178 | }) 179 | return lib 180 | } 181 | 182 | 183 | static _LoadLib64Bit() { 184 | static lib, code := Buffer(6960), codeB64 := "" 185 | . "a7gAQVdBVkFVQVQAVVdWU0iB7GgAAgAASI0FiBYBADCJ00SJTCRcQEiJzUSKbAEchAgkkAAAXIsBTIlAxkiNlCSMATSJQFQkKEG5AQEUjYAVHhUA" 186 | . "AEyNA04Qx0QkIAAMAP9QBCiLA1aD+v91LgUASj4AumYPvgKEIMAPhGIEADiF2wB0D0iLC0yNQQACTIkDZokB6wAC/wZI/8Lr2SBFMeS5BgA6RTEA" 187 | . "yUUxwESJ4EgQjbwkmAAQTI20hCSwAXTHhCTAAWbZAADzqwIrAL/uAIcBKaLIAqGEJKACFoQCOQcBDwE5AEzzq0iLRbUADIwCFGYAJQEQCAARQEwk" 188 | . "MEiJ6QEh4L0EMrgEMoQ3AngAcUCBCQUBBDgBBEyJdCQo4wF8AQ//UDCAMQVfgDVYjQVggEsECMCBQ+j3hEsCMgA2+ItPAbIBCYRTuwBIgLYwBjsE" 189 | . "qwEcEAA474FfASSAX6RHhIIbCSSCVA3AEyjABQALTI0dtQ4UyR8AJIEGTImcJP4YwAHCI4QhgR+BE4Mf20UlwBVdwBVmg4NoA3XKCkAC0EEKdV4B" 190 | . "BQE9MwMFAlp1TgEFAR4DdUoQQAIwAQVBvMCqAKR1OQCU7RMHlBFBsOEalOsGQbwBEEA8QDpCQEVAQYP8AgM6TFuEBcGYGIATQbQAgRWLEEAoD4WB" 191 | . "SEyJREQkKMBDTYnwgB8o3hJERMAIg8LGvtAAR4EOdYW+Q0gqZwFQVyqDJzDvAA8DvwIpQW2MAgVCZBBaSnxBrkxHW+nFgnQ9Vv8AKYFv6IJt6YTs" 192 | . "iZNAWCEcifcCeTHSgDi/IQQiXYYYhA+jRiJmlGMQ3aAFQKEwxD8BIANBSWABLiBgAUEDYQQ4ZARMib604gbEBnVoQBhhDwPFi89gKKQWQEeAKP4R" 193 | . "Q0dhNEgJdFvjKXQbdyndBYUmSeA1idpIiawZogHoT6AxoAYPhLACBwEqA0iNUAJIAIkTZscAIgDpFp5hAkAKGwBDAUiLIBMZwIPgIHJKAgCDwHtI" 194 | . "iQtmiUICwQuAfCRcIZ+uUWASD4WpxkpYYBMxYO1FD7b1QidBSrhjQALhN7wkcGVOwwGIXcsBoMsBwQbGAYQCC0jdwE9wgQEBCYEBeIEBIjIVgAFg" 195 | . "gQHQJANo6bc7wSjgGB1KI8Ai4yZ144jpSv8AAAbr7GEqFaENAwAZBWBWvCTAEUE0D4SboAGF7Q/EhIQjVg+EUQEB6SUSLGEgqhBgRITtDwSFTsAD" 196 | . "QY1EJP9Ag/gBD4aSoAGLUWMVZoP4gAsBIDtI8GOEJHihCCAzwUaBjxPhACM06LXAKf/FSEKLQRuLfCRoQ2BI0IuMJEgBK9KhTeEk9AxAAQeowhGg" 197 | . "l6SgASrgDEAPKIxiBCEEwU11oQlwwVHgBFwi2kQHmJHgAA8QlEIHDylEbNXgA1gEB2ABB9gIBwIs3IsBxAkiXQBXKPhZYikwEZQkSIAFAFmJxwKF" 198 | . "gICI/v//SJiE6TMgLP8G6behAaVgNRp1NesuADXvgSykhJtgBesfoQUwtQUY/8c7wKrADQ+PbQEhC40VCg8AAOs64GAI2WAeQUkhMnUlXVEEEQww" 199 | . "wjNQGmBQAumC1hE+g/gUdUivAm+kAoAcoQIEHPSABqIizUsig6s1wtOCfw5CBQk8dS0vPC88AAvxBetOxZADTpMDCHUqISFoB7ItICjrYS8UKRQE" 200 | . "IRR4SA+/tDQEKKVBYyjo7jTzC68O0QMvkQGgB5gBIjqSL4QU/WEWUASBQgFAAiAA6QIQASSLBnAC/8ARAkXCgIkG6e78///SFGYN0QdhMOkEYAKx" 201 | . "EA8GhQMTYwFIOw27C6myEmsNsG4npWPhAARXvxKmY2ADZGMDOWoDqqtvA2wDPWMDCGoDc28DR2kDgBkxJkWJ8TMU/wLAcEcg6KL1///E6TiTDgh1" 202 | . "GCUNhBoShBAc6RqBBY0Vn8IM0hwFD4Xx9lMRNXF4b/IPEPVCxGCANyjjZGVBaQ1DCqOUgQMxQD1xAAVmReECEWmSOYsB/3OUoASjR5VvAQVPabVw" 203 | . "kQHA8g8RhCQIAzzxSAiUJPBBNIsUAmZAhdIPhEn7nxKJghGSEoPAAuvPjym3jykUIXQSrLARUQMUPTRk3vpBW+nXYACnPAkMdRAFMVAO/1AQ64oU" 204 | . "0hcOVQH/FXtwEh/XWAQDkhUOA1EB/xVKL4EVhFczAjVvupABdTXV0QlzP3J9NHJaPw85DzYjMg8gAiwvAkxMfZUlMAdJMAfr5EAD3f8SBgAYgcQR" 205 | . "y1teXwBdQVxBXUFeQThfw5AKAJbNYZtJuIQAJhMeZscCFIAfAMtIidZIx0IIAWMhE2aLCmaD+RAgD4f7Mq7ASNMA6KgBdAlIg8IJcRfr3cABWw+F" 206 | . "u78RaEAqYGnzxuABIijQEYMsiRNgK6ElgFO1vRMEAIAoJ1QkaEjBxOUJNCdMjaQzyQ8nWceySIsgghJTVFDYjVgFgQl0fjOcTIB2YKhIiwcQA1zD" 207 | . "afkVLSMX2NAjZosIwQ13FABIiepI0+qA4kWSDcCQDQPr4JABXQgPhLyREYXJD4QCs3IE8kiJ2ei7U4BjgGqFk+IfBzM5TNSJZPGvtMILi2EJQAf9" 208 | . "ADSoRNKxADHXBNNhAX81BYUAMPwOZoM+CXWgHkiLTggkKRIXCyYdFAv3DHbiUAAsD0yEMeAwIByDyPBGOjBdD4XyEHWEG2bHhAYJ4Ax+COkCQAEh" 209 | . "4AIiD4UXgu5CAoMgAsBaA0iJRghgAhAIAOnkkm75ew/chQ6QD38ecB74oQV9HnK/fx7B538efx54Hqxjcx62DQ+GWODxkAB9WA+E7ZEAsRnkIwEi" 210 | . "mA+EVpAA8A7pB1ENgIXJdPNMjUDyM0CD+VwPhQ2CSUgCArECdSZmx0L+GiIgDMDSDnERiwNMAI1C/hu3AGaLCGaD+SJ1QL/p5gAAAACgXAB1CGbH" 211 | . "Qv5cABTr0gBoLwNoLwDrCsQANGIDNAgA67aFADRmAzQMAOuoABpCbgMaCgDrmgAaciEDGg0A64wAGnR1AgsBGgkA6Xv//0L/ACB1D4VDABJIQIPA" 212 | . "BEG5BAB4SAyJAwEhAIGLQv5MAIsDweAEZolCAP5mQYsIRI1RANBmQYP6CXcFoEQB0OskAA+/AQ8ABXcGjUQIyesKEwAQnwIQD4fu/gT//wAUqUmD" 213 | . "wAIBAT9MiQNB/8l1CKrpCgF3iUr+6QIBAXaLVghMicEBAH0CSCnRiUr8CGZBx4NB6eECAAAAjUHQZoP4CRBBD5bAAFUtD5QAwEEIwA+EuAFBgE7H" 214 | . "BhQAugAEABBIx0YIAAMASIuAA2aDOC11C4ImWIPK/4AigQmLgKX4CDB1DoYTgwMC6xA2g+gxAAsID4cCRQBUSIsLSA+/EAFEjUiBb/kJdwAXTGtO" 215 | . "CApIg4DBAkiJC0mNgHZASIlGCOvXgzEuhHQUAiwIg+HfgEsgRXRW6fACLMACBEG5AkmJA/JIDwQqRoC8BgUA8g8IEUYIADFmiwGDBOgwAWh3wEVr" 216 | . "yYQKmIEv8g8qwIAxAPJBDyrJ8g9eQMHyD1hGCEIM6wbMAjKAY4M+FHUQhw8UQSCBRXQJRTHBR5grdQdEDMAGMckAPgGEGw+HYP3//0xVQCBBhyAP" 217 | . "QCBJACCYAEyJCwHB6+FFBDHJwVUARDnJdAAIa8AKQf/B6wLzQCfI8g8QRgggRYTAdAbBJ+sEmPIPWUApQCCLDgAdAhQAVg+vVghIiTBWCOktABCC" 218 | . "IgUPbIX8wAKAD8KACwQ06QbpwW3BoFNIjQ0kIQCbZg++AQAWGEgAixNI/8FmOwJQD4W2/AGjwkAxEyDr4IA9xoEkdBJNgD0DAnqBA+nGwcfHJAYJ" 219 | . "gHwNJoCJ6auRA8xmdU0AFtADEhZqXQsWbQIWDwYWQYbrSnBFFbBAB+tYwdIPRIUkAQ6NDX+TFQaFixU2wytIiwWtACatgBMIAIPAchZFFmYACAhI" 220 | . "iU6AbwH/UAgQMcDp1MKL+kjTAOqA4gEPhJn7E4JxoTjpfWABTIniAEiJ2ei/+P//YIXAD4WXwQMlPyCUdxgoB3wnB+vcoAPQOg+FaUYC8oAIAAMU" 221 | . "6HfkCE/iCJQkoAGgD0mJ8EiJ6egmzAAWRwt2K6AALA9EhHCidBODyICFOhh9dSlkHcMZiW4ITOk5AQSlEHTUJRC1EEiBxLCAC1teX4BdQVzDkJCQ" 222 | . "ISP/CQD9AR8AHwAfAB8AHwAfAD8fAB8AHwAfAB8ABwAwMQAyMzQ1Njc4OUBBQkNERUagQwAAYQBzAE0AZQCAdABoAG8AZKAEACJVbmtub3duAF9P" 223 | . "YmplY3RfoAAAUAB1oARoYAMCUyIFAABPAHcAKm7gAnJgBnBgAwAAil8gAEVgAnUAbaABwA0KAAkAIgUIJgoAVHlwZV8AdHIAdWUAZmFsc2UgAG51" 224 | . "bGzHA1ZhHGx14APoDQsAU0iBBuzBW0SyiwFMicMgSImUJLihAY1UICRUTI2EgwGJVAAkKDHSSImMJGEhVsdEJFThB+AAIOHhAP9QKIsgqoMDoKQ1" 225 | . "YQdYIK5IAASiDmaJQEQkcEiLQ4CzhAwkiAACYX5EJHhIFovkCwAFYCLPiYQk7pCiDwEGQARYoBKhCCBvW6YQ8ABAwgKAADiFADCTBQkRev9QEFw7" 226 | . "CYBuZItLc0QQkNA2sQ5bA4E2BABXVlNIg+yQMEG7E4ABuwozEFBIhcBmcAQuUT/SAEyNTCQGeTRBFLsUwAG/MQZImYkE/kSQQvf7KdZmAEOJdFn+" 227 | . "Sf/LATADdeaD6QJIYwLBsANEBi0A6xhESJljAoPCMHACFAJZZALoSGPJSAEIyUwB0GcBZoXAAHQdTYXSdA9JAIsSTI1KAk2JYApmiQLrgICwcsGI" 228 | . "AuvbQBSDxDAgQiNhC9EKIEiJcATSdIARSIsCSI1IkEQACmbHACIA6ymJMAPrJIBrInUxAQJqJgMCBNABXKATUAJAxAIiUAXDAmYgTJAICNTpUmAf" 229 | . "QYMAAkTr6WADXHUcYQPvtW8DAvCVx6GAEwLNHwKgAmIA66UQAgwTAoKrHwICZgDrgxACKAp1HxECiR8CAm4IAOleEpf4DXUjMUACD4RgklWOAnIA" 230 | . "1Ok1gwIJhAI3jwKBAhB0AOkMkAGAPbIA+v//AHQLjUgC4CBbXncR6zyNREiBoAAhdgZQBB8Udy0xCRcfBAJ1AATrBBESD7cL6E4dgXW8sZDAAvBr" 231 | . "CkyNiEkCTAEbAemlYAE58BfpneQB3hkTHcQgBeknkOAcGDHATI0MHbNhbKAmCEmJyghmwekgB+IPZkcAD74UE2ZFiRQIQUj/UCD4BHXhKrgQdgDx" 232 | . "BRXgB2ZFQIsUQUyNWTAIGhBmRIkRNAboAXMC3VIjGMM=" 233 | if (64 != A_PtrSize * 8) 234 | throw Error("$Name does not support " (A_PtrSize * 8) " bit AHK, please run using 64 bit AHK") 235 | ; MCL standalone loader https://github.com/G33kDude/MCLib.ahk 236 | ; Copyright (c) 2023 G33kDude, CloakerSmoker (CC-BY-4.0) 237 | ; https://creativecommons.org/licenses/by/4.0/ 238 | if IsSet(lib) 239 | return lib 240 | if !DllCall("Crypt32\CryptStringToBinary", "Str", codeB64, "UInt", 0, "UInt", 1, "Ptr", buf := Buffer(3980), "UInt*", buf.Size, "Ptr", 0, "Ptr", 0, "UInt") 241 | throw Error("Failed to convert MCL b64 to binary") 242 | if (r := DllCall("ntdll\RtlDecompressBuffer", "UShort", 0x102, "Ptr", code, "UInt", 6960, "Ptr", buf, "UInt", buf.Size, "UInt*", &DecompressedSize := 0, "UInt")) 243 | throw Error("Error calling RtlDecompressBuffer",, Format("0x{:08x}", r)) 244 | for import, offset in Map(['OleAut32', 'SysFreeString'], 5744) { 245 | if !(hDll := DllCall("GetModuleHandle", "Str", import[1], "Ptr")) 246 | throw Error("Could not load dll " import[1] ": " OsError().Message) 247 | if !(pFunction := DllCall("GetProcAddress", "Ptr", hDll, "AStr", import[2], "Ptr")) 248 | throw Error("Could not find function " import[2] " from " import[1] ".dll: " OsError().Message) 249 | NumPut("Ptr", pFunction, code, offset) 250 | } 251 | if !DllCall("VirtualProtect", "Ptr", code, "Ptr", code.Size, "UInt", 0x40, "UInt*", &old := 0, "UInt") 252 | throw Error("Failed to mark MCL memory as executable") 253 | lib := { 254 | code: code, 255 | dumps: (this, pObjIn, ppszString, pcchString, bPretty, iLevel) => 256 | DllCall(this.code.Ptr + 0, "Ptr", pObjIn, "Ptr", ppszString, "IntP", pcchString, "Int", bPretty, "Int", iLevel, "CDecl Ptr"), 257 | loads: (this, ppJson, pResult) => 258 | DllCall(this.code.Ptr + 3296, "Ptr", ppJson, "Ptr", pResult, "CDecl Int") 259 | } 260 | lib.DefineProp("bBoolsAsInts", { 261 | get: (this) => NumGet(this.code.Ptr + 5344, "Int"), 262 | set: (this, value) => NumPut("Int", value, this.code.Ptr + 5344) 263 | }) 264 | lib.DefineProp("bEscapeUnicode", { 265 | get: (this) => NumGet(this.code.Ptr + 5360, "Int"), 266 | set: (this, value) => NumPut("Int", value, this.code.Ptr + 5360) 267 | }) 268 | lib.DefineProp("bNullsAsStrings", { 269 | get: (this) => NumGet(this.code.Ptr + 5376, "Int"), 270 | set: (this, value) => NumPut("Int", value, this.code.Ptr + 5376) 271 | }) 272 | lib.DefineProp("fnCastString", { 273 | get: (this) => NumGet(this.code.Ptr + 5392, "Ptr"), 274 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5392) 275 | }) 276 | lib.DefineProp("fnGetArray", { 277 | get: (this) => NumGet(this.code.Ptr + 5408, "Ptr"), 278 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5408) 279 | }) 280 | lib.DefineProp("fnGetMap", { 281 | get: (this) => NumGet(this.code.Ptr + 5424, "Ptr"), 282 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5424) 283 | }) 284 | lib.DefineProp("objFalse", { 285 | get: (this) => NumGet(this.code.Ptr + 5440, "Ptr"), 286 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5440) 287 | }) 288 | lib.DefineProp("objNull", { 289 | get: (this) => NumGet(this.code.Ptr + 5456, "Ptr"), 290 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5456) 291 | }) 292 | lib.DefineProp("objTrue", { 293 | get: (this) => NumGet(this.code.Ptr + 5472, "Ptr"), 294 | set: (this, value) => NumPut("Ptr", value, this.code.Ptr + 5472) 295 | }) 296 | return lib 297 | } 298 | 299 | static _LoadLib() { 300 | return A_PtrSize = 4 ? this._LoadLib32Bit() : this._LoadLib64Bit() 301 | } 302 | 303 | static Dump(obj, pretty := 0) 304 | { 305 | if !IsObject(obj) 306 | throw Error("Input must be object") 307 | size := 0 308 | this.lib.dumps(ObjPtr(obj), 0, &size, !!pretty, 0) 309 | buf := Buffer(size*5 + 2, 0) 310 | bufbuf := Buffer(A_PtrSize) 311 | NumPut("Ptr", buf.Ptr, bufbuf) 312 | this.lib.dumps(ObjPtr(obj), bufbuf, &size, !!pretty, 0) 313 | return StrGet(buf, "UTF-16") 314 | } 315 | 316 | static Load(json) { 317 | _json := " " json ; Prefix with a space to provide room for BSTR prefixes 318 | pJson := Buffer(A_PtrSize) 319 | NumPut("Ptr", StrPtr(_json), pJson) 320 | 321 | pResult := Buffer(24) 322 | 323 | if r := this.lib.loads(pJson, pResult) 324 | { 325 | throw Error("Failed to parse JSON (" r ")", -1 326 | , Format("Unexpected character at position {}: '{}'" 327 | , (NumGet(pJson, 'UPtr') - StrPtr(_json)) // 2, Chr(NumGet(NumGet(pJson, 'UPtr'), 'Short')))) 328 | } 329 | 330 | result := ComValue(0x400C, pResult.Ptr)[] ; VT_BYREF | VT_VARIANT 331 | if IsObject(result) 332 | ObjRelease(ObjPtr(result)) 333 | return result 334 | } 335 | 336 | static True { 337 | get { 338 | static _ := {value: true, name: 'true'} 339 | return _ 340 | } 341 | } 342 | 343 | static False { 344 | get { 345 | static _ := {value: false, name: 'false'} 346 | return _ 347 | } 348 | } 349 | 350 | static Null { 351 | get { 352 | static _ := {value: '', name: 'null'} 353 | return _ 354 | } 355 | } 356 | } 357 | 358 | -------------------------------------------------------------------------------- /lib/Aris/packages.ahk: -------------------------------------------------------------------------------- 1 | ; Avoid modifying this file manually 2 | 3 | #include .\G33kDude\cJson.ahk 4 | #include .\FanaticGuru\GuiReSizer.ahk 5 | -------------------------------------------------------------------------------- /lib/env.ahk: -------------------------------------------------------------------------------- 1 | AddArisToPATH() { 2 | ; Get the current PATH in this roundabout way because of the Store version registry virtualization 3 | CurrPath := g_IsComSpecAvailable ? RunCMD(A_ComSpec . " /c " 'reg query HKCU\Environment /v PATH') : RegRead("HKCU\Environment", "PATH") 4 | CurrPath := RegExReplace(CurrPath, "^[\w\W]*?PATH\s+REG_SZ\s+",,,1) 5 | Global G_RunCMD 6 | if g_IsComSpecAvailable && G_RunCMD.ExitCode 7 | return 8 | if !(LocalAppData := EnvGet("LOCALAPPDATA")) 9 | return 10 | BatContent := '@echo off`n@"' A_AhkPath '" "' A_ScriptFullPath '" "--working-dir" "%cd%" %*' 11 | if !DirExist(LocalAppData "\Programs\Aris") 12 | DirCreate(LocalAppData "\Programs\Aris") 13 | if !FileExist(LocalAppData "\Programs\Aris\Aris.bat") || FileRead(LocalAppData "\Programs\Aris\Aris.bat") != BatContent 14 | FileOpen(LocalAppData "\Programs\Aris\Aris.bat", "w", "CP0").Write(BatContent) 15 | if !InStr(CurrPath, LocalAppData "\Programs\Aris") { 16 | FileOpen(A_ScriptDir "\assets\user-path-backup.txt", "w").Write(CurrPath) 17 | ; https://stackoverflow.com/questions/9546324/adding-a-directory-to-the-path-environment-variable-in-windows 18 | g_IsComSpecAvailable ? RunWait(A_ComSpec ' /c SETX PATH "' CurrPath ';' LocalAppData '\Programs\Aris"',, "Hide") : RegWrite(CurrPath ';' LocalAppData '\Programs\Aris', "REG_SZ", "HKCU\Environment", "PATH") 19 | } 20 | } 21 | 22 | RemoveArisFromPATH() { 23 | if !(g_LocalAppData) 24 | return 25 | 26 | CurrPath := g_IsComSpecAvailable ? RunCMD(A_ComSpec . " /c " 'reg query HKCU\Environment /v PATH') : RegRead("HKCU\Environment", "PATH") 27 | CurrPath := RegExReplace(CurrPath, "^[\w\W]*?PATH\s+REG_SZ\s+",,,1) 28 | 29 | Global G_RunCMD 30 | if g_IsComSpecAvailable && G_RunCMD.ExitCode 31 | return 32 | 33 | if InStr(CurrPath, ";" g_LocalAppData "\Programs\Aris") { 34 | g_IsComSpecAvailable ? RunWait(A_ComSpec ' /c SETX PATH "' StrReplace(CurrPath, ";" g_LocalAppData "\Programs\Aris") '"',, "Hide") : RegWrite(StrReplace(CurrPath, ";" g_LocalAppData "\Programs\Aris"), "REG_SZ", "HKCU\Environment", "PATH") 35 | } 36 | if FileExist(g_LocalAppData "\Programs\Aris\Aris.bat") { 37 | DirDelete(g_LocalAppData "\Programs\Aris", true) 38 | } 39 | } 40 | 41 | IsArisInPATH(onlyCurrentInstance:=1) { 42 | if !(g_LocalAppData) 43 | return false 44 | CurrPath := RegRead("HKCU\Environment", "PATH", "") 45 | CurrPath := RegExReplace(CurrPath, "^[\w\W]*?PATH\s+REG_SZ\s+",,,1) 46 | if !CurrPath || !InStr(CurrPath, g_LocalAppData "\Programs\Aris") 47 | return false 48 | if !FileExist(g_LocalAppData "\Programs\Aris\Aris.bat") 49 | return false 50 | if !onlyCurrentInstance 51 | return true 52 | CurrContents := FileRead(g_LocalAppData "\Programs\Aris\Aris.bat") 53 | if !InStr(CurrContents, A_AhkPath) || !InStr(CurrContents, A_ScriptFullPath) 54 | return false 55 | return true 56 | } 57 | 58 | AddArisShellMenuItem() { 59 | BaseKey := GetArisShellRegistryKey() 60 | if g_IsComSpecAvailable { 61 | RunCMD(A_ComSpec . " /c reg add " BaseKey '\Shell\Aris /t REG_SZ /d "Install Aris packages" /f') 62 | RunCMD(A_ComSpec . " /c reg add " BaseKey '\Shell\Aris\command /t REG_SZ /d "\"' A_AhkPath '\" \"' A_ScriptFullPath '\" \"%1\"" /f') 63 | } else { 64 | RegWrite("Install Aris packages", "REG_SZ", BaseKey '\Shell\Aris') 65 | RegWrite('"' A_AhkPath '" "' A_ScriptFullPath '" "%1"', "REG_SZ", BaseKey '\Shell\Aris\command') 66 | } 67 | } 68 | 69 | RemoveArisShellMenuItem() { 70 | BaseKey := GetArisShellRegistryKey() 71 | g_IsComSpecAvailable ? RunCMD(A_ComSpec . " /c reg delete " BaseKey '\Shell\Aris /f') : RegDeleteKey(BaseKey '\Shell\Aris') 72 | } 73 | 74 | IsArisShellMenuItemPresent(onlyCurrentInstance:=1) { 75 | try { 76 | Current := RegRead(GetArisShellRegistryKey() "\Shell\Aris\command") 77 | if onlyCurrentInstance && (!Current || !InStr(Current, A_AhkPath) || !InStr(Current, A_ScriptDir)) 78 | return 0 79 | return 1 80 | } 81 | return 0 82 | } 83 | 84 | GetArisShellRegistryKey() { 85 | BaseKey := "HKCU\SOFTWARE\Classes\AutoHotkeyScript" 86 | try { 87 | RegRead(BaseKey '\Shell\Aris\command') 88 | return BaseKey 89 | } 90 | 91 | ; Check for Store Edition 92 | Loop Reg "HKCU\SOFTWARE\Classes\.ahk\OpenWithProgids", "V" 93 | KeyName := A_LoopRegName 94 | if IsSet(KeyName) 95 | return "HKCU\SOFTWARE\Classes\" KeyName 96 | 97 | return "HKCU\SOFTWARE\Classes\AutoHotkeyScript" 98 | } -------------------------------------------------------------------------------- /lib/hash.ahk: -------------------------------------------------------------------------------- 1 | ; HashFile by Deo 2 | ; https://autohotkey.com/board/topic/66139-ahk-l-calculating-md5sha-checksum-from-file/ 3 | ; Modified for AutoHotkey v2 by lexikos. 4 | 5 | /* 6 | HASH types: 7 | 1 - MD2 8 | 2 - MD5 9 | 3 - SHA 10 | 4 - SHA256 11 | 5 - SHA384 12 | 6 - SHA512 13 | */ 14 | HashFile(filePath, hashType:=2) 15 | { 16 | static PROV_RSA_AES := 24 17 | static CRYPT_VERIFYCONTEXT := 0xF0000000 18 | static BUFF_SIZE := 1024 * 1024 ; 1 MB 19 | static HP_HASHVAL := 0x0002 20 | static HP_HASHSIZE := 0x0004 21 | 22 | switch hashType { 23 | case 1: hash_alg := (CALG_MD2 := 32769) 24 | case 2: hash_alg := (CALG_MD5 := 32771) 25 | case 3: hash_alg := (CALG_SHA := 32772) 26 | case 4: hash_alg := (CALG_SHA_256 := 32780) 27 | case 5: hash_alg := (CALG_SHA_384 := 32781) 28 | case 6: hash_alg := (CALG_SHA_512 := 32782) 29 | default: throw ValueError('Invalid hashType', -1, hashType) 30 | } 31 | 32 | f := FileOpen(filePath, "r") 33 | f.Pos := 0 ; Rewind in case of BOM. 34 | 35 | HCRYPTPROV() => { 36 | ptr: 0, 37 | __delete: this => this.ptr && DllCall("Advapi32\CryptReleaseContext", "Ptr", this, "UInt", 0) 38 | } 39 | 40 | if !DllCall("Advapi32\CryptAcquireContextW" 41 | , "Ptr*", hProv := HCRYPTPROV() 42 | , "Uint", 0 43 | , "Uint", 0 44 | , "Uint", PROV_RSA_AES 45 | , "UInt", CRYPT_VERIFYCONTEXT) 46 | throw OSError() 47 | 48 | HCRYPTHASH() => { 49 | ptr: 0, 50 | __delete: this => this.ptr && DllCall("Advapi32\CryptDestroyHash", "Ptr", this) 51 | } 52 | 53 | if !DllCall("Advapi32\CryptCreateHash" 54 | , "Ptr", hProv 55 | , "Uint", hash_alg 56 | , "Uint", 0 57 | , "Uint", 0 58 | , "Ptr*", hHash := HCRYPTHASH()) 59 | throw OSError() 60 | 61 | read_buf := Buffer(BUFF_SIZE, 0) 62 | 63 | While (cbCount := f.RawRead(read_buf, BUFF_SIZE)) 64 | { 65 | if !DllCall("Advapi32\CryptHashData" 66 | , "Ptr", hHash 67 | , "Ptr", read_buf 68 | , "Uint", cbCount 69 | , "Uint", 0) 70 | throw OSError() 71 | } 72 | 73 | if !DllCall("Advapi32\CryptGetHashParam" 74 | , "Ptr", hHash 75 | , "Uint", HP_HASHSIZE 76 | , "Uint*", &HashLen := 0 77 | , "Uint*", &HashLenSize := 4 78 | , "UInt", 0) 79 | throw OSError() 80 | 81 | bHash := Buffer(HashLen, 0) 82 | if !DllCall("Advapi32\CryptGetHashParam" 83 | , "Ptr", hHash 84 | , "Uint", HP_HASHVAL 85 | , "Ptr", bHash 86 | , "Uint*", &HashLen 87 | , "UInt", 0 ) 88 | throw OSError() 89 | 90 | loop HashLen 91 | HashVal .= Format('{:02x}', (NumGet(bHash, A_Index-1, "UChar")) & 0xff) 92 | 93 | return HashVal 94 | } 95 | 96 | MD5(s) { 97 | size := StrPut(s, "UTF-8") - 1 ; bin has no null 98 | bin := Buffer(size) 99 | StrPut(s, bin, "UTF-8") 100 | 101 | MD5_CTX := Buffer(104) 102 | DllCall("advapi32\MD5Init", "ptr", MD5_CTX) 103 | DllCall("advapi32\MD5Update", "ptr", MD5_CTX, "ptr", bin, "uint", size) 104 | DllCall("advapi32\MD5Final", "ptr", MD5_CTX) 105 | 106 | VarSetStrCapacity(&md5, 32 + 1) ; str has null 107 | DllCall("crypt32\CryptBinaryToString", "ptr", MD5_CTX.ptr+88, "uint", 16, "uint", 0x4000000c, "str", md5, "uint*", 33) 108 | return md5 109 | } -------------------------------------------------------------------------------- /lib/ui-main.ahk: -------------------------------------------------------------------------------- 1 | LaunchGui(FileOrDir?, SelectedTab := 1) { 2 | g_MainGui.Width := 640, g_MainGui.Height := 425 3 | 4 | g_MainGui.OnEvent("Size", GuiReSizer) 5 | g_MainGui.OnEvent("Close", (*) => ExitApp()) 6 | 7 | SB := g_MainGui.AddStatusBar(, "Undefined package") 8 | SB.GetPos(,,, &SB_Height) ; Get default values for StatusBar and a button to adjust for screen scaling 9 | g_MainGui.LoadPackageBtn := g_MainGui.AddButton(, "Load package") 10 | g_MainGui.LoadPackageBtn.GetPos(,,, &Btn_Height) 11 | 12 | g_MainGui.FolderTV := g_MainGui.Add("TreeView", "r25 w200 x10 y7", "Package files") 13 | g_MainGui.FolderTV.X := 10, g_MainGui.FolderTV.Height := -(SB_Height+Btn_Height+10), g_MainGui.FolderTV.WidthP := 0.3 14 | g_MainGui.FolderTV.OnEvent("ContextMenu", ShowFolderTVContextMenu) 15 | 16 | if IsSet(FileOrDir) { 17 | SplitPath(FileOrDir, &OutFileName:="", &OutDir:="") 18 | FullDirPath := OutDir 19 | Loop files OutDir, "D" { 20 | FullDirPath := A_LoopFileFullPath 21 | break 22 | } 23 | LoadPackageFolder(FullDirPath) 24 | } else 25 | LoadPackageFolder(FullDirPath := (g_Config.Has("last_project_directory") && DirExist(g_Config["last_project_directory"]) ? g_Config["last_project_directory"] : A_WorkingDir)) 26 | 27 | g_MainGui.PackageJson := LoadPackageJson() 28 | 29 | SB.SetText(g_MainGui.PackageJson["name"] ? (g_MainGui.PackageJson["name"] "@" (g_MainGui.PackageJson["version"] || "undefined-version")) : "Undefined package: add package name and version in metadata.") 30 | g_MainGui.LoadPackageBtn.Y := -(SB_Height+Btn_Height+5) 31 | g_MainGui.ModifyMetadata := g_MainGui.AddButton("x+27", "Modify metadata") 32 | g_MainGui.ModifyMetadata.Anchor := g_MainGui.FolderTV, g_MainGui.ModifyMetadata.AnchorIn := false, g_MainGui.ModifyMetadata.YP := 1.0, g_MainGui.ModifyMetadata.Y := 5, g_MainGui.ModifyMetadata.XP := 1.0, g_MainGui.ModifyMetadata.X := -92 33 | g_MainGui.ModifyMetadata.OnEvent("Click", LaunchModifyMetadataGui) 34 | g_MainGui.LoadPackageBtn.OnEvent("Click", LoadPackageFromGui) 35 | 36 | g_MainGui.Tabs := g_MainGui.AddTab3("w410 h395 x220 y6", ["Current package", "Index", "Settings"]) 37 | g_MainGui.Tabs.UseTab(1) 38 | g_MainGui.Tabs.XP := 0.30, g_MainGui.Tabs.X := 15, g_MainGui.Tabs.W := -5, g_MainGui.Tabs.H := -(SB_Height+5) 39 | 40 | P := g_MainGui.Tabs.Package := {TabName:"Package"} 41 | P.LV := g_MainGui.Add("ListView", "r10 w390 Section -Multi", ["Package name", "Version", "Allowed versions", "Installed", "Scope", "In index"]) 42 | P.LV.W := -15 43 | P.LV.OnEvent("ItemSelect", PackageLVItemSelected) 44 | P.LV.OnEvent("ContextMenu", ShowPackageLVContextMenu) 45 | P.LV.TabName := "Package" 46 | P.ReinstallBtn := g_MainGui.AddButton("w50", "Reinstall") 47 | P.ReinstallBtn.OnEvent("Click", PackageAction.Bind(P, "reinstall",0,1)) 48 | P.RemoveBtn := g_MainGui.AddButton("x+10 yp+0 w50", "Remove") 49 | P.RemoveBtn.OnEvent("Click", PackageAction.Bind(P, "remove",0,1)) 50 | P.UpdateBtn := g_MainGui.AddButton("x+10 yp+0 w50", "Update") 51 | P.UpdateBtn.OnEvent("Click", PackageAction.Bind(P, "update",0,1)) 52 | P.UpdateLatestBtn := g_MainGui.AddButton("x+10 yp+0", "Force update") 53 | P.UpdateLatestBtn.OnEvent("Click", PackageAction.Bind(P, "update-latest",,1)) 54 | P.AddBtn := g_MainGui.AddButton("x+10 yp+0 w50", "Add") 55 | P.AddBtn.OnEvent("Click", PackageAction.Bind(P, "install-external",0,1)) 56 | P.ModifyRangeBtn := g_MainGui.AddButton("x+10 yp+0 w80", "Modify range") 57 | P.ModifyRangeBtn.OnEvent("Click", ModifyPackageVersionRange.Bind(P.LV)) 58 | P.Metadata := g_MainGui.Add("Edit", "xs y+10 w390 h140") 59 | P.Metadata.W := -15, P.Metadata.H := -(SB_Height+15) 60 | 61 | PopulatePackagesTab(P) 62 | 63 | g_MainGui.Tabs.UseTab(2) 64 | 65 | I := g_MainGui.Tabs.Index := {TabName:"Index"} 66 | I.LV := g_MainGui.Add("ListView", "r10 w390 Section -Multi", ["Package name", "Installed version", "Allowed versions", "Source"]) 67 | I.LV.W := -15, I.LV.H := -215 68 | I.LV.OnEvent("ItemSelect", IndexLVItemSelected) 69 | I.LV.OnEvent("DoubleClick", PackageAction.Bind(I, "install",0,1)) 70 | I.LV.OnEvent("ContextMenu", ShowPackageLVContextMenu) 71 | I.LV.TabName := "Index" 72 | I.SearchText := g_MainGui.Add("Text",, "Search:") 73 | 74 | AnchorUnder := (o, to, X, Y) => (o.Anchor := to, o.AnchorIn := false, o.YP := 1.0, o.Y := Y, o.X := X) 75 | AnchorAfter := (o, to, X, Y) => (o.Anchor := to, o.AnchorIn := false, o.XP := 1.0, o.Y := Y, o.X := X) 76 | 77 | AnchorUnder(I.SearchText, I.LV, 5, 7) 78 | I.Search := g_MainGui.Add("Edit", "x+5 yp-2 -Multi") 79 | AnchorUnder(I.Search, I.LV, 45, 5) 80 | I.Search.OnEvent("Change", OnIndexSearch) 81 | I.SearchByStartCB := g_MainGui.Add("Checkbox", "x+10 yp+4", "Match start") 82 | AnchorAfter(I.SearchByStartCB, I.Search, 7, 3) 83 | I.SearchByStartCB.OnEvent("Click", (*) => OnIndexSearch(I.Search)) 84 | I.SearchCaseSenseCB := g_MainGui.Add("Checkbox", "x+5 yp", "Match case") 85 | AnchorAfter(I.SearchCaseSenseCB, I.SearchByStartCB, 5, 0) 86 | I.SearchCaseSenseCB.OnEvent("Click", (*) => OnIndexSearch(I.Search)) 87 | 88 | I.InstallBtn := g_MainGui.AddButton("xs y+8 w60", "Install") 89 | AnchorUnder(I.InstallBtn, I.LV, 5, 30) 90 | I.InstallBtn.OnEvent("Click", PackageAction.Bind(I, "install",0,1)) 91 | I.QueryVersionBtn := g_MainGui.AddButton("x+10 yp+0", "Query versions") 92 | AnchorAfter(I.QueryVersionBtn, I.InstallBtn, 5, 0) 93 | I.QueryVersionBtn.OnEvent("Click", LaunchVersionSelectionGui) 94 | I.UpdateIndexBtn := g_MainGui.AddButton("x+10 yp+0", "Update index") 95 | AnchorAfter(I.UpdateIndexBtn, I.QueryVersionBtn, 5, 0) 96 | I.UpdateIndexBtn.OnEvent("Click", UpdatePackageIndexPopulateTab) 97 | I.Metadata := g_MainGui.Add("Edit", "xs y+10 w390 h120 ReadOnly") 98 | I.Metadata.F := (this, G, *) => (I.LV.GetPos(&LVX, &LVY, &LVW, &LVH), G.GetPos(,,&GW,&GH), this.GetPos(&X, &Y, &W, &H), this.Move(LVX, NewY := LVY+LVH+60, LVW, GH-NewY-SB_Height-55)) 99 | 100 | PopulateIndexTab(I) 101 | 102 | g_MainGui.Tabs.UseTab(3) 103 | 104 | S := g_MainGui.Tabs.Settings := {} 105 | g_MainGui.AddGroupBox("w200 h45 Section", "Package settings") 106 | 107 | g_MainGui.AddGroupBox("w195 x+10 yp+0 h90", "Path and shell") 108 | S.AddRemoveFromPATH := g_MainGui.AddButton("xp+20 yp+20 w150", (IsArisInPATH() ? "Remove Aris from PATH" : "Add Aris to PATH")) 109 | S.AddRemoveFromPATH.OnEvent("Click", (btnCtrl, *) => btnCtrl.Text = "Remove Aris from PATH" ? (RemoveArisFromPATH(), btnCtrl.Text := "Add Aris to PATH", g_Config["add_to_path"] := 0, SaveSettings()) : (AddArisToPATH(), btnCtrl.Text := "Remove Aris from PATH", g_Config["add_to_path"] := 1, SaveSettings()) ) 110 | S.AddRemoveShellMenuItem := g_MainGui.AddButton("xp y+10 w150", (IsArisShellMenuItemPresent() ? "Remove Aris from shell" : "Add Aris to shell")) 111 | S.AddRemoveShellMenuItem.OnEvent("Click", (btnCtrl, *) => btnCtrl.Text = "Remove Aris from shell" ? (RemoveArisShellMenuItem(), btnCtrl.Text := "Add Aris to shell", g_Config["add_to_shell"] := 0, SaveSettings()) : (AddArisShellMenuItem(), btnCtrl.Text := "Remove Aris from shell", g_Config["add_to_shell"] := 1, SaveSettings()) ) 112 | 113 | S.GlobalInstalls := g_MainGui.AddCheckbox("xs+10 ys+20 " (g_Config["global_install"] ? "Checked" : ""), "Install all packages globally") 114 | g_MainGui.AddGroupBox("xs ys+50 w200 h65", "Updates") 115 | S.AutoUpdateIndex := g_MainGui.AddCheckbox("xp+10 yp+20 " (g_Config["auto_update_index_daily"] ? "Checked" : ""), "Auto-update index once daily") 116 | S.CheckArisUpdates := g_MainGui.AddCheckbox((g_Config["check_aris_updates_daily"] ? "Checked" : ""), "Check for Aris updates daily") 117 | 118 | g_MainGui.AddGroupBox("xs w405 h50", "GitHub") 119 | g_MainGui.AddText("xp+10 yp+20", "Github private token:") 120 | S.GithubToken := g_MainGui.AddEdit("x+5 yp-3 w280 r1", g_Config["github_token"]) 121 | 122 | S.SaveSettings := g_MainGui.AddButton("xs+150 y+20 w100", "Save settings") 123 | S.SaveSettings.SetFont("bold") 124 | S.SaveSettings.OnEvent("Click", (*) => (ApplyGuiConfigChanges(), SaveSettings(true))) 125 | 126 | S.Uninstall := g_MainGui.AddButton("xs+305 y+135 w100", "Uninstall Aris") 127 | S.Uninstall.SetFont("bold") 128 | S.Uninstall.OnEvent("Click", UninstallAris) 129 | 130 | g_MainGui.Tabs.UseTab(0) 131 | if SelectedTab != 1 132 | g_MainGui.Tabs.Choose(SelectedTab) 133 | 134 | g_MainGui.Move(,, g_MainGui.Width, g_MainGui.Height) ; Force draw of controls to remove flicker 135 | Sleep -1 136 | g_MainGui.Show("w" g_MainGui.Width " h" g_MainGui.Height) 137 | P.Metadata.Opt("+ReadOnly") ; If this isn't done after showing the GUI, the Edit may display black if the cursor was located inside of it 138 | 139 | Print.DefineProp("call", {call:(this, msg) => ((ctrl := ((g_MainGui.Tabs.Value = 1) ? g_MainGui.Tabs.Package.Metadata : g_MainGui.Tabs.Index.Metadata), ctrl.Value .= msg "`n", PostMessage(0x115, 7, 0,, ctrl.hWnd)))}) 140 | if Print.Buffer 141 | Print(Trim(Print.Buffer)), Print.Buffer := "" 142 | 143 | /* 144 | ; This can be used to set a small identifying icon to the tray menu large icon, because by 145 | ; default the AHK icon is shown. However, if Aris is ran from cmd.exe then that issue isn't present. 146 | hIcon := DllCall("LoadImage", "ptr", 0, "str", A_ScriptDir "\assets\main.ico", "uint", 2, "int", 0, "int", 0, "uint", 0x10, "ptr") 147 | CLSID_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}" 148 | IID_ITaskbarList3 := "{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}" 149 | ITaskbarList3 := ComObject(CLSID_TaskbarList, IID_ITaskbarList3) 150 | ComCall(3, ITaskbarList3) 151 | ComCall(18, ITaskbarList3, "ptr", g_MainGui.hWnd, "ptr", hIcon, "str", "Aris") 152 | DllCall("CloseHandle", "ptr", hIcon) 153 | */ 154 | 155 | if IsSet(OutFileName) && OutFileName { 156 | Print "Installing dependencies from `"" OutFileName "`"`n" 157 | PackageAction(P, "install-external", FileOrDir, 0) 158 | if FileExist("package.json") { 159 | Print "`n----------------------------------------------------`nInstalling packages from package.json`n" 160 | PackageAction(P, "install-external", "package.json", 0) 161 | } 162 | } 163 | 164 | if !g_Config.Has("check_aris_updates_daily") || (g_Config["check_aris_updates_daily"] && (Abs(DateDiff(A_NowUTC, g_Config["check_aris_updates_daily"], "Days")) >= 1)) { 165 | CheckArisUpdate() 166 | g_Config["check_aris_updates_daily"] := A_NowUTC 167 | SaveSettings() 168 | } 169 | } 170 | 171 | CheckArisUpdate() { 172 | Print "Checking for Aris updates..." 173 | if !(releases := QueryGitHubReleases("Descolada/ARIS/main")) || !(releases is Array) || !releases.Length { 174 | Print "Couldn't find any Aris releases" 175 | return 176 | } 177 | PackageJson := LoadPackageJson(A_ScriptDir) 178 | if VerCompare(releases[1]["tag_name"], PackageJson["version"]) <= 0 { 179 | Print "Aris is already up-to-date" 180 | return 181 | } 182 | 183 | if MsgBox("Aris update found. Do you wish to update to " releases[1]["tag_name"] "?", "Aris update", 0x4) != "Yes" 184 | return 185 | 186 | LoadPackageFolder(A_ScriptDir) 187 | UpdateWorkingDirPackage() ; This should exit the application if successful 188 | MsgBox "Failed to update Aris!" 189 | } 190 | 191 | LVGetPackageInfo(LV) { 192 | Selected := LV.GetNext(0) 193 | if !Selected 194 | return 0 195 | return {PackageName: LV.GetText(Selected, 1), Version: LV.GetText(Selected, 2), Selected: Selected} 196 | } 197 | 198 | PackageAction(Tab, Action, Input?, ClearOutput:=1, *) { 199 | Result := 1 200 | if Action != "install-external" { 201 | PackageInfo := LVGetPackageInfo(Tab.LV) 202 | if !PackageInfo { 203 | ToolTip "Select a package first!" 204 | SetTimer ToolTip, -3000 205 | return 206 | } 207 | } 208 | if ClearOutput 209 | Tab.Metadata.Value := "" 210 | switch Action, 0 { 211 | case "reinstall": 212 | RemovePackage(PackageInfo.PackageName "@" PackageInfo.Version, false) 213 | Result := InstallPackage(PackageInfo.PackageName "@" PackageInfo.Version) 214 | case "remove": 215 | if Result := RemovePackage(PackageInfo.PackageName "@" PackageInfo.Version) 216 | PackageInfo.Selected := Min(PackageInfo.Selected, Tab.LV.GetCount()-1) 217 | case "update": 218 | Result := InstallPackage(PackageInfo.PackageName "@" g_InstalledPackages[PackageInfo.PackageName].DependencyVersion, 1) 219 | case "update-latest": 220 | Result := InstallPackage(PackageInfo.PackageName "@latest") 221 | case "install": 222 | Result := InstallPackage(PackageInfo.PackageName) 223 | if !Result && g_Index.Has(PN := PackageInfo.PackageName) && g_Index[PN].Has("repository") && (Repo := g_Index[PN]["repository"] is String ? g_Index[PN]["repository"] : g_Index[PN]["repository"]["url"]) && Repo ~= "forums:|autohotkey\.com" { 224 | Print("`nRetrying to download latest version from AutoHotkey forums...") 225 | InstallPackage(PackageInfo.PackageName "@latest") 226 | } 227 | case "install-external": 228 | if Input && (Input is String) { 229 | Result := InstallPackageDependencies(Input, 0) 230 | } else { 231 | IB := InputBox('Install a package from a non-index source.`n`nInsert a source (GitHub repo, Gist, archive file URL) from where to install the package.`n`nIf installing from a GitHub repo, this can be "Username/Repo" or "Username/Repo@Version" (queries from releases) or "Username/Repo@commit" (without quotes).', "Add package", "h240") 232 | if IB.Result != "Cancel" 233 | Result := InstallPackage(IB.Value) 234 | } 235 | } 236 | if Result { 237 | if !InStr(Action, "remove") 238 | OutputAddedIncludesString(!!InStr(Action, "update")) 239 | LoadPackageFolder(A_WorkingDir) 240 | PopulateTabs() 241 | } 242 | try { 243 | Tab.LV.Modify(PackageInfo.Selected, "Select") 244 | if Action = "remove" && Result 245 | PackageLVItemSelected(Tab.LV, PackageInfo.Selected, 1) 246 | } 247 | } 248 | 249 | ModifyPackageVersionRange(LV, *) { 250 | Selected := LV.GetNext(0) 251 | if !Selected { 252 | ToolTip "Select a package first!" 253 | SetTimer ToolTip, -3000 254 | return 255 | } 256 | IB := InputBox('Insert a new allowed version range for the package.`n`nPossible options:`nlatest : latest release or commit (includes major releases)`n^x.y.z : allow minor version update (y)`n~x.y.z : allow patch update (z)`n>x.y.z : greater than x.y.z`n=x.y.z <=a.b.c : range between x.y.z and a.b.c', "Modify version range", "h240", PreviousVersion := LV.GetText(Selected, 3)) 257 | if IB.Result != "Cancel" { 258 | PackageJson := LoadPackageJson() 259 | PackageName := LV.GetText(Selected, 1) 260 | PreviousValue := PackageJson["dependencies"][PackageName] 261 | PackageJson["dependencies"][PackageName] := InStr(PreviousValue, "@") ? StrReplace(PreviousValue, "@" PreviousVersion, "@" IB.Value) : IB.Value 262 | FileOpen("package.json", 0x1).Write(JSON.Dump(PackageJson, true)) 263 | 264 | LoadPackageFolder(A_WorkingDir) 265 | PopulateTabs() 266 | } 267 | } 268 | 269 | PackageLVItemSelected(LV, Item, Selected) { 270 | if !Selected 271 | return 272 | PackageName := LV.GetText(Item, 1), Version := LV.GetText(Item, 2) 273 | 274 | if !g_InstalledPackages.Has(PackageName) 275 | return 276 | SelectedPackage := g_InstalledPackages[PackageName] 277 | 278 | Tab := g_MainGui.Tabs.Package 279 | 280 | if FileExist(g_MainGui.CurrentLibDir SelectedPackage.InstallName "\package.json") { 281 | Info := LoadPackageJson(g_MainGui.CurrentLibDir SelectedPackage.InstallName) 282 | if Info.Has("keywords") && IsObject(Info["keywords"]) 283 | Info["keywords"] := ArrayJoin(Info["keywords"], ", ") 284 | Info["main"] := SelectedPackage.Main 285 | } else if g_Index.Has(SelectedPackage.PackageName) 286 | Info := g_Index[SelectedPackage.PackageName] 287 | else { 288 | Tab.Metadata.Value := "No information available about this package (missing package.json and index entry)." 289 | return 290 | } 291 | 292 | Tab.Metadata.Value := ExtractPackageDescription(Info) "`n`n#include `; " ConstructInstallCommand(SelectedPackage, SelectedPackage.InstallVersion (SelectedPackage.BuildMetadata ? "+" SelectedPackage.BuildMetadata : "")) 293 | } 294 | 295 | IndexLVItemSelected(LV, Item, Selected) { 296 | if !Selected 297 | return 298 | PackageName := LV.GetText(Item, 1) 299 | Tab := g_MainGui.Tabs.Index 300 | Tab.Metadata.Value := ExtractPackageDescription(g_Index[PackageName]) 301 | Tab.InstallBtn.Text := LV.GetText(Item, 4) = "Yes" ? "Reinstall" : "Install" 302 | } 303 | 304 | UpdatePackageIndexPopulateTab(*) => (UpdatePackageIndex(), PopulateIndexTab(I)) 305 | 306 | ExtractPackageDescription(Info) { 307 | Content := "" 308 | 309 | if Info.Has("description") 310 | Content .= "Description: " Info["description"] "`n" 311 | if Info.Has("author") { 312 | if (Info["author"] is String) && Info["author"] 313 | Content .= "Author: " Info["author"] "`n" 314 | else if Info["author"].Has("name") 315 | Content .= "Author: " Info["author"]["name"] "`n" 316 | } 317 | if Info.Has("main") { 318 | if (Info["main"] is String) && Info["main"] 319 | Content .= "Main: " Info["main"] "`n" 320 | else if Info.Has("files") { 321 | if (Info["files"] is String) && Info["files"] 322 | Content .= "Main: " StrSplit(StrReplace(Info["files"], "\", "/"), "/")[-1] "`n" 323 | else if (Info["files"] is Array) && (Info["files"].Length = 1) 324 | Content .= "Main: " StrSplit(StrReplace(Info["files"][1], "\", "/"), "/")[-1] "`n" 325 | } 326 | } 327 | if Info.Has("homepage") 328 | Content .= "Homepage: " Info["homepage"] "`n" 329 | if Info.Has("license") 330 | Content .= "License: " Info["license"] "`n" 331 | if Info.Has("keywords") && Info["keywords"] 332 | Content .= "Keywords: " Info["keywords"] "`n" 333 | if Info.Has("dependencies") && Info["dependencies"].Count { 334 | Content .= "Dependencies:`n" 335 | for Dependency, Version in Info["dependencies"] 336 | Content .= "`t" Dependency "@" Version "`n" 337 | } 338 | if Info.Has("repository") { 339 | if Info["repository"]["type"] = "github" { 340 | if InStr(Info["repository"]["url"], ":") 341 | Content .= "GitHub repository: " Info["repository"]["url"] 342 | else { 343 | Split := StrSplit(Info["repository"]["url"], "/") 344 | Content .= "GitHub repository: https://github.com/" Split[1] "/" Split[2] 345 | } 346 | } else if Info["repository"]["type"] = "gist" 347 | Content .= "Gist URL: https://gist.github.com/" StrSplit(Info["repository"]["url"], "/")[1] 348 | else 349 | Content .= "Repository: " Info["repository"]["type"] ":" Info["repository"]["url"] 350 | } 351 | return Content 352 | } 353 | 354 | PopulateTabs() { 355 | PopulatePackagesTab(g_MainGui.Tabs.Package) 356 | PopulateIndexTab(g_MainGui.Tabs.Index) 357 | } 358 | 359 | PopulatePackagesTab(Tab) { 360 | g_MainGui.Dependencies := Dependencies := QueryPackageDependencies() 361 | Tab.LV.Opt("-Redraw") 362 | Tab.LV.Delete() 363 | 364 | for PackageName, PackageInfo in g_InstalledPackages { 365 | VersionRange := "", InIndex := g_Index.Has(PackageName) ? "Yes" : "No" 366 | if Dependencies.Has(PackageName) 367 | VersionRange := Dependencies[PackageName].DependencyVersion 368 | IsInstalled := g_InstalledPackages.Has(PackageName) 369 | Tab.LV.Add(, PackageName, IsInstalled ? PackageInfo.InstallVersion : "", VersionRange, IsInstalled ? "Yes" : "No", PackageInfo.Global ? "global" : "local", InIndex) 370 | } 371 | Tab.LV.ModifyCol(1, g_InstalledPackages.Count ? unset : 100) 372 | Tab.LV.ModifyCol(2, 50) 373 | Tab.LV.ModifyCol(4, 50) 374 | Tab.LV.ModifyCol(5, 50) 375 | Tab.LV.ModifyCol(6, 50) 376 | Tab.LV.Opt("+Redraw") 377 | Sleep -1 378 | } 379 | 380 | PopulateIndexTab(Tab) { 381 | g_MainGui.UnfilteredIndex := [] 382 | 383 | Tab.LV.Opt("-Redraw") 384 | Tab.LV.Delete() 385 | 386 | for PackageName, Info in g_Index { 387 | if !InStr(PackageName, "/") || !IsObject(Info) 388 | continue 389 | 390 | g_MainGui.UnfilteredIndex.Push([PackageName, g_InstalledPackages.Has(PackageName) ? g_InstalledPackages[PackageName].InstallVersion : unset, g_InstalledPackages.Has(PackageName) ? g_InstalledPackages[PackageName].DependencyVersion : unset, g_Index[PackageName]["repository"]["type"]]) 391 | Tab.LV.Add(, g_MainGui.UnfilteredIndex[-1]*) 392 | } 393 | Tab.LV.ModifyCol(1) 394 | Tab.LV.ModifyCol(4, 80) 395 | if Tab.Search.Value 396 | OnIndexSearch(Tab.Search) 397 | Tab.LV.Opt("+Redraw") 398 | Sleep -1 399 | } 400 | 401 | LoadPackageFolder(FullPath) { 402 | FullPath := Trim(FullPath, "/\") "\" 403 | 404 | PrevWorkingDir := A_WorkingDir 405 | try { 406 | SetWorkingDir(FullPath) 407 | RefreshWorkingDirGlobals() 408 | g_Config["last_project_directory"] := FullPath 409 | SaveSettings() 410 | } catch Error as err { 411 | Print("Failed to load package from " FullPath) 412 | PrintError(err, 0) 413 | FullPath := FullPath == PrevWorkingDir ? A_ScriptDir : PrevWorkingDir 414 | SetWorkingDir(FullPath) 415 | RefreshWorkingDirGlobals() 416 | } 417 | 418 | g_MainGui.CurrentFolder := FullPath 419 | g_MainGui.CurrentLibDir := g_LocalLibDir "\" 420 | 421 | FolderTV := g_MainGui.FolderTV 422 | FolderTV.Opt("-Redraw") 423 | FolderTV.Delete() 424 | split := StrSplit(Trim(FullPath, "\"), "\") 425 | 426 | ItemID := FolderTV.Add(split[-1], 0, "Expand") 427 | AddSubFoldersToTree(FolderTV, FullPath, Map(), ItemID) 428 | FolderTV.Opt("+Redraw") 429 | } 430 | 431 | AddSubFoldersToTree(TV, Folder, DirList, ParentItemID := 0) { 432 | Loop Files, Folder "\*.*", "FD" 433 | { 434 | if A_LoopFileName ~= "^(\.git|\.vscode)$" 435 | continue 436 | ItemID := TV.Add(A_LoopFileName, ParentItemID, "Expand") 437 | DirList[ItemID] := A_LoopFilePath 438 | if DirExist(A_LoopFileFullPath) 439 | AddSubFoldersToTree(TV, A_LoopFileFullPath, DirList, ItemID) 440 | } 441 | } 442 | 443 | OnIndexSearch(Search, *) { 444 | Query := Search.Value 445 | Tab := g_MainGui.Tabs.Index 446 | LV := Tab.LV 447 | LV.Opt("-Redraw") 448 | LV.Delete() 449 | StartsWithCompare := (v1) => v1 ~= (Tab.SearchCaseSenseCB.Value ? "" : "i)") "\b\Q" Query "\E" 450 | SubstrCompare := (v1) => InStr(v1, Query, Tab.SearchCaseSenseCB.Value) 451 | if Query = "" { 452 | for Row in g_MainGui.UnfilteredIndex 453 | LV.Add(, Row*) 454 | } else { 455 | if Tab.SearchByStartCB.Value { 456 | CompareFunc := StartsWithCompare 457 | FilteredIndex := [] 458 | for Row in g_MainGui.UnfilteredIndex 459 | if CompareFunc(Row[1]) 460 | FilteredIndex.Push(Row) 461 | } else { 462 | FilteredIndex := [] 463 | for Row in g_MainGui.UnfilteredIndex { 464 | PackageName := Row[1], IndexEntry := g_Index[PackageName] 465 | if StartsWithCompare(StrSplit(PackageName, "/",, 2)[-1]) { 466 | Row.Weight := 10000, FilteredIndex.Push(Row) 467 | } else if StartsWithCompare(PackageName) { 468 | Row.Weight := 1000, FilteredIndex.Push(Row) 469 | } else if SubStrCompare(PackageName) { 470 | Row.Weight := 100, FilteredIndex.Push(Row) 471 | } else if IndexEntry.Has("keywords") && StartsWithCompare(IndexEntry["keywords"]) { 472 | Row.Weight := 10, FilteredIndex.Push(Row) 473 | } else if IndexEntry.Has("description") && StartsWithCompare(IndexEntry["description"]) { 474 | Row.Weight := 1, FilteredIndex.Push(Row) 475 | } else 476 | Row.Weight := 0 477 | } 478 | FilteredIndex := ObjectSort(FilteredIndex, "Weight",, true) 479 | } 480 | 481 | for Row in FilteredIndex 482 | LV.Add(, Row*) 483 | } 484 | LV.Opt("+Redraw") 485 | } 486 | 487 | ApplyGuiConfigChanges() { 488 | S := g_MainGui.Tabs.Settings 489 | g_Config["github_token"] := S.GithubToken.Value 490 | g_Switches["global_install"] := g_Config["global_install"] := S.GlobalInstalls.Value 491 | g_Config["auto_update_index_daily"] := S.AutoUpdateIndex.Value ? g_Config["auto_update_index_daily"] || 20240101000000 : 0 492 | g_Config["check_aris_updates_daily"] := S.CheckArisUpdates.Value ? g_Config["check_aris_updates_daily"] || 20240101000000 : 0 493 | } 494 | 495 | SaveSettings(ShowToolTip := false) { 496 | FileOpen(A_ScriptDir "\assets\config.json", "w").Write(JSON.Dump(g_Config, true)) 497 | if (ShowToolTip) { 498 | ToolTip("Settings saved!") 499 | SetTimer ToolTip, -3000 500 | } 501 | } 502 | 503 | LaunchVersionSelectionGui(*) { 504 | G := Gui("+MinSize400x200 +Resize", "Package metadata") 505 | G.OnEvent("Size", GuiReSizer) 506 | I := g_MainGui.Tabs.Index 507 | PackageName := I.LV.GetText(Selected := I.LV.GetNext(0), 1) 508 | if !PackageName || Selected = 0 { 509 | MsgBox "No package selected" 510 | return 511 | } 512 | PackageInfo := InputToPackageInfo(PackageName) 513 | if PackageInfo.RepositoryType = "github" 514 | Columns := ["Release/commit", "Date", "Message"] 515 | else if PackageInfo.RepositoryType = "forums" { 516 | Columns := ["Snapshot date", "Comments"] 517 | if !PackageInfo.ThreadId { 518 | ParseRepositoryData(PackageInfo) 519 | } 520 | } else if PackageInfo.RepositoryType = "gist" { 521 | Columns := ["Commit", "Date"] 522 | } else { 523 | MsgBox 'This package repository is of type "' PackageInfo.RepositoryType '" for which querying version info isn`'t currently supported.' 524 | G.Destroy() 525 | return 526 | } 527 | G.LVVersions := G.Add("ListView", "w380 h200", Columns) 528 | G.LVVersions.X := 5, G.LVVersions.Y := 5, G.LVVersions.W := -5, G.LVVersions.H := -35 529 | 530 | G.BtnInstall := G.Add("Button", "x140", "Install selected") 531 | G.BtnInstall.Y := -30, G.BtnInstall.XP := 0.5, G.BtnInstall.X := -50 532 | G.BtnInstall.OnEvent("Click", VersionSelectionInstallBtnClicked.Bind(G, PackageName)) 533 | G.Show("w400 h240") 534 | g_MainGui.Opt("+Disabled") 535 | G.OnEvent("Close", (*) => (g_MainGui.Opt("-Disabled"), G.Destroy())) 536 | 537 | PopulateVersionsLV(PackageInfo, G.LVVersions) 538 | } 539 | 540 | VersionSelectionInstallBtnClicked(G, PackageName, *) { 541 | Version := G.LVVersions.GetText(selected := G.LVVersions.GetNext(0), 1) 542 | if Version = "" || G.LVVersions.GetText(selected, 2) = "" 543 | return 544 | WinClose(G) 545 | g_MainGui.Tabs.Index.Metadata.Value := "" 546 | InstallPackage(PackageName "@" Version,2) 547 | OutputAddedIncludesString() 548 | LoadPackageFolder(A_WorkingDir) 549 | PopulateTabs() 550 | } 551 | 552 | PopulateVersionsLV(PackageInfo, LV) { 553 | Found := [] 554 | if PackageInfo.RepositoryType = "github" { 555 | LV.ModifyCol(1, 160) 556 | LV.Add(, "Querying GitHub releases...") 557 | if (releases := QueryGitHubReleases(PackageInfo.Repository)) && (releases is Array) && releases.Length { 558 | Found.Push(["Releases:"]) 559 | for release in releases 560 | Found.Push([release["tag_name"], release["published_at"]]) 561 | } 562 | LV.Add(, "Querying GitHub commits...") 563 | if (commits := ((CommitsPath := GetPathForGitHubCommits(PackageInfo.Files)) != "" ? QueryGitHubRepo(PackageInfo.Repository, "commits?per_page=100&path=" CommitsPath) : QueryGitHubCommits(PackageInfo.Repository))) && commits is Array && commits.Length { 564 | if Found.Length 565 | Found.Push([""]) 566 | Found.Push(["Commits:"]) 567 | for commit in commits 568 | Found.Push([SubStr(commit["sha"], 1, 7), commit["commit"]["author"]["date"], commit["commit"]["message"]]) 569 | } 570 | LV.ModifyCol(1, 100) 571 | LV.ModifyCol(2, 120) 572 | LV.Delete() 573 | if !Found.Length 574 | Found := [["No releases or commits found"]] 575 | for Item in Found 576 | LV.Add(, Item*) 577 | LV.ModifyCol(3) 578 | } else if PackageInfo.RepositoryType = "forums" { 579 | LV.Opt("+SortDesc") 580 | LV.Add(, "Querying snapshots, this may take time...") 581 | LV.ModifyCol(1) 582 | LV.ModifyCol(2, 160) 583 | Matches := QueryForumsReleases(PackageInfo) 584 | if !WinExist(LV.hwnd) 585 | return 586 | LV.Delete() 587 | LV.Add(, "latest", "Unversioned from live forums") 588 | for Match in Matches { 589 | LV.Add(, Match.Version, " ") 590 | } else 591 | LV.Add(, "No snapshots found in Wayback Machine") 592 | LV.ModifyCol(1) 593 | } else if PackageInfo.RepositoryType = "gist" { 594 | LV.Add(, "Querying Gist commits...") 595 | LV.ModifyCol(1) 596 | Gist := QueryGitHubGist(PackageInfo.Repository) 597 | LVItems := [] 598 | for Info in Gist["history"] { 599 | LVItems.Push([SubStr(Info["version"], 1, 7), Info["committed_at"]]) 600 | } 601 | LV.Delete() 602 | for Item in LVItems 603 | LV.Add(, Item*) 604 | } 605 | } 606 | 607 | LaunchModifyMetadataGui(*) { 608 | G := Gui("+MinSize640x480", "Package metadata") 609 | G.Show("w280 h300") 610 | G.AddText("Section h20 +0x200", "Name:") 611 | G.PName := G.AddEdit("yp r1 w95", g_PackageJson["name"]) 612 | G.PName.ToolTip := WordWrap("The name of the package must be in the format Author/PackageName, where both Author and PackageName contain only URL-safe characters. For example, slashes \/ are not allowed. ") 613 | G.AddText("yp h20 +0x200", "Author:") 614 | G.PAuthor := G.AddEdit("yp w83 r1", g_PackageJson["author"] is String ? g_PackageJson["author"] : g_PackageJson["author"].Has("name") ? g_PackageJson["author"]["name"] : "") 615 | G.PAuthor.ToolTip := WordWrap("Full name or username of the author.") 616 | G.AddText("h20 xs +0x200", "Version:") 617 | G.PVersion := G.AddEdit("yp w87 r1", g_PackageJson["version"]) 618 | G.PVersion.ToolTip := WordWrap("The version of the package must follow semantic versioning rules.") 619 | G.AddText("yp h20 +0x200", "License:") 620 | G.PLicense := G.AddEdit("yp w78 r1", g_PackageJson["license"]) 621 | G.PLicense.ToolTip := WordWrap('Use a SPDX license identifier for the license you`'re using, or a string "SEE LICENSE IN ", or UNLICENSED if you do not wish to grant others the right to use a private or unpublished package under any terms.') 622 | G.AddText("h20 xs +0x200", "Main file:") 623 | G.PMain := G.AddEdit("yp x75 r1 w195", g_PackageJson["main"]) 624 | G.PMain.ToolTip := WordWrap("The main entry-point of the package which will be added to packages.ahk") 625 | G.AddText("h20 xs +0x200", "Description:") 626 | G.PDescription := G.AddEdit("yp x75 r2 w195", g_PackageJson["description"]) 627 | G.PDescription.ToolTip := WordWrap("A short description of your package.") 628 | G.AddText("h20 xs +0x200", "Repository:") 629 | G.PRepository := G.AddEdit("yp x75 r1 w195", g_PackageJson["repository"] is String ? g_PackageJson["repository"] : g_PackageJson["repository"].Has("url") ? g_PackageJson["repository"]["url"] : "") 630 | G.PRepository.ToolTip := WordWrap('Where the package will be downloaded from. If omitted then the default is "Author/PackageName" which will be interpreted as a GitHub repository. This can also be a full path to a GitHub repo, or a Gist identifier, or a zip/tarball link.') 631 | G.AddText("h20 xs +0x200", "Keywords:") 632 | G.PKeywords := G.AddEdit("yp x75 r1 w195", g_PackageJson["keywords"] is Array ? ArrayJoin(g_PackageJson["keywords"], ", ") : "") 633 | G.PKeywords.ToolTip := WordWrap("Comma-delimited keywords that can be used to search for your package.") 634 | G.AddText("h20 xs +0x200", "Files:") 635 | G.PFiles := G.AddEdit("yp x75 r1 w195", g_PackageJson["files"]) 636 | G.PFiles.ToolTip := WordWrap('Comma-delimited file names, or a pattern of files such as "lib\*.ahk", or a directory, which will be included in the package if used as a dependency.') 637 | G.AddText("h20 xs +0x200", "Bugs:") 638 | G.PBugs := G.AddEdit("yp x75 r1 w195", g_PackageJson["bugs"] is Map ? (g_PackageJson["bugs"].Has("url") ? g_PackageJson["bugs"]["url"] : "") : g_PackageJson["bugs"]) 639 | G.PBugs.ToolTip := WordWrap("The URL at which bug reports may be filed.") 640 | G.AddText("h20 xs +0x200", "Hover over the textboxes to see additional info.") 641 | G.AddButton(,"Save metadata").OnEvent("Click", SavePackageMetadata.Bind(G)) 642 | g_MainGui.Opt("+Disabled") 643 | G.OnEvent("Close", (*) => (g_MainGui.Opt("-Disabled"), G.Destroy())) 644 | OnMessage(0x0200, On_WM_MOUSEMOVE) 645 | } 646 | 647 | On_WM_MOUSEMOVE(wParam, lParam, msg, Hwnd) { 648 | static PrevHwnd := 0, PrevTimer := 0 649 | if (Hwnd != PrevHwnd) { 650 | Text := "", ToolTip() ; Turn off any previous tooltip. 651 | if PrevTimer 652 | SetTimer PrevTimer, 0 653 | if CurrControl := GuiCtrlFromHwnd(Hwnd) { 654 | if !CurrControl.HasOwnProp("ToolTip") 655 | return ; No tooltip for this control. 656 | Text := CurrControl.ToolTip 657 | SetTimer (PrevTimer := (() => ToolTip(Text))), -1000 658 | SetTimer ToolTip, -4000 ; Remove the tooltip. 659 | } 660 | PrevHwnd := Hwnd 661 | } 662 | } 663 | 664 | LoadPackageFromGui(*) { 665 | dir := DirSelect("*" g_MainGui.CurrentFolder) 666 | if !dir 667 | return 668 | g_MainGui.Tabs.Index.Metadata.Value := "" 669 | g_MainGui.Tabs.Package.Metadata.Value := "" 670 | 671 | LoadPackageFolder(dir) 672 | PopulateTabs() 673 | } 674 | 675 | SavePackageMetadata(G, *) { 676 | global g_PackageJson 677 | for Field in ["name", "version", "license", "main", "description"] 678 | g_PackageJson[Field] := G.P%Field%.Value 679 | 680 | if G.PAuthor.Value { 681 | if g_PackageJson["author"] is Map 682 | g_PackageJson["author"]["name"] := G.PAuthor.Value 683 | else 684 | g_PackageJson["author"] := G.PAuthor.Value 685 | } 686 | 687 | if G.PRepository.Value { 688 | if g_PackageJson["repository"] is Map 689 | g_PackageJson["repository"]["url"] := G.PRepository.Value 690 | else 691 | g_PackageJson["repository"] := G.PRepository.Value 692 | } 693 | 694 | if G.PKeywords.Value { 695 | keywords := StrSplit(G.PKeywords.Value, ",") 696 | for i, keyword in keywords 697 | keywords[i] := Trim(keyword) 698 | g_PackageJson["keywords"] := keywords 699 | } 700 | 701 | if G.PFiles.Value { 702 | files := StrSplit(G.PFiles.Value, ",") 703 | for i, f in files 704 | files[i] := Trim(f) 705 | g_PackageJson["files"] := files 706 | } 707 | 708 | if G.PBugs.Value { 709 | if g_PackageJson["bugs"] is Map 710 | g_PackageJson["bugs"]["url"] := G.PBugs.Value 711 | else 712 | g_PackageJson["bugs"] := G.PBugs.Value 713 | } 714 | FileOpen("package.json", "w").Write(JSON.Dump(g_PackageJson, true)) 715 | WinClose G 716 | } 717 | 718 | ShowFolderTVContextMenu(FolderTV, Item, IsRightClick, *) { 719 | static FolderMenu 720 | FolderMenu := Menu() 721 | if Item { 722 | Folder := FolderTV.GetText(Item), ParentId := Item 723 | while ParentId := FolderTV.GetParent(ParentId) 724 | Folder := FolderTV.GetText(ParentId) "\" Folder 725 | FullPath := StrSplitLast(A_WorkingDir, "\")[1] "\" Folder 726 | if DirExist(FullPath) 727 | FolderMenu.Add("Open in Explorer", (*) => Run('explore "' FullPath '"')) 728 | else 729 | FolderMenu.Add("Edit file", (*) => Run('edit "' FullPath '"')) 730 | } 731 | FolderMenu.Add("Open project folder in Explorer", (*) => Run('explore "' A_WorkingDir '"')) 732 | FolderMenu.Show() 733 | } 734 | 735 | ShowPackageLVContextMenu(LV, Item, IsRightClick, *) { 736 | Tab := LV.TabName = "Index" ? g_MainGui.Tabs.Index : g_MainGui.Tabs.Package 737 | PackageMenu := Menu() 738 | if !(Item && (PackageName := LV.GetText(Item))) { 739 | if LV.TabName = "Index" { 740 | PackageMenu.Add("Update index", UpdatePackageIndexPopulateTab) 741 | } else { 742 | PackageMenu.Add("Install external package", PackageAction.Bind(Tab, "install-external",0,1)) 743 | } 744 | } else { 745 | if g_InstalledPackages.Has(PackageName) { 746 | PackageMenu.Add("Modify version range", ModifyPackageVersionRange.Bind(LV)) 747 | PackageMenu.Add("Update", PackageAction.Bind(Tab, "update",0, 1)) 748 | PackageMenu.Add("Force update to latest", PackageAction.Bind(Tab, "update-latest",, 1)) 749 | PackageMenu.Add("Reinstall", PackageAction.Bind(Tab, "reinstall",0, 1)) 750 | PackageMenu.Add("Remove", PackageAction.Bind(Tab, "remove",0, 1)) 751 | } else { 752 | PackageMenu.Add("Install", PackageAction.Bind(Tab, "install",0, 1)) 753 | PackageMenu.Add("Query versions", LaunchVersionSelectionGui) 754 | } 755 | } 756 | PackageMenu.Show() 757 | } 758 | 759 | UninstallAris(*) { 760 | if MsgBox("This action will delete the current folder Aris is running in, and remove any shell and PATH entries.`n`nAre you sure you want to continue?", "Warning", 0x4|0x30) = "No" 761 | return 762 | RemoveArisFromPATH() 763 | RemoveArisShellMenuItem() 764 | try DirDelete(A_ScriptDir, 1) 765 | if !FileExist(A_ScriptFullPath) { 766 | MsgBox("Aris successfully uninstalled.", "Aris", 0x40) 767 | ExitApp 768 | } else 769 | MsgBox("Failed to delete the Aris folder. Delete the main folder manually to uninstall.", "Aris", 0x10) 770 | } -------------------------------------------------------------------------------- /lib/utils.ahk: -------------------------------------------------------------------------------- 1 | class Mapi extends Map { 2 | CaseSense := "Off" 3 | } 4 | 5 | WordWrap(str, column:=56, indentChar:="") { 6 | if !IsInteger(column) 7 | throw TypeError("WordWrap: argument 'column' must be an integer", -1) 8 | out := "" 9 | indentLength := StrLen(indentChar) 10 | 11 | Loop parse, str, "`n", "`r" { 12 | if (StrLen(A_LoopField) > column) { 13 | pos := 1 14 | Loop parse, A_LoopField, " " 15 | if (pos + (LoopLength := StrLen(A_LoopField)) <= column) 16 | out .= (A_Index = 1 ? "" : " ") A_LoopField 17 | , pos += LoopLength + 1 18 | else 19 | pos := LoopLength + 1 + indentLength 20 | , out .= "`n" indentChar A_LoopField 21 | 22 | out .= "`n" 23 | } else 24 | out .= A_LoopField "`n" 25 | } 26 | return SubStr(out, 1, -1) 27 | } 28 | 29 | StrSplitLast(str, delim) => (pos := InStr(str, delim,,-1)) ? [SubStr(str, 1, pos-1), SubStr(str, pos+StrLen(delim))] : [str] 30 | 31 | ArrayJoin(arr, delim:=",") { 32 | result := "" 33 | for v in arr 34 | result .= (v ?? "") delim 35 | return (len := StrLen(delim)) ? SubStr(result, 1, -len) : result 36 | } 37 | 38 | /* 39 | * ObjectSort() by bichlepa 40 | * 41 | * Description: 42 | * Reads content of an object and returns a sorted array 43 | * 44 | * Parameters: 45 | * obj: Object which will be sorted 46 | * keyName: [optional] 47 | * Omit it if you want to sort an array of strings, numbers etc. 48 | * If you have an array of objects, specify here the key by which contents the object will be sorted. 49 | * callBackFunction: [optional] Use it if you want to have custom sort rules. 50 | * The function will be called once for each value. It must return a number or string. 51 | * reverse: [optional] Pass true if the result array should be reversed 52 | */ 53 | ObjectSort(obj, keyName := "", callbackFunc := "", reverse := false) { 54 | temp := Map() 55 | sorted := [] ; Return value 56 | 57 | for oneKey, oneValue in (((obj is Map) || (obj is Array)) ? obj : obj.OwnProps()) { 58 | ; Get the value by which it will be sorted 59 | if keyName 60 | value := oneValue is Map ? oneValue[keyName] : oneValue.%keyName% 61 | else 62 | value := oneValue 63 | 64 | ; If there is a callback function, call it. The value is the key of the temporary list. 65 | if (callbackFunc) 66 | tempKey := callbackFunc(value) 67 | else 68 | tempKey := value 69 | 70 | ; Insert the value in the temporary object. 71 | ; It may happen that some values are equal therefore we put the values in an array. 72 | if !temp.Has(tempKey) 73 | temp[tempKey] := [] 74 | temp[tempKey].Push(oneValue) 75 | } 76 | 77 | ; Now loop through the temporary list. AutoHotkey sorts them for us. 78 | for oneTempKey, oneValueList in temp { 79 | for oneValueIndex, oneValue in oneValueList { 80 | ; And add the values to the result list 81 | if (reverse) 82 | sorted.InsertAt(1, oneValue) 83 | else 84 | sorted.Push(oneValue) 85 | } 86 | } 87 | 88 | return sorted 89 | } 90 | 91 | ; Credit: iPhilip, Source: https://www.autohotkey.com/boards/viewtopic.php?style=17&p=509167#p509167 92 | ; https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows 93 | LD(Source, Target, CaseSense := True) { 94 | if CaseSense ? Source == Target : Source = Target 95 | return 0 96 | Source := StrSplit(Source) 97 | Target := StrSplit(Target) 98 | if !Source.Length 99 | return Target.Length 100 | if !Target.Length 101 | return Source.Length 102 | 103 | v0 := [], v1 := [] 104 | Loop Target.Length + 1 105 | v0.Push(A_Index - 1) 106 | v1.Length := v0.Length 107 | 108 | for Index, SourceChar in Source { 109 | v1[1] := Index 110 | for TargetChar in Target 111 | v1[A_Index + 1] := Min(v1[A_Index] + 1, v0[A_Index + 1] + 1, v0[A_Index] + (CaseSense ? SourceChar !== TargetChar : SourceChar != TargetChar)) 112 | Loop Target.Length + 1 113 | v0[A_Index] := v1[A_Index] 114 | } 115 | return v1[Target.Length + 1] 116 | } 117 | 118 | ConvertRange(OldValue, OldMin, OldMax, NewMin, NewMax) => (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin 119 | 120 | MoveFilesAndFolders(SourcePattern, DestinationFolder, DoOverwrite := false) { 121 | if DoOverwrite = 1 122 | DoOverwrite := 2 ; See DirMove for description of mode 2 vs. 1. 123 | ; First move all the files (but not the folders): 124 | FileMove SourcePattern, DestinationFolder, DoOverwrite 125 | ; Now move all the folders: 126 | Loop Files, SourcePattern, "D" ; D means "retrieve folders only". 127 | DirMove A_LoopFilePath, DestinationFolder "\" A_LoopFileName, DoOverwrite 128 | } 129 | 130 | DirCreateEx(FullPath) { 131 | Dir := "" 132 | for Path in StrSplit(FullPath, "\") { 133 | Dir := (Dir ? Dir "\" : "") Path 134 | if !DirExist(Dir) 135 | DirCreate(Dir) 136 | } 137 | } 138 | 139 | RegExMatchAll(haystack, needleRegEx, startingPosition := 1) { 140 | out := [], end := StrLen(haystack)+1 141 | While startingPosition < end && RegExMatch(haystack, needleRegEx, &outputVar, startingPosition) 142 | out.Push(outputVar), startingPosition := outputVar.Pos + (outputVar.Len || 1) 143 | return out 144 | } 145 | 146 | ; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=74647 147 | RunCMD(P_CmdLine, P_WorkingDir := "", P_Codepage := "CP0", P_Func := 0, P_Slow := 1) 148 | { 149 | ; RunCMD Temp_v0.99 for ah2 By SKAN on D532/D67D @ autohotkey.com/r/?p=448912 150 | 151 | Global G_RunCMD 152 | 153 | If Not IsSet(G_RunCMD) 154 | G_RunCMD := {} 155 | 156 | G_RunCMD := {PID: 0, ExitCode: ""} 157 | 158 | Local CRLF := Chr(13) Chr(10) 159 | , hPipeR := 0 160 | , hPipeW := 0 161 | , PIPE_NOWAIT := 1 162 | , HANDLE_FLAG_INHERIT := 1 163 | , dwMask := HANDLE_FLAG_INHERIT 164 | , dwFlags := HANDLE_FLAG_INHERIT 165 | 166 | DllCall("Kernel32\CreatePipe", "ptrp",&hPipeR, "ptrp",&hPipeW, "ptr",0, "int",0) 167 | , DllCall("Kernel32\SetHandleInformation", "ptr",hPipeW, "int",dwMask, "int",dwFlags) 168 | , DllCall("Kernel32\SetNamedPipeHandleState", "ptr",hPipeR, "uintp",PIPE_NOWAIT, "ptr",0, "ptr",0) 169 | 170 | Local B_OK := 0 171 | , P8 := A_PtrSize=8 172 | , STARTF_USESTDHANDLES := 0x100 173 | , STARTUPINFO 174 | , PROCESS_INFORMATION 175 | 176 | PROCESS_INFORMATION := Buffer(P8 ? 24 : 16, 0) ; PROCESS_INFORMATION 177 | , STARTUPINFO := Buffer(P8 ? 104 : 68, 0) ; STARTUPINFO 178 | 179 | , NumPut("uint", P8 ? 104 : 68, STARTUPINFO) ; STARTUPINFO.cb 180 | , NumPut("uint", STARTF_USESTDHANDLES, STARTUPINFO, P8 ? 60 : 44) ; STARTUPINFO.dwFlags 181 | , NumPut("ptr", hPipeW, STARTUPINFO, P8 ? 88 : 60) ; STARTUPINFO.hStdOutput 182 | , NumPut("ptr", hPipeW, STARTUPINFO, P8 ? 96 : 64) ; STARTUPINFO.hStdError 183 | 184 | Local CREATE_NO_WINDOW := 0x08000000 185 | , PRIORITY_CLASS := DllCall("Kernel32\GetPriorityClass", "ptr",-1, "uint") 186 | 187 | B_OK := DllCall( "Kernel32\CreateProcessW" 188 | , "ptr", 0 ; lpApplicationName 189 | , "ptr", StrPtr(P_CmdLine) ; lpCommandLine 190 | , "ptr", 0 ; lpProcessAttributes 191 | , "ptr", 0 ; lpThreadAttributes 192 | , "int", True ; bInheritHandles 193 | , "int", CREATE_NO_WINDOW | PRIORITY_CLASS ; dwCreationFlags 194 | , "int", 0 ; lpEnvironment 195 | , "ptr", DirExist(P_WorkingDir) ? StrPtr(P_WorkingDir) : 0 ; lpCurrentDirectory 196 | , "ptr", STARTUPINFO ; lpStartupInfo 197 | , "ptr", PROCESS_INFORMATION ; lpProcessInformation 198 | , "uint" 199 | ) 200 | 201 | DllCall("Kernel32\CloseHandle", "ptr",hPipeW) 202 | 203 | If Not B_OK 204 | Return ( DllCall("Kernel32\CloseHandle", "ptr",hPipeR), "" ) 205 | 206 | G_RunCMD.PID := NumGet(PROCESS_INFORMATION, P8 ? 16 : 8, "uint") 207 | 208 | Local FileObj 209 | , Line := "" 210 | , LineNum := 1 211 | , sOutput := "" 212 | , ExitCode := 0 213 | 214 | FileObj := FileOpen(hPipeR, "h", P_Codepage) 215 | , P_Slow := !! P_Slow 216 | 217 | Sleep_() => (Sleep(P_Slow), G_RunCMD.PID) 218 | 219 | While DllCall("Kernel32\PeekNamedPipe", "ptr",hPipeR, "ptr",0, "int",0, "ptr",0, "ptr",0, "ptr",0) 220 | and Sleep_() 221 | While G_RunCMD.PID and not FileObj.AtEOF 222 | Line := FileObj.ReadLine() 223 | , sOutput .= StrLen(Line)=0 and FileObj.Pos=0 224 | ? "" 225 | : ( 226 | P_Func 227 | ? P_Func.Call(Line CRLF, LineNum++) 228 | : Line CRLF 229 | ) 230 | 231 | hProcess := NumGet(PROCESS_INFORMATION, 0, "ptr") 232 | , hThread := NumGet(PROCESS_INFORMATION, A_PtrSize, "ptr") 233 | 234 | , DllCall("Kernel32\GetExitCodeProcess", "ptr",hProcess, "ptrp",&ExitCode) 235 | , DllCall("Kernel32\CloseHandle", "ptr",hProcess) 236 | , DllCall("Kernel32\CloseHandle", "ptr",hThread) 237 | , DllCall("Kernel32\CloseHandle", "ptr",hPipeR) 238 | , G_RunCMD := {PID: 0, ExitCode: ExitCode} 239 | 240 | Return RTrim(sOutput, CRLF) 241 | } 242 | 243 | ExecScript(Script, args:="") { 244 | shell := ComObject("WScript.Shell") 245 | exec := shell.Exec('"' A_AhkPath '" /ErrorStdOut * ' args) 246 | exec.StdIn.Write(Script) 247 | exec.StdIn.Close() 248 | return {Output:exec.StdOut.ReadAll(), ExitCode:exec.ExitCode} 249 | } 250 | 251 | QuoteFile(name) => InStr(name, " ") ? '"' name '"' : name 252 | 253 | RemoveAhkSuffix(name) => RegExReplace(name, "\.ahk?\d?(?=$|@)") 254 | 255 | FindMatchingAssets(needle, assetArray) { 256 | if !InStr(needle, ".") 257 | throw ValueError("The needle must contain at least one . character", -1, needle) 258 | matches := [] 259 | if !InStr(needle, "*") { ; No wildcard, try to find partial match 260 | for k, v in assetArray { 261 | if InStr(v["name"], needle) 262 | matches.Push(v) 263 | } 264 | } else { ; Wildcard present 265 | ; Escape legal file name characters with RegEx meanings 266 | needle := RegExReplace(needle, "[\\\.\^\$\+\{\}\[\]\(\)\``]", "\$0") 267 | needle := StrReplace("^" needle "$","*",".*") ; Replace the wildcard 268 | for k, v in assetArray { 269 | if RegExMatch(v["name"], needle, &found:="") && found[0] 270 | matches.push(v) 271 | } 272 | } 273 | return matches 274 | } -------------------------------------------------------------------------------- /lib/version.ahk: -------------------------------------------------------------------------------- 1 | GetVersionRangeCompareFunc(Range) { 2 | Range := StrLower(Range), OtherRange := "" 3 | Split := StrSplit(Range := Trim(Range), " ",, 2) 4 | if Split.Length > 1 { 5 | OtherRange := Split[2], Range := Split[1] 6 | } 7 | if Range = "*" 8 | Range := "latest" 9 | if Range && Range != "latest" { 10 | Plain := RegExReplace(Range, "[^\w-.]") 11 | if SubStr(Plain, 1, 1) = "v" 12 | Plain := SubStr(Plain, 2) 13 | if IsVersionSha(Plain) || IsVersionMD5(Plain) 14 | return (v) => v == Plain 15 | 16 | split := StrSplit(Plain, ".") 17 | if split.Length = 3 && split[3] = "x" 18 | split[3] := "0", Range := "~" Range, Plain := StrReplace(Plain, ".x", ".0") 19 | if split.Length = 2 && split[2] = "x" 20 | split[2] := "0", Range := "^" Range, Plain := StrReplace(Plain, ".x", ".0") 21 | CropLength := RegExReplace.Bind(,"^([~^><=]*\d{10,10})\d+", "$1") 22 | Plain := CropLength(Plain), Range := CropLength(Range) 23 | switch SubStr(Range, 1, 1) { 24 | case "~": ; Only accept patch versions 25 | CompareFunc := (v) => (v:=CropLength(v), VerCompare(v, ">=" Plain) && VerCompare(v, (split.Length > 1) ? "<" split[1] "." (Integer(split[2])+1) : "=" split[1])) 26 | case "^": ; Only accept minor and patch versions 27 | CompareFunc := (v) => (v:=CropLength(v), VerCompare(v, ">=" Plain) && VerCompare(v, "<" (Integer(split[1])+1))) 28 | case ">", "<": 29 | CompareFunc := (v) => VerCompare(CropLength(v), Range) 30 | default: 31 | CompareFunc := (v) => VerCompare(CropLength(v), "=" Plain) 32 | } 33 | } else 34 | CompareFunc := (v) => true 35 | if OtherRange 36 | return (v) => CompareFunc(v) && GetVersionRangeCompareFunc(OtherRange).Call(v) 37 | return CompareFunc 38 | } 39 | 40 | IsVersionSha(version) => StrLen(version) = 7 && IsAlnum(version) 41 | IsVersionMD5(version) => StrLen(version) = 10 && IsAlnum(version) 42 | IsSemVer(input) => !RegExMatch(input, "(^\w{7}$)|^\w{10}$") && RegExMatch(input, "^[><=^~]*v?(?:((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)|\d+|\d+\.\d+|latest|\*)$") 43 | IsVersionCompatible(version, range) => GetVersionRangeCompareFunc(range).Call(version) -------------------------------------------------------------------------------- /lib/web.ahk: -------------------------------------------------------------------------------- 1 | ObjToQuery(oData) { ; https://gist.github.com/anonymous1184/e6062286ac7f4c35b612d3a53535cc2a?permalink_comment_id=4475887#file-winhttprequest-ahk 2 | static HTMLFile := InitHTMLFile() 3 | if (!IsObject(oData)) { 4 | return oData 5 | } 6 | out := "" 7 | for key, val in (oData is Map ? oData : oData.OwnProps()) { 8 | out .= HTMLFile.parentWindow.encodeURIComponent(key) "=" 9 | out .= HTMLFile.parentWindow.encodeURIComponent(val) "&" 10 | } 11 | return "?" RTrim(out, "&") 12 | } 13 | 14 | InitHTMLFile() { 15 | doc := ComObject("HTMLFile") 16 | doc.write("") 17 | return doc 18 | } 19 | 20 | EncodeDecodeURI(str, encode := true) { 21 | VarSetStrCapacity(&result:="", pcchEscaped:=500) 22 | if encode { 23 | DllCall("Shlwapi.dll\UrlEscape", "str", str, "ptr", StrPtr(result), "uint*", &pcchEscaped, "uint", 0x00080000 | 0x00002000) 24 | } else { 25 | DllCall("Shlwapi.dll\UrlUnescape", "str", str, "ptr", StrPtr(result), "uint*", &pcchEscaped, "uint", 0x10000000) 26 | } 27 | VarSetStrCapacity(&result, -1) 28 | return result 29 | } 30 | 31 | DownloadURL(url) { 32 | local req := ComObject("Msxml2.XMLHTTP") 33 | req.open("GET", url, true) 34 | req.send() 35 | while req.readyState != 4 36 | Sleep 100 37 | if req.status == 200 { 38 | return req.responseText 39 | } else 40 | throw Error("Download failed", -1, url) 41 | } 42 | 43 | ; Forum Topic: www.autohotkey.com/forum/topic51342.html 44 | UnHTM( HTM ) { ; Remove HTML formatting / Convert to ordinary text by SKAN 19-Nov-2009 45 | Static HT := "ááââ´´ææàà&ååãã&au" 46 | . "mlä&bdquo„¦¦&bull•ç縸¢¢&circˆ©©¤¤&dagger†&dagger‡°" 47 | . "°÷÷ééêêèèððëë&euro€&fnofƒ½½¼¼¾¾>>&h" 48 | . "ellip…ííîî¡¡ìì¿¿ïï««&ldquo“&lsaquo‹&lsquo‘<<&m" 49 | . "acr¯&mdash—µµ··  &ndash–¬¬ññóóôô&oeligœòò&or" 50 | . "dfªººøøõõöö¶¶&permil‰±±££"`"»»&rdquo”®" 51 | . "®&rsaquo›&rsquo’&sbquo‚&scaronš§§­­¹¹²²³³ßßþþ&tilde˜&tim" 52 | . "es×&trade™úúûûùù¨¨üüýý¥¥ÿÿ" 53 | TXT := RegExReplace(HTM, "<[^>]+>"), R := "" ; Remove all tags between "<" and ">" 54 | Loop Parse, TXT, "&`;" ; Create a list of special characters 55 | L := "&" A_LoopField ";", R .= (InStr(HT, "&" A_LoopField) && !InStr(R, L, 1) ? L:"") 56 | R := SubStr(R, 1, -1) 57 | Loop Parse, R, "`;" ; Parse Special Characters 58 | If F := InStr(HT, A_LoopField) ; Lookup HT Data 59 | ; StrReplace() is not case sensitive 60 | ; check for StringCaseSense in v1 source script 61 | ; and change the CaseSense param in StrReplace() if necessary 62 | TXT := StrReplace(TXT, A_LoopField "`;", SubStr(HT, (F+StrLen(A_LoopField))<1 ? (F+StrLen(A_LoopField))-1 : (F+StrLen(A_LoopField)), 1)) 63 | Else If ( SubStr(A_LoopField, 2, 1)="#" ) 64 | ; StrReplace() is not case sensitive 65 | ; check for StringCaseSense in v1 source script 66 | ; and change the CaseSense param in StrReplace() if necessary 67 | TXT := StrReplace(TXT, A_LoopField "`;", SubStr(A_LoopField, 3)) 68 | Return RegExReplace(TXT, "(^\s*|\s*$)") ; Remove leading/trailing white spaces 69 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "email": "", 4 | "name": "Descolada", 5 | "website": "https://github.com/Descolada" 6 | }, 7 | "bugs": { 8 | "url": "https://github.com/Descolada/Aris/issues" 9 | }, 10 | "dependencies": { 11 | "FanaticGuru/GuiReSizer": "2ba5b65", 12 | "G33kDude/cJson": "^2.0.0" 13 | }, 14 | "description": "A basic package manager for AutoHotkey", 15 | "homepage": "github.com/Descolada/Aris", 16 | "keywords": [ 17 | "package", 18 | "manager" 19 | ], 20 | "license": "MIT", 21 | "main": "aris.ahk", 22 | "name": "Descolada/Aris", 23 | "repository": { 24 | "type": "github", 25 | "url": "Descolada/Aris" 26 | }, 27 | "version": "0.7.2-alpha" 28 | } --------------------------------------------------------------------------------