KeyBind HowTo: v1.2.0 Reading this through one time will super-charge your KeyBind endeavours! This file is stuffed with tricks and tips and insights which at the time of writing are available nowhere else. It will take you a *lot* less time to read than it took me to write! If you plan to use KeyBind extensively, I heartily recommend this. This document was originally written to help with KeyBind's ini-only settings but these days there is the Config Editor, which enables you to get to all this stuff in a far more intuitive and less error-prone way. This document has been kept up-to-date, though, and probably has information found nowhere else. It has gotten quite /long/. I recommend you use your search function! Introduction to KeyBind: KeyBind performs "Tasks". A "Task" (as far as KeyBind is concerned) is comprised of one or more "Commands" A Command is simply a special word with braces after it, e.g.. DoubleClick() Sometimes with parameters inside the braces, e.g.. Visit(https://google.com) which instruct KeyBind to perform some action which you yourself might have performed, except automatically, and without any expense of time or effort on your part. There are many, *many* commands to choose from. Tasks can be trivial or complex. One or two commands can be strung together, and when your needs develop, you can create "scripts", which are plain text files with a command on each line. Scripts can be huge, and can also call other scripts, allowing for an organised, modular and powerful approach to your automation. Activators: Every task needs to be activated in some way. There are four main types: HotKey: Some keystroke or combination of keystrokes/mouse is actioned. Schedule: A preset date and/or time arrives. These can be repeating, e.g. every 30m, or year, or whatever. Sentinel: Folder Sentinel: A file lands in its watched folder. File Sentinel: Its watched file has been altered in some way. Trigger: Window trigger: A specific window or app activates (brought to the foreground), or an app dies. System Event trigger: You lock or wake your PC, sign in, insert USB stick, idle for X minutes, etc. ClipBoard trigger: Something happened there, maybe matching some string. Window And Titles: Window Triggers and HotKeys both rely on KeyBind's ability to know which window is which; to be able to differentiate between windows which are important and require action, and those which don't. When we create new Window Triggers or HotKey app "groups", we need to supply KeyBind with a string which will match the window's title somehow. KeyBind calls this a "Catcher". A "string", for those who don't code, is simply a string of charcters; any word or phrase is a "string". A simple Catcher might be "Chrome", which would catch any window with the word "Chrome" in its Title. Here are all the properties you can use to catch windows.. TITLE - The Window's Title. This is the default method; a "Title" Sub-String (aka. "partial") match. It is case-sensitive by default, so "Foo" matches "FoodBaby" and "BarFool", but not "football" or "you fool!". You can also match by: CLASS - The internal window classname. REGEXPTITLE - Window title using a regular expression. REGEXPCLASS - Window classname using a regular expression. X:n;Y:n;W:n;H:n - The position and size of a window. INSTANCE - The 1-based instance when all other given properties match. Exact Match only affects title text. CLASS, position, size and instance always compare exactly, with or without it. Catchers with no title text in them (coordinates, classes and the like) are always exact anyway, so the editor keeps them that way: the Exact option locks on and the list shows them exact-blue (or pink, with Always). You can set multiple properties inside a single definition, using semi- colons to separate the individual properties. The following definition would match the /second/ instance of a window with the title, "Funky Window" AND the CLASS name, "Groovy Class".. Wait a minute! I hear the learned say, class definitions use square braces, not angle braces. True, but as these are stored inside [ini] sections, we need to switch those in our definitions to prevent the ini functions exploding. KeyBind will switch them back internally. Deal with it. It was that or curly braces! *ew*. You can use square braces in the GUI. The following definition would match either of /three/ separate windows: Yes, we have just created an app "group". HotKeys in this section will be active for all three of these apps, which are the three main web browsers on folk's most systems. And yes, the possibilities are vast. I might yet make a "group create" function for the config GUI. Any command or setting which requires a "Catcher", can use any or all of the above methods and properties to catch a window. Processing Priority: As you know; probably; KeyBind's [app] HotKeys take priority over Global HotKeys as well as over any built-in keyboard shortcuts an app might have.. KeyBind [App Group] HotKeys >> KeyBind [Global] HotKeys >> Current App's HotKeys But what if two KeyBind [App Group] sections match the current window? Which section will fire? The simple answer is, all of them! Well, sorta. Consider the following ini [app] sections.. ; This is a "group". This catches THREE apps.. [] ^!{NUMPAD5}=WinMove(4|4|@DesktopWidth-8|@DesktopHeight-8) ; This catches only Google Chrome, when at eBay.. [eBay - Google Chrome] {NUMPAD0}=@ScriptsDir\Examples\Drag+Drop-eBay-Image.kc {NUMPADDOT}=^w ; This catches any Chrome window.. [Google Chrome] {Esc}=^w KeyBind will process your ini file in the order it is written. As an example, let's say we hit Ctrl+Alt+Numpad5 whilst viewing an eBay page in Chrome.. KeyBind scans its list of apps and discovers it catches our first (REGEXPTITLE) section. Then it checks if there is a matching HotKey for this "app". There is, so it fires the task. Done. Now let's say we hit 0 on the Numpad; KeyBind again catches against the first section, but this time finds no corresponding HotKey. But it doesn't stop; it moves onto the next catch and Bingo! There is a HotKey set for {Numpad0}, KeyBind fires the task. Done. If I am at corz.org when I hit Numpad0, nothing happens (well, I get a zero). There is no HotKey for Numpad0 in the "group" (REGEXPTITLE) section; nor in the "base" [Google Chrome] section, so even though KeyBind caught the Window twice, there was no corresponding HotKey in either section and so no task to perform. The Numpad0 and NumpadDot HotKeys /only/ work when I'm at eBay, and only in Chrome. In essense, HotKeys I want to /always/ work in Chrome I put in the base (final) [Google Chrome] section, and then, if I need more fine-tuned Window catching, I create sections /above/ that with more specific criteria. So, the complete "processing priority" is.. * Highest (ini order) app's HotKeys. * Lowest (ini order) app's HotKeys. * Global HotKeys. * Program Keyboard Shortcuts. The position of the [Global] section has no effect on this order. And don't forget, if one of your global HotKeys interferes with an app's built-in keybard shortcuts, you can set a dash as the HotKey task for that app, instructing KeyBind to ignore its global HotKey for that app, e.g.. [Notepad++] ^!{s}=- [Global] ^!{s}=Date() Here the global HotKey will work normally everywhere except in Notepad++, where it will fire Notepad++'s built-in shortcut command, which on my system is "Save As". I think that about covers titles and classes. The two (amazingly useful and incredibly powerful) Regexp "descriptions" use the Perl-Compatible Regular Expression Engine (PCRE). It would take weeks, perhaps months of intense study to fully understand its available functionality, but even with the simplest expressions (like in the example above), you can do extremely powerful things. I like Ctrl+Alt+Numpad5 to put my current working window exactly where it is supposed to be, whatever it might be. To be able to have three or four different "groups" of sizes available, "Full-screen", "tall documents", "Wide Net Tools", and so on, is a real boon. An organised desktop makes for good productivity and a clear mind! There's one more property you can use to match a window, and that is its position and size. The following matches a window by its dimensions.. In this case, full-screen windows. This is not one I use a lot myself, but as we have the ability to move and resize window with pixel- precision, I can see how it might be useful. And remember, everything I've written about matching window titles for HotKey app sections also applies to _Window_Triggers_. I like space, and desktop real-estate is always at a premium. My Numpad window placement system goes a long way towards ensuring I can always butt my mouse up against a particular part of an edge of the screen and get to a particular window. But some apps want to change all that, maximizing themselves to fill my entire desktop! The Cheek! [Window Triggers] *=WinMove(4|4|@DesktopWidth-8|@DesktopHeight-8) That trigger will catch *any* window which is maximized; restore, resize and move it to be *slightly* smaller than the desktop, so I can still click all around the edges. Note: this only works if your desktop is 1366x768. Curiously, a maximized window's dimensions are 6px bigger on all sides, than the actual desktop! The dimensions picker (available from KeyBind's tray menu), makes light work of discovering your own numbers. Low-Level Hooks. What now? I hear you ask. Well, KeyBind can setup some low-level "hooks" in Windows OS, basically just asking Windows to let us into the queue for "shit happening" with the mouse, essentially clicks and wheel. Once inside the actual Windows event queue, our click and wheel triggers (and that is ALL KeyBind - optionally - uses this for) can dive in and take over that event, saying, "MY CLICK!", and it's all ours. Switched OFF, KeyBind can still perform clicks and wheel motions inside your apps, 100%, you loses none of the awesome KeyBind functionality, only the ability to *activate* Tasks using clicks and wheel. Now Why? I hear you say. Well, obviously it's limitless, but personally, I like to have an always-handy admin menu. So I hit my KeyBind modifier keys (our old favourites, Ctrl+Win+Alt) and CLICK! anywhere, and my admin menu appears. All the admin tools I use a /lot/, are there. On a click. Of course I also have a regular HotKey for it, too. And other stuff. There's also "raw" hooks mode, which is similar, but rather than dive right into the actual queue (where, if we don't deal with our own messages pronto, like within 300ms, we get booted out of the queue!) raw mode instead gets a "copy" of the queue to work with. There are some subtle differences between the two worth noting. For example, in raw mode, because we are only working with a copy of the queue, your clicks should pass straight through. I have noticed that the key order of the modifiers can impact these low-level hooks. Ctrl, Then Win, Then Alt, simply doesn't work, for example. I usually just mash all three and don't notice, but you should be aware of this if you employ low-level hooks. Dynamic @Macros (aka. "Macros"): Many of the settings and most of the commands accept some kind of @Macro or "Macro" as part or all of the value. A Dynamic Token is a string begining with an "@" symbol which, at run-time, is transformed into the current value the @Macro represents. For example, @Date would magically transform into the current date, whatever it might be at the time. Now you get an idea of how handy @Macros can be. Dynamic Macros allow for a high degree of flexibility in your commands and settings. As a crude example, you might use some date Macros in the name of your log file.. dump_file=@DataDir\debug_@Year-@Mon-@Mday@@Hour.@Min.@Sec.log That log file would then get a name something like.. C:\Users\Me\AppData\Roaming\corz\KeyBind\debug_2018-05-05@21.09.30.log Using this dynamic name, your log file would *not* be deleted at launch time, but instead a new, timestamped log file would be created. You could use the facility to have "daily" logging, or whatever. Of course, this is a trivial example. The real fun start when you use this facility inside your tasks. In addition to @Macros (and user-created variables - more later) you can use any Windows Environment Variable anywhere in KeyBind and it will be automagically expanded to its current value. You can get to a *big* list of you system's current "ENV_VAR" via KeyBind's About Box. All the bult-in @Macros. These are replaced dynamically with their current values. Some are aliases of each other. Use whichever is most natural for you. Most work in preferences and tasks. Task-only macros are noted below. Path @Macros: @Documents Current user's "My Documents" directory. @MyDocuments Current user's "My Documents" directory. @Desktop Current user's Desktop. @TempDir Probably "C:\Users\\AppData\Local\Temp" @DataDir KeyBind data directory. @ScriptsDir Your current scripts folder (set by scripts_dir below). @HomeDir Your user directory. @HomeDrive Drive letter of drive containing current user's home directory. @HomePath Directory part of current user's home directory. @ProgramFiles Path to Program Files folder. @UserProfileDir Path to current user's Profile folder. @UserDir Path to current user's Profile folder. @Me Current user's user name. @User Current user's user name. @UserName Current user's user name. @ThisApp Full path to running app (KeyBind.exe). @KeyBind Full path to running app (KeyBind.exe). Monitor work-area @Macros: @WorkAreaLeft Usable left edge of the active window's monitor. @WorkAreaTop Usable top edge of that monitor. @WorkAreaRight Usable right edge of that monitor. @WorkAreaBottom Usable bottom edge of that monitor. The monitor is selected from the active window's centre when the tokens are expanded. An off-screen window uses its nearest monitor. Windows excludes space reserved by a taskbar or docked desktop toolbar on any edge. These work on secondary monitors and can return negative coordinates. Values are desktop coordinates, not width or height; right and bottom are immediately beyond the usable pixels. Subtract left from right for width, or top from bottom for height. A failed monitor lookup falls back to the full virtual desktop bounds. For example, place a window ten pixels inside the usable top-left: WinMove(@WorkAreaLeft+10|@WorkAreaTop+10|600|400) The countdown defaults use the usable bottom-right of that monitor: countdown_x=@WorkAreaRight-208 countdown_y=@WorkAreaBottom-105 These position the full timer GUI's top-left. Taskbar space is already excluded; do not subtract a guessed taskbar height again. Dragging a timer saves numeric positions, which remain exact. Timers with opening parameters use their own keys: CountDown(2m) saves countdown_2m_x/y; CountDown(2h 10m) saves countdown_2h_10m_x/y. Missing group coordinates use the corresponding generic countdown_x/y preference. Date & time @Macros: @Hour Hours value of clock in 24-hour format. Range is 00 to 23. @Mday Current day of month. Range is 01 to 31. @Min Minutes value of clock. Range is 00 to 59. @Mon Current month. Range is 01 to 12. @MSec Milliseconds value of clock. Range is 000 to 999. The update frequency of this value depends on the timer resolution of your hardware and may not update every millisecond. @Sec Seconds value of clock. Range is 00 to 59. @Wday Numeric day of week. Range is 1 to 7 which corresponds to Sunday through Saturday. @Yday Current day of year. Range is 001 to 365 (366 for leap years) @Year Current four-digit year. @Time The current time using the time format specified in your computer's regional settings. If your computer's regional settings are not accessible KeyBind returns the time in the "h:mm:ss tt" format @Date The current date, in the format specified by your date_format setting. Default is: @year-@mon-@mday. @DateTimeX This is a special macro which will return the Date and Time in a variety of formats. The "X" is an integer between 0 and 5: 0 - The date and time. The date part as a short date, the time part as a long time. 1 - The date using the long date format specified in your computer's regional settings. 2 - The date using the short date format specified in your computer's regional settings. 3 - The time using the time format specified in your computer's regional settings. 4 - The time using the 24-hour format (hh:mm). 5 - The time using the 24-hour format (hh:mm:ss). Usage: e.g. Text(@DateTime0) >> 27/05/2018 12:24:55 Text(@DateTime1) >> 27 May 2018 Text(@DateTime2) >> 27/05/2018 Text(@DateTime3) >> 12:25:44 Text(@DateTime4) >> 12:25 Text(@DateTime5) >> 12:26:08 If you attempt to specify an integer outside the range (0-5) you will get back something like "2018-05-27Time6", which serves you right. Count @Macros: @Count shows the running number, starting at 1 when KeyBind launches. Use Count() or add + or - after the macro to change it in a task. See Count() below. Sentinel Rename() @Macros: @Sequence = Numeric sequence. Optionally specify zero padding. @Random = Random string name. Optionally specify length. @Stamp = Date and/or Time stamp file names. Optionally specify return date/time format. @StampDate = Shortcut for simple Date Stamp @StampTime = Shortcut for simple Time Stamp. See the "Sentinel Commands" section (below) for more details about using these Sentinel Rename() macros. There is also a special macro, @ExitValue, which contains any return value from the previous command. At the end of a Task, this macro is reset to an empty value. Obviously, you don't want to use /any/ of these macro names for your own user variables, as you access these variables via @Macros. Attempting to re-use the built-in @Random macro: VarAssign(Random|foobar)**Speak(@ExitValue|100|-1|George) Will get you: "That Macro Is Reserved!" In a posh voice, if you have George installed. Whatever the voice, you still won't get to assign anything to @Random; it's reserved. This will work fine. VarAssign(Fandom|foobar)**Speak(@Fandom|100|-1|George) HotKeys (aka. "Key Binding"): This is how it all started - the primary reason for KeyBind's existence. That is, the basic ability to press one key (or key combination) and have the program I am working in receive a completely different set of keystrokes, so I can use "Esc" to close Explorer windows, for example. A valid HotKey, like all of KeyBind's triggers, is a simple data pair in your ini file, something like so.. {Esc}=^w It's basically, Trigger=Task. To switch a HotKey or trigger off without deleting it, put a ~ (tilde) at the very start of its line. It stays in the lists, greyed-out, and won't fire. For HotKeys, the trigger is the HotKey itself; the keys you press; so on the left is the key we will be hitting (or key combination (more later)) and on the right, the task we want to perform. In this case, the task is a simple sending of keystrokes (Ctrl+W). In the absence of valid KeyBind commands to encapsulate the data, KeyBind assumes all characters to be KeyStrokes. So in the above example, we hit "Esc" and the program we are in receives the keystrokes "Ctrl+W". For many apps this is the shortcut to close a window or tab. "Esc" is way more intuitive and natural for this task. The "Esc" is inside Curly Braces {} because it is a "special" key that can't be described with a single character (the one you hit). Many keys are like this and it works for all keys. If in doubt, use curly braces. Certain single characters represent keyboard modifier keys: ^ => Ctrl ! => Alt + => Shift # => Windows Key Any other special key needs to be enclosed in {Curly Braces}, e.g.. Ctrl + Alt + Numpad5 ==> ^!{NUMPAD5} Basically, any key that isn't a single charatcer needs to be inside curly braces, e.g. {Delete}, {Down}, {End}, {Enter}, {Esc}, {F10} and so on. See the [Keys] section in KeyBind Strings.ini for a list of ALL the keys. If you use the config editor to create commands, all this is taken care of automatically. Now we understand what's going on, let's add that first task. Create a section for each app you want to customise.. [Catcher] This name is what KeyBind will use to determine in which program you want the HotKey to operate. We call this name, a "Catcher". See "Window And Titles" (above) for more details about creating effective Catchers. Some windows/apps can be caught with simply their title (which can be a substring). This matches Google Chrome web browser nicely.. [Chrome] Of course, it would also match an open Explorer folder named, "My Chrome Bumper stickers collection", so you might want to instead use.. [Google Chrome] Or even.. [ - Google Chrome] Of course we could use one of the other, more sophisticated catchers, [CLASS:] designations and REGEXPTITLE: definitions, and so on, but for now, this works fine. Let's make some HotKeys! The actual HotKey commands go directly under our new [section title]. Technically, "inside" the section. For me, this Hotkey is a must in Chrome, Explorer and many others, too.. [Google Chrome] {Esc}=^w Done. Reload KeyBind (from the tray menu), The new keybinding is set. Any other keybindings you want for Chrome, simply place beneath that one. Anything up until the next [section] will be considered [Google Chrome] keybindings, aka. HotKeys. There is a [Global] section for HotKeys which will be active ALL the time, regardless of what app is currently active. [app] tasks override [Global] tasks, so you can happily set [Global] tasks and [app] tasks for the exact same HotKey sequence. Where a [Global] KeyBind HotKey may conflict with a particular apps built-in keyboard shortcuts you can tell KeyBind to ignore that [Global] HotKey in a particular app by simply setting a dash as the task for that HotKey, e.g.. [Notepad++] ^!{s}=- [Global] ^!{s}=Date() Here the global HotKey will work normally everywhere except in Notepad++, where it will fire Notepad++'s built-in shortcut command, which on my system is "Save As". This is a stupid example. You will find better uses. So, App HotKeys take priority over Global HotKeys AND an App's built-in hotkeys. KeyBind will "catch" a window; recognise it; by its title, matching ANY part of the title. Often this is easy to guess; "Google Chrome" actually currently matches "Pyrates|Mega Bloks Pyrates Wiki | FANDOM powered by Wikia - Google Chrome" on my system, which no one could have guessed, at least the first bit. KeyBind only cares that our chosen [section name] appears *somewhere* in the title, so any browser tab will match just fine. The match is case-sensitive by default. You can change this in KeyBind Options. Some apps are fiendishly difficult to catch, changing their title with every window!. Fortunately KeyBind can also, if you tell it to, match the "CLASS" of the window. In the above example (on my setup) Chrome windows have a CLASS:"Chrome_WidgetWin_1". Creating the section may be simple, but /discovering/ that section [name] can be a challenge. Fortunately KeyBind comes with a built-in facility which enables you to get this information about whatever window your mouse is currently hovering over by simply pressing the CAPSLOCK key. The information will pop up in a tooltip which will stay on-screen until you deactivate the CAPSLOCK key. That information is also saved to a file in the KeyBind data directory, collecting all your window info for that session. When KeyBind launches it deletes the file. You can also optionally have window info sent directly to the clipboard on each sample. See the examples below for how to use CLASSES in your [section names]. The keystroke shortcuts use the standard AutoIt Send() format. See the AutoIt Send() documentation for many more details.. https://www.autoitscript.com/autoit3/docs/functions/Send.htm https://www.autoitscript.com/autoit3/docs/appendix/SendKeys.htm You may have to fiddle with the exact keystroke, not forgetting the curly braces (always smart), e.g. "^!{NUMPAD0}" to match Ctrl+Alt+Numpad0. You can send a whole series of keys, like so.. ^!{w}=!v{Y}{O} Which should (when the user presses Ctrl+Alt+w) do Alt+v, then Y, then O, to open up the view properties window in Explorer. Tada! Problem solved. You can send simple text, e.g. ^!{a}=This is some text\nAnd another line here It's fairly rudimentary, but will enable you to insert oft-used snippets of text into whatever document/form you are in. You can do wacky stuff, too, like send 30 "S" characters ("{S 30}") or hold the "a" key down ("{a down}") and lots more. See the fine documentation (URLs above) for more details. Include linebreaks with "\n". Only that exact sequence is translated; \And remains literal. Note: If you are sending keys to programs, you may find that some programs are choosy about capital letters and ALT keys, i.e. "!A" is not the same as "!a". The first is interpreted as ALT+SHIFT+A, the second, as ALT+a. If in doubt, use lowercase! As well as regular key strokes, you can perform "special" commands. More on that in the "Task Commands" section below. You can also create HotKeys straight from a task with NewHotKey(). Supply which app it belongs to, the key combination and what it should do, with pipes between them. The task goes last because it may itself contain pipes.. NewHotKey(Global|^!#h|NewHotKey()) This creates a Global HotKey, Ctrl+Alt+Win+h, which opens the New HotKey wizard again when pressed. Supply all three values and the HotKey is created with no dialogs, ready to use. Leave anything out and you get that dialog, with anything you supplied pre-filled. A plain NewHotKey() opens the wizard blank, starting with the app list. Window Triggers. As well as watching for your keystrokes, KeyBind can also watch for windows. We call these "Window Triggers" and they can be extremely useful. They are optional; turn them on when you want tasks to run as windows come to the foreground. Think of it like a HotKey that was fired at KeyBind's launch along these lines Wait(Title of Window)**** KeyBind will *always* be looking out for these windows, and as soon as any of your Window Triggers becomes active (brought to the front) the task will run. Windows can be set to trigger "once" when they first appear, or "always" so the task run every time the window appears. It's best left at "once", because you can, if required, force individual triggers to *always* fire by prepending the window title match string with an asterisk ("*") character.. [Window Triggers] Downloads=WinMove(@DesktopWidth/5+4|@DesktopHeight/4-64|@DesktopWidth/1.25|@DesktopHeight/2+128) *Downloads={F5}{End} If you set the default to "always", there is no way to force "once" behaviour. See the HowTo for more details. In this example, the window is moved only once when it first appears, but the Refresh+End fires every time the window is brought to the front. If you want your match string to be an *exact* match to the window title, prepend the string with a pipe character ("|"), like so.. [Window Triggers] |B:\Downloads\foo={F5}{End} Normally, KeyBind will do a partial match of your string; "Downloads" would match a window titled "B:\Downloads\foo". Using the pipe, you would need to specify as above to match that window. If you used only "Downloads".. |Downloads={F5}{End} it would match only the top level of your downloads folder when launched via the Windows Launch API (where the windows title is simply "Downloads". Dive in even one level and KeyBind will ignore the window again. I like this arrangement. If I open my Downloads folder via Windows Shell API, I get the behaviour I specifed in my KeyBind trigger and if I open that folder by some shortcut that uses the standard Windows explorer mechanism, the folder opens with the title of "B:\Downloads" (yours will likely be different), and is ignored by KeyBind, so essentially I can have two window triggers for the exact same window. Or one window trigger and a neat choice to open the folder with or without Actions, depending on how I intend to use the folder. F-L-E-X-I-B-I-L-I-T-Y! Window Trigger "Grace" Period: Window Triggers can have "Grace periods. That is, you can tell KeyBind to discard the "triggered" state of this window after a certain period of time, so, for example, if I set a new tab in Chrome (as in my above example), but this time added a grace period of 5m.. Google Chrome|5m=^t When I switch to Chrome, if it has been 5 minutes since I was last in Chrome, I get a new tab, otherwise nothing happens (well, the counter is reset and it will be at least 5m before KeyBind considers firing this trigger again). You can use any number from 1-999 and any of the following charcters: s,m,h,d. s=seconds, m=minutes, h=hours and d=days, of course. Split it from your main catcher with the usual "|" pipe charcter. Here's a nice one.. |5m=WinMove(4|4|@DesktopWidth-8|@DesktopHeight-8) That will ensure all my system's browsers' windows are exactly where I like them to be, every 5 minutes. Oh Yeah! NOTE: KeyBind watches foreground-window changes as they happen. If Windows cannot provide those events, KeyBind falls back to checking at the trigger_rate interval. You can set that interval from 0.1 to 10 seconds. Other Triggers: System events, ClipBoard events, almost anything can be used to trigger a KeyBind Task. Setup in config editor or use this command: NewTrigger() [Ctrl+Win+Alt+N] Creates a new Window, System or ClipBoard Trigger using a wizard. Sentinels: Each Sentinel watches its own folder, and if files appear in there, KeyBind performs actions on them. Simple. You can have as many Sentinels as you like, each with its own folder, tasks and check rate. This facility is especially designed for use when collecting lots of resources that all have the same name, like eBay Auction page images, for example. With this facility, you simply drag them from your browser into a Sentinel folder and let KeyBind take care of the rest. A handful of settings control each Sentinel. Enable/disable it, the folder to watch, and what to do with files discovered in there. You manage them all from the Sentinels tab of the config editor, where a drop-down picks which Sentinel you are configuring, or by editing the [Sentinels] section of the ini file by hand. You can even create one straight from a task with NewSentinel(). A Sentinel whose folder goes missing switches itself off until you point it somewhere valid again, or the folder becomes valid, when it carries straight on. A File Sentinel watches one file. When that file changes, its task can use @WatchedFile for the file's full path. @DroppedItem and @DroppedItemName apply only to Folder Sentinel arrivals. In a Sentinel task you can, as with regular tasks, have multiple commands separated by "**"; they will be performed in order, often relying on the exit values of previous commands. The default Sentinel command is: Ignore() Sentinel Commands: These commands are unique to the Sentinel. In the case of rename(), a simplified form of a regular command; simplified because the source file path is known - it was only just discovered in your Sentinel Folder! Folder Sentinel tasks must contain MoveTo() unless the first command is Ignore(). MoveTo() may appear anywhere in the sequence. File Sentinel tasks do not require it. This is obvious, if you think about it, but I suspect many won't, being busy and all, so KeyBind will check for you and warn you if the Task isn't valid. See below for more details about how to use MoveTo(). No, really. Okay, "Rename" can currently do one of two things: generate a random name or create a numeric sequence. For a random name do: Rename(@Random) You can set the length of the name by sending an optional second parameter. Here we set it to 10 characters (the default is 12 characters): Rename(@Random|10) For a numeric sequence do: Rename(@Sequence) This would rename files to 1.ext, 2.ext, 3.ext. You can pad out the numbers to as many digits as you like, e.g. to 5 digits: Rename(@Sequence|5) This would rename files to 00001.ext, 00002.ext, 00003.ext, and so on. You can reset the sequence back to 1 from the KeyBind system tray menu. Finally, you can use a Timestamp for your new name. This makes it easy to figure out what went where, when, later: Rename(@Stamp) This would get you back a name something like: 2018-05-30_16.27.48.jpg Of course you can send parameters. In this case, one of three integers, the default 0 (or empty, as above), gets you a date+time stamp, e.g., for a simple date stamp do: Rename(@Stamp|2) Other values you can use: 1 = Date & Time 2 = Date 3 = Time Making any of these numbers negative will append the stamp to the end of the original filename, rather than replace it, e.g.. Rename(@Stamp|-2) The filename would come back something like: Original-Filename_2018-05-3016.27.48.jpg Once @Random has named a file, @LastRandom holds that full path, so later commands can process it, e.g. Rename(@Random)**Speak(@LastRandom filed!) There are short formats for quickly creating the other most common types: Rename(@Stamp) == Rename(@Stamp|1) [for reference] Rename(@StampDate) == Rename(@Stamp|2) Rename(@StampTime) == Rename(@Stamp|3) To keep the original name and add text before the extension: Rename(@Append_sorted) A generator name resolves like its standalone namesake, with an optional length after it: Rename(@Append@Random|18) In a Folder Sentinel task, @DroppedItem is the incoming item's full path and @DroppedItemName is just its bare name. Use @WatchedFile in a File Sentinel task for the watched file's full path. Only @Append inserts before the dot: @DroppedItemName_sorted would land after the extension, breaking the file type: This is a simplified version of the regular Rename() command, specifically for files landing in your Sentinel Folder. You could use the full version to the same effect: Rename(@DroppedItem|@Random|true|5) OpenWith(Program/default) In a Sentinel task, open the incoming file with the program you choose. Supply the program's full path: OpenWith(C:\Program Files\IrfanView\i_view64.exe) Use "default" to open it in whatever app Windows would use: OpenWith(default) MoveTo(Folder) Move the incoming file to the folder you choose. Give the target directory in the command, like so: MoveTo(Z:\TEMP\DUMP) If a file of the exact same name already exists in the target directory and MoveTo() was your /only/ command, KeyBind will not move the file. Clearly your interaction is required. If KeyBind was /previously/ (in the previous command) instructed to rename the file, it will that try again, up to 100 times, until it gets a unique path for your file: Incredibly, you can also use all the regular commands in your Sentinel tasks! There is a token: @DroppedItem you can use to place the full path of the current dropped file into your commands. The @DroppedItemName token gets just the name, e.g. (and this is hilarious, by the way): Rename(@Random|15)**MoveTo(Z:\TEMP\DUMP)**Speak(@DroppedItemName moved successfully!|100|-2|George) Okay, random gibberish sppken in a posh English voice isn't entirely useful, but it does demonstrate the power of this facility. NOTE: At this time, there has been almost no testing of the regular-commands- on-dropped-items facility, so please let me know how you get on, any quirks, bugs, foibles and such. If you want to take your Sentinel to the next level, KeyBind allows you to have fine-grained control over what happens to the files that land there, with different sets of commands for different file types. You can even create your own groups. A note about "Random" names.. Note: As you may be aware, there is no such thing as "truly" random. The random generator in KeyBind is damn good - The Mersenne Twister algorithm: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html but after some thousands of files you will find that KeyBind has to try harder and harder to get unique random names (ones that haven't been assigned before). Of course the solution is to move some/all files out of the target directory. You might also consider changing the length of the name for the next batch. So if you are *really* quick off the mark, like me, and you have a folder with *thousands* of randomly named files (which are getting harder and harder for KeyBind to not replicate), you *might* need to set this to 2. 1, nah! For some uses, once a minute or even once a day would be fine (60). Note: You can use "human" time in this setting, e.g. "1m" or "2h" for one minute or two hours, respectively. If you dont supply a unit, KeyBind assumes you want seconds. Folder Watching enables you to have a one-drop-fits-all solution for incoming files, as well as a few other interesting scenarios. You might have images renamed to a random name and put in one place, custom files renamed to a sequence and placed somewhere else, opened in some app, with parameters. The possibilities are already limitless. NOTE: Directories inside a Sentinel folder will be completely ignored. OpenTargetDir() Open the destination folder used by this Sentinel task. Put this after MoveTo(), so KeyBind knows which folder to open: MoveTo(Z:\TEMP\DUMP)**OpenTargetDir() System Events: Besides HotKeys, Window Triggers, Schedules and Sentinels, tasks can also be wired to events that happen in your system. Saves from the Config Editor take effect straight away. If you edit the ini file by hand, reload KeyBind afterwards so Idle and process triggers notice the change. Startup: Fires when KeyBind starts itself along with Windows, right after you sign in. This happens once; a later re-launch of KeyBind by its startup shortcut or task does not fire it again. Login: Fires at the same moment as Startup, so you can keep the two kinds of task apart. A regular manual launch of KeyBind fires neither event; it only runs your built-in startup task, if you have one. Note: plain text in your startup task (and Startup/Login event tasks) is skipped, not typed. At sign-in time no window can be trusted with keystrokes, so only real commands run. Both events fire only when KeyBind is launched by its startup shortcut or scheduled task within the first minute after you sign in. Logout: Fires as you sign out, including when a task signs you off (try SystemLogOff()). Windows is about to close the session, so keep the task short and sweet. Shutdown: Fires as Windows shuts down or restarts. Windows is on its way out, so these tasks get seconds, not minutes; keep them quick. A restart fires this event, but does not fire Logout. Manual exits (the tray Exit, the abort HotKey, a reload) fire neither event; they run your built-in shutdown task, if you have one. And when a task shuts Windows down for you, the Shutdown event still fires - nice. Lock and Unlock: Fire when you lock or unlock your Windows session. Sleep: Fires just before the PC sleeps. Windows allows only a brief moment for this task, so keep it short and quick. Wake: Fires after the PC resumes. Idle: Fires after your chosen number of minutes without keyboard or mouse input. It can fire again after you return and later become idle. IdleEnd: Fires when you come back after being away. Give the minutes away that counts, so short breaks do nothing. Idle Ignores: programs that stop Idle and IdleEnd events while they are in the foreground, so a film in your media player does not count as being away. Set this in Options under Runtime and Speech, with each entry separated by a semicolon. USBIn and USBOut: Fire when you plug in or unplug a drive, such as a USB stick. Leave the match empty for any drive, or give a letter (E), a label (MyStick) or the volume ID to watch one drive. KeyBind remembers each drive, including ones already plugged in at launch, so removals match the same way. Inside the task, @USBDrive holds the drive itself (E:\) for your script, with @USBLabel and @USBID for its name and ID. NetworkUp and NetworkDown: Fire when your network connection comes up or drops. KeyBind checks every few seconds, so these can take a moment. OnAC and OnBattery: Fire when you plug in or unplug the charger and the PC swaps between mains and battery power. BatteryLow: Fire when the battery runs low. Laptops only, obviously. ProcessStart and ProcessEnd: Fire when a program starts or stops. Give the program name, e.g. notepad.exe (or pick it with Choose). KeyBind checks every couple of seconds. BluetoothConnect and BluetoothDisconnect: Fire when a Bluetooth gadget, such as headphones, connects or leaves. Paired gadgets sitting idle do not count; KeyBind watches what is actually connected, every few seconds. DisplayChange: Fires when the screen count or desktop size changes. This covers plugging or unplugging a monitor, docking or undocking, and resolution changes. Give a count (2) to fire only for that many screens, or leave the match empty for any change. Inside the task, @DisplayCount contains the new screen count. KeyBind checks every few seconds. AudioChange: Fires when playback devices arrive or leave. Plugging in headphones and unplugging speakers are typical examples. Inside the task, @AudioDevice contains the current device names. KeyBind checks every few seconds. WifiChange: Fires when your wifi network changes. This covers joining, leaving and swapping networks. Give a network name to fire only for that one, or leave the match empty for any change. Inside the task, @SSID contains the joined network, or nothing when wifi dropped. KeyBind checks about every ten seconds. ClipBoard Events: In the Config Editor, create a ClipBoard Trigger and give it a name. Choose Updated when the clipboard changes, including clearing it or copying an image. Choose Text for changes that contain text, then select Any, Contains, Exact or Regex. Contains and Exact match case; Regex uses Perl-compatible Regular Expressions (PCRE). Use @ClipData in the task for the text captured at the time of the change. @ClipBoard reads whatever is in the clipboard when the task runs. A ClipBoard task that copies something itself does not trigger another ClipBoard task. ClipBoard triggers pause when KeyBind is suspended. Try them all: Here is a little suite which shows off everything ClipBoard triggers can do. Create one trigger for each, give it its own name, then copy things and watch them fire.. Updated fires on every change, even clearing the clipboard or copying a picture: MessageBox(Clipboard changed|Something new landed in the clipboard.) Text with Any fires whenever the clipboard contains text: Speak(You copied @ClipData) Text with Contains fires when the text contains your words. Matching is case-sensitive, so ''Sale'' will not match ''sale''. This one keeps a bargains file and tells you about it.. FileAppendData(@Desktop\bargains.txt|@Hour:@Min:@Sec - @ClipData\n)**MessageBox(Bargain spotted|@ClipData) Text with Exact fires only when the whole clipboard is exactly that word, case and all.. Speak(Time for lunch!)**FileAppendData(@Desktop\lunch.log|@Hour:@Min:@Sec - lunch mentioned\n) Text with Regex fires when the text matches your pattern. Put the pattern in the Match box. This one saves every web address you copy, into a file.. https?://\S+ FileAppendData(@Desktop\links.txt|@ClipData\n)**InfoBox(Link saved|@ClipData) Here are a few more patterns which all do something useful. Each gets its own trigger, with the pattern in the Match box.. Email addresses.. [\w.]+@[\w.]+\.[a-zA-Z]{2,} FileAppendData(@Desktop\emails.txt|@ClipData\n)**InfoBox(Email saved|@ClipData) Order numbers like #48291.. #[0-9]+ FileAppendData(@Desktop\orders.txt|@Hour:@Min:@Sec - @ClipData\n)**InfoBox(Order spotted|@ClipData) Prices like $19.99, pence and all. Whole pounds like $20 will not match.. \$[0-9]+\.[0-9]{2} FileAppendData(@Desktop\prices.txt|@ClipData\n)**MessageBox(Price spotted|@ClipData) IP addresses like 192.168.0.1.. \b[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\b FileAppendData(@Desktop\servers.txt|@ClipData\n)**MessageBox(Server spotted|@ClipData) @ClipData holds the text from the moment the trigger fired, while @ClipBoard reads the live clipboard when expanded. They can differ after an external clipboard change, a queued delay or a copy in the task. A task that copies never sets off another ClipBoard trigger, so this one is safe. It stamps the clipboard, but logs what you originally copied.. Copy(Logged at @Hour:@Min:@Sec)**FileAppendData(@Desktop\copy-log.txt|@ClipData\n) Task Commands: These all have () braces after them. These are the main commands you use to create tasks. See the section about "Command Sequences" for creating tasks with multiple commands. In the syntax headings, | separates parameters, / separates choices for one parameter, and [] encloses optional parameters. Do not type the brackets or the list of choices. Use one choice, such as Sentinels(on|Inbox), or omit optional parameters: Sentinels(). Copy([Text]) Cut() Paste() The usual ClipBoard operations. For plain text. Copy() will copy whatever is currently selected into the clipboard, the equivalent of "^c". Cut() works just like "^x" (Ctrl+X). You can also put the contents of the clipboard into a variable for later use as a @Macro. More on that later. For Copy() you can also do Copy(), the being whatever you like. Dynamic @Macros are accepted in the command. See below. PastePlainText() pastes the clipboard as plain text. When you copy something formatted, from a web page or a document, say, this drops the fonts, colours and links and pastes just the words, which is handy when the target app would otherwise pick up the source styling. If the clipboard is empty, or holds something that is not text, you just get a regular paste. ChangeCase() converts the case of some text. Name the mode first, then where the text lives: ChangeCase(title|@Selected) title-cases the highlighted text (or the word at the caret) and pastes it back over itself, ChangeCase(upper|@ClipBoard) rewrites the clipboard, and ChangeCase(sentence|@myvar) updates your @myvar variable. Send anything else, even a bare word matching a variable, and it comes straight back in @ExitValue as literal text, so ChangeCase(lower|HELLO) gives you "hello" without touching anything. Modes are upper (uppercase), lower (lowercase), title and sentence, in any letter case. FindReplace() finds text with a regular expression and saves the result to a variable, leaving the source alone. Name the source first, as with ChangeCase(), then the pattern, the replacement and the variable: FindReplace(the cat sat|cat|dog|result) puts "the dog sat" in @result, while @ExitValue holds how many swaps were made (1, here). Name @Selected or @ClipBoard as the source to work on a selection or the clipboard instead. The pattern is always a regular expression, so escape punctuation (VarAssign(quote|total: $19)** FindReplace(@quote|total: \$(\d+)|total: USD \1|fixed) rewrites it as "total: USD 19", keeping the amount), and leave the replacement empty to delete matches. CopyAppend() and CutAppend() pile grabs onto the clipboard and keep each grab in a numbered slot, up to your ClipBoard Slots setting. PasteSlot() pastes one slot or a joined range: PasteSlot(2-6), PasteSlot(5-), PasteSlot(-7). When supplied no parameters, PasteSlot() invokes the canonical ClipBoardSlots() and shows the slot viewer to pick. ClearSlots() wipes every created row and puts the base entry back in the clipboard, ClearSlots(3) drops one row and rebuilds the pile from the survivors. A fresh Copy() or a copy of your own ends the pile. SortLines(), DeDupeLines() and WordCount() tidy the pile. Name @Selected, @ClipBoard, a variable or literal text, or nothing for the clipboard: SortLines() sorts, DeDupeLines() drops later duplicates keeping order, WordCount() counts words into @ExitValue. Num2Words() turns such a count into English words, as its own step: WordCount()**Num2Words(@ExitValue). Text(Text) Huh? I thought you could send text directly? I hear you say. This is true. HOWEVER, you have the fantastic ability to send modifier keys and these are expressed using characters like "!" and "+". So what if you wanted KeyBind to type out "Have a Nice Day!"? ... Right! You got it! So the Text() command send text raw; as-is; into whatever document you are in. Hashes, pluses, whatever, will appear as typed, directly at the caret position. And yes, you can still use linebreaks.. ^!{a}=Text(My Name\nMy Adddress\nMy Address Line Two\nCITY\nMY POSTCODE\n@date\n) The savvy among you will have spotted the "\n" UNIX linebreak characters. Nice. These are actually translated into Windows CRLF "\r\n" for typing into whatever document you are in, but using "\n" in commands is easier. Another good reason to use the Text() command to output plain text. Date() This will insert the current date at the caret position. You can also set the date format inside the main [KeyBind] section, using standard AutoIt string format and @date tokens (see below for example usage). ^!{a}=Date() If you are paying attention, you will spot that you can also use the @date token inside you plain Text() commands, to insert the current date, using whatever rules you set in the date_format preference. So yes, smarty-pants, you could achive the same with: Text(@date). This is a handy shortcut, is all. Very useful in file naming, too. Time() Inserts the current time at the Caret position. No use for file names! And again, there is also a @Time macro that you can use inside commands, so you could achieve the same thing with Text(@Time). Launch(Item/Command) This will launch items, run apps, execute shell commands, and so on. Examples: ^!+{l}=Launch(regedit.exe) ^!+{l}=Launch("C:\Program Files\Text Ed\Notepad++\notepad++.exe" "C:\Users\Me\Document.txt") ^!+{l}=Launch(control panel) This uses a basic system "Run" command, often just what you need. This one will open your screensaver control panel.. Launch("C:\Windows\System32\rundll32.exe" shell32.dll,Control_RunDLL desk.cpl,screensaver,@screensaver) Since Vista, so does this.. Launch(control.exe desk.cpl,screensaver,@screensaver) You can also use the ShellExecute API to execute your commands. With this mechanism you can open documents (with their default app) by simply providing their path, and much, much more. To activate ShellExecute, use a pipe character as your FIRST character: ^!+{l}=Launch(|"C:\Users\Me\Document.txt") ShellExecute enables us to, amongst other things, use the groovy Windows shell commands. Open the Add/Remove Programs Control Panel.. ^!+{l}=Launch(|shell:ChangeRemoveProgramsFolder) Open the Recycle Bin.. ^!+{l}=Launch(|shell:RecycleBinFolder) Using tokens instead of hard locations is smart - they keep working regardless of the actual physical location of the item. There are approximately one zillion of these shell commands. See here.. https://winaero.com/blog/list-of-shell-commands-in-windows-10/ There are other, even bigger, lists out there! You can also access some "special" folders via their CLSID: This one is "My Computer": ^!+{l}=Launch(|"::{D20EA4E1-3957-11d2-A40B-0C5020524153}") Extra pipes add command parameters, then a verb (print, edit and friends; leave it empty for the usual open): ^!+{l}=Launch(|notepad.exe|C:\Temp\notes.txt) ^!+{l}=Launch(|C:\Temp\report.txt||print) Note: If you launch a .lnk file (shortcut) KeyBind will launch the target. Tip: If something *still* doesn't work, add/remove the pipe and try again! Launch rights: When KeyBind is running elevated, Launch() commands cleverly start programs non-elevated, with normal user rights, as some programs will misbehave when running as admin, not accepting drag-and-drop and other things. To launch a program with admin rights, prepend the command with a greater-than sign (right-angled bracket), e.g.. Launch(>regedit.exe) You get the usual elevation prompt (if you have AUC prompts enabled) and the program starts elevated . You can use it with plain program commands and DOS commands. NOTE: the | ShellExecute form of Launch() *always* launches apps at KeyBind's own level. Why? ... Pipe commands open documents, addresses and shell objects, but Windows offers elevation only for *programs*, so a piped file like foobar.msc cannot elevate. Instead, name the program, e.g. Launch(>eventvwr.exe) rather than piping eventvwr.msc. DOS Commands: Finally for Launch(), you should find that DOS commands work okay with a regular Launch() command, but if not, you can invoke special DOS command handling behaviour by prepending your command with an asterisk, e.g.. Launch(*dir /ad "@HomeDir") Which would be a silly command to run because nothing gets done and you can't even *see* nothing getting done! If you want to run commands where you want to see DOS output, use.. Launch(*show*dir /ad "@HomeDir") The command prompt will remain open at the end of the command so you can see the output, interact with the terminal and so on. And of course you can use all the regular @Macros. KillProcess(Program/Process ID) Stops a running program immediately. Give its name or process ID, for example KillProcess(notepad.exe). Terminate() does the same job: Terminate(Program/Process ID) Terminates a running process. Supply the program name or PID: e.g.. Terminate(regedit.exe) WinMove(X|Y|Width|Height[|Window]) alias: WindowMove(X|Y|Width|Height[|Window]) This will resize and/or move a window to a new location, e.g.. ^!{NUMPAD5}=WinMove(@DesktopWidth/2|12|@DesktopWidth/2|@DesktopHeight-20) As well as regular numbers (integers), you can use the @DesktopWidth and @DesktopHeight tokens to calculate positions on-screen, i.e. "top-left-and- down-a-bit". See below for more examples. You can also use the @Center token to place the X or Y position to the centre of the screen. Yes, it's the US spelling of center, like in HTML. Be careful, though. @Center is a handy @Macro to use, and for moving the mouse, or positining windows, it does what you expect - puts the object in the centre of your screen. HOWEVER, when you use the @Center token, KeyBind deducts half the width/height of the final window width/height from the value, placing the /centre/ of the window at the centre of the screen. If you use @Center as a way to get "@DesktopWidth/2" with WinMove(), you may not get the results you expect. If you want your window CENTERED on-screen use: WinMove(@Center|@Center). The @Center token is "special", see, saves you having to calculate the minus-half-the-window/height-width bit. If you want the TOP-LEFT of your window at exactly the centre of the screen, use: WinMove(@DesktopWidth/2|@DesktopHeight/2). I like to have a range of window sizes and positions available using the Ctrl+Alt+NUMPAD layout, corresponding to the position on my desktop. Sometime I'll want a size 7 (top-left) window in position 3 (bottom-right), so again these is a huge flexibility with this arrangement. I simply hit Ctrl+Alt+NUMPAD7 and then Alt+Click+Drag it (KDE-Mover-Sizer, people!) into the bottom-right. As the positions correspond to the sizes of windows miost often used in those positions, I usually don't have to move them at all. SnapWin() / WinSnap() Two names for the same command: pull the active window back inside its display, so a lost off-screen window comes back into view. Neither takes a parameter, e.g.. SnapWin() Activate(Notepad++)**SnapWin() KeyBind uses the window centre to pick the nearest display and keeps the window inside the work area, clear of the taskbar. Oversized windows pin to the top-left corner. Maximized and minimized windows are left alone, and when the window sits inside already, nothing moves. Url(URL) You can achieve this with launch, but here is a handy shortcut for it: ^!{home}=Url(https://google.com) LockPC() / LockWorkStation() Two names for the same command: lock Windows and leave your session running. Neither takes a parameter. SystemShutdown() Shut down Windows and power off the PC. SystemReboot() Restart Windows. SystemLogOff() Log off the current Windows user. SystemSleep() Put the PC to sleep. SystemHibernate() Hibernate the PC. CDTrayOpen([Drive Letter]) Open the first optical drive tray, or name a drive, e.g. CDTrayOpen(D). CDTrayClose([Drive Letter]) Close an optical drive tray. Like CDTrayOpen(), you can give a drive letter. Some laptop trays must be closed by hand. ScreenSaver() One guess what this does. Your current screensaver will fire into action as if by magic! ^!{l}=ScreenSaver() MouseMove(X|Y[|absolute/relative/window|Speed]) You can have your HotKey move the mouse. The command looks like this: ^+{r}=MouseMove(100|0) Pipe "|" characters separate the various settings. That command would move the mouse to screen position x=100, y=0 (top-left). Coordinates are absolute screen positions by default. Use "relative" (or "r") to move from the current mouse position. Use "window" to move from the foreground window's top-left corner. ^+{r}=MouseMove(100|0|relative) For example, this moves the pointer 100 pixels right and 50 pixels down from the foreground window's top-left corner: ^+{r}=MouseMove(100|50|window|5) You can also set the speed. 0 is instant, 100 is SLOW. The default is 10. ^+{r}=MouseMove(100|0|relative|5) If you leave a value blank, the default is used, so you can specify the speed without having to specify the coordinate type. ^+{r}=MouseMove(100|0||5) MouseClick(X|Y[|absolute/relative/window|Speed|right/left/middle/main/menu/primary/secondary|Clicks]) / Click(X|Y[|absolute/relative/window|Speed|right/left/middle/main/menu/primary/secondary|Clicks]) This is just like the above command, except the mouse "clicks" at the end. ^+{t}=MouseClick(100|0) You can set the same parameters for coords and mouse movement speed: ^+{t}=MouseClick(100|0|relative|25) You can also specify which button to click "l", "r", or "m": ^+{t}=MouseClick(100|0|relative|25|m) Technically, you can use, left, middle (m), right (r), primary (p), main, secondary, and menu. Using anything else gets you a left click. Finally, you can tell KeyBind to click the mouse multiple times: ^+{t}=MouseClick(100|0|relative|25|m|2) "2" is a common setting: a double-click. You can have up to 100 clicks in one command. As with mousemove, blank settings use the default. A double- click @ current mouse position: ^+{t}=MouseClick(||r|||2) Essentially we are setting, X=0, Y=0, movement=relative, default speed, default button (left) and 2 clicks. (also see: "DoubleClick()", below). With window positioning, KeyBind checks the active window is still the one Activate() woke, waking it again if focus wandered. If the window is gone, the task stops instead of clicking blind. In the above two mouse commands, any of the settings can be left blank: ^+{t}=Click() Is fine. Also, when using absolute coordinates, you can use "@Center" to specify the middle of the screen (for x or y). You can use it in calculations, too, e.g.. Click(@Center-20|@Center+10) Also note, When you have your mouse buttons "swapped", some of those designations will change, as in the following table: Button String Normal Click "Swapped" Click ------ ------------ --------------- "left" / "l" Left Left "middle" / "m" Middle Middle "right" / "r" Right Right "primary" / "p" Left Right "secondary" / "s" Right Left "menu" / "u" Right Left "main" Left Right MouseDown([right/left/middle/main/menu/primary/secondary]) MouseUp([right/left/middle/main/menu/primary/secondary]) Perform a mouse button operation at the current mouse position. You can specify which button to use, same strings as above, e.g.. ^+{m}=MouseDown(l) If you don't specify a button, you get the default (left) button. If you want to drag-and-drop stuff, see the next command: MouseWheel([up/down[|Notches[|Pause]]]) Scroll up or down. Give the direction, number of notches (1-100) and, if needed, a delay between notches in milliseconds: MouseWheel(up|5|50) That scrolls five notches, pausing 50ms between each. ClickDrag(Start X|Start Y|End X|End Y[|right/left/middle/main/menu/primary/secondary|Mouse Speed|Coordinate Mode]) Click and drag from one point to another. Give the starting X and Y, then the finishing X and Y: ClickDrag(x1|y1|x2|y2[|mouse button|speed|coordinate mode]) By default, both points are screen positions. "relative" measures both points from the pointer position when the command starts. "window" measures both from the foreground window's top-left corner. The optional mouse button defaults to left. The optional speed defaults to 10; 0 is instant and 100 is very slow. To start at the pointer's current position, use literal "x" and "y" for the starting coordinates: ClickDrag(x|y|3|@Center) This drags from the pointer to screen X=3, halfway down the screen. You can use "x" or "y" on its own to keep just that coordinate. These shortcuts still use the pointer's actual position with "relative" or "window". For scripters: to drag a new desktop item from near the top-left corner to the pointer's current position, use: ClickDrag(100|100|MouseGetPos(0)|MouseGetPos(1)) Adjust the starting X and Y to match the item's position. This drags 300 pixels to the right from the current pointer position: ClickDrag(0|0|300|0|left|10|relative) This drags between two points inside the foreground window: ClickDrag(100|50|400|50|left|10|window) Use "-" for any optional setting to keep its default. For example, this keeps the default button and speed while using relative points: ClickDrag(0|0|300|0|-|-|relative) CopyAppend() This copies whatever text you have selected onto the /end/ of the clipboard, so the old contents are not destroyed. The new data is appended to the old. ^+{c}=CopyAppend I use Shift+Ctrl+C for this (as in above example), as it's most intuitive. Note: No line-breaks or any characters are added between old and new data. CutAppend() Same as above but cuts the data, instead of copies. ^+{x}=CutAppend SelectWord() Selects the word around the caret, which can be handy when you aren't near your mouse. The following replicates a common shortcut on a popular app: ^{w}=SelectWord() DoubleClick() Performs a double-click with the left mouse button. This would select the word directly under the mouse if you held the mouse over a word in a text document. It could do other stuff, too, of course: ^{w}=DoubleClick() You could achive this with the MouseClick() command; this is an easy shortcut, basically double-clicking wherever the mouse is right now. The two above commands make multi-selections a breeze. At least in Notepad++ MagPicker([oneshot/on/off/toggle]) / Mag([oneshot/on/off/toggle]) You can also use Mag(), which is easier in a sequence of commands, but I think MagPicker() stands out better inside an ini sertion. This is a groovy Magnifier Color-Picker you can call up at any time on a HotKey. It will follow your mouse around until you *click* somewhere, at which point it will optionally copy the hex value of the color directly under the mouse pointer into the Windows ClipBoard and optionally create a handy "full" color report saved to a file or your ClipBoard. I say optionally; your call. You could simply use it as a wee magnifier / coordinate finder. If you are working with colors, the full report details your color selection in no less than nine color value formats, either to a file (the default) or the clipboard. The former can also be set to open instantly on new colors. The report looks something like this: Color Picked @ 01:05:52: FBAF04 Converted Color Values: RGB Int: 251,175,4 AutoIt RGB: 0xFBAF04 AutoIt BGR: 0x04AFFB Delphi Hex: 0004AFFB Visual C++ Hex: 0x0004AFFB RGB Float: 0.98,0.69,0.02 Hue/Sat/Lum: 42,0.97,0.5 CMYK: 0,0.303,0.984,0.016 Web Hex: FBAF04 You can set the output format from the system tray menu. If you have the prefix enabled, this will be reflected inside your report. Speak(Text[|Volume|Rate|Voice|Wait]) Have your computer speak some text. You can set the volume from 1-100, e.g.. Speak(Home-again Home-again Jiggeddy-Jig|66) You can also set the rate of speech, from -10 to 10: Speak(Home again, Home again, Jiggedy-Jig|66|2) If you know what you are doing, you can also alter parameters in the middle of the speech with XML, stuff like this: Speak(I can also talk really fast|100|-1) Note: if you set the rate in the main command, this becomes the "base" level, affecting all other rate settings within the speech (aka. absspeed). See inside the example scripts folder for examples of speech with variabl pitch and speed, emphasis, voice-switching and more. see: https://msdn.microsoft.com/en-us/library/ee431815(v=vs.85).aspx The final preference you can set in your speech command is which voice to use. This can be a substring of one of your system's speech voices (see the KeyBind tray menu for a list of those). For example, if you want "Microsoft Hazel Desktop", you can simply use "hazel": Speak(I have a posh English voice|100|-2|Hazel) Like the XML commands, this will override any defaults you have set here. You can, of course, set the voice as well as *many* other parameters directly inside the speech, using XML, but this is a handy way to easily set the main parameters (volume/rate/voice). You can even insert Audio Files directly (and conditionally) into your speech. See the following article for more details: https://docs.microsoft.com/en-us/cortana/skills/speech-synthesis-markup-language If the "text" to speak is a URL, KeyBind will open the URL and grab text onwards from a point which you can specify by adding an asterisk, like this: https://edition.cnn.com/articles*Articles*Regions And KeyBind with read the page to you, from "Articles" all the way up to the optional second specified point; "Regions". If you omit the second parameter, KeyBind reads right up to the end (unusually not what you want). If the "text" is the path to a file on your system, KeyBind will load that file as an XML SAPI speech file, where you can go to town with formatting and XML speech commands. Have fun! And of course, any of these scripts can be activated with /any/ trigger. Note for hackers: On my system at least, I have two sets of voices in the registry. One small, regular section (default 3 voices) and another, much more interesting section with all the other voices I have installed also showing. If I export the registry entries from the "OneCore" section and switch them to the regular section, import them into the registry.. WHAM! Those extra voices show up and work fine in KeyBind and other apps that use the SAPI TTS voices. Awesome! George, read my news, man! Note also: when using these "extra" voices, MS SAPI (the back-end speech engine) will not set one of these voices when you are processing certain proper XML scripts. You will need to enter voice commands inside the script. After a major Windows update, you will likely need to repeat the above procedure. What a pain! NOTE: If you feed correctly formatted times and dates to the speech engine, you will get back the properly spoken times and dates. e.g.. 2018-03-16 = "The Sixteenth of April, Two Thousand and Eighteen" 09:43:26 = "Nine Forty-Three and Twenty-Six Seconds" I have noticed the Speech engine understands other stuff, too. This: FileSize(C:\TEMP\1gb.test|MB)**Speak(@ExitValue MB) Will respond with "One Thousand and Twenty Four Megabytes". Kewl! SpeakSelected() This will speak whatever text you currently have selected, using your default voice, voice speed, volume, etc. This uses the Windows ClipBoard to store the text and is analagous to running: Copy()**Speak(@ClipBoard|100) Hold On! That's TWO Commands. Yes. Read on.. WebSearchSelected() Does a web search of your currently selected word. Parameters can be setup in your ini so you can simply do: WebSearchSelected() Or you can supply parameters in the command: WebSearchSelected(https://duckduckgo.com/?q=@Selected) DefineSelected([URL|Start|End|Variable]) Speaks a definition for selected text. If nothing is selected, KeyBind uses the word under the caret. Set speak_task_define_url and speak_task_define_start in KeyBind.ini to choose the lookup page and the start of its definition. Put @Selected in the URL where the word or phrase belongs. KeyBind encodes it for the URL. The end marker is optional. For scripters: DefineSelected([url|start|end|variable]) overrides the lookup settings for one task. Use - to keep a setting. Add a variable name in the fourth position to store the definition instead of speaking it. For example, DefineSelected(-|-|-|definition) saves it as @definition. Beep(frequency[|dur|vol|wave|pan|adsr|phase|duty]) Plays a generated tone. Give the frequency in Hz, then anything else as named keys in any order; a bare value after the frequency simply means the duration: Beep(500) A plain 500Hz sine for 1s (the default duration). Beep(880|250ms|wave=square|duty=25) A short, thin square tone. The keys are dur= (time in the usual formats, 10ms to 10s), vol= (0 to 100), wave= (sine, triangle, saw, square, pulse), pan= (-100 is left, 100 is right), adsr= (attack,decay,sustain,release), phase= (degrees) and duty= (pulse width in percent; pulse and square only). Beep(660|200ms|wave=saw)**Pause(150ms)**Beep(520|200ms|wave=saw) A harsh two-tone alert that cuts through background noise. Beep(880|dur=400ms|wave=sine|adsr=30,50,70,200) A soft chime that swells in and fades away instead of clicking on. Frequency range is from 37 to 32767. Setting values outside these ranges gets you the default settings. Chord(Note[;Note...]) Plays two or more Beep-style notes together, starting on the same sample. Separate the notes with semicolons; each note takes the same parameters as Beep(). Up to 8 notes. The chord lasts as long as its longest note, and every note is checked before anything plays, so one bad note stops the whole chord. Chord(155.56|750ms|wave=sine;185|750ms|wave=square;233.08|750ms|wave=saw) An Eb minor sixth chord with each note its own wave type. PlaySound(File[|wait]) Plays a sound file. File can be WAV/MP3. You can optionally tell KeyBind to halt execution of the current task until the sound playing completes, like so: PlaySound(C:\Path\To\Sound.mp3|true) By default, the audio file is played asynchronously, so there is no waiting for it to complete before continuing on with the rest of the commands in the task, if there are any. This.. PlaySound() ..will stop a currently playing sound. SetVolume(Volume) Sets the audio volume to a percentage value, e.g.. SetVolume(90) This can be handy for setting a particular volume before playing an audio file, amongst other uses. You can also shift the volume by relative values, e.g.. SetVolume(+10) Which increases the volume by 10%. -10 would shift it down 10%. If you try to nudge the volume outside its set range you get the min/max value. Command Sequences. The following commands might seem a little strange until you realise that you can send *sequences* of commands. That's right! To do this, you simply separate them with a double asterisk, like so: ^!+{p}=KeyDelay(50)**Launch(|SystemPropertiesAdvanced.exe)**Wait(System Properties|3s)**Activate(System Properties)**^{Tab}**Pause(250)**{Tab}{Tab}!{o}**{down} Woah! Aye. So that command will open the Advanced System Properties, switch to the system protection tab, open the system protection dialog, and disable system protection. DO NOT OKAY THAT DIALOG! It's just a wee example of the sort of shennanigans you can get up to with command sequences. You can also put command sequences inside a file. Put each command on a new line and put the path to the file as your command inside your ini file: ^!+{4}=@DataDir\Scripts\control.kc Note the example's (not strictly necessary here) use of Pause()... Pause(Duration[|blocking]) / Sleep(Duration[|blocking]) This causes the command sequence to pause for a specified time, in milliseconds. Smallest time is 10. There is no upper limit. You can specify the time in Milliseconds (ms), Seconds (s), Hours (h) and Days (d). e.g.. Sleep(5m) See Wait(below) for more time format examples. Other commands and command sequences, hotkeys, triggers and such will still execute as normal during this time. This is handy when you need to wait for a period of time before your next command in a sequence. Wait(Window[|Timeout]) Unlike the simple Pause() (above), the Wait() command will wait for a *window*. Use some string which will match the window title. A partial, case-insensitive match is all that is required.=, e.g. to match "B:\Downloads\Games" you could use, for example, "Downloads", /or/ "games". Other commands will continue to process while KeyBind waits for your particular window to come to the front. By default, KeyBind will wait indefinitely. You can set how long KeyBind should wait for a window, by adding a "|" pipe character, followed by the number of milliseconds to wait: Wait(Control|500) You can specify the time in seconds, minutes and hours and days (s,m,h,d). If you do not specify a unit, it will be interpreted as milliseconds: Wait(Control|3500) Wait(Control|5s) Wait(Control|10m) Wait(Control|2h) Wait(Control|7d) If a window Wait() times-out, the rest of the commands are discarded and the command queue for that trigger is cleared. It can now be re-activated. Note: if you do not specify a time, KeyBind will wait for the window for /ever/, which is wasteful. This was internally complex to pull-off so please use it a lot! Activate(Window[|Timeout]) This will bring a window to the front. Enter some string you want to match to its title and if the window exists KeyBind will activate it. You can use all the usual goodies in the window title here, classes, regex, etc, but it is probably best to keep it simple for Activate() Activate(Google Chrome) If you do use some regexp malarkey that matches multiple windows, KeyBind will activate the most recently activated window of the group: Activate([REGEXPTITLE:(?i)(.*Google Chrome.*|.*μTorrent.*|.*Mozilla Firefox.*)]) Note: If a window cannot be activated within a sequence of commands, the sequence is aborted. A small Sleep() is recommended before activating windows within a sequence of (fast moving) commands, e.g. Sleep(500) You can specify how long you are willing to wait for the window to activate, using the usual time notations, e.g.. Activate(Google Chrome|10s) Remaining commands in the task will wait for the specified amount of time before continuing. NOTE: The activate command returns a window "handle". This can be used directly in a window catcher (in commands which use a catcher) or in an If()/IfNot() condition, to check the window was successfully activated. Activate(Control Panel|10s)**CloseWindow(@ExitValue) CloseWindow(Window) Closes a window. If the window has data to save or what-not, it will prompt you about this, or do whatever its closing protocol dictates. Supply a Window Catcher. Usual rules apply: CloseWindow(Google Chrome) If you leave the Catcher out, the current window will be closed. If you specify multiple windows (with RECEXP), the most recently active will be closed. KillWindow(Window) Forcibly closes a window. It's closing protocol can get stuffed. Supply a Window Catcher. Usual rules apply: KillWindow(Google Chrome) NOTE: Although KillWindow() can work on both minimized and hidden windows, some windows (notably explorer windows) can only be terminated using CloseWindow(). If you leave the Catcher out, the current window will be closed. If you specify multiple windows (with RECEXP), the most recently active will be killed. Minimize([Window]) Minimizes a window. Supply a Window Catcher. Usual rules apply: Minimize(Google Chrome) If you leave the Catcher out, the current window will be minimized. Maximize([Window]) Maximizes a window. Supply a Window Catcher. Usual rules apply: Maximize(Google Chrome) If you leave the Catcher out, the current window will be maximized. Restore([Window]) Restores a minimized or maximized window to its normal size. Supply a Window Catcher. Usual rules apply: Restore(Google Chrome) If you leave the Catcher out, the window your task last touched will be restored, or the current window when the task touched none yet. This makes Minimize()**Pause(2s)**Restore() work on any window, as minimizing passes focus elsewhere. WindowOnTop([Window|Value]) / OnTop([Window|Value]) Pins a window above all others. Supply a Window Catcher and an on/off value, e.g. WindowOnTop(Google Chrome|off). Usual rules apply: WindowOnTop() If you leave everything out, the current window will be pinned. KeyDelay(INT/+INT/-INT/-) This sets the delay between keys sent, the same as the master sendkey_delay setting above, except you can set this right in the middle of a command sequence, as many times as you like. Values in milliseconds, between 0 and 1000. e.g.. ^!+{4}=KeyDelay(65)**Text(do ya think I'm control? )**Pause(1000)**KeyDelay(400)**Text(???)**Pause(900)**KeyDelay(40)**Text(\nwell do ya?) The usual starting delay is your sendkey_delay preference (25ms unless you changed it). KeyBind restores that setting after the task. Dimensions([oneshot/on/off/toggle]) This activates a handy Window Dimensions Plucker, which is a ToolTip that glues itself to the top-left of the window under the mouse and shows you its X and Y position as well as width and height. Click and these dimensions are copied to your clipboard - handy for creating WinMove() prefs and much more. ^!#{0}=Dimensions() As a cute little extra feature; if you have the plucker setup on a global HotKey, that HotKey' shortcut will appear in your tray menu: "Pluck Window Dimensions Ctrl+Win+Alt+0" This is true of /any/ commands you have setup on a global HotKey where applicable); their HotKey's shortcut will appear in your system tray menu, so you never forgt the shortcut! Count() @Count shows the running counter. It starts at 1 each time KeyBind launches and keeps its value across tasks until you change it. Use Count() to change the value. A leading + or - adds or subtracts; an unsigned number sets the value. You can also set it from a KeyBind user variable, provided its value is an integer. Count(+1) adds one Count(-1) subtracts one Count(10) sets the counter to ten Count(@foobar) sets it to the integer in @foobar In any command, put + or - immediately after the macro to change the counter by one before using that value. Each occurrence changes it once. FileSave(C:\Temp\file_@Count+.txt|some-data) With the default starting value, this writes file_2.txt. A later use of @Count then gives 2. An invalid Count() value leaves it unchanged. User Variables: You can create variables in your tasks. These variables are available to other tasks for the life of the current KeyBind instance. There are multiple ways to create variables (explained below) but only one way to get at them, which is by using the token signifier, "@", e.g. Speak(@VarName). When naming your variables, you can use digits, letters and underscores "_". User-Created @Macros have priority over built-in @Macros. For example, if you (stupidly) did this: VarAssign(Date|The date is @Date)**Speak(@Date) You would hear: "The date is the Twenty-Seventh of May, Nineteen Twenty Nine" Or whatever the current date is. I don't recommend overwriting KeyBind's built-in @Macros with your own variable @Macros, but now you know what happens if you ever do. VarAssign(Name|Value) alias: Assign(Name|Value) You can also assign values to variables directly with the VarAssign() command. VarAssign(foo|bar) That would assign the variable called "foo" a value of "bar". To access the variable's value in your commands in the future, simply use "@foo": Note: If you assign a large amount of data to a variable, you may want to free up its memory once you are done using it, like so: VarAssign(foo) Input(Title|Prompt|Variable) Using this command, you can ask the user a question. The answer to this question (the variable) can then be used in later commands in the script. For example, you may want to ask for a file name for items landing in your Sentinel Folder: Input(What to call the file?|Please supply a name for the new file..|NewFileName) This will create an input with a title of "What to call the file?", and with a prompt string, "Please supply a name for the new file..". If the user enters a name, that name will be assigned to the variable "NewFileName". In later commands and in other tasks, you can access this name by doing @NewFileName in your command. e.g.. Input(What to call the file?|Please supply a name for the new file..|NewFileName)**Rename(@DroppedItem|@NewFileName) If(Value[|Expected]) This is used as a conditional test. First, lets' Assign a demo variable: VarAssign(var|@ClipBoard) Now using If() we can test if the @ClipBoard contained the string "foo": If(@var|foo)**Speak(it's foo!) This comparison ignores case, so "Foo" also matches "foo". If the condition is true, the following command queue is processed. If the condition is false, the rest of the command queue is discarded. Use Else() and EndIf() when you want different commands for each result, then carry on with commands which should always run: Download(https://example.com/latest.zip|@Desktop\latest.zip) If(@ExitValue) Beep(1200|200ms) Else() Beep(250|500ms) EndIf() Speak(The download attempt has finished.) The commands between If() and Else() run when the condition is true. The commands between Else() and EndIf() run when it is false. Commands after EndIf() run either way. You can nest conditional blocks. Each Else() and EndIf() belongs to the nearest open If() or IfNot(). EndIf() is optional. Without it, the conditional block simply extends to the end of the task, which is how If() has always worked. Yes, obviously you could do If(@ClipBoard|foo) but I'm demonstrating! And besides, the ClipBoard may have changed between one task and another: Technically, you can do If(C:\real.file|), but the condition will only ever evaluate to true/false. Of course, you may have a variable or other @Macro in there... And remember, user variables are global and permanent for the life of KeyBind. (you can also make them truly permanent - more on that later) IfNot(Item[|Comparison]) Just like If() but checks that the condition is NOT true, and only then continues processing the commands in the task's queue. Otherwise the remaining commands are discarded. Else() Starts the alternative branch of an If() or IfNot() block. This branch runs only when the condition did not match. EndIf() Ends the nearest open If() or IfNot() block. Commands after EndIf() are no longer controlled by that condition. If(FILE PATH)/IfNot(FILE PATH) You can enter a file path as your one condition. In which case IF() / IfNot() check if the file exists and uses that as your condition, so.. If(C:\real.file) = TRUE (remaining commands will be processed) If(C:\not a real.file) = FALSE (remaining commands are discarded) IfNot() returns the opposite results, i.e true if the file does not exist, the remaining commands are processed. IfRunning(Program/Process ID) Check whether a program is running. Give its name or process ID. @ExitValue gets its process ID, or 0 if it is not running. Use If() or IfNot() to decide what happens next.. IfRunning(regedit.exe)**IfNot(@ExitValue)**Launch(regedit.exe)**EndIf() VarLoad(Variable) Loads a user variable so you can use its @Macro in commands. VarLoad(@MyVar) VarsLoadAll() Loads all user variables. VarsLoadAll() VarSave(Variable) Save a user variable to your ini file for future use. Real line breaks are encoded as \n or \r, and literal backslashes as \\. Values over 512 characters after encoding are saved as empty values. Change the limit with var_save_max_size in [KeyBind]. The variable in memory is unchanged. VarSave(@MyVar) VarsSaveAll() Save all current user variables to your ini file so they are available the next time KeyBind launches. Real line breaks are encoded as \n or \r, and literal backslashes as \\. Values over 512 characters after encoding are saved as empty values. Change the limit with var_save_max_size in [KeyBind]. Variables in memory are unchanged. VarsSaveAll() VarDelete(Variable) Delete a saved variable from your ini file and clear its current value.. VarDelete(@MyVar) VarsDeleteAll() Deletes all saved user variables from your ini file and clears their current values. VarsDeleteAll() VarsLoadAll()**VarAssign(foobar|"")**VarsDeleteAll()**VarsSaveAll() VarsDisplay() Show the KeyBind user variables currently available to your tasks. Handy when you cannot remember what you assigned. File Commands.. KeyBind has some basic file commands that you can use.. Download(URL[|Filename]) Fetch a full URL and save it to a file. You can supply the destination filename or leave it out for a regular save dialog.. Download(https://example.com|@Desktop\example.html) For scripters: @ExitValue holds the number of bytes downloaded. HttpGET(URL[|Key=Value...]|Variable) Fetch a web address and put the response text in a variable. Write HttpGET(URL|Variable), or add query values between them: HttpGET(URL|name=value|other=value|Variable). The first | ends the URL; the last starts the variable name. Both the URL and variable name are required. Separate query values with | or &. KeyBind joins them into the URL after ?, using & between values. Query text already present in the URL is kept before any added values. Without query values, the command fetches the URL directly. Type ordinary text for the added names and values; KeyBind converts spaces and other special characters into the form required by a URL. Text you have already encoded, such as %20, is encoded again. A | or & typed inside a value separates it into another query value. Query text already included in the URL is kept as supplied. The variable name may start with @. Its name must begin with a letter A-Z or an underscore, followed only by letters A-Z, digits or underscores. Reserved @Macro names cannot be used. An invalid name or empty URL stops the command before anything is sent. Use - instead of a variable name to fetch without storing a response or changing any variable. @Macros and user variables are expanded in the URL and query values. The destination variable name is used as written; it is not replaced with that variable's contents. If the URL has no ://, KeyBind adds https://. KeyBind waits up to 10 seconds to look up the server address, 10 seconds to connect, 15 seconds to send and 15 seconds to receive. These limits apply separately, so they are not a single limit for the whole request. A response status from 200 to 299 stores the response text exactly as received: arithmetic-looking text is not calculated, and delimiter characters are preserved. If the request fails or receives another status, the destination variable is cleared. A rejected command that never sends a request leaves the variable unchanged. @ExitValue and @HttpStatus contain the response status, such as 200 or 404, or 0 if no status was received. @HttpStatus keeps that value until the next HTTP request. Test the result with If(@ExitValue|200). A response may contain no text, even when successful. The command can fail because its parameters or variable name are invalid, the network request fails, the server returns a status outside 200-299, Windows cannot create the request, or the response cannot be stored. Check the response status to distinguish a server response from a request that received no status. HttpGET(https://example.com|page) HttpGET(https://httpbin.org/get|name=KeyBind|page) For scripters: @ExitValue holds the response status code, @HttpStatus mirrors it.. HttpPOST(URL|Body|Variable) Send data to a web address. Supply all three parts: HttpPOST(URL|Body|Variable). The first | ends the URL; the last starts the variable name. Everything between them is the data to send. For ordinary form values, write name=value pairs separated by | or &. KeyBind converts each name and value into the form required by a web request. Type ordinary text; text already encoded, such as %20, is encoded again. A | or & typed inside a value starts another pair. To send JSON, start the body with { or [; spaces and line breaks before that opening character are allowed. KeyBind sends it as application/json. Valid JSON is sent unchanged, including any | characters inside it. For invalid JSON typed into the command, KeyBind tries these repairs in order: remove commas immediately before closing } or ] characters; remove trailing semicolons; add one missing outer } or ], trying it first without further cleanup, then with trailing commas and semicolons removed, then also removing commas before closing characters; remove surplus closing braces, commas or semicolons after one complete JSON value. It uses the first attempt that produces valid JSON. It does not rewrite inner quotes, names, colons or nesting. A successful repair shows Your JSON had to be repaired. If no repair succeeds, KeyBind sends the original JSON and shows KeyBind could not fix your JSON. JSON sent as-is. Check your syntax. The server then decides whether to accept it. To send a text file as a form value, use name=file:path. To upload a file, use name=upload:path; this sends its original file name and binary contents in the format used for file uploads. The file must exist and be readable, otherwise nothing is sent. Prefixes are case- insensitive. To send a JSON file as the whole body, use JSONfile:path. To use its JSON text as a form value, use name=JSONfile:path. The file must exist, be readable and contain valid JSON; otherwise nothing is sent. File contents used as form values stay together, including any | or & characters. Inside a JSON body, file:, upload: and JSONfile: are ordinary text and do not read files. On a response status from 200 to 299, your variable receives Success! and POST command sent on separate lines, followed by the response text if there is any. For another status, it receives POST ERROR!, then the status and any response text. If no status is received, the message says no response received and includes available error details. A rejected command that never sends a request leaves the variable unchanged. The variable-name rules, - option, @Macro expansion, default https://, time limits and response statuses are described under HttpGET(). Here @Macros and user variables are expanded in the URL and body. @ExitValue and @HttpStatus contain the response status, or 0 if none was received. HttpPOST(https://corz.org/windows/software/keybind/example.php|{"hello": "world"}|reply) HttpPOST(https://corz.org/windows/software/keybind/example.php|name=KeyBind|type=hotkey|reply) HttpPOST(https://corz.org/windows/software/keybind/example.php|token=file:@Desktop\token.txt|reply) HttpPOST(https://corz.org/windows/software/keybind/example.php|JSONfile:@Desktop\payload.json|reply) For scripters: @ExitValue holds the response status code, and your variable holds a human message: Success! plus POST command sent on 200-299, followed by the response text when the server sent any, or POST ERROR! plus the code and whatever data came back.. SendMail(Subject|Body[|To|Attachment]) Send a plain email through your [Mail] ini settings: server, port, SSL flag, username, password, from name and address. Name the subject and body, with an optional to address and attachment, e.g. SendMail(Hello|Testing KeyBind mail). An empty to address uses the stored default. Bodies holding angle brackets go as HTML. The password sits plain in the ini. FileSize(File[|Unit]) Returns the size of a file in the unit you specify.. FileSize(C:\TEMP\1gb.test|MB) Would put "1024" into @ExitValue, which you could then use.. FileSize(C:\TEMP\1gb.test|MB)**Speak(@ExitValue MB) If you don't specify a unit, you get back bytes, which could be a BIG number. Available units are.. KB = Kilobyte MB = Megabyte GB = Gigabyte TB = Terabyte PB = Petabyte EB = Exabyte ZB = Zettabyte YB = Yottabyte (named after Yoda!) FileLineCount(File[|Variable]) Counts the line breaks in a file and puts that total into @ExitValue.. A file with no breaks gives 0.. FileLineCount(C:\Logs\daily.txt) FileLineCount(C:\Logs\daily.txt)**MessageBox(Line count|@ExitValue lines) FileLineCount(C:\Logs\daily.txt|line_total) Stores the count in @line_total and returns assignment status 1 in @ExitValue. Without a named output variable, @ExitValue contains the count. FileTime(File[|1/2]) Get a file's last modified time as YYYY/MM/DD HH:MM:SS in @ExitValue. Use |1 for creation time or |2 for last access.. FileTime(C:\Work\report.txt|1) FileCreate(File[|true/Mode]) Creates a file. Supply the path for the new file.. FileCreate(C:\Path\To\My\File.txt) An existing file is left alone, unless you add true to overwrite it, or any FileOpen() mode number.. FileCreate(C:\Path\To\My\File.txt|true) Any parent directories required will also be created. FolderCreate(Folder) Create a folder, including any missing parent folders.. FolderCreate(C:\Work\NewProject) FileReadData(File|Variable) Reads the contents of a file into a user variable.. FileReadData(C:\Path\To\My\File.doc|MyVariable) You can now access the contents of the file with @MyVariable.. Speak(@MyVariable|100|0|Hazel) FileAppendData(C:\Path\To\an\other\file.txt|@MyVariable) FileOpenDialog() and FileSaveDialog() ask the user to pick or name a file. Give the title and starting folder, then optionally a filter, numeric options and a default name: FileOpenDialog(Pick a file|@Desktop) leaves everything else standard, while FileSaveDialog( Save report|@Desktop|Text files (*.txt)) suggests a .txt name and warns before overwriting. @ExitValue holds the picked path, empty when the box is dismissed. Separate filter groups with a semicolon (a semicolon right before an asterisk stays put); for all the option numbers, see the User Commands entries. FileWriteData(Destination|Data) / FileSave(Destination|Data) Write some data to a file. FileSave() is a shorter name for the same command. FileWriteData(C:\Path\To\File.txt|) KeyBind writes the data you provide to the named file, creating the file if needed or replacing its contents if it already exists. Use FileReadData() first if you want to write another file's contents. To add data without replacing the contents, use FileAppendData(). In the data for either command, \n writes a new line. FileAppendData(Destination|Text) Append some data to the end of a file.. FileAppendData(C:\Path\To\File.txt|) KeyBind adds the data you provide to the end of the named file, creating the file if needed. Use FileReadData() first if you want to append another file's contents. Working examples: files and @Macros These examples use C:\Folder. Run these setup commands once, in order. They create the files used below; edit the two templates to suit you. FolderCreate(C:\Folder) FolderCreate(C:\Folder\Notes) FolderCreate(C:\Folder\Templates) FileSave(C:\Folder\ticket-number.txt|0) FileSave(C:\Folder\capture-number.txt|0) FileSave(C:\Folder\mode.txt|work) FileSave(C:\Folder\Templates\reply.txt|Thanks for your message.) FileSave(C:\Folder\Templates\README.txt|Project notes) Next ticket number: copy "Ticket #1" on the first run, then "Ticket #2", and so on. The file keeps the count when KeyBind restarts. FileReadData(C:\Folder\ticket-number.txt|ticket_number)**Count(@ticket_number)**Copy(Ticket #@Count+)**FileSave(C:\Folder\ticket-number.txt|@Count) Numbered capture: select text first. This copies it into a new file and saves the number for next time. Copy()**FileReadData(C:\Folder\capture-number.txt|capture_number)**Count(@capture_number)**FileSave(C:\Folder\Notes\capture_@Count+.txt|@ClipBoard)**FileSave(C:\Folder\capture-number.txt|@Count) Reusable reply: edit reply.txt whenever the wording changes. This task inserts its current contents at the caret. FileReadData(C:\Folder\Templates\reply.txt|reply)**Copy(@reply)**Paste() Switch modes: each run changes mode.txt from work to personal, or back, and speaks the new mode. The file remembers it across restarts. FileReadData(C:\Folder\mode.txt|mode)**If(@mode|work)**FileSave(C:\Folder\mode.txt|personal)**Speak(Personal mode)**Else()**FileSave(C:\Folder\mode.txt|work)**Speak(Work mode)**EndIf() New project: enter a valid folder name. KeyBind creates that folder and copies your README template into it. Input(New project|Project name?|project)**IfNot(@project|)**FileReadData(C:\Folder\Templates\README.txt|readme)**FolderCreate(C:\Folder\@project)**FileSave(C:\Folder\@project\README.txt|@readme)**EndIf() The counter files must contain only the number, with no trailing line break. Run the setup commands only for a new example folder: FileSave() replaces existing contents, including saved numbers and edited templates. FileCopy(Source|Destination[|1/true/9]) Copy a file to a new location. Supply source and target locations.. FileCopy(C:\Path\To\File-Source.txt|C:\Path\To\File-Target.txt) The optional 3rd value controls overwriting. Leave it out (or use 0, false or -) to keep existing files; use 1 or true to replace them. For scripters: 9 also creates missing destination folders. FileCopy(C:\Path\To\File-source.txt|C:\Path\To\File-target.txt|true) Note: you can use * + ? wildcards in both the source and target paths. FileMove(Source|Destination[|1/true/9]) Essentially identical to the previous command, except the source file is removed at the end of the operation! Again, you can set the third parameter to 1 or true to overwrite a destination file. Leave it out (or use 0, false or -) to keep existing files. For scripters: 9 also creates missing destination folders. FileMove(C:\Path\To\File-Source.Txt|C:\Path\To\File-Target.Txt|true) Note: you can use * wildcards in both the source and target paths. Delete(File Or Folder[|true]) Delete a file or directory. Supply the full path to the file/directory. As with all path preferences, @Macros are allowed. Delete(C:\Path\To\File.ext) You can use Wildcards (* and ?) to delete multiple files. If you supply the path to a directory, you cannot use wildcards. You can, however, supply an optional second parameter which instructs KeyBind to delete recursively, so all the files and folders inside the folder you supplied will be deleted, as well as all the files and folders inside them and so on, except in reverse! Very like the old DOS DelTree command.. Delete(C:\Path\To\Folder|true) Note: with this command, the files and folders are not sent to the recycle bin - they are GONE! Be Very Careful when using this command. Especially as KeyBind usually runs as Admin and could do a lot of damage. OpenTempDir() Opens the temp dir! Recycle(File Or Folder) Send items to the Recycle Bin. Supply the path to a file or folder.. Recycle(C:\Path\To\File.txt) Recycle(C:\Path\To) That's it. If there are files inside the folder, they are sent along with the folder. As we are using the Windows API to recycle the items, you could do Ctrl+Z in Explorer afterwards to restore them. Note: *? Wildcards are accepted for deleting both files and folders. FolderCopy(Source|Destination[|0/false/1/true/9]) Copies a folder to a new location. Supply the source and target locations. The optional 3rd value is 0 or false to keep existing files, 1 or true to replace them, or 9 to also create missing destination folders. Omit it (or use -) for the default, 0. FolderCopy(C:\Path\To\Source|C:\Path\To\Target[|]) FolderSelect() asks the user to pick a folder: FolderSelect( Pick a folder|@Desktop) opens at the desktop, and @ExitValue holds the chosen folder, empty when dismissed. The optional flag falls back to 7, the usual new-folder button, dialog and edit field. FolderMove(Source|Destination[|0/false/1/true/9]) Just like FolderCopy() except that the folder is gone from the original location at the end of the operation. The same 3rd value applies: 0 or false keeps existing files, 1 or true replaces them, and 9 also creates missing destination folders. FolderMove(C:\Path\To\Source|C:\Path\To\Target[|]) Rename(Original|New[|1/true|Setting]) Rename a file or folder. Think of it just like FolderMove()/FileMove() (above), which is exactly what it is. The only difference is that you can supply a simple basename for the target rather than a full path.. Rename(C:\Path\To\OldFolderName|NewFolderName) Rename(C:\Path\To\OldFolderName|C:\Path\To\NewFolderName) Both of the above commands will produce the exact same result. These are functionally identical, too.. Rename(C:\Path\To\Old.txt|C:\Path\To\New.txt) Rename(C:\Path\To\Old.txt|New.txt) The optional 3rd value controls overwriting: leave it out (or use 0, false or -) to keep an existing target; use 1 or true to replace it. The destination folders must already exist; a rename never creates them. Rename(C:\Path\To\Old.txt|Existing.txt|true) When renaming files, you can use * wildcards. EmptyRecycleBin([Drive Letter]) Empties the Recycle Bin on one or all drives. To empty all Recycle Bins, do: EmptyRecycleBin() To empty the Recycle Bin on only the C drive (usually main drive), do: EmptyRecycleBin(C) Menu(Name|Action...) Show a menu at the mouse pointer. Give each item a visible name, then the action it runs. Repeat that pair for each item: Menu(Event Viewer|Launch(|eventvwr.msc)|Services|Launch(|services.msc)|Device Manager|Launch(|devmgmt.msc)) Click an item to run it. Press Esc or click away to cancel. Only the action you choose runs. It can be a single command or a chain: Menu(Lock PC|LockPC()|Screen off and lock|Screen(off)**LockPC()|Open KeyBind data|OpenDataDir()) Use a lone - to add a separator between items: Menu(Mouse Settings|Launch(control mouse)|-|Control Panel|Launch(control)) An item can also run a .kc script: Menu(Run control script|@DataDir\Scripts\control.kc|Show hotkeys|ShowHotKeys()) The sample hotkeys open the first menu with Ctrl+Win+Alt+left-click. To use it yourself, put this under [Global] in your hotkeys INI: ^!#{Click}=Menu(Event Viewer|Launch(|eventvwr.msc)|Services|Launch(|services.msc)|Device Manager|Launch(|devmgmt.msc)) For scripters: | separates names and actions; - is a complete menu entry by itself. A | inside another command's parentheses stays with that command. You can add as many pairs as fit on the screen (roughly one item per 24 pixels of screen height). The entire Menu() command can be up to 32,768 characters. MessageBox(Title[|Message|X|Y|Timeout|On Top]) You can use this to notify the user about something.. MessageBox(KeyBind Notice|Operation Completed Successfully!) The title comes first; add your message as the second parameter.. MessageBox(Success!|Operation Completed Successfully!) You can set the timeout in the fifth slot (0 means no timeout). Use - for default X and Y. MessageBox(Success!|Operation Completed Successfully!|-|-|30) As the speech is Asynchronous with other commands, you can do handy stuff like this (spoken + visual feedback).. Speak(Operation Completed Successfully!)**MessageBox(Success!|Operation Completed Successfully!|-|-|5) Basically, the user gets the MessageBox and the Speech at the same time. Note: You can use "\n", like in regular text commands, to produce line- breaks. ChoiceBox(Title|Message|Option[|Option...]) Ask the user to pick one of several options. ChoiceBox(Favourite colour|Pick one:|Red|Green|Blue) Give the title first, then the message, then the options. The box shows one button per option, and @ExitValue holds whichever one gets picked (empty when the box is dismissed). Chain it straight into the next command: ChoiceBox(Favourite colour|Pick one:|Red|Green|Blue)**MessageBox( You picked @ExitValue) Confirm([Title[|Message]]) Ask a Yes/No/Cancel question. Title and message are optional. Confirm(Continue?|Run the backup now?) Missing or empty slots fall back to Confirm and Are you sure?, so bare Confirm() already gates the next command: Confirm()**MessageBox(You answered @ExitValue) @ExitValue holds the picked button text (empty when dismissed), so branch on it directly: Confirm(Continue?|Run the backup now?)**If(@ExitValue|Yes)**MessageBox(Backing up...)**EndIf() InfoBox(Title[|Message|X|Y|Timeout|On Top]) InfoBox() uses the same parameters as MessageBox(), but KeyBind keeps running while its window is open. Put the title first. If you leave out the message, KeyBind uses the title. X and Y go in the third and fourth slots; use - to keep an optional slot at its default. Each new box clears any message, X or Y you leave out of the INI. InfoBox(open) reopens the saved box without changing those values. InfoBox(close) also leaves them alone. If there is no saved title to open, or no box to close, the next task still runs. InfoBox displays the full text. Saved titles and messages are limited to 512 characters after encoding line breaks and backslashes. Longer text is saved as empty. With no saved message, open uses the title; with no saved title, open fails. MessageBox keeps its position, but does not save its title or message. ProgressBar(Title[|Message|Subtext|X|Y|Options]/Percent/off/close) Show a progress window with a title and main message. By default the ProgressBar() opens unmoveable with title and borders and on-top flag set, but you can change these things in the calling parameters. Optionally add subtext, X and Y positions, and display options if you need them: ProgressBar(Export|Preparing files) Explicit X and Y positions are saved. Use - in either position slot to reuse its saved value. An omitted position centres the window. ProgressBar(Export|Writing files|-|-|-|move) Use an integer on its own to set the percentage, then close the window when the work is done: ProgressBar(50) ProgressBar(off) ProgressBar(close) also closes it. For scripters: the option values are plain=1, notop=2, and move=16. Add names or numbers with +: plain+top, 1+16, and 17 are all valid. Execute(Script) This command enables you to run AutoIt Script code directly. Supply the path to the script.. Execute(C:\Users\Me\Documents\MyScript.au3) Note: your script can't use #include<> statements for scripts that don't exist in your system. Ideally, you want "stripped" scripts, such as output by Au3Stripper, where all the variables and functions required are in the same file. If the code has no #include statements, there isn't an issue. ExecuteSelected() [Default HotKey: Ctrl+Alt+Win+E] This will execute whatever text you have selected, in any applicaton, and run it as AutoIt code. RunSelected() [Default HotKey: Ctrl+Alt+Win+R] This will execute whatever text you have selected, in any applicaton, and run it as KeyBind commands. This is real handy. ShowRunHistory() Shows your run history, most recent first, with time and source kind per task. The log accumulates across launches (capped by max_history_file, 10 MiB default); only this session shows unless you tick Show entire history beside On Top (the show_entire_history setting keeps your choice for future windows). Type to filter the list, click a column header to sort it. It stays open while KeyBind keeps running, and new tasks appear live; older events load as you scroll down. History() opens the same viewer under its everyday name. "Internal" Commands.. There are also a few "internal" commands that you can access inside your scripts and HotKeys. We do this primarily so that you can set your own global HotKeys for them, if required (see Dimensions() above). For on/off commands below, leave the brackets empty to flip the current state. Use "-" to leave it as it is. ResetSequence([Number]) This resets the renaming sequence. The sequence count persists across launches of KeyBind. If you want it reset, you need to do it minfdully with this command or via the system tray menu. By default (and when performed from the system tray menu) the sequence is reset to 1. You can also supply any number to reset it back to, e.g.. ResetSequence(10) CreateStartupTask() Arrange for Windows to start KeyBind when you log on, after a 25-second delay. You can also choose whether KeyBind.exe should always start as administrator. If you choose Yes, the setting remains in place even after you remove the startup task. To change it later, right-click Start with Windows in the Config Editor. Choose 'Give KeyBind.exe admin rights' or 'Strip Admin rights from KeyBind.exe', depending on its current setting. ConfigEditor() Launches the KeyBind Config Editor interface. A nice GUI. ShowHotKeys() Show the HotKeys for the current app, with your global HotKeys underneath. Hold a modifier key to highlight matching shortcuts. OpenDataDir() This will open the KeyBind data directory. OpenSentinelFolder([Names/all]) Open the folder Sentinel is watching in Explorer. EditIniFile() This will open the KeyBind ini file in your preferred text editor. Record([File[|Append]]) Start recording typing, clicks, wheel moves and window changes as a KeyBind script. Record(C:\Temp\job.kc) suggests a destination to the Recording Editor; saving requires its Save File action. Other triggers pause while you record; your HotKeys still work. You can also start or stop recording with the Record HotKey or the tray menu. Set it in Config Editor > Options > Runtime & Speech. StopRecording() Finish recording. With the recorder edit option enabled, open the editor to edit and save the script. With editing disabled, the command does not open the editor or automatically save a file. RecorderSetOption(Option|Value) Tweak one recorder option right now, without reloading. Anything it changes applies live and is never replayed into the recording. RecorderSetOption(min_pause_ms|0) Names: settle_ms, min_pause_ms, click_ms, jitter_px, drag_px, hotkeys (embed or raw), max_events, edit, stoplag_ms, coords (absolute or window). Window mode records clicks relative to the clicked window, with Activate([CLASS:..]) lines, never titles. The change lasts until KeyBind reloads. skip_passwords can only come from the ini and is always refused here. KeyBind(Setting|Value) Change a KeyBind setting from a task or script. Give its ini name (or a shorthand alias), then the new value after a pipe. KeyBind(hooks|off) KeyBind(debug|3) KeyBind(rate|1) Settings handled by KeyBind() are checked and saved. Live settings change immediately; others take effect when next used or reloaded. Invalid values get a brief explanation. Recognised settings (aliases in brackets, separated by commas): low_level_hooks [hooks]: on, off, raw, default or show notify_on_hooks: on or off capslock_info [caps]: on or off copy_window_info [wininfo]: on or off case_sensitive [case]: on or off fixed_trigger_delay [fixed]: on or off color_report_dimensions: on or off abort_hotkey [abort]: key name; cannot be blank record_hotkey [recordkey, record]: key name, or blank to disable sendkey_delay: whole number 0-1000 ms sendkeydown_delay: whole number 0-1000 ms mouse_delay: whole number 0-1000 ms loop_delay [loopdelay, loop]: whole number 10-250 ms debug_level [debug, debugging]: off or 0-10 mouse_pos_scheme [mouse, mousepos]: absolute or relative or window block_time: number 0-60000 seconds trigger_rate [rate]: number 0.1-10 seconds info_file [info]: non-blank path color_report_file [report]: non-blank path conflicts_report: non-blank path dump_file [dumplog, dump]: non-blank path random_seed [seed]: non-blank expression idle_ignore [idle]: any text, including blank start_with_windows [startwin]: on or off (compiled program only) associate_kc_files [associate]: on or off (compiled program only) max_log_size [maxlog]: number 0 or more MB max_history_file [maxhistoryfile]: number 0.1 or more MiB open_report_on_sample: on or off color_add_prefix: on or off color_report_to_file: on or off scripts_dir [scripts]: must be an existing folder editor [edit]: must be an existing exe path log_viewer [viewer]: must be an existing exe path startup_task: task text, or blank for none shutdown_task: task text, or blank for none speak_task_define_start: any text, including blank speak_task_define_end: any text, including blank speak_task_define_url [defineurl]: URL containing @Selected web_search_url [weburl]: URL containing @Selected date_format [date]: non-blank date format import_always_overwrites_tasks: on or off inputbox_font: non-blank font name message_text_size: whole number 1 or more missed_minutes: whole number 0 or more record_coords: absolute or window record_hotkeys: embed or raw recorder_edit: on or off persistent_hotkey_window: on or off The settings listed above accept the values shown beside them. An invalid value for one of these settings is rejected. Setting names not listed above are written directly to the ini without checking their values or showing a success message. That includes names you invent and spelling mistakes. They only have an effect if KeyBind reads that name later; saving a name does not create a new feature. Sentinels([on/off/toggle][|Names]) Enable or disable KeyBind's Sentinel facility. Triggers([on/off/toggle]) Enable or disable every trigger through the master switch. Triggers([on/off/toggle]|window/system/clipboard[|Type...]) Enable or disable one trigger type, leaving the master switch alone. Name several types with pipes, as in Triggers(off|window|system). ReloadWindowTriggers() Pick up Window Trigger changes without restarting KeyBind. Screen([on/off/toggle]) Ask Windows to turn the display on or off: Screen(on) or Screen(off). Screen(), Screen(toggle) and Screen(switch) alternate between the settings requested through this command. KeyBind starts with its remembered setting at on, so the first empty call requests off. Waking the screen with the mouse or keyboard does not update that setting; use explicit on or off when you need a particular state. true, yes and 1 also mean on; false, no and 0 also mean off. Letter case does not matter. Screen(-) makes no change. Unrecognised words make no change and report False. Mouse or keyboard activity can wake the display. Windows and the display hardware determine whether the power request takes effect. For scripters: @ExitValue is True if the Windows call completes, or when - requests no change; False for an unrecognised argument or a failed call. True does not verify the display's actual power state. NewSchedule([Name|frequency=..|date=..|time=..|repeat=..|task=..|skip_apps=..|enabled=..]) Create a new schedule with a wizard. Supplied parameters skip their dialogs; cancel at any step saves nothing. e.g.. NewSchedule(Morning|frequency=Daily|time=9:00am|enabled=true|task=Text(Good morning!)) CountDown([1h 12m 3s][|task]) Open a non-blocking countdown dialog with hour, minute and second selectors, a Start/Stop button and a large live readout. With a duration it starts running at once, otherwise it waits for input. Start pauses and resumes, closing ends the run. At zero it fires your countdown completion from the Sounds options (a sound file plays, anything else runs as a task), or stays open flashing in the warning color when that is empty. e.g.. CountDown(1h 12m 3s) Add a pipe after the duration to supply this timer's completion task: CountDown(2m 10s|Beep(880|100)) CountDown(2m|Beep(880|100)**Text(Tea is ready!)) Only the first pipe separates countdown parameters. All later pipes and ** chains belong to the supplied task, replacing the default countdown_complete action for this timer. Task tokens expand when it finishes. Without a pipe, the default action applies. An empty task (CountDown(2m|)) finishes silently and stays open flashing in the warning color. CountDown(|task) waits for you to choose a duration. Position keys use only the duration, so CountDown(2m|task) uses countdown_2m_x/y. Right-click either readout to enable or disable its completion action. The item reads "Run default Task on completion" for a default action, or "Run supplied Task on completion" for a task in the command. An unchecked timer finishes flashing in the warning color without running either action. The two menus share the check mark; it starts checked on each new timer and is not saved to the INI. Rechecking applies to later completions. The [sounds] preferences countdown_start and countdown_stop contain only Beep() parameters, not commands. Defaults: 372|50 and 245|50. Frequency comes first, followed by pipe-separated duration or dur=, vol=, wave=, pan=, adsr=, phase= and duty= values. Brackets/braces, commands, tokens, spaces, control characters and ** task chains are invalid. Numbers are interpreted and limited to the ranges described for Beep() in the User Commands reference. Empty parameters are invalid; vol=0 is silent. Invalid Config Editor input uses Warning Color and is not saved; the last valid setting remains active. Missing or invalid stored values use the registered default without rewriting the INI. keybind_sounds enables these beeps. keybind_volume is limited to 0..100 and scales the individual tone volume, whose default is 100. countdown_complete accepts a complete task or sound-file path instead. Warning Color is the generic warning_color preference in [KeyBind]. Default: red. It controls invalid-input backgrounds, duplicate-entry highlights, paused-group labels, capture outlines, System Info low-space warnings and countdown completion flashing. Its control is below the CountDown text and transparency controls, with an extra 4 px gap. ScheduleControl(action|name[|setting=value...]) Actions: new, edit, enable, disable, delete, reset Edit a named schedule with "edit". Create a new schedule with "new" A new schedule requires frequency, time, enabled and task. "One Date" and "Custom" schedules also require date=YYYY/MM/DD; Custom needs repeat=15 Minutes (or another count and unit). Put task= /last/, so its pipes "|" reach the task. e.g.. ScheduleControl(new|Morning reminder|frequency=Daily|time=08:30am|enabled=true|task=Beep(880|dur=150ms)) The enable/disable commands essentially enable you to do this: ScheduleControl(edit|Morning reminder|enabled=true) Like this: ScheduleControl(enable|Morning reminder). Which is easier to remember. All ScheduleControl() commands: new edit enable disable reset delete new/edit parameters: frequency Daily, Weekdays, Weekends, One Date or Custom dat YYYY/MM/DD, for One Date and Custom schedules. time HH:MMam/pm repeat Count plus Minutes, Hours, Days, Weeks, Months or Years Only for custom repeating schedules. enabled true or false skip_apps Programs or titles separated by semicolons, the schedule stays primed but will not fire while one of them is at the front (e.g. your movie player). task The actual task, put it last so its pipes reach the task. Example: ScheduleControl(new|Morning reminder|frequency=Daily|time=08:30am|enabled=true|task=Beep(880|dur=150ms)) ScheduleControl(new|Queue check|frequency=Custom|date=2026/10/05|time=08:30am|repeat=15 Minutes|enabled=true|task=MessageBox(Check the queue.)) Schedules([on/off/toggle]) Enable or disable KeyBind's Scheduled Commands feature. StopSpeaking() Halts whatever is currently being spoken. Having this on a HotKey is handy. StopAudio() Immediately stops audio currently produced, PlaySound() playback and generated Beep() tones. Silence() Stop KeyBind's current speech and audio playback. @ExplorerSelection Selected files and folders from Explorer, as full paths separated by line breaks. There are no surrounding quotes or final line break. The active tab supplies the selection. Virtual items without filesystem paths are omitted. Desktop icons and other file managers are not included. Assign your task a HotKey, or save it as a .kc script in your Scripts folder. Select the items in Explorer, then press the HotKey or choose the script from KeyBind's tray menu. KeyBind remembers the Explorer window when its own UI or the tray takes focus. Activating another application clears that remembered window. The list is captured once at task start; tray scripts use the selection captured when the tray menu opens. Nested scripts, repeated items and Wait() continuations keep that list. An independent task captures its own list. The list is not saved to settings, and a restart discards it. An empty selection or no remembered Explorer window gives an empty list. If the selection cannot be read, a task using this token stops with a notification. Actions already completed remain completed. ForEach(@ExplorerSelection|MessageBox(Selected item|@Item)) ForEach() runs the command once per path; @Item is that path. Files and folders can both appear, so choose suitable commands. Spaces, Unicode and @Tokens in filenames remain literal data. Explorer supplies the order; KeyBind does not add sorting. An empty list runs no items. Copy(@ExplorerSelection) Copies the complete list of paths to the clipboard. The @Macros HTML guide contains a complete preparation example which creates two test files and opens their folder, plus examples that show each path, copy the list or save it to a new text file. CopyColor([on/off/toggle]) Set whether KeyBind copies your sampled color to the ClipBoard. ColorReport([on/off/toggle]) Set whether KeyBind creates a full Color Report on sampling. SwitchColorFormat(Number/Name) Change the colour format for the rest of this task. Give a number from 1 to 9, a full format name or an unambiguous beginning of it.. SwitchColorFormat(Web Hex) If the clipboard still holds the last colour KeyBind copied, it is converted immediately for immediate pasting. Suspend([on/off/toggle]) Suspend's KeyBind's HotKey operations. All keyboard hooks are released and no keystrokes, window triggers or Sentinel tasks are processed. Abort() Stop the current task, empty the run queue and restart KeyBind. You can also use the Abort HotKey or Abort and Reload in the tray menu. Set the HotKey in Config Editor > Options > Runtime & Speech. This resets Window Trigger state and does not repeat the original command line. Reload() Restart KeyBind and reload its settings. This keeps the run queue and Window Trigger state, and passes the original command line to the new instance. Use Abort() when you need to stop the task and clear the queue. Quit() KeyBind has left the building. Command-Line: While we're here I should mention that you can also launch KeyBind with commands or paths to script /on/ the command-line, if you know how to do such things: "C:\Program Files\corz\KeyBind\KeyBind.exe" Speak(Welcome to KeyBind|100|-2)**MessageBox(Welcome!|Welcome to KeyBind!|-|-|3) Imagine if I'd set that as the program's default! lol You can instruct KeyBind to launch, run your command(s) and quit directly afterwards by placing a "|" pipe character at the very start of your command, like so: "C:\Program Files\corz\KeyBind\KeyBind.exe" |Speak(I will now Quit. Goodbye!|100|-4) If you set a startup_task AND put a command/script on the command-line, KeyBind will execute both. Note: if an instance of KeyBind is already running when you launch another with a command on the command-line, that command (or script) is passed to the running instance and the new instance quits immediately. You can't send a "|" quit instruction to an already running instance. If no instance is running, the quit instruction will be obeyed and KeyBind will exit afer the commands have been processed. If speech commands have been issued, KeyBind will wait for the Windows Speech API to complete the speech before exiting. Exiting would kill the speech immediatelty, you see. Debug Levels: Each level also shows all the information from the previous levels. 0: off 1: Basic messages and errors. 2: Slightly more info. 3: Standard debug level, most messages now visible. 4: Major user-visible actions and dialog lifecycle (why shit happens) 5: Variable trace inside level-4 flows 6: Hotkey DB + match loop, ConfigEditor import/catcher 7: Shared-library internals (cel.au3 stuff) 8: GUI/widget geometry + INI rename + schedule log gate 9: Array/time helpers 10: Full page text (plus control borders, currently unsused in KeyBind) ---- INCORPORATE UPDATES: ; ; KeyBind minimizes CPU usage wherever possible so you will probably find the ; default setting of 0.5 (twice per second) is just fine. ; Window triggers can action in one of two ways: ; ; once: The actions trigger once in the life of the window. If you close the ; window, this is reset - open it again and your commands run again. ; ; always: Your commands run whenever this window is made active (aka. "brought ; to the front"). This may be highly useful or highly annoying, ; depending on your methodology, setup and needs. ; The default setting is "once". Set here: ; It's best left at "once", because you can, if required, force individual ; triggers to *always* fire by prepending the window title match string with an ; asterisk ("*") character: ; ; [Window Triggers] ; Downloads=WinMove(@DesktopWidth/5+4|@DesktopHeight/4-64|@DesktopWidth/1.25|@DesktopHeight/2+128) ; *Downloads={F5}{End} ; ; If you set the default to "always", there is no way to force "once" behaviour. ; ; See the HowTo for more details. ; You can set a "Grace" Period for Window Triggers. This is set in the ; individual trigger (see the HowTo for how to). Essentially, you can have a ; "once only" window trigger fire again if a specified amount of time has passed ; since you were last in a particular app. For example, if it's been five ; minutes since I was last in a web browser and I switch to a web browser, nine ; times out of ten I want a new tab immediately. KeyBind does this for me so I ; can simply switch and start typing. ; SO, normally, KeyBind checks the time since you were *last* in the window/app ; specified, but if you prefer, you can have KeyBind set the grace period to ; *always* end at the specified time, regardless of whether or not you have ; activated the window in the meantime. So in my example, I would get a new tab ; in Chrome, even if I was just in Chrome 10 seconds ago! Most people will not ; want this. ; ; Default: fixed_trigger_delay=off ; corz.org 2017->