├── .gitattributes ├── .gitignore ├── .vscode ├── ahk.code-snippets ├── launch.json └── settings.json ├── First Setup.lnk ├── LICENSE.md ├── README.md ├── admin ├── ahk.code-workspace └── ahk.todo ├── config ├── editFiles.tls ├── folders.tls ├── hyperlinkWindows.tl ├── listFormats.tls ├── paths.tl ├── programs.tl ├── puttyRecordEditSearch.tls ├── resize.tls ├── search.tls ├── symbols.tls ├── windowActions.tl ├── windowPositionPresets.tls ├── windowPositions.tl └── windows.tl ├── icons ├── color.ico ├── colorRed.ico ├── controllerGreen.ico ├── controllerRed.ico ├── cross.cur ├── hourglass.ico ├── iconCredits.txt ├── mouseGreen.ico ├── mouseRed.ico ├── moveSize.ico ├── moveSizeRed.ico ├── ninja.png ├── ninjaRed.png ├── pictureRed.ico ├── pictureWhite.ico ├── shellGreen.ico ├── shellRed.ico ├── shieldGreen.ico ├── shieldRed.ico ├── vim.ico ├── vimPause.ico └── vimSuspend.ico └── source ├── common ├── base │ ├── actionObjectBase.ahk │ ├── arrayBase.ahk │ ├── objectBase.ahk │ ├── relativeDateTimeBase.ahk │ └── stringBase.ahk ├── class │ ├── actionObject.ahk │ ├── actionObjectCodeSearch.ahk │ ├── actionObjectEMC2.ahk │ ├── actionObjectEpicCode.ahk │ ├── actionObjectEpicStudio.ahk │ ├── actionObjectPath.ahk │ ├── actionObjectSVNLog.ahk │ ├── actionObjectTrackLab.ahk │ ├── actionObjectWebRecord.ahk │ ├── debugTable.ahk │ ├── duration.ahk │ ├── epicRecord.ahk │ ├── flexTable.ahk │ ├── formattedList.ahk │ ├── mousePosition.ahk │ ├── program.ahk │ ├── progressToast.ahk │ ├── relativeDate.ahk │ ├── relativeTime.ahk │ ├── selector.ahk │ ├── selectorChoice.ahk │ ├── selectorGui.ahk │ ├── tableList.ahk │ ├── tableListMod.ahk │ ├── tempSettings.ahk │ ├── textPopup.ahk │ ├── textTable.ahk │ ├── toast.ahk │ ├── visualWindow.ahk │ └── windowInfo.ahk ├── common.ahk ├── external │ ├── HTTPRequest.ahk │ └── commandFunctions.ahk ├── lib │ ├── ahkCodeLib.ahk │ ├── clipboardLib.ahk │ ├── dataLib.ahk │ ├── dateTimeLib.ahk │ ├── epicLib.ahk │ ├── fileLib.ahk │ ├── guiLib.ahk │ ├── hotkeyLib.ahk │ ├── microsoftLib.ahk │ ├── monitorLib.ahk │ ├── phoneLib.ahk │ ├── runLib.ahk │ ├── searchLib.ahk │ ├── selectLib.ahk │ ├── stringLib.ahk │ └── windowLib.ahk ├── program │ ├── chrome.ahk │ ├── ditto.ahk │ ├── emc2.ahk │ ├── epicStudio.ahk │ ├── excel.ahk │ ├── explorer.ahk │ ├── headerDocBlock.ahk │ ├── hyperspace.ahk │ ├── internetExplorer.ahk │ ├── mBuilder.ahk │ ├── mSnippets.ahk │ ├── mtPutty.ahk │ ├── notepadPlusPlus.ahk │ ├── oneNoteTodoPage.ahk │ ├── onenote.ahk │ ├── onetastic.ahk │ ├── outlook.ahk │ ├── putty.ahk │ ├── snapper.ahk │ ├── telegram.ahk │ ├── visualStudio.ahk │ ├── vsCode.ahk │ └── zoom.ahk └── static │ ├── VA.ahk │ ├── commonHotkeys.ahk │ ├── config.ahk │ ├── debug.ahk │ ├── enums.ahk │ ├── hyperlinker.ahk │ ├── scriptTrayInfo.ahk │ ├── titleMatchMode.ahk │ ├── windowActions.ahk │ └── windowPositions.ahk ├── firstSetup.ahk ├── general ├── epic.ahk ├── hotstrings.ahk ├── media.ahk ├── places.ahk ├── programs.ahk ├── selection.ahk ├── system.ahk ├── text.ahk └── window.ahk ├── main.ahk ├── program ├── chrome.ahk ├── ciscoVPN.ahk ├── ditto.ahk ├── emc2.ahk ├── epicStudio.ahk ├── everything.ahk ├── excel.ahk ├── explorer.ahk ├── fastStoneImageViewer.ahk ├── hyperdrive.ahk ├── hyperspace.ahk ├── internetExplorer.ahk ├── kdiff.ahk ├── launchy.ahk ├── notepadPlusPlus.ahk ├── onenote.ahk ├── onetastic.ahk ├── outlook.ahk ├── powerpoint.ahk ├── putty.ahk ├── remoteDesktop.ahk ├── snapper.ahk ├── spotify.ahk ├── sumatraPDF.ahk ├── teams.ahk ├── telegram.ahk ├── tortoise.ahk ├── visualStudio.ahk ├── vsCode.ahk ├── wilma.ahk ├── winMerge.ahk ├── word.ahk └── zoom.ahk ├── standalone ├── activateProgram.ahk ├── addEnvironmentTLSLines.ahk ├── callPhone.ahk ├── changeVolume.ahk ├── colorPicker.ahk ├── compileEpicStudioRegex.ahk ├── compileOnetasticMacros.ahk ├── copySourceToPersonalFolder.ahk ├── dumpActiveWindowInfoToNotepad.ahk ├── equalsDown.ahk ├── findProjectInSolutionsFolder.ahk ├── fixVDIDisplaySettings.ahk ├── generateHyperdriveEnvironments.ahk ├── halfQWERTY.ahk ├── iconTester │ └── iconTester.ahk ├── lockComputer.ahk ├── muteVolume.ahk ├── notesHelper.ahk ├── onenoteOnlineHotkeys.ahk ├── preciseMouse.ahk ├── psxEmulatorController │ ├── XInput.ahk │ └── psxEmulatorController.ahk ├── pullAllRepos.ahk ├── reformatAllTLFiles.ahk ├── releaseModifierKeys.ahk ├── runProgram.ahk ├── sendMediaKey.ahk ├── sendRange.ahk ├── timer.ahk ├── transactionDump.ahk ├── transactionDumpAllCurrent.ahk ├── triggerOutlookQuickStep.ahk ├── updateNotepadPPSupport │ ├── autoCompleteClass.ahk │ ├── autoCompleteMember.ahk │ └── updateNotepadPPSupport.ahk └── xdsDiff.ahk └── sub ├── vimBindings.ahk └── windowMoverSizer.ahk /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General files and extensions that should be ignored 2 | Thumbs.db 3 | *.bak 4 | *.tmp 5 | *.exe 6 | 7 | # Ignore local config info 8 | config/settings.ini 9 | -------------------------------------------------------------------------------- /.vscode/ahk.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "If block": { 3 | "prefix": "if", 4 | "body": [ 5 | "if (${1:condition}) {", 6 | "\t$0", 7 | "}" 8 | ], 9 | "description": "Insert an if block" 10 | }, 11 | "Function": { 12 | "prefix": "function", 13 | "body": [ 14 | "${1:functionName}(${2:parameters}) {", 15 | "\t$0", 16 | "}" 17 | ], 18 | "description": "Insert a function" 19 | }, 20 | "Class skeleton": { 21 | "prefix": "ahkclass", 22 | "body": [ 23 | "/* GDB TODO ", 24 | "\t", 25 | "\tExample Usage", 26 | ";\t\tGDB TODO", 27 | "\t", 28 | "*/", 29 | "", 30 | "class ${className} {", 31 | "\t;region ------------------------------ PUBLIC ------------------------------", 32 | "\t; - Constants", 33 | "\t; - staticMembers", 34 | "\t; - nonStaticMembers", 35 | "\t; - properties", 36 | "\t; - __New()", 37 | "\t; - otherFunctions", 38 | "\t;endregion ------------------------------ PUBLIC ------------------------------", 39 | "\t", 40 | "\t;region ------------------------------ INTERNAL ------------------------------", 41 | "\t; - Constants", 42 | "\t; - staticMembers", 43 | "\t; - nonStaticMembers", 44 | "\t; - functions", 45 | "\t;endregion ------------------------------ INTERNAL ------------------------------", 46 | "\t", 47 | "\t;region ------------------------------ PRIVATE ------------------------------", 48 | "\t; - Constants", 49 | "\t; - staticMembers", 50 | "\t; - nonStaticMembers", 51 | "\t; - functions", 52 | "\t;endregion ------------------------------ PRIVATE ------------------------------", 53 | "\t", 54 | "\t;region ------------------------------ DEBUG ------------------------------", 55 | "\tDebug_TypeName() {", 56 | "\t\treturn \"${className}\"", 57 | "\t}", 58 | "\t", 59 | "\tDebug_ToString(ByRef table) {", 60 | "\t\ttable.addLine(\"GDB TODO\", this.GDBTODO)", 61 | "\t;endregion ------------------------------ DEBUG ------------------------------", 62 | "}", 63 | "" 64 | ], 65 | "description": "The skeleton for a new AHK class" 66 | }, 67 | "Continuation section": { 68 | "prefix": "contsec", 69 | "body": [ 70 | "\"", 71 | "\t(", 72 | "\t\t$0", 73 | "\t)\"" 74 | ], 75 | "description": "Add a continuation section" 76 | }, 77 | "Clipboard as value": { 78 | "prefix": "clip", 79 | "body": "\"${CLIPBOARD/(\")|(\r)|(\n)/${1:+\"\"}${2:+`r}${3:+`n}/g}\"", 80 | "description": "Send the clipboard as a value/expression, escaping quotes and newlines" 81 | }, 82 | "Toast (medium)": { 83 | "prefix": "toastmed", 84 | "body": "Toast.ShowMedium(\"$1\")$0", 85 | "description": "Insert an error toast" 86 | }, 87 | "Error toast": { 88 | "prefix": "errortoast", 89 | "body": "Toast.ShowError(\"$1\")$0", 90 | "description": "Insert an error toast" 91 | }, 92 | "Default value": { 93 | "prefix": "default", 94 | "body": "${1:targetVar} := ${1:targetVar} ? ${1:targetVar} : ${2:defaultValue}", 95 | "description": "Default a variable to a value (if it's false/empty)" 96 | }, 97 | "Region": { 98 | "prefix": "region", 99 | "body": [ 100 | ";region ${1:regionName}", 101 | ";endregion ${1:regionName}" 102 | ], 103 | "description": "Insert a collapsible region" 104 | }, 105 | "Scope region": { 106 | "prefix": "scope", 107 | "body": [ 108 | ";region ------------------------------ ${1|PUBLIC,PRIVATE,INTERNAL,DEBUG|} ------------------------------", 109 | ";endregion ------------------------------ ${1} ------------------------------" 110 | ], 111 | "description": "Insert a collapsible region to denote scope" 112 | }, 113 | "Switch select case": { 114 | "prefix": "switch", 115 | "body": [ 116 | "Switch ${1:value} {", 117 | "\tCase ${2:caseValue}:", 118 | "\t\t$0", 119 | "}", 120 | ], 121 | "description": "Insert a switch statement" 122 | }, 123 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "AHK Debug (Attach)", 9 | "type":"autohotkey", 10 | "request": "attach", 11 | "program": "${file}", 12 | "stopOnEntry": false, 13 | }, 14 | { 15 | "name": "AHK Debug (Run)", 16 | "type": "autohotkey", 17 | "request": "launch", 18 | "program": "${file}", 19 | "args": [] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /First Setup.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/First Setup.lnk -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Gavin Borg 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ahk 2 | === 3 | 4 | A personal repository for my personal ahk library. 5 | -------------------------------------------------------------------------------- /admin/ahk.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".." 5 | }, 6 | { 7 | "path": "..\\..\\ahkPrivate" 8 | }, 9 | { 10 | "path": "..\\..\\ahkTest" 11 | } 12 | ], 13 | "settings": { 14 | "files.encoding": "utf8bom", 15 | "files.autoGuessEncoding": false, 16 | }, 17 | "extensions": { 18 | "recommendations": [ 19 | "mark-wiemer.vscode-autohotkey-plus-plus", 20 | "fabiospampinato.vscode-highlight", 21 | "fabiospampinato.vscode-todo-plus", 22 | "zero-plusplus.vscode-autohotkey-debug", 23 | "thqby.vscode-autohotkey2-lsp" 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /config/editFiles.tls: -------------------------------------------------------------------------------- 1 | @WindowTitle(File to edit:) 2 | 3 | [ NAME ABBREV PATH ] 4 | 5 | # Admin 6 | Todo todo \admin\ahk.todo 7 | 8 | # Config 9 | ~PATH.addToStart(\) { 10 | Hyperlink windows link hyperlinkWindows.tl 11 | Paths path paths.tl 12 | Programs prog programs.tl 13 | Settings s settings.ini 14 | Windows w | win windows.tl 15 | Windows Actions wa | wina windowActions.tl 16 | Window Positions wp | winpos | pos windowPositions.tl 17 | } 18 | 19 | # Private 20 | ~PATH.addToStart(\) { 21 | All current Epic environments allenv allCurrentEpicEnvironments.txt 22 | Private values priv privates.tl 23 | Snapper ignore items snap snapperIgnoreItems.tls 24 | Mapped drives md mappedDrives.tl 25 | Moved folders mf movedFolders.tl 26 | TLG/EMC2 records tlg | emc2 tlg.tls 27 | } 28 | 29 | # ! Code 30 | ~PATH.addToStart(\) { 31 | Main m main.ahk 32 | Common com common\common.ahk 33 | Config con | conf common\static\config.ahk 34 | Command Functions cf common\external\commandFunctions.ahk 35 | Hotstrings h general\hotstrings.ahk 36 | } 37 | Test t \test.ahk 38 | -------------------------------------------------------------------------------- /config/folders.tls: -------------------------------------------------------------------------------- 1 | [ NAME ABBREV PATH CONTEXT ] 2 | 3 | # General 4 | Downloads dl 5 | ~CONTEXT.replaceWith(WORK) { 6 | Specifics spec \Specifics 7 | Shortcuts sc \Shortcuts 8 | Personal pers 9 | Public pub \Public 10 | QuickRef qr \QuickRef 11 | } 12 | 13 | # System 14 | Startup start 15 | Pinned Shortcuts ps \Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar 16 | AutoHotkey lib (documents) ahkl \AutoHotkey\Lib 17 | 18 | # Development 19 | Dev dev 20 | Onetastic Macros ot 21 | NotepadPlusPlus Sessions sess 22 | 23 | ~CONTEXT.replaceWith(WORK) { 24 | # Work Local 25 | Templates tp \Templates 26 | Transaction Diff Output txdiff 27 | EpicStudio Config esc \Epic Systems Corporation\EpicStudio 28 | HSWeb TraceX Files trace \--
29 | S1 Source s1 30 | 31 | # Work Server 32 | Net Home nh 33 | NFS 3 Day n3 34 | NFS Ask na 35 | Temp Daily temp 36 | Temp Daily (Today) ttemp \-- 37 | VDI Settings vdi 38 | UX Shared Resources ux 39 | DBC Design dbcd 40 | DBC Partial Installers dbcpi 41 | Environment TraceX Files etrace 42 | Weekly Search Results search 43 | } 44 | -------------------------------------------------------------------------------- /config/hyperlinkWindows.tl: -------------------------------------------------------------------------------- 1 | [ NAME SET_PATH_METHOD CLOSE_METHOD LINK_POPUP PATH_FIELD_CONTROL_ID TAGGED_STRING_BASE ] 2 | 3 | OneNote POPUP_FIELD ENTER Link ahk_class NUIDialog RICHEDIT60W2 4 | Outlook POPUP_FIELD ENTER ahk_class bosa_sdm_Mso96 RichEdit20W6 5 | PowerPoint POPUP_FIELD ENTER ahk_class bosa_sdm_Mso96 RichEdit20W6 6 | Word POPUP_FIELD ENTER ahk_class bosa_sdm_msword RichEdit20W6 7 | 8 | EMC2 WEB_FIELD ALT_A 9 | EMC2 Popup WEB_FIELD ALT_A 10 | Teams WEB_FIELD ENTER 11 | Mattermost TAGGED_STRING - - - []() 12 | -------------------------------------------------------------------------------- /config/listFormats.tls: -------------------------------------------------------------------------------- 1 | @MinColumnWidth(350) 2 | 3 | [ NAME ABBREV FORMAT CUSTOM_DELIM ] 4 | ( 0 0 0 1 ) 5 | 6 | Array a ARRAY 7 | Space-delimited s SPACE 8 | Comma-delimited c COMMA 9 | Comma-delimited with spaces cs COMMA_SPACED 10 | Underscore_delimited u UNDERSCORE 11 | Newline-delimited nl NEWLINE 12 | OneNote Column o ONENOTE_COLUMN 13 | Custom delimiter cust CUSTOM_DELIM 14 | -------------------------------------------------------------------------------- /config/paths.tl: -------------------------------------------------------------------------------- 1 | ; These are all of the path tags that will be replaced when using Config.replacePathTags(). 2 | 3 | [ NAME KEY PATH CONTEXT ] 4 | 5 | ; Pass-throughs - paths which are retrieved/calculated in Config.getSystemPathTags(). These can also be used in this file. 6 | AHK Root AHK_ROOT 7 | AHK Private AHK_PRIVATE 8 | AHK Test AHK_TEST 9 | 10 | AppData (Roaming) USER_APPDATA 11 | AppData Local USER_APPDATA_LOCAL 12 | Command prompt path CMD 13 | Desktop USER_DESKTOP 14 | Documents USER_DOCUMENTS 15 | EMC2 executable (Current) EMC2_CURRENT_EXE 16 | EpicSource (Current Version) EPIC_SOURCE_CURRENT 17 | OneDrive USER_ONEDRIVE 18 | Program Data PROGRAM_DATA 19 | Program Files PROGRAM_FILES 20 | Program Files (x86) PROGRAM_FILES_86 21 | Start Menu USER_START_MENU 22 | Startup USER_STARTUP 23 | Temp USER_TEMP 24 | User Root USER_ROOT 25 | Windows (System Root) WINDOWS 26 | 27 | ~CONTEXT.replaceWith(WORK) { 28 | ; Private pass-throughs - private tags to replace in folder paths 29 | Epic DBC Design EPIC_DBC_DESIGN 30 | Epic DBC Partial Installers EPIC_DBC_PARTIAL_INSTALLERS 31 | Epic Net Home EPIC_NET_HOME 32 | Epic NFS 3 Day EPIC_NFS_3DAY 33 | Epic NFS 3 Day (Unix) EPIC_NFS_3DAY_UNIX 34 | Epic NFS Ask EPIC_NFS_ASK 35 | Epic Temp Daily EPIC_TEMP_DAILY 36 | Epic Personal EPIC_PERSONAL 37 | Epic VDI Settings EPIC_VDI_SETTINGS 38 | Epic Environment TraceX Files EPIC_HSWEB_TRACE 39 | Epic Shared UX Resources EPIC_UX_SHARED 40 | Epic DBC Weekly Search Results EPIC_WEEKLY_SEARCH_RESULTS 41 | } 42 | 43 | ; General 44 | AHK Config AHK_CONFIG \config 45 | AHK Source AHK_SOURCE \source 46 | Downloads USER_DOWNLOADS \Downloads 47 | 48 | ; Dev 49 | User Dev USER_DEV \Dev WORK 50 | User Dev USER_DEV \Dev HOME 51 | Onetastic Macros ONETASTIC_MACROS \OnetasticMacros 52 | Onetastic Functions ONETASTIC_FUNCTIONS \OnetasticMacros\Functions 53 | 54 | ~CONTEXT.replaceWith(WORK) { 55 | ; Work 56 | Epic Source Current S1 EPIC_SOURCE_S1 \stage1 57 | Epic Source Current S1 Billing Solutions EPIC_SOURCE_S1_BILL_SOLUTIONS \stage1\HSWeb\Solutions\Apps\Billing 58 | Transaction Diff TX_DIFF C:\Program Files\TransactionDiff 59 | EpicStudio Global Highlights EPICSTUDIO_GLOBAL_HIGHLIGHTS \EpicStudioGlobalHighlights 60 | 61 | ; OneDrive folders 62 | ~PATH.addToStart(\) { 63 | NotepadPlusPlus Sessions NOTEPAD_PP_SESSIONS Dev\NotepadPlusPlus Sessions 64 | Transaction Diff Results TX_DIFF_OUTPUT Dev\TransactionDiffOutput 65 | Specifics USER_SPECIFICS Specifics 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /config/programs.tl: -------------------------------------------------------------------------------- 1 | [ NAME PATH MACHINE PATH_TYPE ] 2 | 3 | ~PATH_TYPE.defaultTo(EXE) { 4 | ~PATH.addToStart(\) { 5 | Launchy Launchy\Launchy.exe 6 | Notepad++ Notepad++\notepad++.exe HOME_LAPTOP 7 | ; OneNote Microsoft Office\root\Office16\ONENOTE.EXE 8 | Putty PuTTY\putty.exe 9 | Snapper Epic\Snapper\Snapper.exe 10 | Thunder Thunder\Thunder.exe 11 | Hyperdrive Epic\Hyperdrive\VersionIndependent\Hyperspace.exe 12 | } ~PATH.addToStart(\) { 13 | AutoHotkey WinSpy AutoHotkey\WindowSpy.ahk 14 | EpicStudio EpicStudio\EpicStudio.exe 15 | Chrome Google\Chrome\Application\chrome.exe 16 | Chrome Proxy Google\Chrome\Application\chrome_proxy.exe 17 | Everything Everything\Everything.exe 18 | Internet Explorer Internet Explorer\iexplore.exe 19 | KDiff KDiff3\kdiff3.exe 20 | Notepad++ Notepad++\notepad++.exe 21 | OneNote Microsoft Office\root\Office16\ONENOTE.EXE 22 | Outlook Microsoft Office\root\Office16\OUTLOOK.EXE WORK_DESKTOP 23 | TrueCrypt TrueCrypt\TrueCrypt.exe 24 | Visual Studio Microsoft Visual Studio\2022\Professional\Common7\IDE\devenv.exe 25 | VMware Horizon Client VMware\VMware Horizon View Client\vmware-view.exe 26 | VSCode Microsoft VS Code\Code.exe 27 | Windows Terminal Windows Terminal\WindowsTerminal.exe WORK_VDI 28 | WinMerge WinMerge\WinMergeU.exe 29 | } ~PATH.addToStart(\) { 30 | Explorer explorer.exe 31 | } 32 | 33 | ~PATH_TYPE.replaceWith(URL) { 34 | Messenger https://www.messenger.com 35 | Slack https://app.slack.com/client/ 36 | Gmail https://mail.google.com/mail/u/0/#inbox 37 | Gmail https://mail.google.com/mail/u/1/#inbox WORK_DESKTOP 38 | Teams https://teams.microsoft.com 39 | } 40 | 41 | Process Explorer \Process Explorer\procexp.exe WORK_DESKTOP 42 | Process Explorer \Programs\Process Explorer\procexp.exe WORK_VDI 43 | Process Explorer \ProcessExplorer\procexp.exe 44 | 45 | ~PATH.addToStart(\) { 46 | Beeper Programs\BeeperTexts\Beeper.exe HOME_DESKTOP 47 | GitHub Desktop GitHubDesktop\GitHubDesktop.exe 48 | GrepWin Programs\grepWin\grepWin.exe 49 | GrepWin Apps\grepWin\grepWin.exe HOME_DESKTOP 50 | Slack slack\slack.exe HOME_DESKTOP 51 | VSCode Programs\Microsoft VS Code\Code.exe HOME_DESKTOP 52 | MTPutty Programs\MTPuTTY\mtputty.exe 53 | } 54 | 55 | ~PATH.addToStart(\) { 56 | Spotify Spotify\Spotify.exe 57 | Telegram Telegram Desktop\Telegram.exe 58 | } 59 | 60 | Firefox Portable S:\FirefoxPortable\FirefoxPortable.exe HOME_DESKTOP 61 | EMC2 WORK_DESKTOP | WORK_VDI 62 | 63 | ; Chrome apps (run using "Chrome Proxy" from above) 64 | ~PATH_TYPE.replaceWith(CHROME_APP) { 65 | Beeper kebihpkoclefnhgdieipmimdjhpdkbjc WORK_DESKTOP | WORK_VDI 66 | TickTick cfammbeebmjdpoppachopcohfchgjapd 67 | } 68 | 69 | ; Programs that can be launched by commands 70 | ~PATH_TYPE.replaceWith(COMMAND) { 71 | Windows Terminal wt 72 | Teams ms-teams WORK_DESKTOP 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /config/puttyRecordEditSearch.tls: -------------------------------------------------------------------------------- 1 | [ NAME ABBREV SEARCH_TYPE SEARCH_TEXT ] 2 | ( 0 0 0 1 ) 3 | 4 | Item i I 5 | Text t T 6 | Screen s S 7 | -------------------------------------------------------------------------------- /config/resize.tls: -------------------------------------------------------------------------------- 1 | @WindowTitle(Resize active window to size:) 2 | @MinColumnWidth(350) 3 | 4 | ; WIDTH/HEIGHT can be percentages (include % suffix) or special MAX value from VIsualWindow.Size_Maximize. 5 | ; From AHK Active Window Info, these numbers should match the top set of w/h, not the client ones. 6 | 7 | [ NAME ABBREV WIDTH HEIGHT CONTEXT ] 8 | ( 0 0 1 2 0 ) 9 | 10 | # General sizes 11 | FHD (1920x1080) h | hd 1920 1080 12 | Widescreen (1440x900) w 1440 900 13 | Standard (1280x1024) sd 1280 1024 14 | Small (800x600) sm 800 600 15 | 16 | # Specifics 17 | Fake-maximized fmax | fm 100% 100% 18 | Semi-maximized (fits around time) smax 1460 100% HOME 19 | Quarter q 50% 50% 20 | Social soc 950 750 21 | 22 | # Development 23 | ~CONTEXT.replaceWith(WORK) { 24 | Minimum Hyperspace (2015-) minOld 800 550 25 | Minimum Hyperspace (2017+) min 1280 768 26 | PuTTY on laptop screen pl 1084 1050 27 | } 28 | -------------------------------------------------------------------------------- /config/search.tls: -------------------------------------------------------------------------------- 1 | @WindowTitle(Select type of search) 2 | 3 | [ NAME ABBREV SUBTYPE TYPE_FILTER SEARCH_TYPE APP_KEY CONTEXT SEARCH_TERM IS_REGEX ] 4 | ( 0 0 0 0 0 0 0 1 0 ) 5 | 6 | # Web 7 | ; (SUBTYPE = for query>) 8 | ~SEARCH_TYPE.replaceWith(WEB) { 9 | Google g https://www.google.com/search?q= - - - HOME 10 | Google g https://www.google.com/search?authuser=1&q= - - - WORK 11 | Google Maps gmap | gmaps https://www.google.com/maps/preview?q= - - - HOME 12 | Google Maps gmap | gmaps https://www.google.com/maps/preview?q=&authuser=1 - - - WORK 13 | Gmail gm https://mail.google.com/mail/u/0/#search/ - - - HOME 14 | Gmail gm https://mail.google.com/mail/u/1/#search/ - - - WORK 15 | Youtube yt https://www.youtube.com/results?search_query= 16 | Steam st https://store.steampowered.com/search/?term= 17 | AutoHotkey Docs ahkd https://cse.google.com/cse?cx=010629462602499112316:ywoq_rufgic&q= 18 | Nilesoft Shell Docs ns | nile https://www.google.com/search?q=site:https://nilesoft.org/docs+ 19 | Translate Dutch > English tde | detrans https://translate.google.com/#nl/en/ 20 | Translate English > Dutch ted | edtrans https://translate.google.com/#en/nl/ 21 | } 22 | 23 | # GrepWin 24 | ; (SUBTYPE = folder) 25 | ~SEARCH_TYPE.replaceWith(GREPWIN) { 26 | AHK (all repos) ahk || 27 | AHK Source ahks | ahkf 28 | AHK Todo ahkt - - - - GDB[ ]?TODO 1 29 | Onetastic Macros ot 30 | XGDB Routines x | xgdb \XGDB - - - WORK 31 | } 32 | 33 | # Other 34 | Everything (file search) e | ev - - EVERYTHING 35 | 36 | ~CONTEXT.replaceWith(WORK) { 37 | ~SEARCH_TYPE.replaceWith(CODESEARCH) { 38 | # ! Codesearch 39 | Database d routine 40 | Client (all types) c client 41 | Client (VB) vb client 8 42 | Client (all web) w client 1 43 | Client (web server) ws client 4 44 | Client (web client) wc client 2 45 | Database + Client (all types) dc | cd routine|client 46 | Records r records 47 | Other o | p other 48 | All a routine|client|records|other 49 | 50 | # Codesearch Specifics 51 | Database DBC dd routine - - DBC 52 | } 53 | 54 | # Other 55 | Guru gu - - GURU 56 | DBC Wiki dbc DBC - WIKI 57 | Active QANs q | qan QAN - HUBBLE 58 | Active QANs (DBC only) dq | dqan | qand QAN - HUBBLE DBC 59 | } 60 | -------------------------------------------------------------------------------- /config/symbols.tls: -------------------------------------------------------------------------------- 1 | @WindowTitle(Symbol to insert:) 2 | 3 | [ NAME ABBREV CHAR ] 4 | 5 | # Symbols 6 | ✓ - Check mark chk ✓ 7 | ✗ - Ballot x x ✗ 8 | ← - Leftwards arrow l | left ← 9 | → - Rightwards arrow r | right → 10 | 🡠 - Wide-headed leftwards light barb arrow wl | lw 🡠 11 | 🡢 - Wide-headed rightwards light barb arrow wr | rw 🡢 12 | · - Middle dot dot · 13 | ― - Horizontal bar hline ― 14 | ° - Degree d | deg | degree ° 15 | ≠ - Not equal ne ≠ 16 | -------------------------------------------------------------------------------- /config/windowActions.tl: -------------------------------------------------------------------------------- 1 | [ NAME ESC MIN SELECT_ALL DELETE_WORD CLOSE ACTIVATE BACKTICK MACHINE ] 2 | 3 | ; Values for all columns (except NAME) come from WindowActions.Method_* (for how to do the action) or WindowActions.Action_* (to do some other action, like close on escape key) constants. 4 | 5 | AutoHotkey CLOSE - - SELECT 6 | AutoHotkey WinSpy CLOSE 7 | Beeper CLOSE - - - - - ESCAPE 8 | Cisco VPN CLOSE 9 | EMC2 XDS Open - - - SELECT 10 | EMC2 DLG/QAN/PRJ Open - - - SELECT 11 | Explorer MIN - - - - - ESCAPE 12 | GitHub Desktop CLOSE - - - - - ESCAPE 13 | Messenger MIN - - - - - ESCAPE HOME_DESKTOP 14 | Putty MIN OTHER - - - - ESCAPE 15 | Skype CLOSE 16 | Slack CLOSE - - - - RUN ESCAPE HOME_DESKTOP 17 | Spotify CLOSE CLOSE - - - - ESCAPE 18 | Teams CLOSE CLOSE - - - - ESCAPE 19 | Telegram CLOSE CLOSE - - - RUN ESCAPE 20 | Thunder CLOSE 21 | 22 | ; EpicStudio popups - handle Ctrl+Backspace. 23 | EpicStudio New Object Window - - - SELECT 24 | EpicStudio Tokenize String - - - SELECT 25 | EpicStudio Bookmark Comment - - - SELECT 26 | 27 | ; Web popups - close on Escape. 28 | Chrome Join CLOSE - - - - - ESCAPE 29 | TickTick CLOSE - - - - - ESCAPE 30 | 31 | ; Windows taskbars - don't minimize. 32 | Windows Taskbar - NONE 33 | Windows Taskbar Secondary - NONE 34 | -------------------------------------------------------------------------------- /config/windowPositionPresets.tls: -------------------------------------------------------------------------------- 1 | @WindowTitle(Move/size windows to position preset:) 2 | 3 | ; PRESET = PRESET from windowPositions.tl 4 | [ NAME ABBREV PRESET ] 5 | 6 | Normal n NORMAL 7 | Game on left monitor gl GAME_ON_LEFT 8 | Game on middle monitor gm GAME_ON_MIDDLE 9 | -------------------------------------------------------------------------------- /config/windowPositions.tl: -------------------------------------------------------------------------------- 1 | ; NAME = NAME from windows.tl 2 | ; X/Y/WIDTH/HEIGHT support special constant values from VisualWindow (i.e. RIGHT_EDGE for VisualWindow.X_RightEdge) 3 | 4 | [ NAME X Y WIDTH HEIGHT CONTEXT ACTIVATE MONITOR PRESET ] 5 | 6 | ~PRESET.defaultTo(NORMAL) | X.defaultTo(CENTERED) | Y.defaultTo(CENTERED) { 7 | ~MONITOR.replaceWith(LEFT) { 8 | Outlook - - MAX MAX WORK 9 | ; Work Explorer is a little further left to allow Outlook calendar pane to peek thru nicely. 10 | Explorer - - 1440 900 11 | GitHub Desktop - - 1440 900 12 | GrepWin - - 1440 900 13 | Steam - - 1440 900 HOME 14 | Teams - - 1440 900 WORK 15 | TickTick RIGHT_EDGE TOP_EDGE 1200 750 16 | Putty RIGHT_EDGE TOP_EDGE 1350 100% WORK 17 | MTPutty RIGHT_EDGE TOP_EDGE 1350 100% WORK 18 | Windows Terminal RIGHT_EDGE TOP_EDGE 1440 100% 19 | 20 | # Social windows 21 | ~WIDTH.defaultTo(950) | ~HEIGHT.defaultTo(750) | ~X.replaceWith(RIGHT_EDGE) | ~Y.replaceWith(TOP_EDGE) { 22 | Beeper - - 50% 100% 23 | Messenger 24 | Slack 25 | Telegram 26 | } 27 | } 28 | 29 | ~MONITOR.replaceWith(MIDDLE) { 30 | Chrome - - MAX MAX 31 | Chrome Hyperspace - - 1920 1080 WORK 32 | EpicStudio - - MAX MAX WORK 33 | Hyperspace - - 1920 1080 WORK 34 | Hyperdrive - - 1920 1080 WORK 35 | Process Explorer - - 1440 900 36 | Visual Studio - - MAX MAX WORK 37 | VSCode - - MAX MAX WORK 38 | Zoom - - MAX MAX HOME 39 | } 40 | 41 | ~MONITOR.replaceWith(RIGHT) { 42 | Discord RIGHT_EDGE - 1460 100% HOME 43 | OneNote RIGHT_EDGE - 1460 100% HOME 44 | Spotify RIGHT_EDGE - 1460 100% HOME 1 45 | 46 | Cisco VPN LEFT_EDGE+25 300 - - HOME 47 | EMC2 - - MAX MAX WORK 48 | Notepad++ - - MAX MAX 49 | OneNote - - MAX MAX 50 | Spotify - - MAX MAX - 1 51 | VMware Horizon Client - - MAX MAX WORK 52 | } 53 | 54 | # Gaming presets - mostly quartered social windows on the non-gaming monitor 55 | ~WIDTH.defaultTo(50%) | ~HEIGHT.defaultTo(50%) | ~ACTIVATE.defaultTo(1) { 56 | ~PRESET.replaceWith(GAME_ON_LEFT) | ~MONITOR.replaceWith(MIDDLE) { 57 | Messenger LEFT_EDGE BOTTOM_EDGE 58 | Slack RIGHT_EDGE BOTTOM_EDGE 59 | Telegram RIGHT_EDGE TOP_EDGE 60 | Beeper LEFT_EDGE TOP_EDGE 61 | Chrome - - MAX MAX 62 | } 63 | ~PRESET.replaceWith(GAME_ON_MIDDLE) | ~MONITOR.replaceWith(LEFT) { 64 | Messenger LEFT_EDGE BOTTOM_EDGE 65 | Slack RIGHT_EDGE BOTTOM_EDGE 66 | Telegram RIGHT_EDGE TOP_EDGE 67 | Beeper LEFT_EDGE TOP_EDGE 68 | Chrome - - MAX MAX 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /icons/color.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/color.ico -------------------------------------------------------------------------------- /icons/colorRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/colorRed.ico -------------------------------------------------------------------------------- /icons/controllerGreen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/controllerGreen.ico -------------------------------------------------------------------------------- /icons/controllerRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/controllerRed.ico -------------------------------------------------------------------------------- /icons/cross.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/cross.cur -------------------------------------------------------------------------------- /icons/hourglass.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/hourglass.ico -------------------------------------------------------------------------------- /icons/iconCredits.txt: -------------------------------------------------------------------------------- 1 | Yusuke Kamiyamane ( http://p.yusukekamiyamane.com/ ): 2 | Original icons: 3 | color.ico 4 | hourglass.ico 5 | My adaptations of icons by this artist: 6 | colorRed.ico 7 | moveSize.ico 8 | moveSizeRed.ico 9 | 10 | Double J Design ( http://www.doublejdesign.co.uk/ ) 11 | Original icons (from https://www.iconfinder.com/iconsets/super-mono-reflection ): 12 | controllerGreen.ico 13 | controllerRed.ico 14 | 15 | bokuwatensai ( https://www.deviantart.com/bokuwatensai ): 16 | Original icons (from Chrome Cursor Set - https://www.deviantart.com/bokuwatensai/art/Chrome-Cursor-Set-177736893 ) 17 | cross.cur 18 | 19 | WPZOOM ( https://www.wpzoom.com/ ): 20 | My adaptations of icons by this artist: 21 | mouseGreen.ico 22 | mouseRed.ico 23 | 24 | Turbomilk ( http://turbomilk.com/ ): 25 | Original icons: 26 | shieldGreen.ico 27 | shieldRed.ico 28 | 29 | Everaldo Coelho ( http://www.everaldo.com/ ): 30 | Original icons: 31 | vimPause.ico 32 | My adaptations of icons by this artist: 33 | vim.ico 34 | vimSuspend.ico 35 | 36 | Sandro Pereira ( https://blog.sandro-pereira.com/ ): 37 | Original icons (from https://findicons.com/pack/2297/super_mario ): 38 | shellGreen.ico 39 | My adaptations of icons by this artist: 40 | shellRed.ico 41 | 42 | Unknown artist (can't figure out where I got these from, if they're yours please let me know!): 43 | Original icons: 44 | pictureWhite.ico 45 | My adaptations of icons by this artist: 46 | pictureRed.ico 47 | 48 | Icons8 49 | Original icons: 50 | ninja.png, ninjaRed.png (https://icons8.com/icon/20806/ninja) 51 | -------------------------------------------------------------------------------- /icons/mouseGreen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/mouseGreen.ico -------------------------------------------------------------------------------- /icons/mouseRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/mouseRed.ico -------------------------------------------------------------------------------- /icons/moveSize.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/moveSize.ico -------------------------------------------------------------------------------- /icons/moveSizeRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/moveSizeRed.ico -------------------------------------------------------------------------------- /icons/ninja.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/ninja.png -------------------------------------------------------------------------------- /icons/ninjaRed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/ninjaRed.png -------------------------------------------------------------------------------- /icons/pictureRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/pictureRed.ico -------------------------------------------------------------------------------- /icons/pictureWhite.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/pictureWhite.ico -------------------------------------------------------------------------------- /icons/shellGreen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/shellGreen.ico -------------------------------------------------------------------------------- /icons/shellRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/shellRed.ico -------------------------------------------------------------------------------- /icons/shieldGreen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/shieldGreen.ico -------------------------------------------------------------------------------- /icons/shieldRed.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/shieldRed.ico -------------------------------------------------------------------------------- /icons/vim.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/vim.ico -------------------------------------------------------------------------------- /icons/vimPause.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/vimPause.ico -------------------------------------------------------------------------------- /icons/vimSuspend.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/icons/vimSuspend.ico -------------------------------------------------------------------------------- /source/common/base/objectBase.ahk: -------------------------------------------------------------------------------- 1 | /* Base class to override Object's default base with, so we can add these functions directly to objects. 2 | 3 | Example usage: 4 | ; obj := {"A":1, "B":2} 5 | ; result := obj.contains(2) ; result = "B" 6 | 7 | */ 8 | 9 | class ObjectBase { 10 | ;region ------------------------------ PUBLIC ------------------------------ 11 | ;--------- 12 | ; DESCRIPTION: Check whether this object contains a particular value. 13 | ; PARAMETERS: 14 | ; needle (I,REQ) - The value to search the object for. 15 | ; RETURNS: The first index where we found the value in question. 16 | ; "" if we didn't find it at all. 17 | ;--------- 18 | contains(needle) { 19 | For index,element in this 20 | if(element = needle) 21 | return index 22 | return "" 23 | } 24 | 25 | ;--------- 26 | ; DESCRIPTION: Add the basic members (not including functions) from the given object into 27 | ; this object. 28 | ; PARAMETERS: 29 | ; objectToAppend (I,REQ) - The object to append the contents of. 30 | ; RETURNS: this 31 | ; NOTES: If the new object has the same key as this one, the new value will overwrite 32 | ; our existing one, even if the new one is blank. 33 | ;--------- 34 | mergeFromObject(objectToAppend) { 35 | For index,value in objectToAppend 36 | this[index] := value 37 | 38 | return this 39 | } 40 | 41 | ;--------- 42 | ; DESCRIPTION: Get the keys of this object as an array. 43 | ; RETURNS: A numerically-indexed array of the keys, in order of those keys. 44 | ;--------- 45 | toKeysArray() { 46 | ary := [] 47 | For key,_ in this 48 | ary.push(key) 49 | return ary 50 | } 51 | ;--------- 52 | ; DESCRIPTION: Get the values of this object as an array. 53 | ; RETURNS: A numerically-indexed array of the values, in order of the original keys. 54 | ;--------- 55 | toValuesArray() { 56 | ary := [] 57 | For _,value in this 58 | ary.push(value) 59 | return ary 60 | } 61 | ;endregion ------------------------------ PUBLIC ------------------------------ 62 | } 63 | -------------------------------------------------------------------------------- /source/common/class/actionObjectEpicCode.ahk: -------------------------------------------------------------------------------- 1 | #Include ..\base\actionObjectBase.ahk 2 | 3 | /* Class for performing actions based on a code location in VSCode/EpicCode. 4 | 5 | Note that several other operations are also available from the base class (.copyLink*(), .linkSelectedText*()). 6 | 7 | Example Usage 8 | ; ao := new ActionObjectEpicCode("tagName^routineName") 9 | ; MsgBox, ao.getLinkEdit() ; Link in EpicCode 10 | ; ao.openEdit() ; Open in EpicCode 11 | ; 12 | ; ao := new ActionObjectEpicCode(123456) ; DLG ID 13 | ; ao.openEdit() ; Open DLG in EpicCode 14 | 15 | */ 16 | 17 | class ActionObjectEpicCode extends ActionObjectBase { 18 | ;region ------------------------------ PUBLIC ------------------------------ 19 | ActionObjectType := ActionObject.Type_EpicCode 20 | 21 | ;region Descriptor types 22 | static DescriptorType_Routine := "ROUTINE" ; Server code location, including tag if applicable 23 | static DescriptorType_RoutineCDE := "ROUTINE_CDE" ; Server code location, including tag if applicable - in CDE 24 | static DescriptorType_DLG := "DLG" ; DLG, for opening in EpicCode 25 | ;endregion Descriptor types 26 | 27 | descriptor := "" ; Reference to object 28 | descriptorType := "" ; Type of object (from DescriptorType_* constants) 29 | 30 | ;--------- 31 | ; DESCRIPTION: Create a new reference to a server code object. 32 | ; PARAMETERS: 33 | ; descriptor (I,REQ) - Value representing the object 34 | ; descriptorType (I,OPT) - Type of descriptor, from DescriptorType_* constants. If not given, we'll 35 | ; figure it out based on the descriptor format or by prompting the user. 36 | ;--------- 37 | __New(descriptor, descriptorType := "") { 38 | if(descriptorType = "") 39 | descriptorType := this.determineDescriptorType() 40 | 41 | if(!this.selectMissingInfo(descriptor, descriptorType)) 42 | return "" 43 | 44 | this.descriptor := descriptor 45 | this.descriptorType := descriptorType 46 | } 47 | 48 | ;--------- 49 | ; DESCRIPTION: Get a link to the object (server code location) referenced by descriptor in EpicCode. 50 | ; RETURNS: Link to EpicCode for the code location. 51 | ;--------- 52 | getLink() { 53 | url := "" 54 | 55 | Switch this.descriptorType { 56 | Case this.DescriptorType_Routine, this.DescriptorType_RoutineCDE: 57 | EpicLib.splitServerLocation(this.descriptor, routine, tag) 58 | 59 | if(this.descriptorType = this.DescriptorType_Routine) 60 | environmentId := Config.private["DBC_DEV_ENV_ID"] 61 | else if(this.descriptorType = this.DescriptorType_RoutineCDE) 62 | environmentId := Config.private["CDE_ENV_ID"] 63 | 64 | url := Config.private["EPICCODE_URL_BASE_ROUTINE"] 65 | url := url.replaceTag("ROUTINE", routine) 66 | url := url.replaceTag("TAG", tag) 67 | url := url.replaceTag("ENVIRONMENT", environmentId) 68 | 69 | Case this.DescriptorType_DLG: 70 | url := Config.private["EPICCODE_URL_BASE_DLG"] 71 | url := url.replaceTag("DLG_ID", this.descriptor) 72 | } 73 | 74 | return url 75 | } 76 | ;endregion ------------------------------ PUBLIC ------------------------------ 77 | 78 | ;region ------------------------------ PRIVATE ------------------------------ 79 | ;--------- 80 | ; DESCRIPTION: Try to figure out what kind of descriptor we've been given based on its format. 81 | ; RETURNS: Descriptor type from DescriptorType_* constants 82 | ;--------- 83 | determineDescriptorType() { 84 | ; Full server tag^routine 85 | if(this.descriptor.contains("^")) 86 | return ActionObjectEpicCode.DescriptorType_Routine 87 | 88 | ; DLG IDs are (mostly) numeric, where routines are not. 89 | if(EpicLib.couldBeEMC2ID(this.descriptor)) 90 | return ActionObjectEpicCode.DescriptorType_DLG 91 | 92 | return "" 93 | } 94 | ;endregion ------------------------------ PRIVATE ------------------------------ 95 | } 96 | -------------------------------------------------------------------------------- /source/common/class/actionObjectEpicStudio.ahk: -------------------------------------------------------------------------------- 1 | #Include ..\base\actionObjectBase.ahk 2 | 3 | /* Class for performing actions based on a code location or DLG in EpicStudio. 4 | 5 | Note that several other operations are also available from the base class (.copyLink*(), .linkSelectedText*()). 6 | 7 | Example Usage 8 | ; ao := new ActionObjectEpicStudio("tagName^routineName") 9 | ; MsgBox, ao.getLinkEdit() ; Link in EpicStudio 10 | ; ao.openEdit() ; Open in EpicStudio 11 | ; 12 | ; ao := new ActionObjectEpicStudio(123456) ; DLG ID 13 | ; ao.openEdit() ; Open DLG in EpicStudio 14 | 15 | */ 16 | 17 | class ActionObjectEpicStudio extends ActionObjectBase { 18 | ;region ------------------------------ PUBLIC ------------------------------ 19 | ActionObjectType := ActionObject.Type_EpicStudio 20 | 21 | ;region Descriptor types 22 | static DescriptorType_Routine := "ROUTINE" ; Server code location, including tag if applicable 23 | static DescriptorType_RoutineCDE := "ROUTINE_CDE" ; Server code location, including tag if applicable - in CDE 24 | static DescriptorType_DLG := "DLG" ; DLG, for opening in EpicStudio 25 | ;endregion Descriptor types 26 | 27 | descriptor := "" ; Reference to object 28 | descriptorType := "" ; Type of object (from DescriptorType_* constants) 29 | 30 | ;--------- 31 | ; DESCRIPTION: Create a new reference to a server code object. 32 | ; PARAMETERS: 33 | ; descriptor (I,REQ) - Value representing the object 34 | ; descriptorType (I,OPT) - Type of descriptor, from DescriptorType_* constants. If not given, we'll figure it out 35 | ; based on the descriptor format or by prompting the user. 36 | ;--------- 37 | __New(descriptor, descriptorType := "") { 38 | if(descriptorType = "") 39 | descriptorType := this.determineDescriptorType() 40 | 41 | if(!this.selectMissingInfo(descriptor, descriptorType)) 42 | return "" 43 | 44 | this.descriptor := descriptor 45 | this.descriptorType := descriptorType 46 | } 47 | 48 | ;--------- 49 | ; DESCRIPTION: Get a link to the object (server code location or DLG) referenced by 50 | ; descriptor in EpicStudio. 51 | ; RETURNS: Link to EpicStudio for the code location/DLG. 52 | ;--------- 53 | getLink() { 54 | url := "" 55 | 56 | Switch this.descriptorType { 57 | Case this.DescriptorType_Routine, this.DescriptorType_RoutineCDE: 58 | EpicLib.splitServerLocation(this.descriptor, routine, tag) 59 | 60 | if(this.descriptorType = this.DescriptorType_Routine) 61 | environmentId := Config.private["DBC_DEV_ENV_ID"] 62 | else if(this.descriptorType = this.DescriptorType_RoutineCDE) 63 | environmentId := Config.private["CDE_ENV_ID"] 64 | 65 | url := Config.private["EPICSTUDIO_URL_BASE_ROUTINE"] 66 | url := url.replaceTag("ROUTINE", routine) 67 | url := url.replaceTag("TAG", tag) 68 | url := url.replaceTag("ENVIRONMENT", environmentId) 69 | 70 | Case this.DescriptorType_DLG: 71 | url := Config.private["EPICSTUDIO_URL_BASE_DLG"] 72 | url := url.replaceTag("DLG_ID", this.descriptor) 73 | } 74 | 75 | return url 76 | } 77 | ;endregion ------------------------------ PUBLIC ------------------------------ 78 | 79 | ;region ------------------------------ PRIVATE ------------------------------ 80 | ;--------- 81 | ; DESCRIPTION: Try to figure out what kind of descriptor we've been given based on its format. 82 | ; RETURNS: Descriptor type from DescriptorType_* constants 83 | ;--------- 84 | determineDescriptorType() { 85 | ; Full server tag^routine 86 | if(this.descriptor.contains("^")) 87 | return ActionObjectEpicStudio.DescriptorType_Routine 88 | 89 | ; DLG IDs are (mostly) numeric, where routines are not. 90 | if(EpicLib.couldBeEMC2ID(this.descriptor)) 91 | return ActionObjectEpicStudio.DescriptorType_DLG 92 | 93 | return "" 94 | } 95 | ;endregion ------------------------------ PRIVATE ------------------------------ 96 | } 97 | -------------------------------------------------------------------------------- /source/common/class/actionObjectPath.ahk: -------------------------------------------------------------------------------- 1 | #Include ..\base\actionObjectBase.ahk 2 | 3 | /* Class for performing actions on a path. 4 | 5 | Note that several other operations are also available from the base class (.copyLink*(), .linkSelectedText*()). 6 | 7 | Example Usage 8 | ; ao := new ActionObjectPath("F:\personal\eyobuddy") ; Local path or URL, user will be prompted for which it is 9 | ; MsgBox, ao.getLink() ; Returns path 10 | ; ao.open() ; Opens path (equivalent to .openEdit() or .openWeb()) 11 | ; 12 | ; ao := new ActionObjectPath("google.com", ActionObjectPath.PathType_URL) ; Specify path type if known to avoid prompting 13 | ; ao.openEdit() ; Run URL 14 | 15 | */ 16 | 17 | class ActionObjectPath extends ActionObjectBase { 18 | ;region ------------------------------ PUBLIC ------------------------------ 19 | ActionObjectType := ActionObject.Type_Path 20 | 21 | ;region Path types 22 | static PathType_FilePath := "FILEPATH" ; Local file path 23 | static PathType_URL := "URL" ; URL 24 | ;endregion Path types 25 | 26 | path := "" ; The path itself. 27 | pathType := "" ; The type of path, from PathType_*. 28 | 29 | ;--------- 30 | ; DESCRIPTION: Create a new reference to a path. 31 | ; PARAMETERS: 32 | ; path (I,REQ) - The actual path 33 | ; pathType (I,OPT) - Type of path, from PathType_* constants. If not given, we'll figure it out 34 | ; based on the path format or by prompting the user. 35 | ;--------- 36 | __New(path, pathType := "") { 37 | 38 | ; Make sure there's no quotes or other oddities surrounding the path 39 | path := path.clean([""""]) ; Single double-quote character 40 | 41 | if(pathType = "") 42 | pathType := this.determinePathType(path) 43 | 44 | if(!this.selectMissingInfo(path, pathType)) 45 | return 46 | 47 | this.path := path 48 | this.pathType := pathType 49 | this.postProcess() 50 | } 51 | 52 | ;--------- 53 | ; DESCRIPTION: Determine whether the given string must be this type of ActionObject. 54 | ; PARAMETERS: 55 | ; value (I,REQ) - The value to evaluate 56 | ; pathType (O,OPT) - If the value is a path, the path type 57 | ; RETURNS: true/false - whether the given value must be a path. 58 | ;--------- 59 | isThisType(value, ByRef pathType := "") { 60 | matchedPathType := this.determinePathType(value) 61 | if(matchedPathType = "") 62 | return false 63 | 64 | pathType := matchedPathType 65 | return true 66 | } 67 | 68 | ;--------- 69 | ; DESCRIPTION: Get a link to the path (that is, the path itself). 70 | ; RETURNS: The path 71 | ;--------- 72 | getLink() { 73 | if(this.pathType = ActionObjectPath.PathType_FilePath) { 74 | if(!FileExist(this.path)) { ; Don't try to open a non-existent local path 75 | Toast.ShowError("Local file or folder does not exist", this.path) 76 | return "" 77 | } 78 | } 79 | 80 | return this.path 81 | } 82 | ;endregion ------------------------------ PUBLIC ------------------------------ 83 | 84 | ;region ------------------------------ PRIVATE ------------------------------ 85 | ;--------- 86 | ; DESCRIPTION: Determine the type of the given path. 87 | ; PARAMETERS: 88 | ; path (I,REQ) - The path itself. 89 | ; RETURNS: The type of path, from PathType_* constants. 90 | ;--------- 91 | determinePathType(path) { 92 | if(StringLib.isURL(path)) 93 | return ActionObjectPath.PathType_URL 94 | 95 | if(FileLib.isFilePath(path)) 96 | return ActionObjectPath.PathType_FilePath 97 | 98 | return "" 99 | } 100 | 101 | ;--------- 102 | ; DESCRIPTION: Do some additional processing on the different bits of info about the object. 103 | ; SIDE EFFECTS: Can update this.path. 104 | ;--------- 105 | postProcess() { 106 | Switch this.pathType { 107 | case ActionObjectPath.PathType_URL: 108 | ; For URLs, make sure that they have a protocol at the start so Windows knows how to run it as a URL 109 | ; (not a local path). 110 | if(!this.path.contains("//")) ; No protocol 111 | this.path := "https://" this.path ; Add a protocol on so Windows knows to run it as a URL. 112 | 113 | case ActionObjectPath.PathType_FilePath: 114 | this.path := FileLib.cleanupPath(this.path) 115 | } 116 | } 117 | ;endregion ------------------------------ PRIVATE ------------------------------ 118 | } 119 | -------------------------------------------------------------------------------- /source/common/class/actionObjectTrackLab.ahk: -------------------------------------------------------------------------------- 1 | #Include ..\base\actionObjectBase.ahk 2 | 3 | /* Class for performing actions on TrackLab (Git) objects. 4 | 5 | Note that several other operations are also available from the base class (.copyLink*(), .linkSelectedText*()). 6 | 7 | Example Usage 8 | ; ao := new ActionObjectTrackLab("commit a526d5") 9 | ; MsgBox, ao.getLink() ; Link (in TrackLab) 10 | ; ao.open() ; Open (in TrackLab) 11 | ; 12 | ; ao := new ActionObjectTrackLab("a526d2") ; ID without an INI, user will be prompted for the INI 13 | ; ao.open() ; Open 14 | 15 | */ 16 | 17 | class ActionObjectTrackLab extends ActionObjectBase { 18 | ;region ------------------------------ PUBLIC ------------------------------ 19 | ActionObjectType := ActionObject.Type_TrackLab 20 | 21 | ;region Object actions 22 | static SubType_ViewCommit := "VIEW_COMMIT" 23 | static SubType_DLGBranch := "DLG_BRANCH" 24 | static SubType_FileHistory_S1 := "FILE_HISTORY_S1" 25 | static SubType_FileHistory_FINAL := "FILE_HISTORY_FINAL" 26 | static SubType_FileBlame_S1 := "FILE_BLAME_S1" 27 | static SubType_FileBlame_FINAL := "FILE_BLAME_FINAL" 28 | ;endregion Object actions 29 | 30 | id := "" ; ID of the object 31 | subType := "" ; Thing to launch, from SubType_* 32 | 33 | ;--------- 34 | ; DESCRIPTION: Create a new reference to a TrackLab object. 35 | ; PARAMETERS: 36 | ; id (I,REQ) - ID of the object 37 | ; subType (I,OPT) - SubType of the object, from ActionObjectTrackLab.SubType_*. Prompted for if 38 | ; not given. 39 | ;--------- 40 | __New(id, subType := "") { 41 | if(!this.selectMissingInfo(id, subType)) 42 | return "" 43 | 44 | this.id := id 45 | this.subType := subType 46 | } 47 | 48 | ;--------- 49 | ; DESCRIPTION: Determine whether the given string MUST be this type of ActionObject. 50 | ; PARAMETERS: 51 | ; value (I,REQ) - The value to evaluate 52 | ; subType (O,OPT) - If the value is a TrackLab record, the subType. 53 | ; id (O,OPT) - If the value is a TrackLab record, the ID. 54 | ; RETURNS: true/false - whether the given value must be a TrackLab object. 55 | ; NOTES: Must be effectively static - this is called before we decide what kind of object to return. 56 | ;--------- 57 | isThisType(value, ByRef subType := "", ByRef id := "") { 58 | if(!Config.contextIsWork) 59 | return false 60 | 61 | if(value.startsWithAnyOf(["git ", "commit "], matchedPrefix)) { 62 | subType := this.SubType_ViewCommit 63 | id := value.removeFromStart(matchedPrefix) 64 | return true 65 | } 66 | 67 | return false 68 | } 69 | 70 | ;--------- 71 | ; DESCRIPTION: Get a link to the object. 72 | ; RETURNS: Link to TrackLab 73 | ;--------- 74 | getLink() { 75 | ; Specific branches, pulled out here for readability 76 | stage1Branch := Config.private["GIT_BRANCH_CURRENT_S1"] 77 | finalBranch := Config.private["GIT_BRANCH_CURRENT_FINAL"] 78 | 79 | Switch this.subType { 80 | Case this.SubType_ViewCommit: 81 | return Config.private["TRACKLAB_GIT_COMMIT"].replaceTags({ COMMIT: this.id }) 82 | Case this.SubType_DLGBranch: 83 | return Config.private["TRACKLAB_GIT_FILE_HISTORY"].replaceTags({ BRANCH: "dlg/" this.id, FILEPATH: "" }) 84 | Case this.SubType_FileHistory_S1: 85 | return Config.private["TRACKLAB_GIT_FILE_HISTORY"].replaceTags({ BRANCH: stage1Branch, FILEPATH: this.id }) 86 | Case this.SubType_FileHistory_FINAL: 87 | return Config.private["TRACKLAB_GIT_FILE_HISTORY"].replaceTags({ BRANCH: finalBranch, FILEPATH: this.id }) 88 | Case this.SubType_FileBlame_S1: 89 | return Config.private["TRACKLAB_GIT_FILE_BLAME"].replaceTags({ BRANCH: stage1Branch, FILEPATH: this.id }) 90 | Case this.SubType_FileBlame_FINAL: 91 | return Config.private["TRACKLAB_GIT_FILE_BLAME"].replaceTags({ BRANCH: finalBranch, FILEPATH: this.id }) 92 | } 93 | 94 | return "" 95 | } 96 | ;endregion ------------------------------ PUBLIC ------------------------------ 97 | } 98 | -------------------------------------------------------------------------------- /source/common/class/actionObjectWebRecord.ahk: -------------------------------------------------------------------------------- 1 | #Include ..\base\actionObjectBase.ahk 2 | 3 | /* Class for performing actions on various web records (helpdesk tickets, NullEx posts, etc.) 4 | 5 | Note that several other operations are also available from the base class (.copyLink*(), .linkSelectedText*()). 6 | 7 | Example Usage 8 | ; ao := new ActionObjectWebRecord("HDR 123456") 9 | ; MsgBox, ao.getLinkWeb() ; Link to helpdesk request (equivalent to .getLinkEdit()) 10 | ; ao.openWeb() ; Open web portal to request (equivalent to .openEdit()) 11 | 12 | */ 13 | 14 | class ActionObjectWebRecord extends ActionObjectBase { 15 | ;region ------------------------------ PUBLIC ------------------------------ 16 | ActionObjectType := ActionObject.Type_WebRecord 17 | 18 | ;region Record types 19 | static RecordType_Helpdesk := "HELPDESK" ; Helpdesk ticket 20 | static RecordType_NullEx := "NULLEX" ; NullEx post 21 | ;endregion Record types 22 | 23 | id := "" ; Record ID 24 | recordType := "" ; Record type 25 | 26 | ;--------- 27 | ; DESCRIPTION: Create a new reference to a web record. 28 | ; PARAMETERS: 29 | ; id (I,REQ) - ID of the record. 30 | ; recordType (I,OPT) - The type of record, from ActionObjectWebRecord.RecordType_*. If not given, we'll try to 31 | ;--------- 32 | __New(id, recordType := "") { 33 | if(!this.selectMissingInfo(id, recordType)) 34 | return "" 35 | 36 | this.id := id 37 | this.recordType := recordType 38 | } 39 | 40 | ;--------- 41 | ; DESCRIPTION: Determine whether the given string must be this type of ActionObject. 42 | ; PARAMETERS: 43 | ; value (I,REQ) - The value to evaluate 44 | ; recordType (O,OPT) - If the value is a web record, the type of web record (from ActionObjectWebRecord.RecordType_*) 45 | ; id (O,OPT) - If the value is a web record, the ID 46 | ; RETURNS: true/false - whether the given value must be a web record. 47 | ;--------- 48 | isThisType(value, ByRef recordType := "", ByRef id := "") { 49 | if(!Config.contextIsWork) 50 | return false 51 | 52 | if(value.startsWithAnyOf(["HDR ", "helpdesk "], matchedType)) { 53 | recordType := this.RecordType_Helpdesk 54 | id := value.removeFromStart(matchedType) 55 | return true 56 | } 57 | 58 | if(value.startsWithAnyOf(["NullEx "], matchedType)) { 59 | recordType := this.RecordType_NullEx 60 | id := value.removeFromStart(matchedType) 61 | return true 62 | } 63 | 64 | return false 65 | } 66 | 67 | ;--------- 68 | ; DESCRIPTION: Get a link to the record. 69 | ; RETURNS: Link to the record. 70 | ;--------- 71 | getLink() { 72 | Switch this.recordType { 73 | Case ActionObjectWebRecord.RecordType_Helpdesk: 74 | return Config.private["HELPDESK_BASE"].replaceTag("ID", this.id) 75 | 76 | Case ActionObjectWebRecord.RecordType_NullEx: 77 | return Config.private["NULLEX_BASE"].replaceTag("ID", this.id) 78 | } 79 | 80 | return "" 81 | } 82 | ;endregion ------------------------------ PUBLIC ------------------------------ 83 | } 84 | -------------------------------------------------------------------------------- /source/common/class/mousePosition.ahk: -------------------------------------------------------------------------------- 1 | /* Simple class that represents a mouse position and can easily tell you how far the mouse is from that position currently. 2 | 3 | Example Usage 4 | ; mp := new MousePosition() ; Stores off current mouse position 5 | ; originalXPos := mp.x ; Original X coordinate of the mouse 6 | ; mp.getDistanceFromCurrentPosition(distanceX, distanceY) 7 | 8 | */ 9 | 10 | class MousePosition { 11 | ;region ------------------------------ PUBLIC ------------------------------ 12 | x := 0 ; X coordinate for the mouse at the time this instance was created. 13 | y := 0 ; Y coordinate for the mouse at the time this instance was created. 14 | 15 | ;--------- 16 | ; DESCRIPTION: Create a new MousePosition object which stores off the current mouse position. 17 | ;--------- 18 | __New() { 19 | MouseGetPos(x, y) 20 | this.x := x 21 | this.y := y 22 | } 23 | 24 | ;--------- 25 | ; DESCRIPTION: Calculates the distance that the mouse has moved, relative to where it was 26 | ; when this instance was created. 27 | ; PARAMETERS: 28 | ; distanceX (O,OPT) - The distance along the X axis (if the mouse moved to the right, this is positive) 29 | ; distanceY (O,OPT) - The distance along the Y asix (if the mouse moved down, this is positive) 30 | ;--------- 31 | getDistanceFromCurrentPosition(ByRef distanceX, ByRef distanceY) { 32 | MouseGetPos(x, y) 33 | 34 | distanceX := x - this.x 35 | distanceY := y - this.y 36 | } 37 | ;endregion ------------------------------ PUBLIC ------------------------------ 38 | } 39 | -------------------------------------------------------------------------------- /source/common/class/program.ahk: -------------------------------------------------------------------------------- 1 | ; Class that represents a specific program and all the information needed to run it. 2 | 3 | class Program { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | 6 | ;region Path types (affect how the path is run) 7 | static PathType_COMMAND := "COMMAND" ; A command 8 | static PathType_EXE := "EXE" ; A "normal" path to an executable 9 | static PathType_WinApp := "WIN_APP" ; A windows app (fka universal app) 10 | static PathType_URL := "URL" ; A web URL 11 | static PathType_ChromeApp := "CHROME_APP" ; A Google Chrome app 12 | ;endregion Path types (affect how the path is run) 13 | 14 | name := "" ; Name of the program 15 | path := "" ; Full filepath to launch the program 16 | pathType := "" ; The type of path from Program.PathType_* 17 | 18 | ;--------- 19 | ; DESCRIPTION: Creates a new instance of Program. 20 | ; PARAMETERS: 21 | ; programAry (I,REQ) - Array of information about the program to store. Format: 22 | ; programAry["NAME"] - Name of the program. Should match a single row 23 | ; in windows.tl for identification purposes. 24 | ; ["PATH"] - The full filepath to launch the program. 25 | ; RETURNS: Reference to a new Program object 26 | ;--------- 27 | __New(programAry) { 28 | this.name := programAry["NAME"] 29 | this.path := programAry["PATH"] 30 | this.pathType := programAry["PATH_TYPE"] 31 | 32 | ; Replace any path or private tags 33 | this.path := Config.replacePathTags(this.path) 34 | this.path := Config.replacePrivateTags(this.path) 35 | } 36 | 37 | ;--------- 38 | ; DESCRIPTION: Run this program with the given arguments. 39 | ; PARAMETERS: 40 | ; args (I,OPT) - The command-line arguments to pass to the program when we run it. Only used for EXE-type paths (not 41 | ; windows apps or URLs). 42 | ; RETURNS: false if we couldn't run the program, true otherwise. 43 | ;--------- 44 | run(args := "") { 45 | ; Safety checks 46 | if(this.pathType = this.PathType_EXE) { 47 | if(!FileExist(this.path)) { 48 | Toast.ShowError("Could not run " this.name, "Path does not exist: " this.path) 49 | return false 50 | } 51 | } 52 | 53 | ; Path type determines how we run the path 54 | Switch this.pathType { 55 | Case this.PathType_COMMAND, this.PathType_EXE, this.PathType_URL: 56 | Run(this.path.appendPiece(" ", args)) 57 | 58 | ; Windows apps - path is the logical path, found using instructions here: 59 | ; https://answers.microsoft.com/en-us/windows/forum/windows_10-windows_store/starting-windows-10-store-app-from-the-command/836354c5-b5af-4d6c-b414-80e40ed14675) 60 | Case this.PathType_WinApp: 61 | Run("explorer.exe " this.path) ; Must be run this way, not as user (possibly needs to be as admin) 62 | 63 | Case this.PathType_ChromeApp: 64 | Config.runProgram("Chrome Proxy", "--profile-directory=Default --app-id=" this.path) 65 | } 66 | 67 | return true 68 | } 69 | ;endregion ------------------------------ PUBLIC ------------------------------ 70 | } 71 | -------------------------------------------------------------------------------- /source/common/class/relativeTime.ahk: -------------------------------------------------------------------------------- 1 | #Include ..\base\relativeDateTimeBase.ahk 2 | 3 | /* Calculates and sends a time relative to the class's instantiation (or the user submitting their relative time string, if one not provided to the constructor). 4 | 5 | Relative time string format 6 | The relative time string is in this format: 7 | 8 | Unit - The unit to shift the time by (see "Units" section below) 9 | Operator - Plus (+) or minus (-) for the direction to shift 10 | ShiftAmount - How much to shift the time by, in the provided unit 11 | 12 | Units 13 | This class supports a few time units, including: 14 | h - hours 15 | m - minutes 16 | n - minutes (stands for "now") 17 | s - seconds 18 | 19 | Example Usage 20 | ; rt := new RelativeTime("h+5") ; 5 hours in the future, at the time this line runs 21 | ; newTime := rt.instant ; Get the calculated instant 22 | ; rt.SendInFormat("hh:mm:ss") ; Send the calculated date in a specific format 23 | 24 | */ 25 | 26 | class RelativeTime extends RelativeDateTimeBase { 27 | ;region ------------------------------ PUBLIC ------------------------------ 28 | ;--------- 29 | ; DESCRIPTION: Create a new representation of a time relative to right now. 30 | ; PARAMETERS: 31 | ; relativeTime (I,REQ) - The relative time string to use to find the new time. 32 | ;--------- 33 | __New(relativeTime) { 34 | this.loadCurrentDateTime() 35 | this.shiftByRelativeString(relativeTime) 36 | } 37 | ;endregion ------------------------------ PUBLIC ------------------------------ 38 | 39 | ;region ------------------------------ PRIVATE ------------------------------ 40 | ;--------- 41 | ; DESCRIPTION: Handle the actual time shift relative to now. 42 | ; PARAMETERS: 43 | ; shiftAmount (I,REQ) - The amount to shift 44 | ; unit (I,REQ) - The unit to shift in 45 | ;--------- 46 | doShift(shiftAmount, unit) { 47 | if(unit = "n") ; Relative minutes can also be written as "n" for now. 48 | unit := "m" 49 | 50 | ; All of the time units (hours, minutes, seconds) are supported by EnvAdd(), so just use that. 51 | this._instant := EnvAdd(this._instant, shiftAmount, unit) ; Can't use += format because it doesn't support this.*-style variable names. 52 | this.updatePartsFromInstant() 53 | } 54 | ;endregion ------------------------------ PRIVATE ------------------------------ 55 | } 56 | -------------------------------------------------------------------------------- /source/common/class/selectorChoice.ahk: -------------------------------------------------------------------------------- 1 | ; Representation of a single choice within a Selector object. 2 | 3 | class SelectorChoice { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | ;--------- 6 | ; DESCRIPTION: The full data object for this choice. 7 | ;--------- 8 | dataObject { 9 | get { 10 | return this.data 11 | } 12 | } 13 | 14 | ;--------- 15 | ; DESCRIPTION: The display name for the given choice. 16 | ;--------- 17 | name { 18 | get { 19 | return this.data["NAME"] 20 | } 21 | } 22 | 23 | ;--------- 24 | ; DESCRIPTION: The (first) abbreviation for the choice (the one we'll display next to the choice). Note that if 25 | ; there were multiple abbreviations given as an array, this will just be the first one. 26 | ;--------- 27 | displayAbbrev { 28 | get { 29 | return (this.allAbbrevs)[1] 30 | } 31 | } 32 | 33 | ;--------- 34 | ; DESCRIPTION: All abbreviations for the given choice. Always an array, even if there's just 35 | ; a single abbreviation. 36 | ;--------- 37 | allAbbrevs { 38 | get { 39 | return DataLib.forceArray(this.data["ABBREV"]) 40 | } 41 | set { 42 | this.data["ABBREV"] := DataLib.forceArray(value) 43 | } 44 | } 45 | 46 | ;--------- 47 | ; DESCRIPTION: Create a new SelectorChoice instance. 48 | ; PARAMETERS: 49 | ; dataIn (I,REQ) - Assocative array of data that the choice contains. 50 | ; Format: 51 | ; dataIn[LABEL] := VALUE 52 | ; Special subscripts: 53 | ; "ABBREV" - Abbreviation of choice, can also be an array. 54 | ; The first one (the display one) will be available via .displayAbbrev 55 | ; "NAME" - Name of choice, later available via .name 56 | ; RETURNS: Reference to new SelectorChoice object 57 | ;--------- 58 | __New(dataIn) { 59 | this.data := dataIn 60 | this.data["ABBREV"] := DataLib.forceArray(this.data["ABBREV"]) ; Force abbreviations to be an array internally 61 | } 62 | 63 | ;--------- 64 | ; DESCRIPTION: Determine whether the given string matches any of the abbreviations 65 | ; (including those not displayed) for this choice. 66 | ; PARAMETERS: 67 | ; stringToTest (I,REQ) - String to check against this choice. 68 | ; RETURNS: true if it matches, false otherwise. 69 | ;--------- 70 | matchesAbbrev(stringToTest) { 71 | if(stringToTest = "") 72 | return false 73 | 74 | abbrev := this.data["ABBREV"] 75 | if(isObject(abbrev)) 76 | return stringToTest.isAnyOf(abbrev) 77 | else 78 | return (stringToTest = abbrev) 79 | } 80 | ;endregion ------------------------------ PUBLIC ------------------------------ 81 | 82 | ;region ------------------------------ PRIVATE ------------------------------ 83 | data := {} ; {label: value} 84 | ;endregion ------------------------------ PRIVATE ------------------------------ 85 | } 86 | -------------------------------------------------------------------------------- /source/common/common.ahk: -------------------------------------------------------------------------------- 1 | ;region Basic settings for all scripts 2 | #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. 3 | #SingleInstance, Force ; Running this script while it's already running just replaces the existing instance. 4 | #LTrim ; Trim whitespace from left of continuation sections (so they can be indented as I wish). 5 | SendMode, Input ; Recommended for new scripts due to its superior speed and reliability. 6 | SetWorkingDir, % A_ScriptDir ; Ensures a consistent starting directory. 7 | ;endregion Basic settings for all scripts 8 | 9 | ;region Standard base replacement 10 | #Include %A_LineFile%\..\base 11 | #Include stringBase.ahk 12 | #Include arrayBase.ahk 13 | #Include objectBase.ahk 14 | 15 | ; Strings (technically all non-objects, since they all share a base class - see https://www.autohotkey.com/docs/Objects.htm#Pseudo_Properties ) 16 | "".base.base := StringBase ; Can't replace the base itself, but can give the base a new base instead. 17 | 18 | ; Arrays and Objects (based on https://autohotkey.com/board/topic/83081-ahk-l-customizing-object-and-array/ ) 19 | ; Redefine Array() to use our new ArrayBase base class 20 | Array(params*) { 21 | ; Since params is already an array of the parameters, just give it a 22 | ; new base object and return it. Using this method, ArrayBase.__New() 23 | ; is not called and any instance variables are not initialized. 24 | params.base := ArrayBase 25 | return params 26 | } 27 | ; Redefine Object() to use our new ObjectBase base class 28 | Object(params*) { 29 | ; Create a new object derived from ObjectBase. 30 | objectInstance := new ObjectBase 31 | 32 | ; For each pair of parameters, store the key-value pair. 33 | Loop, % params.MaxIndex() // 2 { 34 | key := params[A_Index * 2 - 1] 35 | value := params[A_Index * 2] 36 | objectInstance[key] := value 37 | } 38 | 39 | ; Return the new object. 40 | return objectInstance 41 | } 42 | ;endregion Standard base replacement 43 | 44 | ;region Includes 45 | #Include %A_LineFile%\..\class 46 | #Include actionObject.ahk 47 | #Include duration.ahk 48 | #Include epicRecord.ahk 49 | #Include flexTable.ahk 50 | #Include formattedList.ahk 51 | #Include mousePosition.ahk 52 | #Include program.ahk 53 | #Include progressToast.ahk 54 | #Include relativeDate.ahk 55 | #Include relativeTime.ahk 56 | #Include selector.ahk 57 | #Include tableList.ahk 58 | #Include tempSettings.ahk 59 | #Include textPopup.ahk 60 | #Include textTable.ahk 61 | #Include toast.ahk 62 | #Include visualWindow.ahk 63 | #Include windowInfo.ahk 64 | 65 | #Include %A_LineFile%\..\external 66 | #Include commandFunctions.ahk 67 | #Include HTTPRequest.ahk 68 | 69 | #Include %A_LineFile%\..\lib 70 | #Include ahkCodeLib.ahk 71 | #Include clipboardLib.ahk 72 | #Include dataLib.ahk 73 | #Include dateTimeLib.ahk 74 | #Include epicLib.ahk 75 | #Include fileLib.ahk 76 | #Include guiLib.ahk 77 | #Include hotkeyLib.ahk 78 | #Include microsoftLib.ahk 79 | #Include monitorLib.ahk 80 | #Include phoneLib.ahk 81 | #Include runLib.ahk 82 | #Include searchLib.ahk 83 | #Include selectLib.ahk 84 | #Include stringLib.ahk 85 | #Include windowLib.ahk 86 | 87 | #Include %A_LineFile%\..\program 88 | #Include chrome.ahk 89 | #Include ditto.ahk 90 | #Include emc2.ahk 91 | #Include epicStudio.ahk 92 | #Include excel.ahk 93 | #Include explorer.ahk 94 | #Include hyperspace.ahk 95 | #Include internetExplorer.ahk 96 | #Include mBuilder.ahk 97 | #Include mSnippets.ahk 98 | #Include mtPutty.ahk 99 | #Include notepadPlusPlus.ahk 100 | #Include onenote.ahk 101 | #Include onetastic.ahk 102 | #Include outlook.ahk 103 | #Include putty.ahk 104 | #Include snapper.ahk 105 | #Include telegram.ahk 106 | #Include visualStudio.ahk 107 | #Include vsCode.ahk 108 | #Include zoom.ahk 109 | 110 | #Include %A_LineFile%\..\static 111 | #Include config.ahk 112 | #Include commonHotkeys.ahk 113 | #Include debug.ahk 114 | #Include enums.ahk 115 | #Include hyperlinker.ahk 116 | #Include scriptTrayInfo.ahk 117 | #Include titleMatchMode.ahk 118 | #Include VA.ahk 119 | #Include windowActions.ahk 120 | #Include windowPositions.ahk 121 | ;endregion Includes 122 | 123 | ;region Initialization 124 | Config.Init() 125 | ;endregion Initialization -------------------------------------------------------------------------------- /source/common/external/HTTPRequest.ahk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/source/common/external/HTTPRequest.ahk -------------------------------------------------------------------------------- /source/common/lib/dateTimeLib.ahk: -------------------------------------------------------------------------------- 1 | ; Date and time utility functions. 2 | 3 | class DateTimeLib { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | ;--------- 6 | ; DESCRIPTION: Replace tags matching different formats supported by FormatTime. 7 | ; PARAMETERS: 8 | ; inString (I,REQ) - The string to replace tags in 9 | ; dateTime (I,OPT) - The date/time to use when replacing tags 10 | ; RETURNS: The updated string 11 | ;--------- 12 | replaceTags(inString, instant := "") { ; instant defaults to A_Now (based on FormatTime's behavior) 13 | outString := inString 14 | 15 | ; All formats supported by FormatTime 16 | formatsAry := ["d","dd","ddd","dddd","M","MM","MMM","MMMM","y","yy","yyyy","gg","h","hh","H","HH","m","mm","s","ss","t","tt","","Time","ShortDate","LongDate","YearMonth","YDay","YDay0","WDay","YWeek"] 17 | 18 | For _,format in formatsAry { 19 | dateTimeBit := FormatTime(instant, format) 20 | outString := outString.replaceTag(format, dateTimeBit) 21 | } 22 | 23 | return outString 24 | } 25 | 26 | ;--------- 27 | ; DESCRIPTION: Figure out the last date in the provided month/year. 28 | ; PARAMETERS: 29 | ; monthNum (I,OPT) - The month number to check 30 | ; year (I,OPT) - The year to check 31 | ; RETURNS: The last date (with leading 0) in the given month. 32 | ;--------- 33 | getLastDateOfMonth(monthNum := "", year := "") { 34 | ; Default in today's month/year if either is not given 35 | monthNum := monthNum ? monthNum : A_MM ; Current month number (with leading 0, though that doesn't matter) 36 | year := year ? year : A_YYYY ; Current year 37 | 38 | ; Get number of the next month 39 | nextMonthNum := monthNum + 1 40 | if(nextMonthNum = 13) ; Wrap around at end of year 41 | nextMonthNum := 1 42 | 43 | dateString := year nextMonthNum.prePadToLength(2, "0") ; First day of following month in YYYYMM format 44 | dateString += -1, Days ; Go back a day to get to the last day of the given month 45 | 46 | return FormatTime(dateString, "dd") ; Date with leading 0 (matches A_DD) 47 | } 48 | ;endregion ------------------------------ PUBLIC ------------------------------ 49 | } 50 | -------------------------------------------------------------------------------- /source/common/lib/guiLib.ahk: -------------------------------------------------------------------------------- 1 | ; Gui-related helper functions. 2 | 3 | class GuiLib { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | ;--------- 6 | ; DESCRIPTION: Show the user a yes/no confirmation popup to the user. 7 | ; PARAMETERS: 8 | ; message (I,REQ) - The message to show in the popup. 9 | ; title (I,OPT) - The title of the popup 10 | ; RETURNS: true/false - whether the user clicked the "Yes" button. 11 | ;--------- 12 | showConfirmationPopup(message, title := "") { 13 | MsgBoxButtons_YesNo := 4 14 | MsgBox, % MsgBoxButtons_YesNo, % title, % message 15 | IfMsgBox, Yes 16 | return true 17 | return false 18 | } 19 | 20 | ;--------- 21 | ; DESCRIPTION: Apply a title format (heavy weight, underline) for the next set of controls 22 | ; being added to the gui. 23 | ;--------- 24 | applyTitleFormat() { 25 | Gui, Font, w600 underline ; Heavier weight (not quite bold), underline. 26 | } 27 | ;--------- 28 | ; DESCRIPTION: Clear a title format (heavy weight, underline) for the next set of controls 29 | ; being added to the gui. 30 | ;--------- 31 | clearTitleFormat() { 32 | Gui, Font, norm 33 | } 34 | 35 | ;--------- 36 | ; DESCRIPTION: Get the size of a label with the given text. 37 | ; PARAMETERS: 38 | ; text (I,REQ) - The text to measure the size of. 39 | ; width (O,OPT) - The width of the label needed to hold the given text. 40 | ; height (O,OPT) - The height of the label needed to hold the given text. 41 | ; SIDE EFFECTS: This adds a hidden label to the gui (specifically, adds it so we can see the 42 | ; size, then hides it). 43 | ; NOTES: This assumes that the formatting/default gui for the text in question are 44 | ; already in effect. 45 | ;--------- 46 | getLabelSizeForText(text, ByRef width := "", ByRef height := "") { 47 | global ; Needed for the dynamic variable used to reference the text control 48 | 49 | SizeMeasuringLabelUniqueId++ 50 | local varName := "Var" SizeMeasuringLabelUniqueId 51 | 52 | Gui, Add, Text, % "v" varName, % text 53 | controlSize := GuiControlGet("Pos", varName) 54 | width := controlSize["W"] 55 | height := controlSize["H"] 56 | 57 | GuiControl, Hide, % varName ; GuiControl, Delete not yet implemented, so just hide the temporary control. 58 | } 59 | 60 | ;--------- 61 | ; DESCRIPTION: Create a global to assign to a control so we can reference the control (with 62 | ; GuiControl, or get the value with .getDynamicGlobal) dynamically. 63 | ; PARAMETERS: 64 | ; varName (I,REQ) - The name of the global variable to create. 65 | ; NOTES: This basically exists to let us hide the static/global requirement for 66 | ; variables used by gui controls - as long as the global is only referenced 67 | ; via indirection, it won't be treated as a local variable in other functions. 68 | ;--------- 69 | createDynamicGlobal(varName) { 70 | global 71 | %varName% := "" 72 | } 73 | ;--------- 74 | ; DESCRIPTION: Get the value of a control using the dynamic global (created with 75 | ; .createDynamicGlobal) that's assigned to it. 76 | ; PARAMETERS: 77 | ; varName (I,REQ) - The name of the global variable to get the value of. 78 | ; RETURNS: The value in the specified global (aka the value of the control). 79 | ; NOTES: This basically exists to let us hide the static/global requirement for 80 | ; variables used by gui controls - as long as the global is only referenced 81 | ; via indirection, it won't be treated as a local variable in other functions. 82 | ;--------- 83 | getDynamicGlobal(varName) { 84 | global 85 | local value := %varName% 86 | return value 87 | } 88 | ;endregion ------------------------------ PUBLIC ------------------------------ 89 | } 90 | 91 | -------------------------------------------------------------------------------- /source/common/lib/hotkeyLib.ahk: -------------------------------------------------------------------------------- 1 | ; Helper functions for hotkeys. 2 | 3 | class HotkeyLib { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | ;--------- 6 | ; DESCRIPTION: Release all modifier keys. This is useful when certain modifier keys get "stuck" down. 7 | ;--------- 8 | releaseAllModifiers() { 9 | modifierKeys := ["LWin", "RWin", "Ctrl", "LCtrl", "RCtrl", "Alt", "LAlt", "RAlt", "Shift", "LShift", "RShift"] 10 | For _,modifier in modifierKeys { 11 | if(GetKeyState(modifier)) 12 | Send, {%modifier% Up} 13 | } 14 | } 15 | 16 | ;--------- 17 | ; DESCRIPTION: Wait for the given hotkey to be fully released (all modifiers included). 18 | ; PARAMETERS: 19 | ; hotkeyString (I,OPT) - The hotkey to wait on. If not set, we'll use A_ThisHotkey to get the 20 | ; hotkey that triggered this function. 21 | ;--------- 22 | waitForRelease(hotkeyString := "") { 23 | if(!hotkeyString) 24 | hotkeyString := A_ThisHotkey 25 | 26 | Loop, Parse, hotkeyString 27 | { 28 | keyName := HotkeyLib.getKeyNameFromHotkeyChar(A_LoopField) 29 | if(keyName) 30 | KeyWait, % keyName 31 | } 32 | } 33 | 34 | 35 | ;--------- 36 | ; DESCRIPTION: Send a set of keys in a way that they can be caught and handled by other hotkeys in the same script. 37 | ; PARAMETERS: 38 | ; keys (I,REQ) - The keys to send, for use with the Send command. 39 | ;--------- 40 | sendCatchableKeys(keys) { 41 | settings := new TempSettings().sendLevel(1) ; Level 1: keystrokes can be caught and handled by other hotkeys. 42 | Send, % keys 43 | settings.restore() 44 | } 45 | ;endregion ------------------------------ PUBLIC ------------------------------ 46 | 47 | ;region ------------------------------ PRIVATE ------------------------------ 48 | ;--------- 49 | ; DESCRIPTION: Given a character from a hotkey string, figure out the name of the corresponding key. 50 | ; PARAMETERS: 51 | ; hotkeyChar (I,REQ) - The character to identify. 52 | ; RETURNS: The name of the hotkey character, suitable for use with Send or KeyWait. 53 | ; NOTES: This isn't comprehensive - doesn't handle things like UP, for example. 54 | ;--------- 55 | getKeyNameFromHotkeyChar(hotkeyChar) { 56 | if(!hotkeyChar) 57 | return "" 58 | 59 | Switch hotkeyChar { 60 | Case "*","$","~": return "" ; Special characters for how a hotkey is checked 61 | Case " ": return "" ; Space within hotkey (means nothing) - probably around an & or similar. 62 | Case "#": return "LWin" ; There's no generic "Win", so just pick the left one. 63 | Case "!": return "Alt" 64 | Case "^": return "Ctrl" 65 | Case "+": return "Shift" 66 | Default: return hotkeyChar ; Otherwise, probably a letter or number. 67 | } 68 | } 69 | ;endregion ------------------------------ PRIVATE ------------------------------ 70 | } 71 | -------------------------------------------------------------------------------- /source/common/lib/runLib.ahk: -------------------------------------------------------------------------------- 1 | ; Utility functions for running scripts, commands, and other programs. 2 | 3 | class RunLib { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | ;--------- 6 | ; DESCRIPTION: Run a command with cmd.exe. 7 | ; PARAMETERS: 8 | ; commandToRun (I,REQ) - The command to run. 9 | ; workingDirectory (I,OPT) - The working directory to run the command in. 10 | ; stayOpen (I,OPT) - Set to true if you want the window to stay open after the command has run. 11 | ;--------- 12 | runCommand(commandToRun, workingDirectory := "", stayOpen := false) { 13 | ; Set /C or /K (command and close, or command and stay up) based on input. 14 | if(stayOpen) 15 | runString := A_ComSpec " /K " commandToRun 16 | else 17 | runString := A_ComSpec " /C " commandToRun 18 | 19 | ; Debug.popup("Command string", commandToRun, "Run string", runString) 20 | Run(runString, workingDirectory) 21 | } 22 | 23 | ;--------- 24 | ; DESCRIPTION: Run the given command as a non-elevated user, even if the script is running as admin. 25 | ; PARAMETERS: 26 | ; cmd (I,REQ) - The command to run. 27 | ; args (I,OPT) - Parameters to pass (if this is a filepath to a program). 28 | ;--------- 29 | runAsUser(cmd, args := "") { 30 | RunLib.shellRun(cmd, args) 31 | } 32 | 33 | ;--------- 34 | ; DESCRIPTION: Run the given command and return the output. 35 | ; PARAMETERS: 36 | ; command (I,REQ) - Command to run. 37 | ; RETURNS: The output from the command, as passed to standard out. 38 | ;--------- 39 | runReturn(command) { 40 | fullCommand := A_ComSpec . " /c """ . command . """" 41 | shell := comobjcreate("wscript.shell") 42 | exec := (shell.exec(fullCommand)) 43 | stdout := exec.stdout.readall() 44 | return stdout 45 | } 46 | ;endregion ------------------------------ PUBLIC ------------------------------ 47 | 48 | ;region ------------------------------ PRIVATE ------------------------------ 49 | /* 50 | ShellRun by Lexikos 51 | requires: AutoHotkey_L 52 | license: http://creativecommons.org/publicdomain/zero/1.0/ 53 | 54 | Credit for explaining this method goes to BrandonLive: 55 | http://brandonlive.com/2008/04/27/getting-the-shell-to-run-an-application-for-you-part-2-how/ 56 | 57 | Shell.ShellExecute(File [, Arguments, Directory, Operation, Show]) 58 | http://msdn.microsoft.com/en-us/library/windows/desktop/gg537745 59 | 60 | Function found here: 61 | https://autohotkey.com/board/topic/108434-run-ahk-as-admin-or-not-dilemma/#entry648428 62 | 63 | Parameters 64 | 1 application to launch 65 | 2 command line parameters 66 | 3 working directory for the new process 67 | 4 "Verb" (For example, pass "RunAs" to run as administrator) 68 | 5 Suggestion to the application about how to show its window - see the msdn link for possible values 69 | */ 70 | shellRun(prms*) { 71 | shellWindows := ComObjCreate("{9BA05972-F6A8-11CF-A442-00A0C90A8F39}") 72 | 73 | desktop := shellWindows.Item(ComObj(19, 8)) ; VT_UI4, SCW_DESKTOP 74 | 75 | ; Retrieve top-level browser object. 76 | SID_STopLevelBrowser := "{4C96BE40-915C-11CF-99D3-00AA004AE837}" 77 | IID_IShellBrowser := "{000214E2-0000-0000-C000-000000000046}" 78 | 79 | if(ptlb := ComObjQuery(desktop, SID_STopLevelBrowser, IID_IShellBrowser)) { 80 | ; IShellBrowser.QueryActiveShellView -> IShellView 81 | if(DllCall(NumGet(NumGet(ptlb + 0) + 15 * A_PtrSize), "ptr", ptlb, "ptr*", psv := 0) = 0) { 82 | ; Define IID_IDispatch. 83 | VarSetCapacity(IID_IDispatch, 16) 84 | NumPut(0x46000000000000C0, NumPut(0x20400, IID_IDispatch, "int64"), "int64") 85 | 86 | ; IShellView.GetItemObject -> IDispatch (object which implements IShellFolderViewDual) 87 | DllCall(NumGet(NumGet(psv + 0) + 15 * A_PtrSize), "ptr", psv, "uint", 0, "ptr", &IID_IDispatch, "ptr*", pdisp := 0) 88 | 89 | ; Get Shell object. 90 | shell := ComObj(9, pdisp, 1).Application 91 | 92 | ; IShellDispatch2.ShellExecute 93 | shell.ShellExecute(prms*) 94 | 95 | ObjRelease(psv) 96 | } 97 | ObjRelease(ptlb) 98 | } 99 | } 100 | ;endregion ------------------------------ PRIVATE ------------------------------ 101 | } -------------------------------------------------------------------------------- /source/common/lib/selectLib.ahk: -------------------------------------------------------------------------------- 1 | ; Helper functions for dealing with selected text 2 | 3 | class SelectLib { 4 | ;region ------------------------------ PUBLIC ------------------------------ 5 | ;--------- 6 | ; DESCRIPTION: Get the selected text using the clipboard. 7 | ; RETURNS: The selected text. 8 | ;--------- 9 | getText() { 10 | return ClipboardLib.getWithHotkey("^c") 11 | } 12 | 13 | ;--------- 14 | ; DESCRIPTION: Get the first line of the selected text. 15 | ; RETURNS: The portion of the selected text before the first newline. 16 | ;--------- 17 | getFirstLine() { 18 | return ClipboardLib.getWithHotkey("^c").firstLine() 19 | } 20 | 21 | ;--------- 22 | ; DESCRIPTION: Get the first line of the selected text, cleaned. 23 | ; RETURNS: The cleaned first line of the selected text. 24 | ;--------- 25 | getCleanFirstLine() { 26 | return ClipboardLib.getWithHotkey("^c").firstLine().clean() 27 | } 28 | 29 | ;--------- 30 | ; DESCRIPTION: Select the current line of text. 31 | ;--------- 32 | selectCurrentLine() { 33 | ; Start with End as in some places, Home can put us in an inconsistent place relative to any 34 | ; indentation (i.e. hitting home when you're at the start of the line jumps to the start/end 35 | ; of the indentation). 36 | Send, {End}{Shift Down}{Home}{Shift Up} 37 | } 38 | 39 | ;--------- 40 | ; DESCRIPTION: Select the given text, within the currently selected block of text. 41 | ; PARAMETERS: 42 | ; needle (I,REQ) - The text to select. 43 | ;--------- 44 | selectTextWithinSelection(needle) { 45 | if(needle = "") 46 | return 47 | 48 | selectedText := SelectLib.getText() 49 | if(selectedText = "") 50 | return 51 | 52 | ; Determine where in the string our needle is 53 | needleStartPos := selectedText.contains(needle) 54 | if(!needleStartPos) 55 | return 56 | 57 | ; Debug.popup("io.selectTextWithinSelection","Finished processing", "Selection",selectedText, "Needle",needle, "Needle start position",needleStartPos, "Number of times to go right",numRight) 58 | Send, {Left} ; Get to start of selection. 59 | numRight := needleStartPos - 1 60 | Send, {Right %numRight%} ; Get to start of needle. 61 | Send, {Shift Down} 62 | needleLen := needle.length() 63 | Send, {Right %needleLen%} ; Select to end of needle. 64 | Send, {Shift Up} 65 | } 66 | ;endregion ------------------------------ PUBLIC ------------------------------ 67 | } 68 | -------------------------------------------------------------------------------- /source/common/program/ditto.ahk: -------------------------------------------------------------------------------- 1 | class Ditto { 2 | ;region ------------------------------ PUBLIC ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Force Ditto to save the current clipboard state as a clip. Useful when you want to 5 | ; add something to the clipboard history, but restore the current clipboard as well. 6 | ;--------- 7 | saveCurrentClipboard() { 8 | Send, ^!+c 9 | } 10 | ;endregion ------------------------------ PUBLIC ------------------------------ 11 | } 12 | -------------------------------------------------------------------------------- /source/common/program/emc2.ahk: -------------------------------------------------------------------------------- 1 | class EMC2 { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Insert a specific SmartText in the current field. 5 | ; PARAMETERS: 6 | ; smartTextName (I,REQ) - Name of the SmartText to insert. Should be part of the user's 7 | ; favorites as we pick the first one with a matching name. 8 | ; SIDE EFFECTS: Focuses the first "field" in the SmartText after inserting. 9 | ;--------- 10 | insertSmartText(smartTextName) { 11 | Send, ^{F10} 12 | WinWaitActive, SmartText Lookup 13 | Sleep, 500 14 | SendRaw, % smartTextName 15 | Send, {Enter} 16 | Sleep, 500 17 | Send, {Enter} 18 | 19 | WinWaitClose, SmartText Lookup 20 | Sleep, 500 ; EMC2 takes a while to get back to ready. 21 | Send, {F2} ; Focus the first "field" in the SmartText. 22 | } 23 | 24 | ;--------- 25 | ; DESCRIPTION: Insert a specific SmartPhrase and select the first element in it. 26 | ; PARAMETERS: 27 | ; phraseName (I,REQ) - The name of the phrase (to be sent with a . in front) 28 | ;--------- 29 | insertSmartPhrase(phraseName) { 30 | HotkeyLib.waitForRelease() ; Held-down keys mess with the SmartPhrase butler, so wait for them to be released first. 31 | Send, .%phraseName%{F2} ; Insert the SmartPhrase, selecting the first field inside 32 | } 33 | 34 | ;--------- 35 | ; DESCRIPTION: Use the right-click menu to launch the currently-selected worklist item in web. Useful because we 36 | ; don't have title information to pull from when we're in a worklist. 37 | ;--------- 38 | openCurrentWorklistItemWeb() { 39 | Send, {AppsKey} ; Right-click simulation 40 | Sleep, 100 ; Wait for right-click menu to appear 41 | Send, v{Enter} ; "View * as HTML", "View *", or "View * in Browser" are all the first "V" item in the menu 42 | return 43 | } 44 | 45 | ;--------- 46 | ; DESCRIPTION: Send a list of DBC developer TLGs to a grid column (for emailing designs out for reviewers). 47 | ;--------- 48 | sendDBCDevIDs() { 49 | IDs := Config.private["WORK_DBC_IDS"].split(",") 50 | IDs.removeFirstInstanceOf(Config.private["WORK_ID"]) ; Don't include myself, don't need to email myself separately. 51 | 52 | For _,id in IDs { 53 | SendRaw, % id 54 | Send, {Enter} 55 | } 56 | } 57 | ;endregion ------------------------------ INTERNAL ------------------------------ 58 | } 59 | -------------------------------------------------------------------------------- /source/common/program/excel.ahk: -------------------------------------------------------------------------------- 1 | class Excel { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: AutoFit the column widths for the entire sheet. 5 | ;--------- 6 | autoFixColumnWidth() { 7 | Send, ^a^a ; Select All (twice to get everything) 8 | Send, !hoi ; Home tab > Format > AutoFit Column Width 9 | } 10 | 11 | ;--------- 12 | ; DESCRIPTION: Bold the header row and freeze it. 13 | ;--------- 14 | boldFreezeHeaderRow() { 15 | Send, ^{Home} ; Get back to top-left cell 16 | Send, +{Space} ; Select full row 17 | Send, ^b ; Bold 18 | Send, !wfr ; View tab > Freeze Panes > Freeze Top Row 19 | } 20 | ;endregion ------------------------------ INTERNAL ------------------------------ 21 | } 22 | -------------------------------------------------------------------------------- /source/common/program/hyperspace.ahk: -------------------------------------------------------------------------------- 1 | class Hyperspace { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Determine whether any version of Hyperspace is active. 5 | ; RETURNS: true if a Hyperspace is active, false otherwise. 6 | ; NOTES: We can't use the Config.isWindowActive() here because the EXE is version- 7 | ; specific and we want to support any version. 8 | ;--------- 9 | isAnyVersionActive() { 10 | if(Config.isWindowActive("EMC2")) ; Don't count EMC2 towards this. 11 | return false 12 | 13 | if(WinActive("ahk_class ThunderRT6FormDC")) 14 | return true 15 | if(WinActive("ahk_class ThunderFormDC")) 16 | return true 17 | if(WinActive("ahk_class ThunderRT6MDIForm")) 18 | return true 19 | if(WinActive("ahk_class ThunderMDIForm")) 20 | return true 21 | 22 | return false 23 | } 24 | 25 | ;--------- 26 | ; DESCRIPTION: Log into Hyperspace with the provided username and password. 27 | ; PARAMETERS: 28 | ; username (I,REQ) - Username to log in with 29 | ; password (I,REQ) - Password to log in with 30 | ;--------- 31 | login(username, password) { 32 | ; Close the smart card login popup if it's open. 33 | if(WinActive("Smart Card Login")) 34 | Send, {Esc} 35 | 36 | Send, %username%{Tab} 37 | Send, %password%{Enter} 38 | HotkeyLib.releaseAllModifiers() 39 | 40 | Send, {Space} 41 | } 42 | ;endregion ------------------------------ INTERNAL ------------------------------ 43 | 44 | ;region ------------------------------ PRIVATE ------------------------------ 45 | ;--------- 46 | ; DESCRIPTION: Get the HTML from the current display in Hyperspace. 47 | ; RETURNS: The HTML from the current display in Hyperspace. 48 | ;--------- 49 | getCurrentDisplayHTML() { 50 | copyHTMLFunction := ObjBindMethod(Hyperspace, "copyDisplayHTML") 51 | return ClipboardLib.getWithFunction(copyHTMLFunction) 52 | } 53 | 54 | ;--------- 55 | ; DESCRIPTION: Copy the current display's HTML to the clipboard. 56 | ;--------- 57 | copyDisplayHTML() { 58 | ; Grab the HTML with HTMLGrabber hotkey. 59 | SendPlay, , ^!+c 60 | } 61 | ;endregion ------------------------------ PRIVATE ------------------------------ 62 | } 63 | -------------------------------------------------------------------------------- /source/common/program/internetExplorer.ahk: -------------------------------------------------------------------------------- 1 | class InternetExplorer { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | moveURLToDefaultBrowser(){ 4 | url := ControlGetText("Edit1", "A") ; Get URL from URL bar control 5 | if(!url) { 6 | Debug.toast("No URL found in Internet Explorer") 7 | return 8 | } 9 | 10 | WinClose ; Close the window 11 | Run, % url ; Open in default browser 12 | } 13 | 14 | pickF12Element() { 15 | if(!WindowLib.isVisible(this.F12DevToolsTitleString)) ; Apparently a non-visible window with this string can exist so we can't just check WinExist. 16 | firstTimeOpening := true 17 | 18 | Send, {F12} ; Open or switch to F12 Dev Tools 19 | WinWaitActive, % this.F12DevToolsTitleString 20 | 21 | if(firstTimeOpening) 22 | Sleep, 1000 ; Give it a few seconds to finish loading before we send stuff to it 23 | 24 | ; Make sure we're not focused on the toolbar - it doesn't accept hotkeys. 25 | if(ControlGetFocus("A") = this.ClassNN_F12DevToolsToolbar) 26 | Send, ^2 ; Focus Console tab 27 | Sleep, 100 28 | Send, ^1 ; Focus back to Dom Explorer tab - this should focus what's inside. 29 | 30 | Send, ^b ; Element picker hotkey 31 | } 32 | 33 | ;--------- 34 | ; DESCRIPTION: Open the file-type link under the mouse. 35 | ;--------- 36 | openLinkTarget() { 37 | path := ClipboardLib.getWithFunction(ObjBindMethod(InternetExplorer, "getLinkTargetOnClipboard")) 38 | if(path) { 39 | Toast.ShowShort("Got link target, opening:`n" path) 40 | Run(path) 41 | } else { 42 | Toast.ShowError("Failed to get link target") 43 | } 44 | } 45 | 46 | ;--------- 47 | ; DESCRIPTION: Copy the file-type link under the mouse, also showing the user a toast about it. 48 | ;--------- 49 | copyLinkTarget() { 50 | ClipboardLib.copyWithFunction(ObjBindMethod(InternetExplorer, "getLinkTargetOnClipboard")) 51 | ClipboardLib.toastNewValue("link target") 52 | } 53 | ;endregion ------------------------------ INTERNAL ------------------------------ 54 | 55 | ;region ------------------------------ PRIVATE ------------------------------ 56 | static F12DevToolsTitleString := "ahk_class F12FrameWindow ahk_exe IEXPLORE.EXE" 57 | static ClassNN_F12DevToolsToolbar := "Internet Explorer_Server8" 58 | 59 | ;--------- 60 | ; DESCRIPTION: Copy the target of the link under the mouse to the clipboard. 61 | ;--------- 62 | getLinkTargetOnClipboard() { 63 | Click, Right 64 | Sleep, 100 ; Wait for right-click menu to appear 65 | Send, t{Enter} ; Copy Shortcut 66 | } 67 | ;endregion ------------------------------ PRIVATE ------------------------------ 68 | } 69 | -------------------------------------------------------------------------------- /source/common/program/mBuilder.ahk: -------------------------------------------------------------------------------- 1 | class MBuilder { 2 | ;region ------------------------------ PUBLIC ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Run linting for the DLG found in the active window's title. 5 | ;--------- 6 | lintCurrentDLG() { 7 | record := EpicLib.getBestEMC2RecordFromText(WinGetActiveTitle()) 8 | if(record.ini != "DLG" || record.id = "") { 9 | Toast.ShowError("Could not open DLG in MBuilder", "Record ID was blank or was not a DLG ID") 10 | return 11 | } 12 | 13 | this.lintDLG(record.id) 14 | } 15 | 16 | ;--------- 17 | ; DESCRIPTION: Run linting for the given DLG's routines. 18 | ; PARAMETERS: 19 | ; dlgId (I,REQ) - DLG ID 20 | ;--------- 21 | lintDLG(dlgId) { 22 | if(!dlgId) { 23 | Toast.ShowError("Could not open DLG in MBuilder", "DLG ID was blank") 24 | return 25 | } 26 | 27 | Toast.ShowShort("Linting DLG in MBuilder: " dlgId) 28 | 29 | Run(Config.private["MBUILDER_URL_BASE"].replaceTags({"COMMAND":2, "ID":dlgId})) ; 2-Lint a DLG's Routines 30 | } 31 | ;endregion ------------------------------ PUBLIC ------------------------------ 32 | } -------------------------------------------------------------------------------- /source/common/program/mtPutty.ahk: -------------------------------------------------------------------------------- 1 | class MTPutty { 2 | ;region ------------------------------ PUBLIC ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Attach all orphaned PuTTY windows to the MTPutty window. 5 | ;--------- 6 | attachOrphanedPuttyWindows() { 7 | this.focusParentWindow() 8 | 9 | Send, ^+a ; Attach PuTTY session (configured in MTPutty) 10 | WinWaitActive, Attach, , 5 ; Wait up to 5s for the attach window to become active 11 | Send, {Tab 2} ; Tab to window list 12 | Send, {Home}{Shift Down}{End}{Shift Up} ; Select the whole thing 13 | Send, {Enter} ; Submit 14 | } 15 | 16 | ;--------- 17 | ; DESCRIPTION: Rename the tab to match its corresponding PuTTY window's window title. When you 18 | ; attach an orphaned window, it just uses the process ID as the tab title. 19 | ;--------- 20 | fixPuttyTabTitle() { 21 | this.focusParentWindow() 22 | Send, {F2} ; Launch the rename window 23 | Send, {Enter} ; Accept with blank value (restores default) 24 | 25 | ; Currently focus stays on the top-level window - the user can hit the ^` hotkey to get back to the 26 | ; tab, but for some reason AHK can't. 27 | } 28 | ;endregion ------------------------------ PUBLIC ------------------------------ 29 | 30 | ;region ------------------------------ PRIVATE ------------------------------ 31 | ;--------- 32 | ; DESCRIPTION: Focus the parent (top-level) window of MTPutty. This is the window that contains all the tabs. 33 | ;--------- 34 | focusParentWindow() { 35 | ; The first time this gets focus, it focuses its active child window - focusing it twice gets us to 36 | ; the actual top-level window. 37 | WindowActions.activateWindowByName("MTPutty") 38 | WindowActions.activateWindowByName("MTPutty") 39 | } 40 | ;endregion ------------------------------ PRIVATE ------------------------------ 41 | } 42 | -------------------------------------------------------------------------------- /source/common/program/notepadPlusPlus.ahk: -------------------------------------------------------------------------------- 1 | ; Notepad++ 2 | class NotepadPlusPlus { 3 | ;region ------------------------------ PUBLIC ------------------------------ 4 | 5 | openTempText(text) { 6 | ; Stick the text in a file 7 | tempPath := FileLib.writeToOldestTempFile(text) 8 | 9 | ; Open that file in Notepad++ 10 | Config.runProgram("Notepad++", tempPath) 11 | } 12 | ;endregion ------------------------------ PUBLIC ------------------------------ 13 | } 14 | -------------------------------------------------------------------------------- /source/common/program/onetastic.ahk: -------------------------------------------------------------------------------- 1 | class Onetastic { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Open the XML popup for the current macro or function. 5 | ;--------- 6 | openEditXMLPopup() { 7 | Send, !u ; Function 8 | Send, x ; Edit XML 9 | WinWaitActive, Edit XML 10 | } 11 | 12 | ;--------- 13 | ; DESCRIPTION: Copy the XML for the current macro or function. 14 | ;--------- 15 | copyCurrentXML() { 16 | Onetastic.openEditXMLPopup() 17 | xml := ControlGetText("Edit1", "A") 18 | 19 | ClipboardLib.set(xml) ; Can't use ClipboardLib.setAndToast() because we don't want to show all of the XML 20 | if(Clipboard = "") 21 | Toast.ShowError("Failed to get XML") 22 | else 23 | Toast.ShowMedium("Clipboard set to new XML") 24 | 25 | if(xml) 26 | Send, {Esc} ; Close the popup 27 | } 28 | ;endregion ------------------------------ INTERNAL ------------------------------ 29 | } 30 | -------------------------------------------------------------------------------- /source/common/program/putty.ahk: -------------------------------------------------------------------------------- 1 | class Putty { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ; IDM_RECONF, found in Putty's source code in window.c: https://github.com/codexns/putty/blob/master/windows/window.c 4 | static ChangeSettingsOption := 0x50 5 | 6 | ;--------- 7 | ; DESCRIPTION: Wipe the screen, optionally also clearing scrollback. 8 | ; PARAMETERS: 9 | ; clearScrollback (I,OPT) - Set to true to also clear scrollback. 10 | ;--------- 11 | wipeScreen(clearScrollback := false) { 12 | Send, !{Space} ; Open menu 13 | Send, t ; Reset terminal 14 | 15 | if(clearScrollback) { 16 | Send, !{Space} 17 | Send, l ; Clear scrollback 18 | } 19 | 20 | Sleep, 100 21 | Send, {Enter} ; Show prompt 22 | } 23 | 24 | ;--------- 25 | ; DESCRIPTION: Prompt for some text, then insert it (without overwriting) by inserting spaces. 26 | ;--------- 27 | insertArbitraryText() { 28 | ; Popup to get the text. 29 | textIn := InputBox("Insert text (without overwriting)", , , 500, 100) 30 | if(textIn = "") 31 | return 32 | 33 | ; Get the length of the string we're going to add. 34 | inputLength := textIn.length() 35 | 36 | ; Insert that many spaces. 37 | Send, {Insert %inputLength%} 38 | 39 | ; Actually send our input text. 40 | SendRaw, % textIn 41 | } 42 | 43 | ;--------- 44 | ; DESCRIPTION: Search within record edit screens with Home+F9 functionality. 45 | ; PARAMETERS: 46 | ; usePrevious (I,OPT) - Set to true to use the last search type/text instead of prompting the 47 | ; user. This is ignored if there was no last search type/text. 48 | ; SIDE EFFECTS: Sets Putty.LastSearch_* to whatever is chosen here for re-use later. 49 | ;--------- 50 | recordEditSearch(usePrevious := false) { 51 | ; Start with the last search type/text if requested. 52 | if(usePrevious) { 53 | searchType := Putty.LastSearch_Type 54 | searchText := Putty.LastSearch_Text 55 | } 56 | 57 | ; If no previous values (or not using them), prompt the user for how/what to search. 58 | if(searchType = "" || searchText = "") { 59 | data := new Selector("puttyRecordEditSearch.tls").prompt() 60 | searchType := data["SEARCH_TYPE"] 61 | searchText := data["SEARCH_TEXT"] 62 | } 63 | 64 | ; If still nothing, bail. 65 | if(searchType = "" || searchText = "") 66 | return 67 | 68 | ; Run the search. 69 | Send, {Home}{F9} 70 | Send, %searchType%{Enter} 71 | SendRaw, % searchText 72 | Send, {Enter} 73 | 74 | ; Store off the latest search for use with ^g later. 75 | Putty.LastSearch_Type := searchType 76 | Putty.LastSearch_Text := searchText 77 | } 78 | 79 | ;--------- 80 | ; DESCRIPTION: Open the Change Settings menu 81 | ;--------- 82 | openSettingsWindow() { 83 | PostMessage, MicrosoftLib.Message_WindowMenu, Putty.ChangeSettingsOption, 0 84 | } 85 | 86 | ;--------- 87 | ; DESCRIPTION: Open the current log file 88 | ;--------- 89 | openCurrentLogFile() { 90 | logFilePath := Putty.getLogFilePath() 91 | if(logFilePath) 92 | Run(logFilePath) 93 | } 94 | ;endregion ------------------------------ INTERNAL ------------------------------ 95 | 96 | ;region ------------------------------ PRIVATE ------------------------------ 97 | ; For Home+F9 searching repeatedly. 98 | static LastSearch_Type := "" 99 | static LastSearch_Text := "" 100 | 101 | ;--------- 102 | ; DESCRIPTION: Get the log file for the current Putty session via the settings window. 103 | ; RETURNS: The path to the log file 104 | ; SIDE EFFECTS: Temporarily opens the settings window, then closes it. 105 | ;--------- 106 | getLogFilePath() { 107 | if(!WinActive("ahk_class PuTTY")) 108 | return "" 109 | 110 | Putty.openSettingsWindow() 111 | 112 | ; Wait for the popup to show up 113 | WinWaitActive, ahk_class PuTTYConfigBox 114 | 115 | Send, !g ; Category pane 116 | Send, l ; Logging tree node 117 | Sleep, 500 118 | Send, !f ; Log file name field 119 | 120 | logFile := SelectLib.getText() 121 | 122 | Send, !c ; Cancel 123 | return logFile 124 | } 125 | ;endregion ------------------------------ PRIVATE ------------------------------ 126 | } 127 | -------------------------------------------------------------------------------- /source/common/program/telegram.ahk: -------------------------------------------------------------------------------- 1 | class Telegram { 2 | ;region ------------------------------ PUBLIC ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Share the provided URL to Telegram and focus the normal chat. 5 | ; PARAMETERS: 6 | ; url (I,REQ) - The URL to share. 7 | ;--------- 8 | shareURL(url) { 9 | launchURL := this.ShareURLBase.replaceTag("URL", url) 10 | Run(launchURL) 11 | 12 | WinWaitActive, % Config.windowInfo["Telegram"].idString 13 | Sleep, 500 ; Give the share faux-popup time to appear. 14 | 15 | Send, {Down 2}{Enter} ; Select my target chat (the "Normal" one). 16 | } 17 | ;endregion ------------------------------ PUBLIC ------------------------------ 18 | 19 | ;region ------------------------------ INTERNAL ------------------------------ 20 | ;--------- 21 | ; DESCRIPTION: Focus the "Normal" chat that's the only one I use in Telegram. 22 | ;--------- 23 | focusNormalChat() { 24 | Send, ^1 25 | } 26 | ;endregion ------------------------------ INTERNAL ------------------------------ 27 | 28 | ;region ------------------------------ PRIVATE ------------------------------ 29 | ; Shares the given URL to telegram desktop, prompting you to pick a chat. 30 | static ShareURLBase := "tg://msg_url?url=" 31 | ;endregion ------------------------------ PRIVATE ------------------------------ 32 | } 33 | -------------------------------------------------------------------------------- /source/common/program/visualStudio.ahk: -------------------------------------------------------------------------------- 1 | class VisualStudio { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Send code to show a popup (in a ViewBehavior in TypeScript). 5 | ; PARAMETERS: 6 | ; defaultVarList (I,OPT) - The default list of variables to use, shows in the popup. 7 | ;--------- 8 | sendDebugCodeStringTS(defaultVarList := "") { 9 | varList := InputBox("Enter variables to send debug string for", , , 500, 100, , , , , defaultVarList) 10 | if(ErrorLevel) ; Popup was cancelled or timed out 11 | return 12 | 13 | mainTemplate := " 14 | ( LTrim 15 | $$(this).alert("""" 16 | 17 | `); 18 | )" 19 | lineTemplate := "+ ""\n"" + "": "" + " 20 | 21 | if(varList = "") { 22 | line := lineTemplate.replaceTag("VAR", "todo") 23 | code := mainTemplate.replaceTag("LINES", line) 24 | ClipboardLib.send(code) 25 | 26 | ; Select the "todo" label on the only line for the user to replace 27 | Send, {Left 2}{Up}{Right 11}{Shift Down}{Right 4}{Shift Up} 28 | 29 | } else { 30 | lines := "" 31 | For _,varName in varList.split(",", " ") { 32 | lines := lines.appendLine(lineTemplate.replaceTag("VAR", varName)) 33 | } 34 | 35 | code := mainTemplate.replaceTag("LINES", lines) 36 | ClipboardLib.send(code) 37 | } 38 | } 39 | ;endregion ------------------------------ INTERNAL ------------------------------ 40 | 41 | ;region ------------------------------ PRIVATE ------------------------------ 42 | ; Hotkeys 43 | static Hotkey_CopyCurrentFile := "^+c" 44 | ;endregion ------------------------------ PRIVATE ------------------------------ 45 | } 46 | -------------------------------------------------------------------------------- /source/common/program/zoom.ahk: -------------------------------------------------------------------------------- 1 | class Zoom { 2 | ;region ------------------------------ INTERNAL ------------------------------ 3 | ;--------- 4 | ; DESCRIPTION: Swap between gallery and speaker views. 5 | ;--------- 6 | toggleView() { 7 | if(this.isGalleryView) 8 | this.switchToSpeakerView() 9 | else 10 | this.switchToGalleryView() 11 | } 12 | 13 | ;--------- 14 | ; DESCRIPTION: Swap to specific views. 15 | ;--------- 16 | switchToSpeakerView() { 17 | Send, % this.Hotkey_SpeakerView 18 | this.isGalleryView := false 19 | } 20 | switchToGalleryView() { 21 | Send, % this.Hotkey_GalleryView 22 | this.isGalleryView := true 23 | } 24 | ;endregion ------------------------------ INTERNAL ------------------------------ 25 | 26 | ;region ------------------------------ PRIVATE ------------------------------ 27 | static isGalleryView := true ; Most rooms I frequent start in gallery view. 28 | 29 | ; Hotkeys configured in Zoom 30 | static Hotkey_SpeakerView := "!{F1}" 31 | static Hotkey_GalleryView := "!{F2}" 32 | 33 | ;endregion ------------------------------ PRIVATE ------------------------------ 34 | } 35 | -------------------------------------------------------------------------------- /source/common/static/enums.ahk: -------------------------------------------------------------------------------- 1 | ; This script holds classes representing enumerations of constants. 2 | 3 | ; Text alignment 4 | class TextAlignment { 5 | ;region ------------------------------ PUBLIC ------------------------------ 6 | ;region Text alignment options 7 | static Left := "LEFT" ; The title must start with the string. 8 | static Right := "RIGHT" ; The title may contain the string anywhere inside. 9 | static Center := "CENTER" ; The title must exactly equal the string. 10 | ;endregion Text alignment options 11 | ;endregion ------------------------------ PUBLIC ------------------------------ 12 | } 13 | -------------------------------------------------------------------------------- /source/common/static/titleMatchMode.ahk: -------------------------------------------------------------------------------- 1 | ; The title match mode 2 | class TitleMatchMode { 3 | ;region ------------------------------ PUBLIC ------------------------------ 4 | ;region Title match mode options 5 | static Start := 1 ; The title must start with the string. 6 | static Contains := 2 ; The title may contain the string anywhere inside. 7 | static Exact := 3 ; The title must exactly equal the string. 8 | static RegEx := "RegEx" ; The title must match the provided regex. 9 | ;endregion Title match mode options 10 | 11 | ;--------- 12 | ; DESCRIPTION: Map a set of string values, to the actual numeric values that will work with SetTitleMatchMode. 13 | ; PARAMETERS: 14 | ; stringMode (I,REQ) - String version of any match mode (see .MatchModeString_*). 15 | ; RETURNS: Value from TitleMatchMode.* that can be used with SetTitleMatchMode. 16 | ;--------- 17 | convertFromString(stringMode) { 18 | Switch stringMode { 19 | Case this.MatchModeString_Start: return this.Start 20 | Case this.MatchModeString_Contains: return this.Contains 21 | Case this.MatchModeString_Exact: return this.Exact 22 | Case this.MatchModeString_RegEx: return this.RegEx 23 | } 24 | } 25 | 26 | ;--------- 27 | ; DESCRIPTION: Check whether the two strings match, taking the given titleMatchMode into account. 28 | ; PARAMETERS: 29 | ; haystack (I,REQ) - The first string, that we want to check for a match 30 | ; needle (I,REQ) - The value to search for (first string should contain/start with/equal/match this regex) 31 | ; matchMode (I,REQ) - The match mode to use, from TitleMatchMode.* 32 | ; RETURNS: true/false - do the titles match? 33 | ;--------- 34 | matches(haystack, needle, matchMode) { 35 | Switch matchMode { 36 | Case TitleMatchMode.Start: return haystack.startsWith(needle) 37 | Case TitleMatchMode.Contains: return (haystack.contains(needle) > 0) 38 | Case TitleMatchMode.Exact: return (haystack = needle) 39 | Case TitleMatchMode.RegEx: return (haystack.matchesRegEx(needle) > 0) 40 | } 41 | } 42 | ;endregion ------------------------------ PUBLIC ------------------------------ 43 | 44 | ;region ------------------------------ PRIVATE ------------------------------ 45 | ; String versions of the match modes, for use in places that we can't use the constants at the top. 46 | static MatchModeString_Start := "START" 47 | static MatchModeString_Contains := "CONTAINS" 48 | static MatchModeString_Exact := "EXACT" 49 | static MatchModeString_RegEx := "REGEX" 50 | ;endregion ------------------------------ PRIVATE ------------------------------ 51 | } -------------------------------------------------------------------------------- /source/firstSetup.ahk: -------------------------------------------------------------------------------- 1 | ; Set up my various AHK scripts for the first time (basically an "install") and launch my main script. 2 | 3 | #Include %A_ScriptDir%\common\common.ahk 4 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 5 | progToast := new ProgressToast("First-time setup") 6 | 7 | ; Various paths needed throughout. 8 | ahkRootPath := FileLib.getParentFolder(A_ScriptDir, 1) 9 | userPath := EnvGet("HOMEDRIVE") EnvGet("HOMEPATH") 10 | startupFolder := ahkRootPath "\source" 11 | mainAHKPath := startupFolder "\main.ahk" 12 | 13 | ; Check for command line arguments - which machine to use, and whether to suppress the "run now?" prompt. 14 | machineChoice := A_Args[1] 15 | useSlimMode := A_Args[2] 16 | 17 | ; Settings INI file 18 | progToast.nextStep("Settings file") 19 | machineInfo := selectSettings(machineChoice) 20 | if(!machineInfo) 21 | ExitApp 22 | iniPath := ahkRootPath "\config\settings.ini" 23 | IniWrite(iniPath, "Main", "CONTEXT", machineInfo["NEW_CONTEXT"]) 24 | IniWrite(iniPath, "Main", "MACHINE", machineInfo["NEW_MACHINE"]) 25 | 26 | ; Library pointer script 27 | progToast.nextStep("Library pointer script") 28 | pointerContents := " 29 | ( LTrim 30 | ; This acts as a pointer that any file can find, which points to the correct location of the common folder and its scripts. 31 | #Include " ahkRootPath "\source\common\common.ahk 32 | )" 33 | includeLibFolder := A_MyDocuments "\AutoHotkey\Lib" 34 | if(!FileLib.createFolderIfNoExist(includeLibFolder, true)) { 35 | Toast.ShowError("AHK documents lib folder doesn't exist and we couldn't create it.") 36 | ExitApp 37 | } 38 | FileLib.replaceFileWithString(includeLibFolder "\includeCommon.ahk", pointerContents) 39 | 40 | if(!useSlimMode) { 41 | ; Hide all .git system files and folders, for a cleaner appearance. 42 | progToast.nextStep("Hiding .git files and folders") 43 | For _,name in [".git", ".gitignore", ".gitattributes"] { 44 | Loop, Files, %ahkRootPath%\*%name%, RDF 45 | { 46 | FileSetAttrib, +H, %A_LoopFileFullPath% 47 | } 48 | } 49 | } 50 | 51 | progToast.finish() 52 | 53 | ; In slim mode, make sure any old instances are closed before running new ones. 54 | if(useSlimMode) { 55 | ; From https://www.autohotkey.com/board/topic/77272-close-all-ahk-scripts-except-one/ 56 | For process in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process where name LIKE 'Autohotkey%.exe' and not CommandLine like '%" "firstSetup.ahk" "%' ") 57 | Process, Close, % process.ProcessId 58 | } 59 | 60 | if(useSlimMode || GuiLib.showConfirmationPopup("Run now?")) 61 | Run(mainAHKPath, startupFolder) 62 | 63 | ExitApp 64 | 65 | ; Use a Selector to key into the settings we need. 66 | selectSettings(machineChoice) { 67 | s := new Selector().setTitle("Select Machine to set up:") 68 | s.addChoice(new SelectorChoice({ NAME:"Home Desktop" , ABBREV:["desk", "HOME_DESKTOP"], NEW_CONTEXT:"HOME", NEW_MACHINE:"HOME_DESKTOP" })) 69 | s.addChoice(new SelectorChoice({ NAME:"Home Laptop" , ABBREV:["hlap", "HOME_LAPTOP" ], NEW_CONTEXT:"HOME", NEW_MACHINE:"HOME_DESKTOP" })) 70 | s.addChoice(new SelectorChoice({ NAME:"Work Desktop" , ABBREV:["work", "WORK_DESKTOP"], NEW_CONTEXT:"WORK", NEW_MACHINE:"WORK_DESKTOP" })) 71 | s.addChoice(new SelectorChoice({ NAME:"Work VDI" , ABBREV:["vdi" , "WORK_VDI" ], NEW_CONTEXT:"WORK", NEW_MACHINE:"WORK_VDI" })) 72 | return s.select(machineChoice) 73 | } -------------------------------------------------------------------------------- /source/general/media.ahk: -------------------------------------------------------------------------------- 1 | ; Up and down at an interval. 2 | #PgUp::Send {Volume_Up 5} 3 | #PgDn::Send {Volume_Down 5} 4 | 5 | ; Toggle Mute. 6 | #Enter:: 7 | toggleMute() { 8 | SoundSet, +1, , MUTE 9 | if(SoundGet("", "MUTE") = "On") 10 | muteMessage := "Volume muted" 11 | else 12 | muteMessage := "Volume unmuted" 13 | Toast.ShowMedium(muteMessage) 14 | } 15 | 16 | ; Media control 17 | ^!Down:: Send, {Media_Play_Pause} 18 | ^!Left:: Send, {Media_Prev} 19 | ^!Right::Send, {Media_Next} 20 | ^!Up:: 21 | Media_Stop:: 22 | Config.runProgram("Spotify") 23 | return 24 | -------------------------------------------------------------------------------- /source/general/places.ahk: -------------------------------------------------------------------------------- 1 | ; Hotkeys for opening different locations, both local (folders) and remote (URLs). 2 | 3 | ; Specific folders 4 | !+a::openPath("AHK_ROOT") 5 | $!+d::openPath("USER_DOWNLOADS") ; $ because otherwise it conflicts with our Deluminate site-specific toggle hotkey in Chrome 6 | !+o::openPath("USER_ONEDRIVE") 7 | !+u::openPath("USER_ROOT") 8 | !+s::openPath("EPIC_SOURCE_S1_BILL_SOLUTIONS") 9 | openPath(folderName) { 10 | folderPath := Config.path[folderName] 11 | if(FileLib.folderExists(folderPath)) 12 | Run(folderPath) 13 | } 14 | 15 | ; Open folder from list 16 | !+w:: 17 | selectFolder() { 18 | folderPaths := new Selector("folders.tls").setIcon(Config.getProgramPath("Explorer")).promptMulti("PATH") 19 | For _, path in folderPaths { 20 | path := Config.replacePathTags(path) 21 | path := DateTimeLib.replaceTags(path) ; For any date/time-based folder paths, use the current date/time. 22 | 23 | ; If the folder doesn't exist, try to create it (with permission from user) 24 | if(!FileLib.folderExists(path)) { 25 | if(!FileLib.folderExists(FileLib.getParentFolder(path))) { 26 | Toast.ShowError("Could not open chosen folder", "Neither the folder nor its parent folder exist.") 27 | return ; Not going to try creating if not even the parent exists. 28 | } 29 | 30 | if(GuiLib.showConfirmationPopup("This folder does not exist:`n" path "`n`nCreate it?", "Folder does not exist")) 31 | FileCreateDir, % path 32 | } 33 | if(FileLib.folderExists(path)) 34 | Run(path) 35 | } 36 | } 37 | 38 | ; Send cleaned-up path (remove odd garbage from around path, switch to mapped network drives) 39 | !+p:: sendCleanedUpPath() 40 | !+#p::sendCleanedUpPath(true) ; Force Unix path 41 | sendCleanedUpPath(mapToUnix := false) { 42 | path := FileLib.cleanupPath(clipboard) 43 | 44 | if(mapToUnix) 45 | path := FileLib.mapWindowsPathToUnix(path) 46 | 47 | SendRaw, % path 48 | } 49 | 50 | ; Selector to allow easy editing of config or code files that we edit often 51 | !+c:: 52 | selectEditFile() { 53 | filePaths := new Selector("editFiles.tls").setIcon(Config.getProgramPath("VSCode")).promptMulti("PATH") 54 | For _, path in filePaths { 55 | path := Config.replacePathTags(path) 56 | if(!FileExist(path)) { 57 | Toast.ShowError("Script does not exist: " path) 58 | return 59 | } 60 | 61 | VSCode.editScript(path) 62 | } 63 | } 64 | 65 | 66 | ;region Websites 67 | ^!+f:: Run("http://feedly.com/i/latest") 68 | ^!+m:: Config.runProgram("Gmail") 69 | ^!+#m::Config.runProgram("Messenger") 70 | ^!+a:: 71 | openUsualSites() { 72 | Config.runProgram("Gmail") 73 | Sleep, 100 74 | Run("https://lemmy.world/") 75 | Sleep, 100 76 | Run("http://feedly.com/i/latest") 77 | } 78 | 79 | ; OneNote Online 80 | !+t::Run(Config.private["ONENOTE_ONLINE_NOTEBOOK_DO"]) 81 | ;endregion Websites 82 | -------------------------------------------------------------------------------- /source/general/programs.ahk: -------------------------------------------------------------------------------- 1 | ; Hotkeys to run/activate various programs. 2 | 3 | !`:: Config.runProgram("Process Explorer") 4 | #b:: Config.runProgram("Beeper") 5 | #e:: Config.activateProgram("Explorer", Explorer.ThisPCFolderUUID) ; Start up at "This PC" folder if we have to run it. 6 | #s:: Config.runProgram("Slack") 7 | #p:: Config.activateProgram("MTPutty") 8 | ^!+g::Config.activateProgram("Chrome") 9 | ^!+n::Config.activateProgram("Notepad++") 10 | ^!+t::Config.activateProgram("TickTick") 11 | ^!#t::Config.runProgram("Teams") 12 | ^!#v::Config.runProgram("VSCode", "--profile Default") 13 | ^!#/::Config.activateProgram("AutoHotkey WinSpy") 14 | 15 | ; Some programs are work-specific 16 | #If Config.contextIsWork 17 | ^!+e:: Config.activateProgram("EMC2", "EMC2Update env=TRACKAPPTCP") ; EMC2 needs these parameters to start up correctly. 18 | ^!+s:: Config.activateProgram("EpicStudio") 19 | ^!+u:: Config.activateProgram("Thunder") 20 | ^!#+v::Config.runProgram("Visual Studio") 21 | #If 22 | 23 | ; Some programs are only available on specific machines 24 | #If Config.machineIsHomeDesktop 25 | ^!#f:: 26 | ; Safety check for VPN 27 | if(Config.doesWindowExist("Cisco VPN")) { 28 | MsgBox, VPN running! 29 | return 30 | } 31 | Config.runProgram("Firefox Portable") 32 | return 33 | #If Config.machineIsHomeDesktop || Config.machineIsWorkDesktop || Config.machineIsHomeLaptop 34 | #f:: Config.activateProgram("Everything") 35 | #t:: Config.runProgram("Telegram") 36 | ^!+o::Config.activateProgram("OneNote") 37 | ^!#g::Config.activateProgram("GitHub Desktop") 38 | #If Config.machineIsWorkDesktop 39 | ^!#e::Config.activateProgram("Outlook") 40 | #If 41 | 42 | ; Open up a temporary file in Notepad++ as a scratchpad. 43 | ^!#n::NotepadPlusPlus.openTempText("") ; Blank to clear it out 44 | -------------------------------------------------------------------------------- /source/general/selection.ahk: -------------------------------------------------------------------------------- 1 | ; Actions taken using the currently-selected text. 2 | 3 | ; Search 4 | !+f::SearchLib.selectedTextPrompt() 5 | 6 | ; Turn the selected text into a link to the URL on the clipboard. 7 | ^+k:: 8 | linkSelectedText() { 9 | HotkeyLib.waitForRelease() 10 | if(!Hyperlinker.linkSelectedText(Clipboard, errorMessage)) 11 | Toast.ShowError("Failed to link selected text", errorMessage) 12 | } 13 | 14 | ; Open - open a variety of different things based on the selected text. 15 | ^!#o:: new ActionObject(SelectLib.getText()).openWeb() 16 | ^!#+o::new ActionObject(SelectLib.getText()).openEdit() 17 | 18 | ; Copy link - copy links to a variety of different things based on the selected text. 19 | ^!#l:: new ActionObject(SelectLib.getText()).copyLinkWeb() 20 | ^!#+l::new ActionObject(SelectLib.getText()).copyLinkEdit() 21 | 22 | ; Hyperlink - get link based on the selected text and then apply it to that same text. 23 | ^!#k:: new ActionObject(SelectLib.getText()).linkSelectedTextWeb() 24 | ^!#+k::new ActionObject(SelectLib.getText()).linkSelectedTextEdit() 25 | 26 | ; Grab the selected text and pop it into a new Notepad++ window 27 | !#v:: 28 | selectedTextToNotepad() { 29 | ; Check physical state so we can tell the difference between the keys being pressed vs. sent by keyboard macros. 30 | if(!GetKeyState("v", "P")) 31 | return 32 | 33 | ; Get the selected text to use 34 | selectedText := SelectLib.getText() 35 | if(selectedText = "") 36 | return 37 | 38 | ; Open it up in Notepad++ 39 | NotepadPlusPlus.openTempText(selectedText) 40 | } 41 | -------------------------------------------------------------------------------- /source/general/system.ahk: -------------------------------------------------------------------------------- 1 | ; System-level hotkeys and overrides. 2 | 3 | ;region Lock/suspend 4 | ; Call the Windows API function "SetSuspendState" to have the system suspend or hibernate. 5 | ; Parameter #1: Pass 1 instead of 0 to hibernate rather than suspend. 6 | ; Parameter #2: Pass 1 instead of 0 to suspend immediately rather than asking each application for permission. 7 | ; Parameter #3: Pass 1 instead of 0 to disable all wake events. 8 | ~^!+#s::DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0) 9 | 10 | ; Alternate lock computer hotkeys 11 | +#l::DllCall("LockWorkStation") 12 | #If Config.machineIsHomeDesktop 13 | $Volume_Mute::DllCall("LockWorkStation") 14 | #If 15 | ;endregion Lock/suspend 16 | 17 | ;region Keyboard mapping 18 | #If Config.machineIsWorkDesktop || Config.machineIsWorkVDI 19 | ; Extra buttons on the ergonomic keyboard as left/right clicks (disable them in MS mouse and keyboard) 20 | Browser_Back:: HotkeyLib.sendCatchableKeys("{LButton}") 21 | Browser_Forward::HotkeyLib.sendCatchableKeys("{RButton}") 22 | #If Config.machineIsHomeLaptop || Config.machineIsWorkDesktop || Config.machineIsWorkVDI 23 | AppsKey::RWin ; No right windows key on these machines, so use the AppsKey (right-click key) instead. 24 | #If 25 | ;endregion Keyboard mapping 26 | 27 | ;region Special hotkey handling 28 | ; Release all modifier keys, for cases when some might be "stuck" down. 29 | *#Space::HotkeyLib.releaseAllModifiers() 30 | 31 | ; CapsLock is used by various other hotkeys, so this is the only way to actually use it as CapsLock. 32 | ^!CapsLock::SetCapsLockState, On 33 | 34 | ; Disable various Windows hotkeys I don't want. 35 | #=:: ; Magnifier 36 | #-:: 37 | return 38 | ;endregion Special hotkey handling 39 | 40 | ; GDB TODO window cache debug issue 41 | ^+!0::testFunc() 42 | testFunc() { 43 | Config.debugOn := !Config.debugOn 44 | MsgBox, % "Config debug flag set to: " Config.debugOn 45 | } 46 | ^+!9::testSearch() 47 | testSearch() { 48 | Config.findWindowInfo("A") 49 | } -------------------------------------------------------------------------------- /source/general/text.ahk: -------------------------------------------------------------------------------- 1 | ; Hotkeys for getting/sending and manipulating text. 2 | 3 | ; Populate the clipboard from an input box. 4 | !v:: 5 | setClipboard() { 6 | text := InputBox("Set clipboard", "Enter text to set the clipboard to:") 7 | if (text) 8 | ClipboardLib.setAndToast(text, "value") 9 | } 10 | 11 | ; Send clipboard as plain text. 12 | ^!v:: 13 | HotkeyLib.waitForRelease() 14 | Send, {Text}%Clipboard% 15 | return 16 | 17 | ; Send a (newline-separated) text/URL combo from the clipboard as a link. 18 | ^+#k:: 19 | sendLinkedTextFromClipboard() { 20 | HotkeyLib.waitForRelease() 21 | 22 | value := clipboard.replace("`r`n", "`n") ; Replace `r`n with just `n to avoid counting/highlighting mishaps 23 | text := value.beforeString("`n") 24 | url := value.afterString("`n") 25 | 26 | ; Send and select the text 27 | ClipboardLib.send(text) 28 | textLen := text.length() 29 | Send, {Shift Down}{Left %textLen%}{Shift Up} 30 | 31 | if(!Hyperlinker.linkSelectedText(url, errorMessage)) 32 | Toast.ShowError("Failed to link text", errorMessage) 33 | } 34 | 35 | ; Send the clipboard as a list. 36 | ^#v::new FormattedList(Clipboard).sendList() 37 | 38 | ; Send specific symbols 39 | #`;:: 40 | selectSymbols() { 41 | symbols := new Selector("symbols.tls").promptMulti("CHAR") 42 | For _, symbol in symbols 43 | Send, % symbol 44 | } 45 | -------------------------------------------------------------------------------- /source/general/window.ahk: -------------------------------------------------------------------------------- 1 | ; Consistent hotkeys that do the same basic thing for various windows, but sometimes in a slightly different way. 2 | 3 | ; Select all with special per-window handling. 4 | $^a::WindowActions.selectAll() 5 | 6 | ; Backspace shortcut for those that don't handle it well. 7 | $^Backspace::WindowActions.deleteWord() 8 | 9 | ; Escape key will generally minimize or close things. 10 | ~Escape:: 11 | if(Config.debugOn) ; GDB TODO window cache debug issue 12 | MsgBox, Escaping! 13 | WindowActions.escAction() 14 | KeyWait, Esc, T1 ; Ensures that we don't have fall-through window closing. 15 | return 16 | 17 | ; When escape key is useful but is being used to minimize/close things, use backtick as a replacement. 18 | $`::WindowActions.backtickAction() 19 | 20 | ; Minimizing shortcut. 21 | $!q::WindowActions.minimizeWindow() 22 | 23 | ; Sets current window to stay on top 24 | #+t:: 25 | toggleAlwaysOnTop() { 26 | WinSet, AlwaysOnTop, Toggle, A 27 | if(WindowLib.isAlwaysOnTop("A")) 28 | Toast.ShowMedium("Window set to always on top").setParent("A") 29 | else 30 | Toast.ShowMedium("Window set to NOT always on top").setParent("A") 31 | } 32 | 33 | ; Center current window onscreen. 34 | #+c::WindowLib.center() 35 | 36 | ; Resize window 37 | #+r:: 38 | selectResize() { 39 | if(WindowLib.isNoMoveSizeWindow("A")) { 40 | Toast.ShowError("Invalid window for resizing") 41 | return 42 | } 43 | 44 | data := new Selector("resize.tls").prompt() 45 | if(!data) 46 | return 47 | 48 | new VisualWindow("A").resizeMove(data["WIDTH"], data["HEIGHT"], VisualWindow.X_Centered, VisualWindow.Y_Centered) ; Always center resized window 49 | } 50 | 51 | ; "Fix" window position and size to match configuration TL 52 | #+f::WindowPositions.fixWindow() ; Active window 53 | ^#+f::WindowPositions.fixAllWindows() 54 | 55 | ; Scroll horizontally with Shift held down. 56 | #If !(Config.isWindowActive("EpicStudio") || Config.isWindowActive("Chrome")) ; Chrome and EpicStudio handle their own horizontal scrolling, and doesn't support WheelLeft/Right all the time. 57 | +WheelUp::WheelLeft 58 | +WheelDown::WheelRight 59 | #If 60 | 61 | ; Use the extra mouse buttons to switch tabs in various programs 62 | #If !Config.isWindowActive("Remote Desktop") && !Config.isWindowActive("VMware Horizon Client") && !WinActive("ahk_exe HaloInfinite.exe") 63 | XButton1::activateWindowUnderMouseAndSendKeys("^{Tab}") 64 | XButton2::activateWindowUnderMouseAndSendKeys("^+{Tab}") 65 | activateWindowUnderMouseAndSendKeys(keys) { 66 | idString := WindowLib.getIdTitleStringUnderMouse() 67 | 68 | ; Ignore Windows taskbars entirely. 69 | if(Config.windowInfo["Windows Taskbar"].windowMatches(idString)) 70 | return 71 | if(Config.windowInfo["Windows Taskbar Secondary"].windowMatches(idString)) 72 | return 73 | 74 | WinActivate, % idString 75 | 76 | HotkeyLib.sendCatchableKeys(keys) 77 | } 78 | #If 79 | -------------------------------------------------------------------------------- /source/main.ahk: -------------------------------------------------------------------------------- 1 | ; All scripts with Unicode characters in them should be saved in UTF-8-BOM encoding, so that any Unicode characters inside them are handled appropriately (per https://www.autohotkey.com/docs/FAQ.htm#nonascii ). 2 | 3 | #Warn All ; Show warnings, except for: 4 | #Warn UseUnsetLocal, Off ; Using local variables before they're set (using default values in a function triggers this) 5 | #Warn UseUnsetGlobal, Off ; Using global variables before they're set 6 | #Hotstring * ; Default option: hotstrings do not require an ending character. Use *0 to turn it off for hotstrings that as needed. 7 | 8 | #Include 9 | ScriptTrayInfo.Init("AHK: Main Script", "shellGreen.ico", "shellRed.ico") 10 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Main) 11 | 12 | SetWorkingDir, %A_ScriptDir% ; Ensures a consistent starting directory. 13 | DetectHiddenWindows, On ; Do search hidden windows 14 | SetTitleMatchMode, % TitleMatchMode.Contains ; Match text anywhere inside window titles 15 | SetCapsLockState, AlwaysOff ; Turn off Caps Lock so it can be used as a hotkey. Keep these three lock states in sync with afterUnsuspend() below. 16 | SetScrollLockState, AlwaysOff ; Turn off Scroll Lock so it can be used as a hotkey. 17 | SetNumLockState, AlwaysOn ; Force NumLock to always stay on. 18 | SetDefaultMouseSpeed, 0 ; Fasted mouse speed for mouse commands (MouseMove in particular) 19 | SetMouseDelay, 0 ; Smallest possible delay after mouse movements/clicks 20 | FileEncoding, UTF-8 ; Read files using UTF-8 encoding by default. 21 | 22 | ; Sub scripts. Must be first to execute so they can spin off and be on their own. 23 | subFolder := A_ScriptDir "\sub\" 24 | Run(subFolder "vimBindings.ahk") 25 | Run(subFolder "windowMoverSizer.ahk") 26 | 27 | ; Include other scripts 28 | ;region General hotkeys 29 | #Include %A_ScriptDir%\general\ 30 | #Include epic.ahk 31 | #Include hotstrings.ahk ; Must go after startup, but before hotkeys begin. 32 | #Include media.ahk 33 | #Include places.ahk 34 | #Include programs.ahk 35 | #Include selection.ahk 36 | #Include system.ahk 37 | #Include text.ahk 38 | #Include window.ahk 39 | ;endregion General hotkeys 40 | ;region Program-specific hotkeys 41 | #Include %A_ScriptDir%\program\ 42 | #Include chrome.ahk 43 | #Include ciscoVPN.ahk 44 | #Include ditto.ahk 45 | #Include emc2.ahk 46 | #Include epicStudio.ahk 47 | #Include everything.ahk 48 | #Include excel.ahk 49 | #Include explorer.ahk 50 | #Include fastStoneImageViewer.ahk 51 | #Include hyperdrive.ahk 52 | #Include hyperspace.ahk 53 | #Include internetExplorer.ahk 54 | #Include kdiff.ahk 55 | #Include launchy.ahk 56 | #Include notepadPlusPlus.ahk 57 | #Include onenote.ahk 58 | #Include onetastic.ahk 59 | #Include outlook.ahk 60 | #Include powerpoint.ahk 61 | #Include putty.ahk 62 | #Include remoteDesktop.ahk 63 | #Include snapper.ahk 64 | #Include spotify.ahk 65 | #Include sumatraPDF.ahk 66 | #Include teams.ahk 67 | #Include telegram.ahk 68 | #Include tortoise.ahk 69 | #Include visualStudio.ahk 70 | #Include vsCode.ahk 71 | #Include wilma.ahk 72 | #Include winMerge.ahk 73 | #Include word.ahk 74 | #Include zoom.ahk 75 | ;endregion Program-specific hotkeys 76 | 77 | ; Before/after suspend hooks to allow *Lock keys to be hotkeys or ignored while script is active, 78 | ; but back to normal when script is suspended. 79 | beforeSuspend() { 80 | SetCapsLockState, Off 81 | SetScrollLockState, Off 82 | SetNumLockState, On 83 | } 84 | afterUnsuspend() { 85 | SetCapsLockState, AlwaysOff 86 | SetScrollLockState, AlwaysOff 87 | SetNumLockState, AlwaysOn 88 | } 89 | -------------------------------------------------------------------------------- /source/program/chrome.ahk: -------------------------------------------------------------------------------- 1 | ; Google Chrome hotkeys. 2 | #If Config.isWindowActive("Chrome") 3 | ; Block "close all tabs" hotkey 4 | ^+w::return 5 | 6 | ; Extensions hotkey. 7 | ^+e:: 8 | Send, !e ; Main hamburger menu 9 | Sleep, 100 10 | Send, e{Enter} ; Extensions submenu 11 | Send, {Enter} ; Manage extensions 12 | return 13 | 14 | ; Handling for file links 15 | ^RButton::Chrome.copyLinkTarget() ; Copy 16 | ^MButton::Chrome.openLinkTarget() ; Open 17 | 18 | ; Send page to IE/Edge 19 | ^+s::Config.runProgram("Internet Explorer", Chrome.getURL()) 20 | 21 | ^!d::Send, !+d ; Deluminate - site-level hotkey (Chrome won't let me bind this directly) 22 | 23 | ; LastPass loses all settings when it updates periodically, so I'm overriding the hotkeys here instead. 24 | !PgDn::!PgUp ; Reverse next/previous site hotkeys 25 | !PgUp::!PgDn 26 | !+l::Run("https://lastpass.com/vault/") ; Just launch this directly, instead of relying on the extension being able to run on the current page. 27 | 28 | ; Chrome hotkeys that do not apply in Hyperspace. 29 | #If Config.isWindowActive("Chrome") && !Config.isWindowActive("Chrome Hyperspace") 30 | ; Options hotkey. 31 | !o:: 32 | HotkeyLib.waitForRelease() ; Presumably needed because the triggering hotkey has alt in it. 33 | Send, !e ; Main hamburger menu. 34 | Sleep, 100 35 | Send, g ; Settings 36 | return 37 | 38 | ; Copy title, stripping off the " - Google Chrome" at the end (and other special handling for specific pages like CodeSearch). 39 | !c::Chrome.copyTitle() 40 | !#c::Chrome.copyTitleLink() 41 | ^!c::EpicLib.copyEMC2RecordIDFromText(Chrome.getTitle()) 42 | ^!#c::Chrome.copyCodeSearchClientPath() 43 | 44 | !t::Telegram.shareURL(Chrome.getURL()) ; Share to Telegram. 45 | 46 | ; Chrome hotkeys that only apply on a DLG. 47 | #If Config.isWindowActive("Chrome") && WinActive("DLG ") 48 | ^+o::EpicStudio.openCurrentDLG() ; Open DLG in EpicStudio 49 | !r::Chrome.openClientSVNLog() ; Open client SVN log for a DLG. 50 | ^+m::MBuilder.lintCurrentDLG() 51 | #If 52 | -------------------------------------------------------------------------------- /source/program/ciscoVPN.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Cisco VPN") 2 | ; Make enter click connect instead of pulling up the options at startup. 3 | NumPadEnter:: 4 | $Enter:: 5 | ControlFocus, Button1, A 6 | Sleep, 100 7 | Send, {Enter} 8 | return 9 | #If 10 | -------------------------------------------------------------------------------- /source/program/ditto.ahk: -------------------------------------------------------------------------------- 1 |  2 | ; Compare the selected text to the last-copied clip. 3 | +#d:: 4 | ; Put the selected text on the clipboard. 5 | Send, ^c 6 | 7 | ; Open Ditto and wait for it to appear 8 | Send, ^+v 9 | WinWaitActive, ahk_class QPasteClass 10 | 11 | ; Select both the latest clip (auto-selected) and the next one down (which was previously the last-copied clip). 12 | Sleep, 500 ; Takes a smidge longer before we can do this for some reason. 13 | Send, +{Down} 14 | 15 | ; Compare with Ditto functionality. 16 | Send, ^{F2} 17 | return 18 | 19 | ; Clip edit window 20 | #IfWinActive, ahk_exe Ditto.exe ahk_class Ditto Edit Wnd 21 | ; Better hotkey to save clip and put it on the clipboard. 22 | ^s:: 23 | Enter:: 24 | NumPadEnter:: 25 | Send, +{Escape} 26 | WinWaitActive, Copy Properties 27 | Send, {Enter} 28 | return 29 | #IfWinActive 30 | -------------------------------------------------------------------------------- /source/program/emc2.ahk: -------------------------------------------------------------------------------- 1 | ; SmartTextBox handling 2 | #If Config.isWindowActive("EMC2") || Config.isWindowActive("EMC2 Popup") 3 | ^+c::Send, ^e ; Apply code formatting 4 | ^.:: ; Start bulleted list 5 | Send, {Home} ; Get to start of line if we're not already there (doesn't handle word wrapping) 6 | Send, *{Space} ; Trigger automatic list creation 7 | Send, {Escape} ; Get rid of the "undo automatic list" popup. 8 | return 9 | ^/:: 10 | Send, {Home} ; Get to start of line if we're not already there (doesn't handle word wrapping) 11 | Send, 1.{Space} ; Trigger automatic list creation 12 | Send, {Escape} ; Get rid of the "undo automatic list" popup. 13 | return 14 | #If 15 | 16 | ; Main EMC2 window 17 | #If Config.isWindowActive("EMC2") 18 | ^h:: Send, ^7 ; Make ^h for server object, similar to ^g for client object. 19 | ^+h::Send, ^h ; Keep access to the "find and replace" hotkey. 20 | $F5::+F5 ; Make F5 work everywhere by mapping it to shift + F5. 21 | ^+t::return ; Block ^+t login from Hyperspace - it does very strange zoom-in things and other nonsense. 22 | 23 | ; Link and record number things based on the current record. 24 | !c:: EpicLib.copyEMC2RecordIDFromText(WinGetTitle("A")) ; Copy ID 25 | ^+o::EpicStudio.openCurrentDLG() ; Take DLG # and pop up the DLG in EpicStudio sidebar. 26 | ^+m::MBuilder.lintCurrentDLG() ; Take DLG # and stick it into MBuilder linting. 27 | 28 | ; SmartPhrase hotstrings. 29 | :X:qa.dbc:: EMC2.insertSmartPhrase("DBCQA") 30 | :X:qa.sdbc::EMC2.insertSmartPhrase("DBCQASIMPLE") 31 | :X:qa.new:: EMC2.insertSmartPhrase("QANEW") 32 | :X:qa.sec:: 33 | EMC2.insertSmartPhrase("SECTION") 34 | Sleep, 750 ; Have to wait for phrase to finish inserting 35 | Send, {Down}{Enter} ; Select and submit the only choice - a list that inserts the text. 36 | return 37 | 38 | ; De-emphasized "contact comment" 39 | ^8::EMC2.insertSmartPhrase("SIDENOTE") 40 | #If 41 | 42 | ; Worklist: use the currently-selected row to perform actions instead of the title. 43 | #If Config.isWindowActive("EMC2 Worklist") 44 | !w::EMC2.openCurrentWorklistItemWeb() ; Open the selected item in web. 45 | #If 46 | 47 | ; DLG open 48 | #If Config.isWindowActive("EMC2 DLG") 49 | !i:: 50 | openDLGIssues() { 51 | record := EpicLib.getBestEMC2RecordFromText(WinGetTitle("A")) 52 | new ActionObjectEMC2(record.id, "DLG-I").openWeb() ; Just use the ID that we got, override the INI with the issues-specific one. 53 | } 54 | !h:: 55 | openDLGHistory() { 56 | record := EpicLib.getBestEMC2RecordFromText(WinGetTitle("A")) 57 | new ActionObjectEMC2(record.id, "DLG-H").openWeb() ; Just use the ID that we got, override the INI with the issues-specific one. 58 | } 59 | #If 60 | 61 | ; Design open 62 | #If Config.isWindowActive("EMC2 XDS") 63 | ; Disable Ctrl+Up/Down hotkeys, never hit these intentionally. 64 | ^Down::return 65 | ^Up:: return 66 | #If 67 | 68 | ; Lock/unlock hotkeys by INI 69 | #If Config.isWindowActive("EMC2 QAN") || Config.isWindowActive("EMC2 XDS") 70 | ^l::Send, !l 71 | #If Config.isWindowActive("EMC2 DLG") 72 | ^l::Send, !+{F5} 73 | #If 74 | 75 | ; Email windows 76 | #If Config.isWindowActive("EMC2 Email Popup") 77 | :X:.dbcdevs::EMC2.sendDBCDevIDs() 78 | #If 79 | -------------------------------------------------------------------------------- /source/program/epicStudio.ahk: -------------------------------------------------------------------------------- 1 | ; EpicStudio hotkeys and helpers. 2 | #If Config.isWindowActive("EpicStudio") 3 | ; Remap some of the tools to get easier access to those I use often. 4 | !1::!3 ; EZParse 5 | !2::!4 ; MBuilderES 6 | !3::!6 ; Error List 7 | !8::!9 ; Item Expert 8 | 9 | ; Line operations 10 | $^d::EpicStudio.deleteLine() 11 | ^l:: EpicStudio.duplicateLine() 12 | 13 | ; Treat ^Enter the same as Enter - I never want to insert a line before the current one. 14 | ^Enter::Send, {Enter} 15 | 16 | ; Use subword navigation with !#left/right, and keep !left/right for history navigation. 17 | !Left::Send, ^+- 18 | !Right::Send, ^+= 19 | ^#Left::Send, !{Left} 20 | ^#Right::Send, !{Right} 21 | 22 | ; Copy current code location 23 | !c:: EpicStudio.copyCleanCodeLocation() ; Cleaned, just the actual location 24 | !#c::EpicStudio.copyLinkedCodeLocation() ; RTF location with link. 25 | 26 | ; Link routine to currently open DLG in EMC2. 27 | ^+l::EpicStudio.linkRoutineToCurrentDLG() 28 | 29 | ; Take DLG # and stick it into MBuilder linting. 30 | ^+m::MBuilder.lintCurrentDLG() 31 | 32 | ; Generate and insert snippets 33 | :X:.snip::MSnippets.insertSnippet() 34 | 35 | ; Fix typos that EpicStudio handles badly 36 | :*0:d QUIT::d QUIT 37 | :*0:d q::d q 38 | 39 | ; Turn an old name line into a scope line. 40 | :X:.scope::EpicStudio.fixNameScope() 41 | 42 | ; Tiny snippet to insert a string or variable (with linking _s) in the middle of something 43 | ::.qsplit:: ; Variable in the middle of a string 44 | ::.qs:: 45 | Send, % """__""" 46 | Send, {Left 2} 47 | return 48 | ::.split:: ; String in the middle of two variables 49 | Send, % "_""""_" 50 | Send, {Left 2} 51 | return 52 | 53 | ; Tag-length-measuring tens string. 54 | ::.taglen:: 55 | Send, {End}{Home 2} ; Get to very start of line (before indent) 56 | Send, {Shift Down}{End}{Shift Up} ; Select entire line 57 | if(SelectLib.getCleanFirstLine()) 58 | Send, {Delete} ; Delete the contents (only needed if the line isn't completely empty, otherwise we lose the newline) 59 | Send, % "`t; " StringLib.getTenString(31, true).removeFromStart("123456") ; First 6 chars are the tab (width=4), semicolon, and space. 60 | return 61 | 62 | ; Contact comment, but also include the REVISIONS: header. 63 | ^+8::EpicStudio.insertContactCommentWithHeader() 64 | 65 | ; Comment "borders" that are sized to match the current line (plus 1 extra overhang) 66 | ^-::EpicStudio.wrapLineInCommentBorder("-") 67 | ^=::EpicStudio.wrapLineInCommentBorder("=") 68 | 69 | ; Debug code strings 70 | :X:gdblog:: ClipboardLib.send(Config.private["M_DEBUG_LOG"]) 71 | :X:dbpop:: ClipboardLib.send(Config.private["M_DEBUG_LOG"]) 72 | :X:gdbbreak:: ClipboardLib.send(Config.private["M_DEBUG_BREAK"]) 73 | :X:gdbpbreak::ClipboardLib.send(Config.private["M_DEBUG_BREAK_PATIENT"]) 74 | :X:.clip:: ClipboardLib.send(EpicStudio.getClipboardAsMString()) 75 | 76 | ; Redo the indentation for the selected documentation lines 77 | ^+Enter:: EpicStudio.selectionToDocBlock().rewrapSelection() 78 | ^+!Enter::EpicStudio.selectionToDocBlock().unwrapSelection() 79 | 80 | ; Debug, auto-search for workstation ID. 81 | ~F5::EpicStudio.launchDebug() 82 | 83 | ; Debug popup 84 | #If Config.isWindowActive("EpicStudio Debug Window") 85 | F5::EpicStudio.runDebugSearch() 86 | #If 87 | -------------------------------------------------------------------------------- /source/program/everything.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Everything") 2 | ; Copy current file/folder paths to clipboard 3 | !c:: ClipboardLib.copyFilePath( "!c") ; Current file path 4 | ^!#c::ClipboardLib.copyFilePathRelativeToSource("!c") ; Current file path, but drop the usual EpicSource stuff up through the DLG folder. 5 | #If 6 | -------------------------------------------------------------------------------- /source/program/excel.ahk: -------------------------------------------------------------------------------- 1 | ; Excel hotkeys. 2 | #If Config.isWindowActive("Excel") 3 | ; Copy the current document location 4 | !c:: 5 | Send, !fi ; File > Info 6 | Sleep, 1000 ; Wait for File pane to finish appearing 7 | ClipboardLib.copyFilePath("c") ; Copy Path 8 | Send, {Esc} ; Close the File pane 9 | return 10 | 11 | ; Save as 12 | ^+s::Send, {F12} 13 | 14 | ; Insert/delete row 15 | ^=:: 16 | Send, ^+= ; Insert popup 17 | Send, !r ; Entire row 18 | Send, {Enter} ; Accept popup 19 | return 20 | $^-:: 21 | Send, ^- ; Delete popup 22 | Send, !r ; Entire row 23 | Send, {Enter} ; Accept popup 24 | return 25 | 26 | ; New worksheet 27 | ^t::Send, +{F11} 28 | 29 | ; Next/previous worksheet 30 | ^Tab:: 31 | XButton1:: 32 | Send, ^{PgDn} 33 | return 34 | ^+Tab:: ; Have to make sure the shift gets released, so can't be basic hotkey (which acts as blind mode?). 35 | XButton2:: 36 | Send, ^{PgUp} 37 | return 38 | 39 | ; Fill down 40 | ^+f::Send, !hfid ; Home tab > Fill > Down 41 | 42 | ; Fix column widths 43 | ^+w::Excel.autoFixColumnWidth() 44 | 45 | ; Bold and freeze the first row (assumed to be a header) 46 | ^+b::Excel.boldFreezeHeaderRow() 47 | 48 | ; Filter and format table nicely. 49 | !b:: 50 | Send, ^a^a ; Select All (twice to get everything) 51 | Send, !at ; Data tab > Filter 52 | Excel.boldFreezeHeaderRow() 53 | Excel.autoFixColumnWidth() 54 | return 55 | #If 56 | -------------------------------------------------------------------------------- /source/program/explorer.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Explorer") 2 | ; Open "new tab" (to This PC) 3 | #e::Send, ^t ; While explorer is already active - otherwise, this activates it. 4 | 5 | ; Copy current folder/file paths to clipboard 6 | !c:: Explorer.copySelectedPath() ; Current file (or folder if nothing selected) 7 | ^!#c::Explorer.copySelectedPathRelativeToSource() ; Current file (or folder if nothing selected), but drop the usual EpicSource stuff up through the DLG folder. 8 | 9 | ; Shortcuts creation 10 | ^+s::Explorer.selectSolutionShortcut() ; DLG solution shortcut 11 | ^!s::Explorer.createRelativeShortcutToFile() ; Relative shortcut 12 | 13 | ; Open EMC2 objects based on the active folder name. 14 | !w::Explorer.getEMC2ObjectFromSelectedFolder().openWeb() 15 | !e::Explorer.getEMC2ObjectFromSelectedFolder().openEdit() 16 | 17 | ; Open Windows Terminal in the current directory. 18 | !r:: 19 | openWindowsTerminalInCurrFolder() { 20 | folderPath := Explorer.getCurrentFolder() 21 | if(!folderPath) 22 | return 23 | 24 | Config.activateProgram("Windows Terminal", "--profile ""Git Bash"" --startingDirectory " folderPath) 25 | } 26 | 27 | #If Config.isWindowActive("Explorer") || WinActive("ahk_class Progman ahk_exe explorer.exe") ; Explorer window or Desktop 28 | ; Hide/show hidden files 29 | #h::Explorer.toggleHiddenFiles() 30 | #If 31 | 32 | #If Explorer.mouseIsOverTaskbar() 33 | ; Middle-click on taskbar buttons to close them. 34 | $MButton:: 35 | closeWindowFromTaskbar() { 36 | ; Open up right-click menu 37 | Send, {RButton} 38 | 39 | ; Wait for the right-click menu to appear (for up to 1 second) 40 | WinWaitActive, % Config.windowInfo["Windows Taskbar Jump Menu"].titleString, , 1 41 | 42 | ; If it didn't (we timed out), show an error toast that this is probably a new 43 | ; window we should add to Explorer.currentWindowHasNoBasicRightClickMenu(). 44 | if (ErrorLevel = 1) { 45 | Toast.ShowError("Failed to close window", "Jump menu did not appear within 1 second") 46 | return 47 | } 48 | 49 | Send, {Up}{Enter} 50 | } 51 | #If 52 | 53 | -------------------------------------------------------------------------------- /source/program/fastStoneImageViewer.ahk: -------------------------------------------------------------------------------- 1 | #IfWinActive, ahk_exe FSViewer.exe 2 | j::Right 3 | k::Left 4 | F9::Escape 5 | #IfWinActive 6 | -------------------------------------------------------------------------------- /source/program/hyperdrive.ahk: -------------------------------------------------------------------------------- 1 | ; Hyperdrive hotkeys. 2 | #If Config.isWindowActive("Hyperdrive") 3 | $F5::+F5 ; Make F5 work everywhere by mapping it to shift + F5. 4 | 5 | ; Login 6 | ^+t:: 7 | Send, !c!o ; Get out of Smart Card prompt (and back to login if there wasn't one). 8 | Send, % Config.private["WORK_ID"] 9 | Send, {Enter} 10 | Send, % Config.private["WORK_PASSWORD"] 11 | Send, {Enter} 12 | 13 | Sleep, 500 14 | Send, ={Enter} ; Same department at prompt, if it shows up (also hits info prompt if that shows up) 15 | return 16 | #If 17 | 18 | ; HSWeb Debug Console 19 | #If WinActive(Config.private["EPIC_HSWEB_CONSOLE_TITLESTRING"]) 20 | ^r:: 21 | selectHSWebConsoleCommand() { 22 | data := new Selector("hswebConsoleCommands.tls").prompt() 23 | if(!data) 24 | return 25 | 26 | WinActivate, % Config.private["EPIC_HSWEB_CONSOLE_TITLESTRING"] ; Make sure focus gets back to the proper window 27 | 28 | code := data["CODE"] 29 | selectText := data["SELECT_TEXT"] 30 | 31 | SendRaw, % code 32 | if(selectText != "") { 33 | Send, ^a ; Select all so we can use selectTextWithinSelection 34 | SelectLib.selectTextWithinSelection(selectText) 35 | } 36 | } 37 | #If 38 | -------------------------------------------------------------------------------- /source/program/hyperspace.ahk: -------------------------------------------------------------------------------- 1 | ; Hyperspace main window 2 | #If Hyperspace.isAnyVersionActive() 3 | $F5::+F5 ; Make F5 work everywhere by mapping it to shift + F5. 4 | ^+t::Hyperspace.login(Config.private["WORK_ID"], Config.private["WORK_PASSWORD"]) ; Login 5 | #If 6 | -------------------------------------------------------------------------------- /source/program/internetExplorer.ahk: -------------------------------------------------------------------------------- 1 | ; Internet Explorer hotkeys. 2 | #If Config.isWindowActive("Internet Explorer") 3 | ; Get URL, close tab, and open the URL in your default web browser. 4 | ^+o::InternetExplorer.moveURLToDefaultBrowser() 5 | ^+c::InternetExplorer.pickF12Element() 6 | 7 | ; Handling for file links 8 | ^RButton::InternetExplorer.copyLinkTarget() ; Copy 9 | ^MButton::InternetExplorer.openLinkTarget() ; Open 10 | #If 11 | -------------------------------------------------------------------------------- /source/program/kdiff.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("KDiff") 2 | ; Show/hide whitespace differences. 3 | ^i:: 4 | Send, !i 5 | Send, {Down} 6 | Send, {Enter} 7 | return 8 | 9 | ; Hotkey to toggle line wrapping. 10 | ^+w:: 11 | Send, !i 12 | Send, {Up 3} 13 | Send, {Enter} 14 | return 15 | 16 | ; Split diff 17 | ^q:: 18 | HotkeyLib.waitForRelease() 19 | Send, {Alt} 20 | Send, {Left 4}{Down} 21 | Send, {Up 3} 22 | Send, {Enter} 23 | return 24 | 25 | ; Swap files 26 | ^!s:: 27 | Send, ^o ; Open window 28 | Send, +{Tab 2} ; Focus starts on OK button, jump to Swap/Copy Names button 29 | Send, {Space} ; Open Swap/Copy Names dropdown 30 | Send, {Down}{Enter} ; Select first option: Swap A<->B 31 | Send, !o ; OK button 32 | return 33 | #If 34 | -------------------------------------------------------------------------------- /source/program/launchy.ahk: -------------------------------------------------------------------------------- 1 | ; Launchy keyword launcher 2 | 3 | ; Protect remote desktop Launchy from host AHK interference. 4 | #If Config.doesWindowExist("Launchy") && !Config.isWindowActive("Remote Desktop") && !Config.isWindowActive("VMware Horizon Client") 5 | ; Use Caps Lock as the trigger key. 6 | CapsLock:: 7 | SetCapsLockState, AlwaysOff 8 | Send, #{End} 9 | return 10 | 11 | #If !Config.doesWindowExist("Launchy") 12 | CapsLock:: 13 | Toast.ShowMedium("Launchy not yet running, launching...") 14 | Config.runProgram("Launchy") 15 | return 16 | #If 17 | -------------------------------------------------------------------------------- /source/program/notepadPlusPlus.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Notepad++") 2 | !x::return ; Block close-document hotkey that can't be changed/removed. 3 | ^+t::Send, !f1 ; Re-open last closed document. 4 | !f:: Send, ^!+f ; Use !f hotkey for highlighting with the first style (ControlSend so we don't trigger other hotkeys) 5 | F6:: Send, ^w ; Close with F6 hotkey, like we do for browsers. 6 | 7 | ; Current file/folder operations 8 | !c:: ClipboardLib.copyCodeLocationPath( "!c") 9 | !#c:: ClipboardLib.copyCodeLocationFile( "!c") 10 | ^!#c::ClipboardLib.copyCodeLocationRelativeToSource("!c") ; Current file + selected text as a function, but drop the usual EpicSource stuff up through the DLG folder. 11 | ^!f:: ClipboardLib.openActiveFileParentFolder( "!c") 12 | #If 13 | -------------------------------------------------------------------------------- /source/program/onenote.ahk: -------------------------------------------------------------------------------- 1 | ; OneNote hotkeys. 2 | #If Config.isWindowActive("OneNote") 3 | ; Block certain hotkeys that I accidentally trigger, but don't want to use 4 | *^+1::return ; Add Outlook task 5 | 6 | ; Make ctrl+tab (and XButtons) switch pages, not sections 7 | ^Tab:: Send, ^{PgDn} 8 | ^+Tab::Send, ^{PgUp} 9 | XButton1::Send, ^{PgDn} 10 | XButton2::Send, ^{PgUp} 11 | ; Make ctrl+page down/up switch sections 12 | ^PgDn::Send, ^{Tab} 13 | ^PgUp::Send, ^+{Tab} 14 | 15 | ; Expand and collapse outlines 16 | !Left:: !+- 17 | !Right::!+= 18 | ; Alternate history back/forward 19 | !+Left:: Send, !{Left} 20 | !+Right::Send, !{Right} 21 | 22 | ; Make line movement alt + up/down instead of alt + shift + up/down to match notepad++ and EpicStudio. 23 | !Up:: !+Up 24 | !Down::!+Down 25 | 26 | ; Horizontal scrolling. 27 | +WheelUp:: OneNote.scrollLeft() 28 | +WheelDown::OneNote.scrollRight() 29 | 30 | ^+0::Send, ^0 ; Since we're using ^0 to set zoom to 100% below, add a replacement hotkey for clearing all tags. 31 | ^!n::Send, ^+n ; 'Normal' text formatting, as ^+n is already being used for new subpage. 32 | ^7:: Send, ^6 ; Make ^7 do the same tag (Done green check) as ^6. 33 | ^+8::SendRaw, % "*" Config.private["INITIALS"] " " FormatTime(, "MM/yy") ; Insert contact comment 34 | ^!4::Send, ^!5 ; Use Header 5 instead of Header 4 - Header 4 is just an italicized Header 3, which isn't distinct enough for me. 35 | 36 | ; Print preview 37 | ^!p:: 38 | Send, !fpr 39 | return 40 | 41 | ; Delete the entire current line 42 | ^d:: 43 | OneNote.escapePastePopup() 44 | OneNote.selectLine() 45 | Send, {Delete} 46 | return 47 | 48 | ; Notebook syncing 49 | ^s:: 50 | OneNote.escapePastePopup() 51 | Send, +{F9} ; Sync This Notebook Now 52 | return 53 | ^+s:: 54 | OneNote.escapePastePopup() 55 | Send, {F9} ; Sync All Notebooks Now 56 | return 57 | 58 | ; Focus notebooks by index 59 | !1::OneNote.focusNotebookWithIndex(1) 60 | !2::OneNote.focusNotebookWithIndex(2) 61 | !3::OneNote.focusNotebookWithIndex(3) 62 | !4::OneNote.focusNotebookWithIndex(4) 63 | !5::OneNote.focusNotebookWithIndex(5) 64 | 65 | ; Various specific commands based on the quick access toolbar. 66 | $^+n::OneNote.newSubpage() 67 | ^+[:: OneNote.promoteSubpage() 68 | ^+]:: OneNote.makeSubpage() 69 | $^+d::OneNote.deletePageWithConfirm() 70 | !m:: OneNote.meetingDetailsFromAnotherDay() 71 | ^0:: OneNote.setZoomTo100Percent() 72 | 73 | ; Onetastic custom styles and macros 74 | ^+c::OneNote.customStylesCode() 75 | ^+i::OneNote.addSubLinesToSelectedLines() 76 | !t:: OneNote.collapseToUnfinishedTags() 77 | ^l:: OneNote.createAndLinkPage() 78 | ^+w::OneNote.widenOutline() 79 | 80 | ; Work-specific macros 81 | ^+a::OneNote.applyDevStructureToCurrentPage() 82 | ^+l::OneNote.createAndLinkDevPage() 83 | ^+p::OneNote.createAndLinkWorkplanPage() 84 | 85 | ; Link handling 86 | !c:: OneNote.copyLinkToCurrentPage() 87 | !#c:: OneNote.copyTitleLinkToCurrentParagraph() 88 | ^RButton::OneNote.copyLinkUnderMouse() 89 | ^MButton::OneNote.removeLinkUnderMouse() 90 | 91 | ; Todo page handling 92 | ^t:: OneNoteTodoPage.collapseToTodayItems() ; Today only, item-level 93 | ^+t:: OneNoteTodoPage.collapseToAllItems() ; All sections, item-level 94 | ^!t:: OneNoteTodoPage.collapseToTodayAll() ; Today only, fully expanded 95 | ^+m:: OneNoteTodoPage.copyForToday() ; New page for today 96 | ^+#m:: OneNoteTodoPage.copyForTomorrow() ; New page for tomorrow 97 | :*X:.devdo::OneNoteTodoPage.insertDevTodos() ; Typical dev list of todo sub-items 98 | :*X:.prjdo::OneNoteTodoPage.insertDevPRJTodos() ; Typical dev list of todo sub-items for a project log 99 | :*X:.sudo:: OneNoteTodoPage.insertDevSUTodos() ; Typical dev SU list of todo sub-items 100 | :*X:.pqado::OneNoteTodoPage.insertPQATodos() ; Typical PQA list of todo sub-items 101 | 102 | ; Update links for a dev structure section header 103 | !+#k::OneNote.linkDevStructureSectionTitle() 104 | #If 105 | -------------------------------------------------------------------------------- /source/program/onetastic.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Onetastic Macro Editor") 2 | ; Insert "empty" (comment) line 3 | ^Enter:: 4 | Send, !Q ; Insert comment 5 | Send, {Enter} ; Edit comment text 6 | WinWaitActive, Comment Editor 7 | Send, {Delete}{Enter} 8 | return 9 | 10 | ; Comment out selected lines 11 | ^`;:: 12 | commandLines := ClipboardLib.getWithHotkey("^c") 13 | numNewlines := commandLines.removeFromEnd("`n").countMatches("`n") ; Figure out how many lines are in the selection, ignoring the trailing newline 14 | Send, !Q ; Insert comment 15 | Send, {Up} ; Get back into previously-selected block 16 | Send, {Shift Down}{Up %numNewlines%}{Shift Up} ; Reselect the original block 17 | Send, ^{Down} ; Move lines down once, which should put them under out new comment line 18 | return 19 | 20 | ; Move line up/down 21 | !Up:: Send, ^{Up} 22 | !Down::Send, ^{Down} 23 | 24 | ; Collapse/expand 25 | !Left:: Send, ^{Left} 26 | !Right::Send, ^{Right} 27 | 28 | ; New macro function 29 | ^n::^NumpadAdd 30 | 31 | ; Import 32 | ^i::Send, !fp ; File > Import 33 | 34 | ; Delete macro 35 | ^d::Send, !fd ; File > Delete 36 | 37 | ; Open function header edit window 38 | ^e::^F2 39 | 40 | ; Open macro info edit window 41 | ^+i::Send, !fi ; File > Edit Macro Info... 42 | 43 | ; Open XML window 44 | ^+o::Onetastic.openEditXMLPopup() 45 | 46 | ; Copy/set current function XML 47 | ^+x::Onetastic.copyCurrentXML() 48 | #If 49 | -------------------------------------------------------------------------------- /source/program/outlook.ahk: -------------------------------------------------------------------------------- 1 | ; Outlook Hotkeys. 2 | 3 | ; Program in general 4 | #If Config.isWindowActive("Outlook") 5 | ; Move selected message(s) to a particular folder, and mark them as read. 6 | $^e::Send, !ho ; Archive 7 | ^+w::Send, ^+1 ; Wait 8 | ^+l::Send, ^+2 ; Later use 9 | 10 | ; Format as code (using custom styles) 11 | ^+c::Send, ^!+2 ; Hotkey used in Outlook (won't let me use ^+c directly) 12 | 13 | ; Bullets and numbering 14 | ^.::^+l 15 | ^/:: 16 | if(Outlook.isMailMessagePopupActive()) 17 | Send, !o ; Format Text tab 18 | else 19 | Send, !e2 ; Message tab 20 | Send, n ; Numbering 21 | Send, {Right} ; First numbering format 22 | Send, {Enter} ; Accept 23 | return 24 | 25 | ; Switch ^f to be find, with forwarding moved to ^+f. 26 | ^f:: 27 | Send, ^g ; Launch Find and Replace window 28 | WinWaitActive, % "Find and Replace" 29 | Send, !d ; Switch to Find tab 30 | return 31 | ^+f::Send, ^f 32 | 33 | ; Toggle dark mode (not available as a command in non-editing message popup) 34 | !d::Outlook.toggleDarkMode() 35 | #If 36 | 37 | ; Mail folders 38 | #If Config.isWindowActive("Outlook") && (Outlook.isCurrentScreenMail() || Outlook.isMailMessagePopupActive()) 39 | ; Copy current message title to clipboard 40 | !c::ClipboardLib.setAndToast(Outlook.getMessageTitle(), "title") 41 | 42 | ; Open the relevant record (if applicable) for the current message 43 | !w::new ActionObjectEMC2(Outlook.getMessageTitle()).openWeb() 44 | !e::new ActionObjectEMC2(Outlook.getMessageTitle()).openEdit() 45 | #If 46 | 47 | ; Normal calendar 48 | #If Outlook.isNormalCalendarActive() 49 | !c::Outlook.copyEMC2RecordIDFromEvent() 50 | !w::Outlook.getEMC2ObjectFromCalendarEvent().openWeb() 51 | !e::Outlook.getEMC2ObjectFromCalendarEvent().openEdit() 52 | ; TLG calendar 53 | #If Outlook.isTLGCalendarActive() 54 | ^+t::Outlook.selectOutlookTLG() 55 | 56 | !c::Outlook.copyEMC2ObjectStringFromTLG() 57 | !w::Outlook.getEMC2ObjectFromTLG().openWeb() 58 | !e::Outlook.getEMC2ObjectFromTLG().openEdit() 59 | #If 60 | 61 | ; Calendar folders 62 | #If Config.isWindowActive("Outlook") && Outlook.isCurrentScreenCalendar() 63 | ; Shortcut to go to today on the calendar (in desired, 3-day view) 64 | ^t:: 65 | ; Go to today. 66 | Send, !h 67 | Send, od 68 | 69 | ; Single-day view. 70 | Send, !1 71 | return 72 | 73 | ; Calendar view: week view. 74 | ^w::Send, ^!3 75 | 76 | ; Show a popup for picking an arbitrary calendar to display. 77 | ^a:: 78 | Send, !h 79 | Send, oc 80 | Send, a 81 | return 82 | 83 | +WheelDown::Send, {Right} 84 | +WheelUp:: Send, {Left} 85 | #If 86 | 87 | ; Universal new email. 88 | #If Config.machineIsWorkDesktop 89 | ^!m::Config.runProgram("Outlook", "/c ipm.note") 90 | #If 91 | -------------------------------------------------------------------------------- /source/program/powerpoint.ahk: -------------------------------------------------------------------------------- 1 | ; PowerPoint hotkeys. 2 | 3 | #If Config.isWindowActive("PowerPoint") 4 | ; Copy the current document location 5 | !c:: 6 | Send, !fi ; File > Info 7 | Sleep, 1000 ; Wait for File pane to finish appearing 8 | ClipboardLib.copyFilePath("c") ; Copy Path 9 | Send, {Esc} ; Close the File pane 10 | return 11 | 12 | ; Presenting (either main screen or presenter view) 13 | #If Config.isWindowActive("PowerPoint Presenting") || Config.isWindowActive("PowerPoint Presenter View") 14 | ; Right-click goes back 15 | RButton::Left 16 | #If 17 | -------------------------------------------------------------------------------- /source/program/putty.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Putty") 2 | ^c::return ; Disable breaking behavior for easy-to-hit-accidentally ^c, PuTTY already has a ^+c hotkey that works too. 3 | *^s::return ; Disable fall-thru XOFF hotkeys (^s and others cause terminal to freeze, unfreeze with ^q) 4 | ^v::Send, +{Insert} ; Normal paste, without all the inserting of spaces. 5 | +Tab::Send, {Left} ; Allow reverse field navigation. 6 | 7 | ; Insert arbitrary text, inserting needed spaces to overwrite. 8 | ^i::Putty.insertArbitraryText() 9 | 10 | ; Screen wipes 11 | ^l::Putty.wipeScreen() 12 | ^+l::Putty.wipeScreen(true) 13 | 14 | ; Get out of Chronicles 15 | ^d:: 16 | Send, +{F7 3} ; Get out of (potentially-nested) open records 17 | Send, {PgDn 3} ; Get out to main menu 18 | Send, quit{Enter} ; Exit 19 | SendRaw, % Config.private["EPIC_LOOKITT"] "`n" ; Get back into Lookitt (in case we left) 20 | Sleep, 100 21 | Putty.wipeScreen() ; Wipe the screen 22 | return 23 | 24 | ; Scroll 1 line at a time 25 | ^WheelUp:: Send, ^{PgUp} 26 | ^WheelDown::Send, ^{PgDn} 27 | 28 | ; Search within record edit screens 29 | ^F9::Putty.recordEditSearch() 30 | ^g:: Putty.recordEditSearch(true) 31 | 32 | ; Open up settings window. 33 | !o::Putty.openSettingsWindow() 34 | 35 | ; Open up the current log file. 36 | ^+o::Putty.openCurrentLogFile() 37 | 38 | ; Send the clipboard as an (appropriately escaped) string. 39 | :X:.clip::SendRaw, % EpicStudio.getClipboardAsMString() 40 | 41 | ; Send specific commands (extra spaces between quotes are purely for readability) 42 | ^z:: SendRaw, % Config.private["EPIC_LOOKITT"] "`n" 43 | ^e:: SendRaw, % "e " ; Chronicles 44 | ^s:: SendRaw, % ";set" "`n" 45 | ^o:: SendRaw, % ";top" "`n" 46 | ^r:: SendRaw, % ";kecr" "`n" 47 | ^h:: SendRaw, % ";hb" "`n" 48 | ^+r::SendRaw, % ";rstat" "`n" 49 | ^+h::SendRaw, % ";hstat" "`n" 50 | ^+e::SendRaw, % ";v" "`n" 51 | ::;je :: ; Include a space so default use of macro (to jump into list) doesn't trigger this 52 | examineJob() { 53 | ; Prompt for process ID 54 | jobId := InputBox("Enter process ID to look up", "Enter job process ID") 55 | if(jobId = "") 56 | return 57 | 58 | Send, `;je{Enter} ; Launch the job list using the actual macro. 59 | Send, % "eP" jobId "`n" ; Jump into examining the provided job. 60 | } 61 | 62 | ; MTPutty pass-throughs 63 | #If Config.isWindowActive("Putty") && Config.doesWindowExist("MTPutty") 64 | ; Attach all "orphaned" putty windows to MTPutty 65 | $^+a::MTPutty.attachOrphanedPuttyWindows() 66 | F2::MTPutty.fixPuttyTabTitle() 67 | #If 68 | -------------------------------------------------------------------------------- /source/program/remoteDesktop.ahk: -------------------------------------------------------------------------------- 1 | ; Disconnect hotkey (for computer that's being remoted into). 2 | $!Esc:: 3 | if(!GuiLib.showConfirmationPopup("Are you sure you want to disconnect from this computer?", "Disconnect?")) 4 | return 5 | RunLib.runCommand("tsdiscon") 6 | SetNumLockState, AlwaysOn 7 | return 8 | 9 | #If Config.isWindowActive("Remote Desktop") || Config.isWindowActive("Remote Desktop Reconnecting") 10 | NumLock::return ; Divert NumLock on the base machine - otherwise it goes off on an infinite loop of trying to restore it for AlwaysOn setting. 11 | 12 | ; Allow escape from remote desktop with hotkey (for computer you're remoting from). 13 | !CapsLock:: ; One of a few keys that the host still captures. 14 | Suspend, Off 15 | Sleep, 50 ; Need a short sleep here for focus to restore properly. 16 | WindowActions.minimizeWindowByName("Remote Desktop") 17 | return 18 | #If !Config.isWindowActive("Remote Desktop") && Config.doesWindowExist("Remote Desktop") 19 | ; Switch back into remote desktop with same hotkey (for computer you're remoting from). 20 | !CapsLock:: 21 | WindowActions.activateWindowByName("Remote Desktop") 22 | return 23 | #If !Config.doesWindowExist("Remote Desktop") 24 | ; Block this hotkey if there's no remote desktop at play at all (because I'm not interested in task view). 25 | !CapsLock::return 26 | #If 27 | -------------------------------------------------------------------------------- /source/program/snapper.ahk: -------------------------------------------------------------------------------- 1 | ; Main Snapper window 2 | #If Config.isWindowActive("Snapper") 3 | ^h:: Snapper.sendItemsToIgnore() ; Send string of items to ignore, based on the given INI. 4 | ^+d::Snapper.diffMultiResponseValues() ; Diff the selected help text 5 | #If 6 | 7 | ; Add record window 8 | #If Config.isWindowActive("Snapper Add Records") 9 | ^Enter::Snapper.addMultipleRecordsFromAddPopup() 10 | #If 11 | -------------------------------------------------------------------------------- /source/program/spotify.ahk: -------------------------------------------------------------------------------- 1 | ; If Spotify is running. 2 | #If Config.doesWindowExist("Spotify") 3 | ; Global search hotkey 4 | #j:: 5 | Config.runProgram("Spotify") 6 | WinWaitActive, % Config.windowInfo["Spotify"].titleString 7 | Send, ^l 8 | return 9 | #If 10 | 11 | #If Config.isWindowActive("Spotify") 12 | ; Alternative search hotkeys (that make more sense than the original) 13 | ^j:: 14 | ^/:: 15 | Send, ^l 16 | return 17 | #If 18 | -------------------------------------------------------------------------------- /source/program/sumatraPDF.ahk: -------------------------------------------------------------------------------- 1 | #IfWinActive, ahk_exe SumatraPDF.exe 2 | ; Bookmarks panel. 3 | ^b::Send, {F12} 4 | 5 | ; Kill unconventional hotkey to quit. 6 | ^q::return 7 | 8 | ; Find forward/back. 9 | ^g::F3 10 | ^+g::+F3 11 | 12 | ; Save as is Ctrl+S 13 | ^+s::Send, ^s 14 | #IfWinActive 15 | -------------------------------------------------------------------------------- /source/program/teams.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Teams") 2 | !a:: Send, ^+m ; Toggle mute 3 | !z:: Send, ^+o ; Toggle video 4 | !o:: Send, ^, ; Settings 5 | ^+/::Send, ^. ; Show hotkeys 6 | :*:xD::(laugh) ; Change my laughing emoji 7 | 8 | ^+c:: ; Code formatting 9 | teamsCodeFormatText() { ; Markdown-style, just wrap it in backticks. 10 | text := SelectLib.getText() 11 | SendRaw, ``%text%`` 12 | } 13 | 14 | ^!c::copyCondensedTeamsConversation() 15 | #If 16 | 17 | ;--------- 18 | ; DESCRIPTION: Take messages copied from Teams, condense them, and put them back on the clipboard. 19 | ;--------- 20 | copyCondensedTeamsConversation() { 21 | clipboard := getCondensedTeamsConversation(SelectLib.getText()) 22 | Toast.ShowMedium("Clipboard set to condensed Teams conversation") 23 | } 24 | 25 | ;--------- 26 | ; DESCRIPTION: Take messages copied from Teams and condense them into a more compact form for saving off. 27 | ; PARAMETERS: 28 | ; messages (I,REQ) - Full copied text of the messages 29 | ; RETURNS: New string in this format (with messages from the same person being combined under one sender name header): 30 | ; senderName 31 | ; message1Text 32 | ; message2Text 33 | ;--------- 34 | getCondensedTeamsConversation(messages) { 35 | conversation := "" 36 | 37 | For _, message in condenseTeamsMessagesBySender(messages) { 38 | conversation := conversation.appendLine(message.sender) 39 | 40 | text := "`t" message.text.replace("`n", "`n`t") ; Indent every line of the message 41 | conversation := conversation.appendLine(text) 42 | } 43 | 44 | return conversation 45 | } 46 | 47 | ;--------- 48 | ; DESCRIPTION: Parse a bunch of copied Teams messages into discrete blocks, divided up by sender name. 49 | ; PARAMETERS: 50 | ; messages (I,REQ) - Full copied text of the messages 51 | ; RETURNS: Array of message objects: {sender, text} 52 | ;--------- 53 | condenseTeamsMessagesBySender(messages) { 54 | condensedMessages := [] 55 | newline := "`r`n" 56 | 57 | For _, message in messages.split([newline newline "["], newline) { 58 | sender := message.firstLine().afterString("] ") 59 | text := message.afterString(newline) 60 | text := text.removeRegEx("`r`n( (like|heart|laugh|surprised|sad|angry) \d+)+$") ; Remove reactions line (at the bottom of a message) 61 | text := text.replace(newline newline, newline) ; Drop extra newlines 62 | 63 | previousMessage := condensedMessages.last() 64 | if(previousMessage.sender = sender) { 65 | previousMessage.text := previousMessage.text.appendLine(text) 66 | } else { 67 | condensedMessages.push( {sender:sender, text:text} ) 68 | } 69 | } 70 | 71 | return condensedMessages 72 | } -------------------------------------------------------------------------------- /source/program/telegram.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("Telegram") 2 | Up::return ; Block quoting behavior by default (Ctrl+Up still works fine) 3 | ^t::Telegram.focusNormalChat() ; Focus normal chat. 4 | :*:xD:::joy{Tab} ; Change my laughing emoji 5 | #If -------------------------------------------------------------------------------- /source/program/tortoise.ahk: -------------------------------------------------------------------------------- 1 | ; Hotkeys for TortoiseGit and TortoiseSVN. 2 | #If Config.isWindowActive("TortoiseSVN") || Config.isWindowActive("TortoiseGit") 3 | ^l::^d ; Duplicate line 4 | ^d::^l ; Delete line 5 | #If 6 | -------------------------------------------------------------------------------- /source/program/visualStudio.ahk: -------------------------------------------------------------------------------- 1 | ; Visual Studio hotkeys. 2 | #If Config.isWindowActive("Visual Studio") 3 | ; Copy current file/folder paths to clipboard 4 | !c:: ClipboardLib.copyCodeLocationPath( VisualStudio.Hotkey_CopyCurrentFile) ; Code location (full path) 5 | !#c:: ClipboardLib.copyCodeLocationFile( VisualStudio.Hotkey_CopyCurrentFile) ; Code location (file name only) 6 | ^!#c::ClipboardLib.copyCodeLocationRelativeToSource(VisualStudio.Hotkey_CopyCurrentFile) ; Code location (path from source) 7 | ^!f:: ClipboardLib.openActiveFileParentFolder( VisualStudio.Hotkey_CopyCurrentFile) 8 | 9 | ; Subword navigation, because I can't use the windows key in hotkeys otherwise 10 | ^#Left:: Send, ^!{Numpad1} ; Previous subword 11 | ^#Right:: Send, ^!{Numpad2} ; Next subword 12 | ^#+Left:: Send, ^!{Numpad3} ; Extend selection previous 13 | ^#+Right::Send, ^!{Numpad4} ; Extend selection next 14 | 15 | :X:dbpop::VisualStudio.sendDebugCodeStringTS(clipboard) ; Debug popup 16 | #If 17 | -------------------------------------------------------------------------------- /source/program/vsCode.ahk: -------------------------------------------------------------------------------- 1 | ; AHK-specific handling 2 | #If Config.isWindowActive("VSCode AHK") 3 | ; For program scripts, swap to corresponding class script and back. 4 | Pause::VSCode.toggleProgramAndClass() 5 | 6 | ; Redo the indentation for the selected documentation lines 7 | ^+Enter:: new HeaderDocBlock().rewrapSelection() 8 | ^+!Enter::new HeaderDocBlock().unwrapSelection() 9 | 10 | ; AHK debug strings 11 | :X:dbpop:: VSCode.sendAHKDebugCodeString("Debug.popup", clipboard) ; Debug popup 12 | :X:dbto:: VSCode.sendAHKDebugCodeString("Debug.toast", clipboard) ; Debug toast 13 | :X:edbpop:: VSCode.sendAHKDebugCodeString("Debug.popupEarly", clipboard) ; Debug popup that appears at startup 14 | :X:dbcon:: VSCode.sendAHKDebugCodeString("Debug.console", clipboard) ; Debug console 15 | ^e:: VSCode.editDebugLine() 16 | 17 | ; Other AHK dev strings 18 | :X:`;`;`;::VSCode.sendDocHeader() 19 | 20 | ; EpicCode-specific handling 21 | #If Config.isWindowActive("VSCode EpicCode") 22 | !c::VSCode.copyCleanEpicCodeLocation() 23 | 24 | ; All profiles (unless overridden above) 25 | #If Config.isWindowActive("VSCode") 26 | ; Current file/folder operations 27 | !c:: ClipboardLib.copyCodeLocationPath( VSCode.Hotkey_CopyCurrentFile) 28 | !#c:: ClipboardLib.copyCodeLocationFile( VSCode.Hotkey_CopyCurrentFile) 29 | ^!f:: ClipboardLib.openActiveFileParentFolder(VSCode.Hotkey_CopyCurrentFile) ; Yes, there's a built-in command for this, but it doesn't work consistently and take forever to happen. 30 | 31 | ; Block/column selection reminder 32 | !#LButton::Toast.ShowShort("Column/block select in VSCode is Alt+Shift+Click.") 33 | 34 | ; Subword navigation (ctrl+win+left/right are stolen by Windows for virtual desktops otherwise) 35 | ^#Left:: Send, ^!{Numpad1} ; Previous subword 36 | ^#Right:: Send, ^!{Numpad2} ; Next subword 37 | ^#+Left:: Send, ^!{Numpad4} ; Select previous subword 38 | ^#+Right::Send, ^!{Numpad6} ; Select next subword 39 | #If 40 | -------------------------------------------------------------------------------- /source/program/wilma.ahk: -------------------------------------------------------------------------------- 1 | #IfWinActive, ahk_exe Epic.Release.Wilma.exe 2 | ^f:: 3 | Send, !m ; Select Manually 4 | Send, {Tab} 5 | Send, 2{Enter}{Tab} ; APP TRACK-CURRENT DEV 6 | Send, 130{Enter}{Tab} ; First Stage QA 7 | Send, 1{Enter} ; Hyperspace 8 | return 9 | #IfWinActive 10 | -------------------------------------------------------------------------------- /source/program/winMerge.ahk: -------------------------------------------------------------------------------- 1 | #If Config.isWindowActive("WinMerge") 2 | ; Rough approximation of Ctrl+Tab (order still gets screwy) 3 | ^Tab::Send, ^{F6} 4 | ^+Tab::Send, ^+{F6} 5 | 6 | ; Jump between differences 7 | ^Up::Send, !{Up} 8 | ^Down::Send, !{Down} 9 | 10 | ; Options 11 | !o::Send, !eo 12 | 13 | ; Remove all synchronization points 14 | !+s::Send, !mh 15 | 16 | ; Fix tab order (it's always MRU, but we can turn MRU back into the order they're in). 17 | ^+f:: 18 | fixWinMergeTabOrder() { 19 | HotkeyLib.waitForRelease() 20 | numTabs := 9 21 | 22 | ; Select each tab in reverse order. 23 | Loop, % numTabs { 24 | tabIndex := numTabs - A_Index + 1 25 | Send, !w ; Window menu 26 | Send, % tabIndex ; Tab index is just that number in the menu 27 | } 28 | } 29 | 30 | ; Toggle word wrap 31 | ^+7:: 32 | Send, !v ; View menu 33 | Send, r ; Wrap lines 34 | return 35 | #If 36 | -------------------------------------------------------------------------------- /source/program/word.ahk: -------------------------------------------------------------------------------- 1 | ; Word hotkeys. 2 | #If Config.isWindowActive("Word") 3 | ; Copy the current document location 4 | !c:: 5 | Send, !fi ; File > Info 6 | Sleep, 1000 ; Wait for File pane to finish appearing 7 | ClipboardLib.copyFilePath("c") ; Copy Path 8 | Send, {Esc} ; Close the File pane 9 | return 10 | 11 | ; Open (dialog, not screen) 12 | ^o::Send, ^!{F2} 13 | 14 | ; Save as 15 | ^+s::Send, {F12} 16 | 17 | ; Find next/previous 18 | ^g::Send, ^{PgDn} 19 | ^+g::Send, ^{PgUp} 20 | 21 | ; Apply bullets and numbering 22 | ^.::^+l 23 | ^/:: 24 | Send, !h ; Home 25 | Send, n ; Numbering 26 | Send, {Right} ; First numbering format 27 | Send, {Enter} ; Accept 28 | return 29 | 30 | ; Toggle extra line spacing after paragraph 31 | ^+a:: 32 | Send, !h ; Home 33 | Send, k ; Line and Paragraph Spacing 34 | Send, a ; Add/Remove Space After Paragraph 35 | return 36 | 37 | ; Strikethrough 38 | ^-:: 39 | Send, !h 40 | Send, 4 41 | return 42 | 43 | ; Add a new comment (default hotkey is used elsewhere) 44 | ^m:: 45 | Send, ^!m 46 | return 47 | 48 | ; Toggle dark/light mode. 49 | !d:: 50 | Send, !w ; View 51 | Sleep, 100 52 | Send, m1 ; Dark mode 53 | return 54 | 55 | ; Jump to next *** token and select it. 56 | F2:: 57 | Send, ^g ; Find/replace popup (Go To tab) 58 | Send, !d ; Find tab 59 | Send, !n ; Focus "Find what" field 60 | Send, *** ; String to search for 61 | Send, !m ; More button (show search options) 62 | Send, !: ; Focus "Search" (direction) dropdown 63 | Send, A ; Search "All" 64 | Send, !l ; Less button (hide search options, so More button is there next time we come through too) 65 | Send, !f ; Find next 66 | Send, {Esc} ; Get out of the find popup/navigation pane 67 | 68 | ; If the find popup is still open (presumably because we hit the "finished searching" popup), close it. 69 | if(WinActive("Find and Replace")) 70 | Send, {Esc} ; Close the popup 71 | return 72 | 73 | ; Make line movement alt + up/down instead of alt + shift + up/down to match notepad++ and ES. 74 | !Up:: Send, !+{Up} 75 | !Down::Send, !+{Down} 76 | 77 | ; Expand/collapse headings 78 | !Right:: 79 | Send, {AppsKey} 80 | Send, e ; Expand / Collapse 81 | Send, {Right} ; In case menu didn't expand because there was another E menu item 82 | Send, e ; Expand Heading 83 | Sleep, 100 84 | if(WinActive("ahk_class Net UI Tool Window ahk_exe WINWORD.EXE")) ; Right-click menu still open, as header was already expanded 85 | Send, {Esc 2} 86 | return 87 | !Left:: 88 | Send, {AppsKey} 89 | Send, e ; Expand / Collapse 90 | Send, {Right} ; In case menu didn't expand because there was another E menu item 91 | Send, c ; Collapse Heading 92 | Sleep, 100 93 | if(WinActive("ahk_class Net UI Tool Window ahk_exe WINWORD.EXE")) ; Right-click menu still open, as header was already collapsed 94 | Send, {Esc 2} 95 | return 96 | #If 97 | -------------------------------------------------------------------------------- /source/program/zoom.ahk: -------------------------------------------------------------------------------- 1 | ; Zoom hotkeys. 2 | #If Config.isWindowActive("Zoom") 3 | ; Specific views, directly 4 | F1::Zoom.switchToSpeakerView() 5 | F2::Zoom.switchToGalleryView() 6 | 7 | ; Remote keyboard has these extra bindings (via rebound keys): 8 | ; Music - Alt+A (toggle mute) 9 | !F3::Zoom.toggleView() ; Lock - Alt+F3 10 | ; Power - Alt+V (toggle video) 11 | #If 12 | -------------------------------------------------------------------------------- /source/standalone/activateProgram.ahk: -------------------------------------------------------------------------------- 1 | ; Activate (or run if not already open) a specific program, to be executed by external program (like Microsoft keyboard special keys). 2 | 3 | #Include 4 | 5 | progName = %1% ; Input from command line 6 | if(!progName) 7 | ExitApp 8 | 9 | Config.activateProgram(progName) 10 | 11 | ExitApp 12 | -------------------------------------------------------------------------------- /source/standalone/callPhone.ahk: -------------------------------------------------------------------------------- 1 | ; Tries to call a specific number via my work phone. 2 | 3 | #Include 4 | 5 | ; Start with any command line arguments. 6 | Loop, % A_Args.Length() { ; Loop like this in case there are spaces (which split up into multiple parameters) 7 | numToCall := numToCall.appendPiece(" ", A_Args[A_Index]) 8 | } 9 | 10 | ; Next try selected text 11 | if (!PhoneLib.isValidNumber(numToCall)) 12 | numToCall := SelectLib.getCleanFirstLine() 13 | 14 | ; Finally, prompt for it 15 | if (!PhoneLib.isValidNumber(numToCall)) { 16 | numToCall := InputBox("Call from work phone", "Enter phone number:") 17 | if (ErrorLevel) 18 | numToCall := "" 19 | } 20 | 21 | ; If we still didn't get something, give up. 22 | if(!PhoneLib.isValidNumber(numToCall)) 23 | ExitApp 24 | 25 | ; Otherwise make it so! 26 | PhoneLib.call(numToCall) 27 | 28 | ExitApp 29 | -------------------------------------------------------------------------------- /source/standalone/changeVolume.ahk: -------------------------------------------------------------------------------- 1 | ; Change the volume by a specific amount and show a toast with the new volume. 2 | ; Applies to the local machine even if remote desktop is fullscreen. 3 | 4 | #Include 5 | #SingleInstance, Off ; Allow multiple instances of this script, so I can quickly turn the volume up/down multiple steps. 6 | #NoTrayIcon 7 | 8 | changeAmount = %1% ; Input from command line - handles both numbers and numbers with a +/- at the start. 9 | changeAmount := DataLib.forceNumber(changeAmount) 10 | if(changeAmount = 0) 11 | ExitApp 12 | 13 | SoundSet, % changeAmount 14 | 15 | currentLevel := Round(SoundGet(), 0) 16 | 17 | styles := {} 18 | styles["BACKGROUND_COLOR"] := "000000" ; Black 19 | styles["FONT_COLOR"] := "CCCCCC" ; Light gray 20 | styles["FONT_SIZE"] := 20 21 | styles["FONT_NAME"] := "Segoe UI" 22 | styles["MARGIN_X"] := 40 23 | styles["MARGIN_Y"] := 20 24 | 25 | t := new Toast("Volume: " currentLevel "%", styles).blockingOn() 26 | t.showForSeconds(1, VisualWindow.X_LeftEdge "+50", VisualWindow.Y_TopEdge "+30") 27 | 28 | ExitApp 29 | -------------------------------------------------------------------------------- /source/standalone/compileEpicStudioRegex.ahk: -------------------------------------------------------------------------------- 1 | ; Compile a bunch of RegEx patterns into a handful of larger ones that each get their own distinct highlight in EpicStudio. 2 | 3 | #Include 4 | 5 | /* .bits file format: 6 | One line per regex bit 7 | Each should be valid by itself 8 | Optional headers should be left-justified (no indentation) and start with a hash (#) 9 | Regex bit lines under a header should not be indented 10 | Optional explanation lines can come after each regex bit line 11 | They must be indented at least once 12 | */ 13 | 14 | ; Start in the relevant folder. 15 | SetWorkingDir, % Config.path["EPICSTUDIO_GLOBAL_HIGHLIGHTS"] 16 | 17 | ; Loop over all .bits files and compile them into .regex files. 18 | Loop, Files, % "*.bits" 19 | { 20 | regexString := "" 21 | For _,line in FileLib.fileLinesToArray(A_LoopFileName) { 22 | if(line = "") ; Empty line 23 | Continue 24 | if(line.startsWith("#")) ; Header 25 | Continue 26 | if(line.startsWith("`t")) ; Explanation line 27 | Continue 28 | 29 | line := "(" line ")" ; Wrap each bit in parens 30 | regexString := regexString.appendPiece("|", line) 31 | } 32 | 33 | ; Generate the name of the compiled regex file from the base name of the original 34 | SplitPath(A_LoopFileName, "", "", "", baseName) 35 | 36 | ; Overwrite the file if it exists 37 | FileLib.replaceFileWithString(baseName ".regex", regexString) 38 | } 39 | 40 | Toast.BlockAndShowMedium("Compiled all .bits files into .regex files") 41 | 42 | ExitApp 43 | -------------------------------------------------------------------------------- /source/standalone/copySourceToPersonalFolder.ahk: -------------------------------------------------------------------------------- 1 | #Include 2 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 3 | progToast := new ProgressToast("Copy source to personal folder").blockingOn() 4 | 5 | ; { sourcePath, destinationPath } 6 | folders := {} 7 | folders[Config.path["AHK_ROOT"]] := Config.path["EPIC_PERSONAL"] "\ahk" 8 | folders[Config.path["AHK_PRIVATE"]] := Config.path["EPIC_PERSONAL"] "\ahkPrivate" 9 | folders[Config.path["AHK_TEST"]] := Config.path["EPIC_PERSONAL"] "\ahkTest" 10 | 11 | main := Config.path["AHK_ROOT"] 12 | private := Config.path["AHK_PRIVATE"] 13 | test := Config.path["AHK_TEST"] 14 | 15 | destMain := Config.path["EPIC_PERSONAL"] "\ahk" 16 | destPrivate := Config.path["EPIC_PERSONAL"] "\ahkPrivate" 17 | destTest := Config.path["EPIC_PERSONAL"] "\ahkTest" 18 | 19 | foldersDisplay := "" 20 | For source, destination in folders 21 | foldersDisplay := foldersDisplay.appendLine(source " => " destination) 22 | confirmationMessage := " 23 | ( 24 | Are you sure you want to replace the contents of these folders? 25 | 26 | " foldersDisplay " 27 | )" 28 | if(!GuiLib.showConfirmationPopup(confirmationMessage, "Delete and replace")) 29 | ExitApp 30 | 31 | ; Delete existing contents of destination folder 32 | progToast.nextStep("Removing existing folders and files from destination") 33 | For _, destination in folders { 34 | Loop, Files, %destination%\*, F ; Files 35 | FileDelete, % A_LoopFilePath 36 | Loop, Files, %destination%\*, D ; Directories 37 | FileRemoveDir, % A_LoopFilePath, 1 ; 1-Delete recursively 38 | } 39 | 40 | ; Copy over everything from source except git-related stuff. 41 | progToast.nextStep("Copying files from source to destination") 42 | gitNames := [".git", ".gitignore", ".gitattributes"] 43 | For source, destination in folders { 44 | SetWorkingDir, % source ; Set working directory and use a relative file pattern so that A_LoopFilePath has only the folders at the start for FileCopy. 45 | Loop, Files, *, FDR ; All files and folder, recursing into folders 46 | { 47 | ; Don't copy over git-related files/folders. 48 | if(A_LoopFilePath.containsAnyOf(gitNames)) ; Check for names in full path so we catch files under ignored folders 49 | Continue 50 | 51 | ; Create folders and copy over files 52 | destinationPath := destination "\" A_LoopFilePath 53 | if(FileLib.folderExists(A_LoopFilePath)) 54 | FileCreateDir, % destinationPath 55 | else 56 | FileCopy, % A_LoopFilePath, % destinationPath 57 | } 58 | } 59 | 60 | progToast.finish() 61 | ExitApp 62 | -------------------------------------------------------------------------------- /source/standalone/dumpActiveWindowInfoToNotepad.ahk: -------------------------------------------------------------------------------- 1 | ; Dump a bunch of info about the active window into a temporary file and open that in Notepad++. 2 | 3 | #Include 4 | 5 | ; Give the target window a chance to regain focus (it presumably lost it when we launched the script). 6 | Sleep, 500 7 | 8 | info := [] 9 | info.push("ID", WinGet("ID", "A")) 10 | info.push("Name", Config.findWindowInfo("A").name) 11 | info.push("EXE", WinGet("ProcessName", "A")) 12 | info.push("Class", WinGetClass("A")) 13 | info.push("Title", WinGetTitle("A")) 14 | info.push("Tooltip Text", WindowLib.getTooltipText()) 15 | info.push("Current Control ID", ControlGetFocus("A")) 16 | info.push("VisualWindow", new VisualWindow("A")) 17 | 18 | Debug.tempFile(info*) 19 | 20 | ExitApp 21 | -------------------------------------------------------------------------------- /source/standalone/equalsDown.ahk: -------------------------------------------------------------------------------- 1 | ; Send the equals key and down a specified number of times. 2 | 3 | #Include 4 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 5 | 6 | ; Set mouseover text for icon 7 | Menu, Tray, Tip, % " 8 | ( LTrim 9 | Equals+Down Sender 10 | Ctrl+R to prompt for how many Equals+Down keystrokes to send. 11 | 12 | Emergency Exit: Ctrl+Shift+Alt+Win+R 13 | )" 14 | 15 | ^r:: 16 | numToSend := InputBox("Send Equals+Down Keystrokes", "Enter how many times to send Equals+Down:") 17 | if(!numToSend || ErrorLevel) 18 | return 19 | 20 | ; Sanity checks 21 | if(!numToSend.isNum()) { 22 | MsgBox, Error: given value was not a number. 23 | return 24 | } 25 | if(numToSend < 1) { 26 | MsgBox, Error: given number is smaller than 1. 27 | return 28 | } 29 | 30 | ; Confirmation if it's a really big number 31 | if(numToSend > 100) { 32 | MsgBox, 4, Delete page?, Are you sure you want to send Equals+Down %numToSend% times? 33 | IfMsgBox, No 34 | return 35 | else IfMsgBox, Cancel 36 | return 37 | else IfMsgBox, Timeout 38 | return 39 | } 40 | 41 | ; Send the keystrokes 42 | Loop, % numToSend { 43 | Send, ={Down} 44 | } 45 | return 46 | -------------------------------------------------------------------------------- /source/standalone/findProjectInSolutionsFolder.ahk: -------------------------------------------------------------------------------- 1 | ; Searches the source solutions folder for solutions that contain a particular project. 2 | 3 | #Include 4 | 5 | ; Get name of project to search for 6 | projectName := InputBox("Search solutions for project", "Enter project to search for:", "", "", 125) 7 | if(projectName = "") 8 | ExitApp 9 | projectName := projectName.appendIfMissing(".csproj") 10 | 11 | tt := new TextTable("Found solutions containing project") 12 | tt.addRow("Project name:", projectName) 13 | 14 | solutions := findSolutions(projectName) 15 | if(solutions = "") 16 | solutions := "" 17 | tt.addRow("Solutions:", solutions) 18 | 19 | new TextPopup(tt).show() 20 | ExitApp 21 | 22 | 23 | findSolutions(projectName) { 24 | tt := new TextTable().setBorderType(TextTable.BorderType_Line) 25 | 26 | searchRoot := Config.path["EPIC_SOURCE_S1"] "\HSWeb\Solutions\Apps\" 27 | Loop, Files, % searchRoot "*.sln", RF ; [R]ecursive, [F]iles (not [D]irectories) 28 | { 29 | content := FileRead(A_LoopFilePath) 30 | if(content.contains(projectName)) 31 | tt.addRow(A_LoopFilePath.removeFromStart(searchRoot)) 32 | } 33 | 34 | return tt.getText() 35 | } 36 | -------------------------------------------------------------------------------- /source/standalone/fixVDIDisplaySettings.ahk: -------------------------------------------------------------------------------- 1 | ; Fix the display setting to be my preferred "Window - Large" setting for all VDIs, as it seems to completely forget this on the regular. 2 | 3 | #Include 4 | 5 | pt := new ProgressToast("Fix VDI display settings").blockingOn() 6 | 7 | ; Make sure to wait until the settings window is active (contains "Display settings" text) 8 | pt.nextStep("Waiting for settings window to be active") 9 | WinWaitActive, VMware Horizon Client ahk_exe vmware-view.exe, Display settings 10 | Sleep, 1000 ; Give it a second to fully load up its contents 11 | 12 | ; Note the name of the last entry so we stop there. 13 | pt.nextStep("Finding last entry to stop at") 14 | ControlFocus, ListBox1, A 15 | Send, {End} 16 | finalName := getCurrentName() 17 | pt.endStep(finalName) 18 | 19 | ; Start with the first VDI entry (Conference Room for the moment) 20 | pt.nextStep("Finding first VDI entry (Esc to stop)") 21 | Send, {Home} 22 | Loop { 23 | Sleep, 250 ; Fields take a bit to load up sometimes. 24 | 25 | if(getCurrentName() = "Conference Room") 26 | Break 27 | 28 | Send, {Down} 29 | } 30 | 31 | ; Loop down through all entries and update the display setting. 32 | pt.nextStep("Fixing VDI entries (Esc to stop)") 33 | Loop { 34 | Sleep, 750 ; Fields take a bit to load up sometimes. 35 | 36 | Control, ChooseString, Window - Large, ComboBox1, A 37 | 38 | if(getCurrentName() = finalName) 39 | Break 40 | 41 | Send, {Down} 42 | } 43 | 44 | pt.finish() 45 | ExitApp 46 | 47 | Esc::ExitApp 48 | 49 | getCurrentName() { 50 | text := WinGetText("A").afterString("VMware Blast (default)") ; Always comes after this line 51 | 52 | ; Comes just before one of these 53 | text := text.beforeString("Customize remote desktop settings:") 54 | text := text.beforeString("&Preferred protocol:") 55 | text := text.beforeString("Scaling:") 56 | 57 | ; Remove leading/trailing newlines 58 | return text.clean() 59 | } 60 | -------------------------------------------------------------------------------- /source/standalone/generateHyperdriveEnvironments.ahk: -------------------------------------------------------------------------------- 1 | ; Generate a Hyperdrive environments file from the environments we have configured for Hyperspace. 2 | 3 | #Include 4 | #LTrim, Off 5 | 6 | HyperdriveConfigFilePath := Config.private["HYPERDRIVE_CONFIG"] "_" Config.private["WORK_ID"] "Config.json" 7 | ConfigFileTemplate := " 8 | ( 9 | { 10 | ""WorkstationID"" : """", 11 | ""CustomerName"" : ""- GDB "", 12 | ""Environments"" : { 13 | 14 | 15 | 16 | } 17 | } 18 | )" 19 | EnvironmentTemplate := " 20 | ( 21 | """" : { 22 | ""DisplayName"": """", 23 | ""HSWebServerURL"": """" 24 | } 25 | )" 26 | 27 | pt := new ProgressToast("Generating Hyperdrive environments config file").blockingOn() 28 | 29 | ; Read in our list of environments 30 | pt.nextStep("Reading in environments") 31 | tl := new TableList("epicEnvironments.tls").filterOutIfColumnBlank("HSWEB_URL") ; Filter out stuff without a URL 32 | ; Debug.popup("tl",tl) 33 | 34 | pt.nextStep("Generating environments XML") 35 | environments := "" 36 | For _,envData in tl.getTable() { 37 | if(envData["HSWEB_URL"].contains(" 4 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 5 | 6 | global mirrorKeys := buildMirrorKeys() 7 | 8 | 9 | ; These keys are optional, but they may help if you are typing on the left-hand side. 10 | CapsLock::Send, {BackSpace} 11 | Space & CapsLock::Send, {Enter} 12 | 13 | ; If Spacebar didn't modify anything, send a real Space keystroke upon release. 14 | Space:: 15 | Send {Space} 16 | return 17 | 18 | ; Mirror hotkeys 19 | Space & 1:: 20 | Space & 2:: 21 | Space & 3:: 22 | Space & 4:: 23 | Space & 5:: 24 | Space & 6:: 25 | Space & 7:: 26 | Space & 8:: 27 | Space & 9:: 28 | Space & 0:: 29 | Space & q:: 30 | Space & w:: 31 | Space & e:: 32 | Space & r:: 33 | Space & t:: 34 | Space & y:: 35 | Space & u:: 36 | Space & i:: 37 | Space & o:: 38 | Space & p:: 39 | Space & a:: 40 | Space & s:: 41 | Space & d:: 42 | Space & f:: 43 | Space & g:: 44 | Space & h:: 45 | Space & j:: 46 | Space & k:: 47 | Space & l:: 48 | Space & `;:: 49 | Space & z:: 50 | Space & x:: 51 | Space & c:: 52 | Space & v:: 53 | Space & b:: 54 | Space & n:: 55 | Space & m:: 56 | Space & ,:: 57 | Space & .:: 58 | Space & /:: 59 | mirroredKey := getMirroredKeyFromHotkey(A_ThisHotkey) 60 | ; Debug.popup("Hotkey",A_ThisHotkey, "Mirrored key",mirroredKey) 61 | 62 | ; {Blind} mode lets us use modifiers with whatever was pressed, too. 63 | Send, {Blind}%mirroredKey% 64 | return 65 | 66 | 67 | buildMirrorKeys() { 68 | keys := {} 69 | 70 | ; Put a "KEY_" in front of each character so that later on when we're retrieving a value, we can force the key to be a string. 71 | keys["KEY_1"] := "0" 72 | keys["KEY_2"] := "9" 73 | keys["KEY_3"] := "8" 74 | keys["KEY_4"] := "7" 75 | keys["KEY_5"] := "6" 76 | keys["KEY_6"] := "5" 77 | keys["KEY_7"] := "4" 78 | keys["KEY_8"] := "3" 79 | keys["KEY_9"] := "2" 80 | keys["KEY_0"] := "1" 81 | 82 | keys["KEY_q"] := "p" 83 | keys["KEY_w"] := "o" 84 | keys["KEY_e"] := "i" 85 | keys["KEY_r"] := "u" 86 | keys["KEY_t"] := "y" 87 | keys["KEY_y"] := "t" 88 | keys["KEY_u"] := "r" 89 | keys["KEY_i"] := "e" 90 | keys["KEY_o"] := "w" 91 | keys["KEY_p"] := "q" 92 | 93 | keys["KEY_a"] := ";" 94 | keys["KEY_s"] := "l" 95 | keys["KEY_d"] := "k" 96 | keys["KEY_f"] := "j" 97 | keys["KEY_g"] := "h" 98 | keys["KEY_h"] := "g" 99 | keys["KEY_j"] := "f" 100 | keys["KEY_k"] := "d" 101 | keys["KEY_l"] := "s" 102 | keys["KEY_;"] := "a" 103 | 104 | keys["KEY_z"] := "/" 105 | keys["KEY_x"] := "." 106 | keys["KEY_c"] := "," 107 | keys["KEY_v"] := "m" 108 | keys["KEY_b"] := "n" 109 | keys["KEY_n"] := "b" 110 | keys["KEY_m"] := "v" 111 | keys["KEY_,"] := "c" 112 | keys["KEY_."] := "x" 113 | keys["KEY_/"] := "z" 114 | 115 | return keys 116 | } 117 | 118 | getMirroredKeyFromHotkey(hotkeyString) { 119 | if(!hotkeyString) 120 | return "" 121 | 122 | keyToMirror := "KEY_" hotkeyString.sub(0) 123 | if(!keyToMirror) 124 | return "" 125 | 126 | ; Debug.popup("Hotkey",hotkeyString, "Key to mirror",keyToMirror, "Result",mirrorKeys[keyToMirror], "MirrorKeys",mirrorKeys) 127 | return mirrorKeys[keyToMirror] 128 | } 129 | -------------------------------------------------------------------------------- /source/standalone/iconTester/iconTester.ahk: -------------------------------------------------------------------------------- 1 | ; Script for testing out a bunch of icons to see how they look in the system tray. 2 | 3 | #Include 4 | ScriptTrayInfo.Init("AHK: Icon Tester", "pictureWhite.ico", "pictureRed.ico") 5 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 6 | 7 | global currentNum ; Number of the current icon in iconsAry 8 | global iconsAry ; Array of icon file names 9 | global t ; Toast object for showing the current icon 10 | 11 | 12 | ; Find all icons in sub-folder, track their paths in an array by number 13 | SetWorkingDir, %A_ScriptDir% 14 | iconsAry := [] 15 | iconsAry[0] := A_IconFile ; Entry 0 is the original icon for the script 16 | Loop, Files, *.* 17 | { 18 | if(A_LoopFileName = A_ScriptName) 19 | Continue 20 | 21 | iconsAry.push(A_LoopFileName) 22 | } 23 | 24 | ; Let the user know how many we found. 25 | if(!iconsAry.maxIndex()) { 26 | Toast.BlockAndShowMedium("No icons found in folder, exiting...") 27 | ExitApp 28 | } 29 | if(iconsAry.maxIndex() = 1) 30 | Toast.ShowMedium("Loaded 1 icon") 31 | else 32 | Toast.ShowMedium("Loaded " iconsAry.maxIndex() " icons") 33 | 34 | ; Set current icon number and show the persistent Toast for the icons 35 | currentNum := 0 36 | t := new Toast().show(VisualWindow.X_RightEdge, VisualWindow.Y_TopEdge) 37 | switchToIconWithNum(0) 38 | 39 | return 40 | 41 | 42 | ; Hotkeys to cycle back/forward through all icons in folder 43 | Left:: switchToIconWithNum(currentNum - 1) 44 | Right::switchToIconWithNum(currentNum + 1) 45 | 46 | ; Hotkeys for specific icons 47 | NumPad0::switchToIconWithNum(0) ; Default icon for script 48 | NumPad1::switchToIconWithNum(1) 49 | NumPad2::switchToIconWithNum(2) 50 | NumPad3::switchToIconWithNum(3) 51 | NumPad4::switchToIconWithNum(4) 52 | NumPad5::switchToIconWithNum(5) 53 | NumPad6::switchToIconWithNum(6) 54 | NumPad7::switchToIconWithNum(7) 55 | NumPad8::switchToIconWithNum(8) 56 | NumPad9::switchToIconWithNum(9) 57 | 58 | 59 | switchToIconWithNum(num) { 60 | num := getFixedIconNum(num) 61 | 62 | ; Find the right icon and use it 63 | iconPath := iconsAry[num] 64 | if(iconPath = "" || !FileExist(iconPath)) { 65 | Toast.ShowError("No icon found", "Icon " num " does not exist") 66 | return 67 | } 68 | Menu, Tray, Icon, % iconPath 69 | 70 | ; Update the current number, and the toast to match 71 | currentNum := num 72 | t.setText(getUpdatedToastMessage()) 73 | } 74 | 75 | getFixedIconNum(num) { 76 | min := iconsAry.minIndex() 77 | max := iconsAry.maxIndex() 78 | 79 | if(num > max) 80 | return min 81 | if(num < min) 82 | return max 83 | 84 | return num 85 | } 86 | 87 | getUpdatedToastMessage() { 88 | if(currentNum = 0) 89 | return "Using icon " currentNum " (original)" 90 | else 91 | return "Using icon " currentNum 92 | } 93 | -------------------------------------------------------------------------------- /source/standalone/lockComputer.ahk: -------------------------------------------------------------------------------- 1 |  2 | DllCall("LockWorkStation") ; Lock workstation. 3 | -------------------------------------------------------------------------------- /source/standalone/muteVolume.ahk: -------------------------------------------------------------------------------- 1 | 2 | SoundSet, 1, , mute 3 | -------------------------------------------------------------------------------- /source/standalone/notesHelper.ahk: -------------------------------------------------------------------------------- 1 | ; Make the superscripting I do in my notes a little more automatic. 2 | 3 | #Include 4 | ScriptTrayInfo.Init("AHK: Notes helper", "ninja.png", "ninjaRed.png") 5 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 6 | DetectHiddenWindows, On 7 | 8 | #If Config.isWindowActive("OneNote") 9 | 10 | ; Hotstrings for various people/directions 11 | :CB0*X?:mm::superscriptSides(true) 12 | :CB0*X?:mL::superscriptSides() 13 | :CB0*X?:mR::superscriptSides() 14 | :CB0*X?:mBL::superscriptSides() 15 | :CB0*X?:mBR::superscriptSides() 16 | :CB0*X?:mFL::superscriptSides() 17 | :CB0*X?:mFR::superscriptSides() 18 | :CB0*X?:mI::superscriptSides() 19 | :CB0*X?:mO::superscriptSides() 20 | :CB0*X?:mBI::superscriptSides() 21 | :CB0*X?:mBO::superscriptSides() 22 | :CB0*X?:mFI::superscriptSides() 23 | :CB0*X?:mFO::superscriptSides() 24 | :CB0*X?:mDL::superscriptSides() 25 | :CB0*X?:mDR::superscriptSides() 26 | :CB0*X?:mDB::superscriptSides() 27 | :CB0*X?:mDF::superscriptSides() 28 | :CB0*X?:mDI::superscriptSides() 29 | :CB0*X?:mDO::superscriptSides() 30 | 31 | :CB0*X?:uu::superscriptSides(true) 32 | :CB0*X?:uL::superscriptSides() 33 | :CB0*X?:uR::superscriptSides() 34 | :CB0*X?:uBL::superscriptSides() 35 | :CB0*X?:uBR::superscriptSides() 36 | :CB0*X?:uFL::superscriptSides() 37 | :CB0*X?:uFR::superscriptSides() 38 | :CB0*X?:uI::superscriptSides() 39 | :CB0*X?:uO::superscriptSides() 40 | :CB0*X?:uBI::superscriptSides() 41 | :CB0*X?:uBO::superscriptSides() 42 | :CB0*X?:uFI::superscriptSides() 43 | :CB0*X?:uFO::superscriptSides() 44 | :CB0*X?:uDL::superscriptSides() 45 | :CB0*X?:uDR::superscriptSides() 46 | :CB0*X?:uDB::superscriptSides() 47 | :CB0*X?:uDF::superscriptSides() 48 | :CB0*X?:uDI::superscriptSides() 49 | :CB0*X?:uDO::superscriptSides() 50 | 51 | :CB0*X?:bL::superscriptSides() 52 | :CB0*X?:bR::superscriptSides() 53 | :CB0*X?:bFL::superscriptSides() 54 | :CB0*X?:bFR::superscriptSides() 55 | :CB0*X?:bBL::superscriptSides() 56 | :CB0*X?:bBR::superscriptSides() 57 | :CB0*X?:bO::superscriptSides() 58 | :CB0*X?:bO::superscriptSides() 59 | :CB0*X?:bFO::superscriptSides() 60 | :CB0*X?:bFO::superscriptSides() 61 | :CB0*X?:bBO::superscriptSides() 62 | :CB0*X?:bBO::superscriptSides() 63 | :CB0*X?:bDL::superscriptSides() 64 | :CB0*X?:bDR::superscriptSides() 65 | :CB0*X?:bDB::superscriptSides() 66 | :CB0*X?:bDF::superscriptSides() 67 | :CB0*X?:bDI::superscriptSides() 68 | :CB0*X?:bDO::superscriptSides() 69 | 70 | ; Degree hotstrings 71 | :B0*?X:45d::dToDegree() 72 | :B0*?X:90d::dToDegree() 73 | :B0*?X:135d::dToDegree() 74 | :B0*?X:180d::dToDegree() 75 | :B0*?X:225d::dToDegree() 76 | :B0*?X:270d::dToDegree() 77 | :B0*?X:315d::dToDegree() 78 | :B0*?X:360d::dToDegree() 79 | 80 | #If 81 | 82 | 83 | superscriptSides(removeLastChar := false) { 84 | hotstring := A_ThisHotkey.afterString(":", true) 85 | if (removeLastChar) { 86 | hotstring := hotstring.sub(1, -1) ; Drop the last char 87 | Send, {Backspace} 88 | } 89 | 90 | length := hotstring.length() 91 | 92 | Send, {Shift Down}{Left %length%}{Shift Up} ; Select text 93 | Send, ^+= ; Superscript 94 | 95 | Send, {Right} ; Deselect, cursor back where it started 96 | ; Send, {Space} ; Distance from superscripted text - otherwise if there's already text after then OneNote de-superscripts what we just superscripted. 97 | Send, ^+= ; Remove superscript 98 | ; Send, {Backspace} ; Remove the extra space from above 99 | } 100 | 101 | dToDegree() { 102 | Send, {Backspace} ; Delete "d" 103 | Send, ° 104 | } 105 | -------------------------------------------------------------------------------- /source/standalone/onenoteOnlineHotkeys.ahk: -------------------------------------------------------------------------------- 1 | ; Click specific buttons in Onenote's online interface with hotkeys that mirror the desktop version. 2 | 3 | #Include 4 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 5 | DetectHiddenWindows, On 6 | 7 | ^+=:: 8 | Click, 428, 279 9 | Click, 428, 340 10 | return 11 | 12 | ^=:: 13 | Click, 428, 279 14 | Click, 428, 310 15 | return -------------------------------------------------------------------------------- /source/standalone/preciseMouse.ahk: -------------------------------------------------------------------------------- 1 | ; Move the mouse very precisely using the keyboard. 2 | 3 | #Include 4 | ScriptTrayInfo.Init("AHK: Precise Mouse Movement", "mouseGreen.ico", "mouseRed.ico") 5 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 6 | CommonHotkeys.setSuspendTimerLabel("HandleKeys") 7 | 8 | ; 200 hotkeys allowed per 2 seconds (to allow long holds for moving mouse further) 9 | #MaxHotkeysPerInterval, 200 10 | #HotkeyInterval, 2000 11 | 12 | ; Global flags/counts per arrow key 13 | global keyRunOnce := {"Left":false, "Right":false, "Up":false, "Down":false} 14 | global keyHeld := {"Left":false, "Right":false, "Up":false, "Down":false} 15 | global keyCounts := {"Left":0, "Right":0, "Up":0, "Down":0} 16 | 17 | ; Show a toast with the controls. 18 | tt := new TextTable().setBorderType(TextTable.BorderType_Line).setColumnDivider(" ") 19 | tt.addRow("Space/Numpad0:", "Left mouse button") 20 | tt.addRow("Arrows:" , "Move mouse") 21 | tt.addRow("Shift (hold):" , "Move slowly") 22 | tt.addRow("Alt (hold):" , "Move quickly") 23 | new Toast(tt.getText()).showForSeconds(5) 24 | 25 | SetTimer, HandleKeys, 10 26 | HandleKeys: 27 | ; For keys held down, add to the counts too 28 | For keyName,_ in keyCounts { 29 | if(!keyHeld[keyName]) ; Only add to counts here if the key is being held down (so first just adds 1, not potentially multiple depending on the timer) 30 | Continue 31 | if(!GetKeyState(keyName, "P")) ; Check physical state - logical state is cleared by triggering hotkeys 32 | Continue 33 | 34 | addToKeyCount(keyName) 35 | } 36 | 37 | ; Store off and clear key counts to make sure we're tracking any further updates that happen while we're handling the actual move 38 | tempCounts := keyCounts.clone() 39 | For keyName,_ in keyCounts 40 | keyCounts[keyName] := 0 41 | 42 | ; Calculate actual x/y movement 43 | moveX := tempCounts["Right"] - tempCounts["Left"] 44 | moveY := tempCounts["Down"] - tempCounts["Up"] 45 | 46 | ; Move the mouse 47 | if(moveX != 0 || moveY != 0) 48 | MouseMove, moveX, moveY, 0, R ; Speed of 0 moves mouse instantly, moving relative to current position 49 | return 50 | 51 | ; Arrow keys (plus any modifiers) move the mouse in that direction. These can also be held down, see loop above. 52 | *Left:: arrowPressed("Left") 53 | *Right::arrowPressed("Right") 54 | *Up:: arrowPressed("Up") 55 | *Down:: arrowPressed("Down") 56 | 57 | ; Releasing the hotkeys clears some flags used to tell what's held down. 58 | Left Up:: arrowReleased("Left") 59 | Right Up::arrowReleased("Right") 60 | Up Up:: arrowReleased("Up") 61 | Down Up:: arrowReleased("Down") 62 | 63 | ; Both space and numpad 0 double as a click 64 | Space:: LButton 65 | NumPad0::LButton 66 | 67 | ;--------- 68 | ; DESCRIPTION: Handle an arrow key being pressed, turning on flags and adding to the key counts. 69 | ; PARAMETERS: 70 | ; keyName (I,REQ) - Name of the key that was released, from "Left"/"Right"/"Up"/"Down". 71 | ;--------- 72 | arrowPressed(keyName) { 73 | ; The first press doesn't count as holding down the key (for the main loop above) - that's only 74 | ; turned on by the second trigger of this hotkey without releasing. 75 | if(keyRunOnce[keyName]) { 76 | keyHeld[keyName] := true 77 | return 78 | } 79 | 80 | addToKeyCount(keyName) 81 | keyRunOnce[keyName] := true 82 | } 83 | 84 | ;--------- 85 | ; DESCRIPTION: Add to the keyCounts array for the given key. The amount added varies depending on 86 | ; which modifier keys are held down. 87 | ; PARAMETERS: 88 | ; keyName (I,REQ) - Name of the key that was released, from "Left"/"Right"/"Up"/"Down". 89 | ;--------- 90 | addToKeyCount(keyName) { 91 | addAmount := 5 ; Basic, no modifier keys pressed 92 | 93 | ; Ctrl/Shift modifiers change mouse move speed 94 | if(GetKeyState("LCtrl", "P")) ; Check physical state for these keys, in case logical state was cleared by triggering hotkeys 95 | addAmount *= 5 ; 5x faster 96 | if(GetKeyState("LShift", "P")) 97 | addAmount /= 5 ; 5x slower 98 | 99 | keyCounts[keyName] := addAmount 100 | } 101 | 102 | ;--------- 103 | ; DESCRIPTION: Handle an arrow key being released, by clearing flags as needed. 104 | ; PARAMETERS: 105 | ; keyName (I,REQ) - Name of the key that was released, from "Left"/"Right"/"Up"/"Down". 106 | ;--------- 107 | arrowReleased(keyName) { 108 | keyRunOnce[keyName] := false 109 | keyHeld[keyName] := false 110 | } 111 | -------------------------------------------------------------------------------- /source/standalone/psxEmulatorController/XInput.ahk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theborg3of5/ahk/12cb3dda72589294ab8283c8f82639c20209ca1a/source/standalone/psxEmulatorController/XInput.ahk -------------------------------------------------------------------------------- /source/standalone/psxEmulatorController/psxEmulatorController.ahk: -------------------------------------------------------------------------------- 1 | ; Extra hotkeys when emulating a PSX with a controller. 2 | 3 | #Include 4 | #Include XInput.ahk 5 | ScriptTrayInfo.Init("AHK: Controller Emulator", "controllerGreen.ico", "controllerRed.ico") 6 | CommonHotkeys.Init(CommonHotkeys.ScriptType_Standalone) 7 | CommonHotkeys.setSuspendTimerLabel("CheckInputState") 8 | 9 | SetTimer, CheckInputState, 100 10 | XInput_Init() 11 | 12 | 13 | CheckInputState: 14 | if(!WinActive("ahk_class EPSX")) 15 | return 16 | 17 | Loop, 4 { 18 | controllerNum := A_Index - 1 ; Controllers are 0-3 19 | if State := XInput_GetState(controllerNum) { 20 | if(State.wButtons & XINPUT_GAMEPAD_DPAD_UP) 21 | sendEmulatorKey("F2") ; Switch save state 22 | if(State.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) 23 | sendEmulatorKey("F4") ; Lock/unlock framerate 24 | } 25 | } 26 | return 27 | 28 | 29 | #IfWinActive, ahk_class EPSX 30 | Joy9:: 31 | sendEmulatorKey("F1") ; Save state 32 | return 33 | Joy10:: 34 | sendEmulatorKey("F3") ; Load state 35 | return 36 | #IfWinActive 37 | 38 | 39 | ; Emulator checks for key being down, not an actual keypress, so this is needed. 40 | sendEmulatorKey(key) { 41 | ; Debug.popup("Sending key", key) 42 | SendInput, {%key% Down} 43 | Sleep, 50 44 | SendInput, {%key% Up} 45 | Sleep, 100 46 | } 47 | -------------------------------------------------------------------------------- /source/standalone/pullAllRepos.ahk: -------------------------------------------------------------------------------- 1 | ; Pull updates to all AHK Git repos at once. 2 | 3 | #Include 4 | 5 | t := new ProgressToast("Pulling all AHK Git repos").blockingOn() 6 | 7 | gitRepos := [] 8 | gitRepos.push(Config.path["AHK_ROOT"]) 9 | gitRepos.push(Config.path["AHK_PRIVATE"]) 10 | gitRepos.push(Config.path["AHK_TEST"]) 11 | 12 | For _,path in gitRepos { 13 | t.nextStep("Updating " path) 14 | 15 | SetWorkingDir, path 16 | result := RunLib.runReturn("git pull --rebase=true") 17 | t.endStep(result.clean()) 18 | } 19 | 20 | t.finish() 21 | ExitApp 22 | -------------------------------------------------------------------------------- /source/standalone/releaseModifierKeys.ahk: -------------------------------------------------------------------------------- 1 | #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. 2 | #SingleInstance, Force ; Running this script while it's already running just replaces the existing instance. 3 | SendMode, Input ; Recommended for new scripts due to its superior speed and reliability. 4 | SetWorkingDir, % A_ScriptDir ; Ensures a consistent starting directory. 5 | 6 | Send, {LWin Up}{RWin Up}{LCtrl Up}{RCtrl Up}{LAlt Up}{RAlt Up}{LShift Up}{RShift Up} 7 | ExitApp 8 | -------------------------------------------------------------------------------- /source/standalone/runProgram.ahk: -------------------------------------------------------------------------------- 1 | ; Activate (or run if not already open) a specific program, to be executed by external program (like Microsoft keyboard special keys). 2 | 3 | #Include 4 | 5 | progName = %1% ; Input from command line 6 | if(!progName) 7 | ExitApp 8 | 9 | Config.runProgram(progName) 10 | 11 | ExitApp 12 | -------------------------------------------------------------------------------- /source/standalone/sendMediaKey.ahk: -------------------------------------------------------------------------------- 1 | ; Send a specific media key, to be executed by external program (like Microsoft keyboard special keys). 2 | 3 | #Include 4 | #NoTrayIcon 5 | 6 | inputKeys = %1% ; Input from command line 7 | if(!inputKeys) 8 | ExitApp 9 | 10 | For _,key in inputKeys.split(",") 11 | Send, {%key%} 12 | 13 | ExitApp 14 | -------------------------------------------------------------------------------- /source/standalone/sendRange.ahk: -------------------------------------------------------------------------------- 1 | ; Generate a Hyperdrive environments file from the environments we have configured for Hyperspace. 2 | 3 | #Include 4 | #LTrim, Off 5 | 6 | ; This is from DataLib.getNumericRangeBits(), keep it up to date with that 7 | prompt := " 8 | ( 9 | Supported formats: 10 | START-END 11 | START:[STEP:]END 12 | 13 | START 14 | Numeric start of the range. 15 | 16 | STEP 17 | How much to increment each time. Defaults to 1. 18 | Step direction is always calculated based on start/end (positive if begin is smaller than end, etc.) 19 | 20 | END (any of) 21 | - A normal number 22 | - [+/-]num: start +/- a number (+5 to specify start+5) [not supported for hyphenated ranges] 23 | - *num: Replace the last few digits of start with the new one (*53 will be start with its last two digits replaced with 53) 24 | )" 25 | 26 | rangeString := InputBox("Enter range to send", prompt, , 1100, 375) 27 | if (rangeString = "") 28 | ExitApp 29 | 30 | rangeAry := DataLib.expandList(rangeString) 31 | if (DataLib.isNullOrEmpty(rangeAry)) { 32 | ClipboardLib.set(rangeString) 33 | Toast.BlockAndShowError("Failed to convert input", "", "Input copied to clipboard") 34 | ExitApp 35 | } 36 | 37 | ClipboardLib.send(rangeAry.join(",")) 38 | 39 | ExitApp 40 | -------------------------------------------------------------------------------- /source/standalone/transactionDump.ahk: -------------------------------------------------------------------------------- 1 | ; Dump a string representation of a client data transaction in a specific environment to a file. 2 | 3 | #Include 4 | 5 | ; Optional input from command line 6 | txId = %1% 7 | 8 | ; Default to the referrals data tx if nothing given on command line. 9 | if(!txId) 10 | txId := Config.private["RFL_TX_ID"] 11 | 12 | ; Create a Selector so the user can pick the environment and give us the TX's ID. 13 | s := new Selector("epicEnvironments.tls").setTitle("Dump Data Transaction from Environment to File") 14 | s.addOverrideFields(["TX_ID"]).setDefaultOverrides({"TX_ID":txId}) ; Add a field for the TX's ID and default it in if it was given already. 15 | data := s.prompt() 16 | if(!data) 17 | ExitApp 18 | 19 | envName := data["NAME"] 20 | envId := data["COMM_ID"] 21 | txId := data["TX_ID"].clean() ; Clean out any leading/trailing odd characters (generally spaces). 22 | 23 | if(envId = "") 24 | ExitApp 25 | if(envId = "LAUNCH") ; Special case - just launching the script without picking an environment 26 | envId := "" 27 | 28 | runString := buildTxDumpRunString(txId, envId, envName) 29 | if(runString) 30 | RunLib.runCommand(runString, Config.path["TX_DIFF"], true) 31 | 32 | ExitApp 33 | 34 | buildTxDumpRunString(txId, environmentCommId := "", environmentName := "") { 35 | if(!txId) 36 | return "" 37 | 38 | ; Build the full output filepath. 39 | if(!environmentName) 40 | if(environmentCommId) 41 | environmentName := environmentCommId 42 | else 43 | environmentName := "OTHER" 44 | outputPath := Config.path["TX_DIFF_OUTPUT"] "\" txId "-" environmentName ".txt" 45 | 46 | ; Build the string to run 47 | runString := Config.private["TX_DIFF_DUMP_BASE"] 48 | runString := runString.replaceTag("TX_ID", txId) 49 | runString := runString.replaceTag("OUTPUT_PATH", outputPath) 50 | 51 | ; Add on the environment if it's given - if not, leave off the flag (which will automatically cause the script to show an environment selector instead). 52 | if(environmentCommId) 53 | runString .= " --env " environmentCommId 54 | 55 | ; Debug.popup("buildTxDumpRunString","Finish", "txId",txId, "outputFolder",outputFolder, "environmentCommId",environmentCommId, "runString",runString) 56 | return runString 57 | } 58 | -------------------------------------------------------------------------------- /source/standalone/transactionDumpAllCurrent.ahk: -------------------------------------------------------------------------------- 1 | ; Dump a string representation of a client data transaction in all current-version environments to files at once. 2 | 3 | #Include 4 | 5 | ; Optional input from command line 6 | txId = %1% 7 | 8 | ; Prompt the user for the transaction ID if nothing was passed via command line 9 | if(!txId) 10 | txId := InputBox("Dump Data Transaction for All Current Environments", "Enter data transaction ID", , , , , , , , Config.private["RFL_TX_ID"]) 11 | 12 | ; Clean out any leading/trailing odd characters (generally spaces). 13 | txId := txId.clean() 14 | if(!txId) 15 | ExitApp 16 | 17 | ; Get the list of environments from a static file. 18 | configPath := FileLib.findConfigFilePath("allCurrentEpicEnvironments.txt") 19 | commIdAry := FileLib.fileLinesToArray(configPath) 20 | ; Debug.popup("commIdAry",commIdAry) 21 | 22 | ; Start in the dump script's directory. 23 | SetWorkingDir, % Config.path["TX_DIFF"] 24 | 25 | For _,commId in commIdAry { 26 | runString := buildTxDumpRunString(txId, commId) 27 | if(runString) 28 | Run(runString) 29 | } 30 | 31 | ExitApp 32 | 33 | buildTxDumpRunString(txId, environmentCommId := "", environmentName := "") { 34 | if(!txId) 35 | return "" 36 | 37 | ; Build the full output filepath. 38 | if(!environmentName) 39 | if(environmentCommId) 40 | environmentName := environmentCommId 41 | else 42 | environmentName := "OTHER" 43 | outputPath := Config.path["TX_DIFF_OUTPUT"] "\" txId "-" environmentName ".txt" 44 | 45 | ; Build the string to run 46 | runString := Config.private["TX_DIFF_DUMP_BASE"] 47 | runString := runString.replaceTag("TX_ID", txId) 48 | runString := runString.replaceTag("OUTPUT_PATH", outputPath) 49 | 50 | ; Add on the environment if it's given - if not, leave off the flag (which will automatically cause the script to show an environment selector instead). 51 | if(environmentCommId) 52 | runString .= " --env " environmentCommId 53 | 54 | ; Debug.popup("buildTxDumpRunString","Finish", "txId",txId, "outputFolder",outputFolder, "environmentCommId",environmentCommId, "runString",runString) 55 | return runString 56 | } 57 | -------------------------------------------------------------------------------- /source/standalone/triggerOutlookQuickStep.ahk: -------------------------------------------------------------------------------- 1 | ; Send a specific media key, to be executed by external program (like Microsoft keyboard special keys). 2 | #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. 3 | #SingleInstance, Force ; Running this script while it's already running just replaces the existing instance. 4 | SendMode, Input ; Recommended for new scripts due to its superior speed and reliability. 5 | SetWorkingDir, %A_ScriptDir% ; Ensures a consistent starting directory. 6 | 7 | ; Run in Outlook only. 8 | if(!WinActive("ahk_class rctrl_renwnd32")) 9 | ExitApp 10 | 11 | quickStepNumber = %1% ; Input from command line 12 | if(!quickStepNumber) 13 | ExitApp 14 | 15 | Send, ^+%quickStepNumber% 16 | -------------------------------------------------------------------------------- /source/standalone/updateNotepadPPSupport/autoCompleteClass.ahk: -------------------------------------------------------------------------------- 1 | ; Represents an entire class that we want to add auto-complete info for. 2 | class AutoCompleteClass { 3 | ;region ------------------------------ INTERNAL ------------------------------ 4 | name := "" ; The class' name 5 | parentName := "" ; The name of the class' parent (if it extends another class) 6 | group := "" ; The group (used for syntax highlighting) 7 | members := {} ; {.memberName: AutoCompleteMember} 8 | 9 | ;--------- 10 | ; DESCRIPTION: Create a new class representation. 11 | ; PARAMETERS: 12 | ; defLine (I,REQ) - The definition line for the class - the one that starts with "class ". 13 | ; group (I,REQ) - The group this class should be part of, for syntax highlighting purposes. 14 | ;--------- 15 | __New(defLine, group) { 16 | this.name := defLine.firstBetweenStrings("class ", " ") ; Break on space instead of end bracket so we don't end up including the "extends" bit for child classes. 17 | if(defLine.contains(" extends ")) 18 | this.parentName := defLine.firstBetweenStrings(" extends ", " {") 19 | 20 | this.group := group 21 | } 22 | 23 | ;--------- 24 | ; DESCRIPTION: Add the given member to this class. 25 | ; PARAMETERS: 26 | ; member (I,REQ) - The member to add. 27 | ;--------- 28 | addMember(member) { 29 | if(member.name = "") 30 | return 31 | 32 | dotName := "." member.name ; The index is the name with a preceding dot - otherwise we start overwriting things like .contains with this array, and that breaks stuff. 33 | this.members[dotName] := member 34 | } 35 | ;--------- 36 | ; DESCRIPTION: Add the given member to this class, but only if a member with the same name 37 | ; doesn't already exist. 38 | ; PARAMETERS: 39 | ; member (I,REQ) - The member to add. 40 | ;--------- 41 | addMemberIfNew(member) { 42 | if(member.name = "") 43 | return 44 | 45 | dotName := "." member.name ; The index is the name with a preceding dot - otherwise we start overwriting things like .contains with this array, and that breaks stuff. 46 | if(this.members.HasKey(dotName)) 47 | return 48 | 49 | this.members[dotName] := member 50 | } 51 | 52 | ;--------- 53 | ; DESCRIPTION: Get the member with the given name. 54 | ; PARAMETERS: 55 | ; name (I,REQ) - The name of the member to retrieve. 56 | ; RETURNS: An AutoCompleteMember instance representing the member. 57 | ;--------- 58 | getMember(name) { 59 | dotName := "." name 60 | return this.members[dotName] 61 | } 62 | 63 | ;--------- 64 | ; DESCRIPTION: Generate the XML for this class and all of its members. 65 | ; RETURNS: The generated XML 66 | ;--------- 67 | generateXML() { 68 | xml := "" 69 | For _,member in this.members 70 | xml := xml.appendLine(member.generateXML(this.name)) 71 | return xml 72 | } 73 | ;endregion ------------------------------ INTERNAL ------------------------------ 74 | } 75 | -------------------------------------------------------------------------------- /source/standalone/xdsDiff.ahk: -------------------------------------------------------------------------------- 1 | ; Grab two raw files of XDS content from the server folder, clean them up and diff them. 2 | ; Goes with my ;xdsdiff macro. 3 | 4 | #Include 5 | 6 | ; Read in the raw files of narrative/content. 7 | rawLeft := FileRead(Config.path["EPIC_NFS_ASK"] "\temp\xdsDiffLeft.txt") 8 | rawRight := FileRead(Config.path["EPIC_NFS_ASK"] "\temp\xdsDiffRight.txt") 9 | 10 | ; Strip out all HTML tags. 11 | htmlRegEx := "i)<\/?(DIV|SPAN|TABLE|TBODY|TR|TD|A|OL|UL|IMG|H[1-6]|!--)[^>]*>|(\r\n)?<\/?LI[^>]*>" ; i = case-insensitive flag 12 | cleanLeft := rawLeft.replaceRegEx(htmlRegEx,"") 13 | cleanRight := rawRight.replaceRegEx(htmlRegEx,"") 14 | 15 | ; Put the cleaned text back in files and diff it. 16 | pathLeft := A_Temp "\ahkDiffLeft.txt" 17 | pathRight := A_Temp "\ahkDiffRight.txt" 18 | FileLib.replaceFileWithString(pathLeft, cleanLeft) 19 | FileLib.replaceFileWithString(pathRight, cleanRight) 20 | Config.runProgram("WinMerge", pathLeft " " pathRight) 21 | 22 | ExitApp 23 | --------------------------------------------------------------------------------