AutoHotkey v2

The Big Changes

The burden of maintaining backward compatibility with legacy features reduces the usability and convenience of the language. The two big problems are that:

  1. IF-statements must usually be enclosed in parentheses to be expressions, which is a big source of confusion and script-bugs.
  2. The equal-sign operator does not assign an expression, so statements like x=y produce a counterintuitive effect. Even after users get used to it, they're still prone to type = instead of :=, which is a big source of script-bugs.

With each passing day, more users begin using AutoHotkey, increasing the total number of people who must tolerate these problems. In light of this, it seems best to make v2 not primarily about "new features" because that would produce a costly delay in its release. However, some new features should be introduced or at least considered, especially ones that would otherwise break compatibility if they were introduced after v2.

Lesser Change: Replacement for the v1 equal-sign operator

Since equal-sign will be used exclusively by expressions in v2, some new method of doing an old-style assignment seems desirable. This is primarily because many existing users like AutoHotkey for its convenience and command-style interface, and such an operator would help preserve that. For example:

var = The value in x is "%x%".  ; Current v1 method.
var = "The value in x is """ . x . """."  ; This is a working substitute in v2, but it's awkward and less readable.
var << The value in x is "%x%".  ; Alternative: Some new operator that has the same effect as equal-sign in v1.
var = "The value in x is ""$x""."  ; Alternative: Resolve $var inside double-quoted strings ($ seems easier than %%).

(Titan: Oh please no, "<<" looks hideous. How about #= or at least something with '=' for clarity.)

The $var approach is attractive because not only is it easier to type than the dual-percent-sign method, the $ character might need to be escaped less often (due to being more rarely used than %). However, if $ seems too confusing or ambiguous (especially for PHP users, who are used to a $ being the mandatory first character in all variable names), the double-percent-sign method could be used instead.

Another thing about the $var method is that it could also be applied to all commands. For example: MsgBox The value in var is $var. However, there would be some ambiguous situations such as $varstring, in which string is intended to be literal text (not part of the variable name). Something like ${var}string could be used in these cases. It's important to verify the rarity these cases because if the braces are needed too frequently, staying with the percent-sign method is probably the better choice.

(Titan: What about an explicit end char like $var;string instead of braces? This goes for RegEx too.)
-> Interesting idea, but it doesn't seem as readable. In fact, it might seem cryptic to anyone unfamiliar with the syntax, not to mention breaking from tradition and thus having more of a learning curve for people going to (or coming from) other languages. On the other hand, it's clearly easier to type. But if the semicolon-or-braces are rarely needed in practice, perhaps the choice between semicolon and braces doesn't matter too much.

(Laszlo: but << conflicts with left shift. Some other construct could be less confusing, but harder to remember, like `=, '= (where the quote reminds about strings))

Obsolete Commands

Some commands will be removed altogether because they cause more confusion than they're worth. Other commands will be replaced with a new, easier equivalent. For example, it seems best to replace most commands that accept a single OutputVar with a function. This is because functions seem more readable and easy-to-memorize in such cases.

However, there is some concern about performance because commands are currently faster than functions (since functions must be evaluated as expressions). But it's likely that future optimizations will alleviate this.

Commands To Be Completely Eliminated

#AllowSameLineComments: Obsolete (it was only used in .aut scripts, which v2 won't support).

#NoEnv: Obsolete because it will be the mandatory behavior in v2.

#MaxMem: Doesn't add enough value to keep? Removing it would also simplify the code and documentation.

FileGetAttrib: Its functionality is already covered by FileExist(). But FileSetAttribute needs to be retained as a command (or convert it to a function). Alternatively, FileGetAttrib() could be made a synonym for FileExist() to ease memorization and improve readability.

Progress and SplashImage: Although these are more convenient than GUI in some cases, perhaps their removal can be justified by the fact that it would be quite a big reduction in code size, and their syntax is a bit clumsy. Also, maintainability is a factor because if these commands are kept, they'll have to be kept in sync with any changes in Vista and future OSes. Finally, people could continue to run such scripts with v1 if they really need those features. On the other hand, Progress/Splash are clearly convenient in some cases, and code size has become less of a concern due to the capabilities of modern hardware.
-> Perhaps a volunteer can be found to write up a function-substitute for Progress/Splash, because coming up with an exact substitute would be costly in development time.

SoundGetWaveVolume/SoundSetWaveVolume: Maybe merge into SoundSet/Get?

Eliminate legacy commands (AutoIt v2) that already have a modern counterpart

SetEnv, Var, Value
EnvAdd, Var, Value [, TimeUnits]
EnvSub, Var, Value [, TimeUnits]
EnvMult, Var, Value
EnvDiv, Var, Value

IfEqual / IfNotEqual, var, value
IfGreater / IfGreaterOrEqual, var, value
IfLess / IfLessOrEqual, var, value

StringLen, OutputVar, InputVar
StringGetPos, OutputVar, InputVar, SearchText [, L#|R#, Offset]
StringMid, OutputVar, InputVar, StartChar [, Count, L]
StringLeft / Right, OutputVar, InputVar, Count
StringTrimLeft / Right, OutputVar, InputVar, Count

WinGetActiveStats, Title, Width, Height, X, Y
WinGetActiveTitle, OutputVar
Repeat / EndRepeat
RightClick / LeftClick
LeftClickDrag / RightClickDrag

Titan: L#|R# are really helpful. Could you add this to InStr()?
-> You're right that something should be created to substitute for L# and R#. Thanks for mentioning it.

Legacy commands to consider keeping (for convenience) even though they have a modern counterpart

IfWinActive / IfWinNotActive [, WinTitle, WinText, ExcludeTitle, ExcludeText]
IfWinExist / IfWinNotExist [, WinTitle, WinText, ExcludeTitle, ExcludeText]

IfInString / IfNotInString, Var, SearchString
IfExist / IfNotExist, File|Dir|Pattern

The following directives seem to complicate the code and documentation more than they're worth


Jonny said: As for eliminating those and #EscapeChar and #CommentFlag, I'll say that I use them myself to change the escape to \ and the comment to // ... Here's my verdict then: Eliminate #DerefChar and #Delimiter, since most people have probably never heard of them anyway, but keep #CommentFlag and #EscapeChar if only to have the options there.

Commands To Be Replaced With Functions

EnvGet, OutputVar, EnvVarName
EnvSet, EnvVar, Value
-> Make EnvSet a function due to ErrorLevel becoming its return value, and because it's the counterpart of EnvGet().

FileGetSize, OutputVar [, Filename, Units]
FileGetVersion, OutputVar [, Filename]
FileGetTime, OutputVar [, Filename, WhichTime (M, C, or A -- default is M)]
FileSetTime [, YYYYMMDDHH24MISS, FilePattern, WhichTime (M|C|A), OperateOnFolders?, Recurse?]

FileSetAttrib, Attributes(+-^RASHNOT) [, FilePattern, OperateOnFolders?, Recurse?]
-> But FileGetAttrib will be eliminated (or made synonymous) since FileExist() covers it. Even so, perhaps it's best to make FileSetAttrib() a function since it's strongly related to functions like FileSetTime().

FileRead, OutputVar, Filename
FileSelectFile, OutputVar [, Options, RootDir[\DefaultFilename], Prompt, Filter]
FileSelectFolder, OutputVar [, *StartingFolder, Options, Prompt]
-> Maybe rename them to FileSelect and DirSelect.

FormatTime, OutputVar [, YYYYMMDDHH24MISS, Format]
GetKeyState, OutputVar, WhichKey [, Mode (P|T)]

Seem slightly better as functions:
FileInstall, Source, Dest [, Flag (1 = overwrite)]
FileCopy, Source, Dest [, Flag (1 = overwrite)]
FileMove, Source, Dest [, Flag (1 = overwrite)]
FileRecycle, FilePattern
FileRecycleEmpty [, C:\]
FileDelete, FilePattern
FileCopyDir, Source, Dest [, Flag]
FileMoveDir, Source, Dest [, Flag (2 = overwrite)]
FileCreateDir, Path
FileRemoveDir, Path [, Recurse? (1 = yes)]
-> Maybe rename FileRemoveDir to FileDeleteDir for consistency with FileDelete?
-> Maybe rename File*Dir to Dir*, for brevity and preciseness. e.g. DirCreate/Copy/GetSize/Move/Remove
-> Drawback to making FileCopy etc into functions: "ErrorLevel is set to the number of files that could not be copied due to an error"."
-> So maybe have as both command and function.
-> But if function, that function should probably also set ErrorLevel to indicate how many files failed?
-> Maybe leave them as commands to pave the way for better file-copy/move functions to be added in the future, namely ones that are so strict like AutoIt's, and more like my mv/cp utilities.

Input [, OutputVar, Options, EndKeys, MatchList]
InputBox, OutputVar [, Title, Prompt, HIDE, Width, Height, X, Y, Font, Timeout, Default]
-> If possible, redesign InputBox's parameter list to be a flex-list or something else that's easier than the current method.

MsgBox [, Options, Title, Text, Timeout]
-> For extremely common command like MsgBox, it might be best to keep both a function and a command. However, that requires that the IfMsgBox command ALSO be kept?

Unlike RunWait, the following group sets ErrorLevel to a frequently-used value. Thus, they might be nicer as functions.
KeyWait, KeyName [, Options]
WinWait, WinTitle, WinText, Seconds [, ExcludeTitle, ExcludeText]
WinWaitActive [, WinTitle, WinText, Seconds, ExcludeTitle, ExcludeText]
WinWaitClose, WinTitle, WinText, Seconds [, ExcludeTitle, ExcludeText]
WinWaitNotActive [, WinTitle, WinText, Seconds, ExcludeTitle, ExcludeText]
ClipWait [, SecondsToWait, 1]
StatusBarWait [, BarText, Seconds, Part#, WinTitle, WinText, Interval, ExcludeTitle, ExcludeText]
StatusBarGetText, OutputVar [, Part#, WinTitle, WinText, ExcludeTitle, ExcludeText]

PostMessage, Msg [, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
SendMessage, Msg [, wParam, lParam, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]

Process, Cmd, PID-or-Name [, Param3]
-> Process often yields an ErrorLevel as its primary result, which isn't very readable.
-> However, a "Process List" sub-command is planned someday, so might be better to keep this as a function? Probably not in this case because readability would be greatly improved to have Process() be a function. By dividing it up into more readable functions like ProcessClose(), ProcessPriority(), ProcessWait(), ProcessWaitClose()

Random, OutputVar [, Min, Max]
-> Some langs have a special function to seed the pseudo random generator:
srand Perl, Perl6, Ruby, Tcl
random.seed Python

Sort, VarName [, Options]
-> Somewhat iffy for performance reasons, since current method might have some good optimizations for "in-place" sorting.

StringLower, OutputVar, InputVar [, T]
StringUpper, OutputVar, InputVar [, T]
-> Other langs: Uppercase / lowercase / capitalized string
upper / lower / capitalize Python
ToUpper / ToLower C#
uc / lc Perl, Perl6
strtoupper / strtolower PHP
strupper / strlower Lua

StringReplace, OutputVar, InputVar, SearchText [, ReplaceText, All]

Commands To Be Replaced with Something Else

EnvUpdate: Replace with it's DllCall/SendMsg counterpart? If so, document that very DllCall/SendMsg trick on the EnvSet() page.

MouseClick, WhichButton [, X, Y, ClickCount, Speed, D|U, R]
-> Superceded by "Click"? But if so the swapping control panel thing might be a minor issue, perhaps too rare for the translator utility to worry about.

OnExit [, Label]
-> Replace with a function so that the exit-reason can be passed? Not a huge benefit though.

FileReadLine, OutputVar, Filename, LineNum
-> Feel some urge to get rid of this command entirely. But since it's convenient in some cases, perhaps it should be kept.
-> PhiLho: Yes, remove it! Most often Loop Read is better and can be used to do the same thing. Plus it make the user feel the cost of the command...
-> Titan: Reading files from a specific position, line or offset from the end are popular requests, so a replacement that covers these would be very much utilized.
-> Laszlo: FileReadLine: it could be very useful, especially if negative line numbers were allowed, to count from the end of the file. In case of large log file, this is often needed.
-> It's outside my experience, so it would probably be best just to build in tail.exe's code someday. So for v2, it's probably best to leave FileReadLine as-is.

SetFormat, float|integer, TotalWidth.DecimalPlaces|hex|d
-> Would be nice to entirely get rid of this in favor of functions that format integers as hex or various other types of strings (how do other languages do this?)
-> However, float needs some way to set precision inside variables. So until variables have native support for storing ints/floats as numbers vs. text, it's probably to keep SetFormat, at least the float part (maybe get rid of the hex part for performance, adding IntToHex() to take its place. But if do that, maybe rename SetFormat to be something like SetFloatPrecision(String).
->Titan: If you're still planning typecasting forget this and have something like (hex)255.67 = 0xff
-> Interesting idea. One problem is that strictly speaking, "hex" isn't a type, it's just a display format. So you would instead write:
(int)255.67 == 0xff
(You probably know that decimal integers and hex integers are *already* the same in AutoHotkey; e.g. 0xFF == 256 in any comparison.)
-> MY: That's a good alternative to IntToHex(): something like: IntToStr(MyInt, "Hex").
-> sprintf-like functiosn in other languages:
sprintf Awk, C, C++, Maple, Matlab, merd, OCaml, Perl, Perl6, PHP, Pike, Ruby
% Python, Ruby
Format C#
printf: Awk, C, C++, Maple, Matlab, merd, OCaml, Perl, PHP, Ruby

If Var [not] between Low and High
-> "Between" is difficult to implement in in expressions, so maybe it's best if the translator just replaces it with a two checks (one for lower bound and one for upper).
-> Perhaps it could be retained as a non-expression (if not ambiguous with expressions), but it might add more confusion than it's worth since it can't be used in expressions, which is counterintuitive.

If Var [not] contains value1,value2,...
If Var [not] in value1,value2,...
-> These should probably eliminated in favor of some new syntax inspired by similar constructs in other popular languages. Alternatively, these could be kept because they don't appear to be ambiguous with normal IF-statements (furthermore, they can be distinguished from normal IF-statements at loadtime [as is done now] to improve runtime performance).

If Var is [not] integer|float|number|digit|xdigit|alpha|upper|lower|alnum|space|time
-> This should probably be replaced by some kind of operator or function inspired by the various methods used in other popular languages.
-> PhiLho: Lua has one function returning the type of the variable: If type(v) == "integer"
-> Laszlo: The problem with Type(x) is that it had to return multiple strings, all that matches, so the user would need another function call to check if the one he is interested in is in the list. In most cases IS(x,Type) is simpler.
-> Good point. I should research how other weakly-typed languages do this, in case they know a better way.

RANGE: inclusive..inclusive --
a .. b Ada, E, merd, MSH, Pascal, Perl, Ruby
range PHP
inclusive .. exclusive a ... b Ruby
a ..! b E
range Python

Transform, OutputVar, Cmd, Value1 [, Value2]
-> Mostly obsolete, but whatever subcommands remain should be either eliminated or made into functions.
-> Laszlo: Transform HTML/Unicode: There could be a library function: convert(x,toForm). Here the string parameter toForm can be "HTML", "HEX", "BINARY", "UTF8", "ANSI", "TEX", etc. E.g. the function determines if x is in UTF8 or HTML form, and acts differently when converting to ANSI or TEXT.
-> Yes, "Transform HTML" is a bit antiquated. Maybe it should just be removed until someone with the time and expertise writes a better replacement like the one you mentioned. By contrast, "Transform Unicode" probably needs to be retained in some fashion, but I don't want to write a lot of new code. So I might just rename it to become a new command or function, while keeping its functionality largely the same.

URLDownloadToFile, URL, Filename
-> Maybe needs nothing other than to be renamed to something shorter.
-> PhiLho: GetURL, for example?
-> Maybe 'hget' and 'fget'?
-> Maybe jonny's name "download" is the best yet in terms of score.

SendRaw, Keys
-> maybe replace with "Send {Raw}", but might not be worth the loss of readability

AutoTrim, On|Off
-> replace with some function to trim whitespace

IfMsgBox, Yes|No|OK|Cancel|Abort|Ignore|Retry|Timeout
-> Replace with msgBox's return value. But if MsgBox *command* is also kept, probably need to keep this too unless ErrorLevel is used or some other method.

SplashTextOff / SplashTextOn [, Width, Height, Title, Text]
-> Maybe could use some renaming and/or parameter reordering.
-> PhiLho: The fact that the option (On/Off) is part of the command is to be eliminated, if the command is kept.
-> It might wind up staying unchanged to conserve development time.

StringCaseSense, On|Off|Locale
-> Maybe make all string-sensitivity things internal to some operators. However, the locale mode is admittedly convenient, and making operators to replace that mode might be cumbersome giving rarity of use.
-> Laszlo: StringCaseSense: It makes sense to set the default string comparison behavior for a script. If a single comparison have to behave differently, it is inconvenient to change the global settings back and forth.

Commands That Accept More Than One OutputVar and Thus Should Stay Commands?

SplitPath, InputVar [, OutFileName, OutDir, OutExtension, OutNameNoExt, OutDrive]

MouseGetPos [, OutputVarX, OutputVarY, OutputVarWin, OutputVarControl, 1|2|3]
WinGetPos [, X, Y, Width, Height, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGetPos [, X, Y, Width, Height, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ImageSearch, OutputVarX, OutputVarY, X1, Y1, X2, Y2, ImageFile
Pixelsearch, OutputVarX, OutputVarY, X1, Y1, X2, Y2, ColorID [, Variation, Fast|RGB]

PixelGetColor, OutputVar, X, Y [, Alt|Slow|RGB]
-> Performance-sensitive, so maybe best to leave as command (especially if PixelSearch will be a command, since it would be a bit incongruous to have one a command and the other a function).

FileGetShortcut, LinkFile [, OutTarget, OutDir, OutArgs, OutDescription, OutIcon, OutIconNum, OutRunState]
FileCreateShortcut, Target, C:\My Shortcut.lnk [, WorkingDir, Args, Description, IconFile, ShortcutKey, IconNumber, RunState]

Titan: Couldn't they output named arrays?
-> Yes, but might not be worth the trouble given the plan for true arrays. Also, named arrays perform considerably worse than explicitly-named output variables due to the latter having an optimization.

Laszlo pointed out that they could be made into functions by passing the variables ByRef, and that any unused/unwanted parameter could be passed "" (or better: omitted entirely by putting two consecutive commas -- but this would require an enhancement and possible polluting of expression evaluation).

Commands That Could Be Replaced With Functions But Maybe Best Not To

Reasons: Having functions with names like Control() is a bit undesirable due to being so general. But maybe it's not that big a deal. Alternatively, could make a series of named/specific functions to take the place of SUB-commands. On the other hand, maybe it's best to keep the Control command like it is because it's a bit "impure" (such as some of its features maybe not working on Vista, or not being optimally designed due to being really old). If so, maybe ControlGet should also be left as-is since it's the obvious counterpart of the Control command.
-> Might actually be more convenient and readable to use a command like FileCopy then explicitly check ErrorLevel afterward, compared to calling a FileCopy() function.

Control, Cmd [, Value, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
(Due to ErrorLevel becoming its return value, and being the counterpart of ControlGet())
(However, perhaps Control should be MERGED with ControlGet to simplify things)
ControlGet, OutputVar, Cmd [, Value, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGetFocus, OutputVar [WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlGetText, OutputVar [, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
(perhaps some of the GET things above should be merged into ControlGet/Control)

ControlFocus [, Control, WinTitle, WinText, ExcludeTitle, ExcludeText]
(merge above into the control command?)
ControlSetText, Control, NewText [, WinTitle, WinText, ExcludeTitle, ExcludeText]
(merge above into the control command?)

GuiControl by analogy to Control?:
GuiControl, Sub-command, ControlID [, Param3]
GuiControlGet, OutputVar [, Sub-command, ControlID, Param4]
-> For "GuiControlGet Pos": Current architecture makes yielding an array from a function difficult or awkward. So maybe best to wait for true arrays (not to mention the fact that it would be a little incongruous to have Gui be a command but GuiControl/Get be a function).

WinGetClass, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinGetText, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinGetTitle, OutputVar [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinSetTitle, WinTitle, WinText, NewTitle [, ExcludeTitle, ExcludeText]
WinSet, AlwaysOnTop|Trans, On|Off|Toggle|Value(0-255) [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinGet, OutputVar [, Cmd, WinTitle, WinText, ExcludeTitle, ExcludeText]
-> For "WinGet List": current architecture makes yielding an array from a function difficult or awkward. So maybe best to wait for true arrays. In addition, that would give the opportunity to design a more flexible/professional WinGet() function.

Drive, Sub-command [, Drive , Value]
(Due to ErrorLevel becoming its return value, and being the counterpart of DriveGet())
(However, perhaps Drive should be MERGED with DriveGet to simplify things)
DriveGet, OutputVar, Cmd [, Value]
DriveSpaceFree, OutputVar, C:\
(merge with Drive function? Maybe too small in cost/benefit to bother with)

SoundGet, OutputVar [, ComponentType, ControlType, DeviceNumber]
SoundSet, NewSetting [, ComponentType, ControlType, DeviceNumber]

SysGet, OutputVar, Sub-command [, Param3]
-> Some SysGet sub-commands return an array, so maybe best to leave SysGet as-is. Current architecture makes returning array from a function awkward, plus a new SysGet() function should probably be revamped to make it more professional/flexible sometime after v2.
-> Laszlo: SysGet: we could turn it into a number of different functions, some with several ByRef parameters for the monitor size. It is not necessary to put the values in an array: Monitor(1, "Work", L,T,R,B) puts the info into the 4 last variable parameters.
-> When the time comes, I'll just try to pick whatever makes sense within the expected time/energy budget for v2.

FileAppend [, Text, Filename]
(although FileAppend makes use of ErrorLevel, it's probably more convenient to have it not be a function -- especially since better file-functions should probably be added sometime after v2 anyway).

IniDelete, Filename, Section [, Key]
IniRead, OutputVar, Filename, Section, Key [, Default]
IniWrite, Value, Filename, Section, Key
RegDelete, HKLM|HKU|HKCU|HKCR|HKCC, SubKey [, ValueName]
RegRead, OutputVar, HKLM|HKU|HKCU|HKCR|HKCC, SubKey [, ValueName]

StringSplit, OutputArray, InputVar [, Delimiters, OmitChars]
-> Current architecture makes yielding an array from a function difficult or awkward. So maybe best to wait for true arrays. In addition, that would give the opportunity to design a more flexible/professional StrSplit() function.

Remaining Commands That Will Still Exist

Gosub, Label
Goto, Label
Return [, Expression]
Exit [, ExitCode]
ExitApp [, ExitCode]
Shutdown, Code

The following group seems pretty good as-is due to its sheer convenience. But it might benefit from some parameter reordering and disambiguation.
Loop [, Count]`n{`n ID := A_Index`n If var%A_Index% =`n break`n}
Loop, FilePattern [, IncludeFolders?, Recurse?]`n{`n FileName := A_LoopFileName`n FileFullPath := A_LoopFileLongPath`n FileRelativeDir := A_LoopFileDir`n command2`n}
Loop, Parse, InputVar [, Delimiters|CSV, OmitChars]`n{`n Line := A_LoopField`n command2`n}
Loop, Read, InputFile [, OutputFile]`n{`n Line := A_LoopReadLine`n command2`n}
Loop, HKLM|HKU|HKCU|HKCR|HKCC [, Key, IncludeSubkeys?, Recurse?]`n{`n RegName := A_LoopRegName`n RegType := A_LoopRegType`n command2`n}

Other commands that will still exist:

Pause [, On|Off|Toggle, OperateOnUnderlyingThread?]
Suspend [, On|Off|Toggle|Permit]
Sleep, Delay

Critical [, Off]
Thread, Setting, P2 [, P3]

SetBatchLines, -1 | 20ms | LineCount
-> Its LineCount portion will probably be eliminated. In fact, perhaps the whole thing should be eliminated, though I don't think it currently affects performance too much.

Run, Target [, WorkingDir, Max|Min|Hide|UseErrorLevel, OutputVarPID]
RunAs [, User, Password, Domain]
RunWait, Target [, WorkingDir, Max|Min|Hide|UseErrorLevel, OutputVarPID]

Gui, sub-command [, Param2, Param3, Param4]
Menu, MenuName, Cmd [, P3, P4, P5]
Hotkey, KeyName [, Label, Options]
ToolTip [, Text, X, Y, WhichToolTip]
TrayTip [, Title, Text, Seconds, Options]
OutputDebug, Text
SetTimer, Label [, Period|On|Off]

SoundBeep [, Frequency, Duration]
SoundPlay, Filename [, wait]

Click: Maybe make MouseClick an exact synonym for it, to help simplify/centralize the documentation with MouseClickDrag and MouseMove. However, maybe those siblings should be changed to support the flexible parameter ordering of the Click command? Also, perhaps MouseClickDrag should be renamed to MouseDrag.

MouseClickDrag, WhichButton, X1, Y1, X2, Y2 [, Speed, R]
MouseMove, X, Y [, Speed, R]

ControlClick [, Control-or-Pos, WinTitle, WinText, WhichButton, ClickCount, Options, ExcludeTitle, ExcludeText]
ControlMove, Control, X, Y, Width, Height [, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlSend [, Control, Keys, WinTitle, WinText, ExcludeTitle, ExcludeText]
ControlSendRaw [, Control, Keys, WinTitle, WinText, ExcludeTitle, ExcludeText]

Send, Keys
SendPlay, Keys
SendEvent, Keys
SendInput, Keys
SendMode, Event|Play|Input|InputThenPlay

SetDefaultMouseSpeed, Speed
SetMouseDelay, Delay
SetControlDelay, Delay
SetWinDelay, Delay
SetKeyDelay [, Delay, PressDuration]
SetStoreCapslockMode, On|Off
SetTitleMatchMode, Fast|Slow|RegEx|1|2|3
DetectHiddenText, On|Off
DetectHiddenWindows, On|Off
CoordMode, ToolTip|Pixel|Mouse [, Screen|Relative]
SetWorkingDir, DirName
BlockInput, On|Off|Send|Mouse|SendAndMouse|Default|MouseMove|MouseMoveOff

SetCapsLockState, On|Off|AlwaysOn|AlwaysOff
SetNumLockState, On|Off|AlwaysOn|AlwaysOff
SetScrollLockState, On|Off|AlwaysOn|AlwaysOff

WinActivate [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinActivateBottom [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinClose [, WinTitle, WinText, SecondsToWait, ExcludeTitle, ExcludeText]
WinKill [, WinTitle, WinText, SecondsToWait, ExcludeTitle, ExcludeText]
WinHide [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinShow [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinMaximize [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinMinimize [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinRestore [, WinTitle, WinText, ExcludeTitle, ExcludeText]
WinMove, WinTitle, WinText, X, Y [, Width, Height, ExcludeTitle, ExcludeText]
WinMinimizeAll / WinMinimizeAllUndo
WinMenuSelectItem, WinTitle, WinText, Menu [, SubMenu1, SubMenu2, SubMenu3, SubMenu4, SubMenu5, SubMenu6, ExcludeTitle, ExcludeText]
-> If arrays are suppoted, maybe have WinMenuSelectItem accept them vs. a list of parameters. But cumbersome to create an array first? Not as much if the following "anonymous" array method would be supported: "WinMenuSelectItem, WinTitle, Text, array("xxx", "yyy")

GroupActivate, GroupName [, R]
GroupAdd, GroupName, WinTitle [, WinText, Label, ExcludeTitle, ExcludeText]
GroupClose, GroupName [, A|R]
GroupDeactivate, GroupName [, R]


Remaining #Directives That Will Still Exist

#ClipboardTimeout milliseconds

#HotkeyInterval Value
#HotkeyModifierTimeout milliseconds
#MaxHotkeysPerInterval Value
#MaxThreads Value
#MaxThreadsBuffer On|Off
#MaxThreadsPerHotkey Value

#Hotstring NewOptions
#IfWinActive / #IfWinNotActive [, WinTitle, WinText]
#IfWinExist / #IfWinNotExist [, WinTitle, WinText]

#Include FileName
#IncludeAgain FileName

#UseHook [On|Off]

#KeyHistory MaxEvents
#LTrim On|Off
#SingleInstance [force|ignore|off]

Show-Warnings, Must-Declare, and Other Syntax Checking

One of the major themes of v2 is to make users more productive. In keeping with this, better syntax checking seems justified, especially since it might break existing scripts in the sense that some of them would otherwise start showing warning dialogs upon startup if this feature were added to v1 (or added after v2). The directive might be called something like #ShowWarnings, and it will probably be enabled by default. Its primary goal is to catch misspelled variable names by alerting users when a variable is read but never written, or vice versa. This would be detected before the script begins running, if possible.

A #MustDeclare directive has also been proposed, which is of special benefit for large scripts. Although this directive would overlap fairly heavily with #ShowWarnings, it might have enough new functionality to be worthwhile. But if implemented, some way of declaring global variables would need to be introduced, perhaps by allowing the global keyword to be used outside of functions. However, it might be best to reserve "global" for use in declaring "super globals", which are visible to all functions. So maybe the generic declaration keyword can be "declare" or "var".

Lazslo: Hopefully, [declared vars] will not interfere with StringSplit or other dynamic variable creation (they just change the value of already statically declared array variables).
-> Good point. I'll have to make sure that doesn't happen because there seems to be a risk of it.

Other Changes

#NoEnv: This behavior will be mandatory because it improves the reliability and performance of scripts. Therefore, #NoEnv will be eliminated since it no longer serves a purpose.

InputVars: Possibly get rid of the concept of an InputVar by allowing percent signs around such variables:

Loop, Parse, InputVar
Loop, Parse, %InputVar%

(However, obvious arrays such as Array%i% should still be recognized.) Although this would break some existing scripts and reduce flexibility, it might be worth it because Input Variables have been cited as a source of confusion by me and others because they deviate in counterintuitive, seemingly haphazard ways from the practice of enclosing vars in percent signs.

Laszlo: InputVars: E.g. in <Loop, Parse, InputVar> it was more logical to allow any expression in place of InputVar. A variable is still valid, but we could have literal strings in quotes, too. <Loop, Parse, %InputVar%> would mean a 2-level dereference, which is rarely used.

Treating blanks as zeroes in math: Decide whether to treat blank variables/sub-expressions as zero in math operations. Other weakly-typed languages seem to think this is a good idea, but there's considerable doubt about cost/benefit. Related topic:

New operators: There's some interest/justification in creating some new operators such as the "like" keyword, which matches a pattern (possibly RegEx). This kind of thing seems like a big benefit in improving the readability and flexibility of expressions.

Characters to be made illegal in variable names: It seems best to outlaw question marks since they're now used for the ternary operator. In addition, it might be best to outlaw the square brackets so that they can be reserved for true arrays (probably to be implemented sometime after v2). Furthermore, there might be other characters that should be outlawed for purity reasons, such as all the high ANSI characters (those above chr(127)).

Auto-concat: It might be best to eliminate automatic concatenation such as x:=y z because that feature reduces error detection and creates ambiguous situations.

Command-line parameters: It seems best to get rid of the %0%, %1% concept and replace it with some built-in variables or a built-in function.

BGR vs. RGB colors: It seems best to switch all color commands (such PixelGetColor) over to RGB mode. The old BGR mode would be entirely eliminated to simplify the documentation.

Sending keystrokes and mouse clicks: It seems best to switch over to SendInput as the default sending mode, due to its superior speed and reliability. Also, the default settings of KeyDelay and MouseDelay (and others) should be reviewed for possible revisions.

SetTitleMatchMode: Perhaps the default mode should become mode 2 rather than 1, since I suspect more people use 2.

Method of Release

There are at least two ways to go about releasing version 2:

1) Gradually, by means of a #v2 directive that v1 scripts can begin using to make their scripts compliant. This would allow a year or two for users to gradually make the transition.

2) Suddenly, with a possible alpha-test period during the development (to gain feedback and ideas).

The original plan was to go with option #1. However, it would be more costly in development time because there would basically be a hybrid version in between v1 and v2 that would support both versions. In addition, it would greatly complicate the documentation during the transition period. Therefore, option #2 is looking like a much better choice.

Whether to Introduce a New File Extension (.ah2 vs. .ahk)

Creating a new file extension such as .ah2 or .ahk2 seems desirable if v2 will have a fairly long alpha/beta-test period. This is because it allows users to easily run v2 scripts without giving up their v1 scripts. In the long run, it also allows v1 and v2 to be kept installed in parallel in case users have old scripts they don't want to convert.

Although creating a new file extension has many drawbacks and will lead to confusion, it may be justified if v2 scripts will generally be incompatible with v1 (and vice versa). For example, scripts might misbehave if accidentally run with the wrong version of AutoHotkey (probably rare, but still a concern).