- If .NET 10 is not installed on your machine, you need to download and run the x64 ".NET Desktop Runtime" installer from here.
- Download and run the Keysharp installer from the Releases page.
- The install path can be optionally added to the $PATH varible, so you can run it from the command line from anywhere.
- The path entry will be removed upon uninstall.
- It also registers Keysharp.exe as the default program to open
.ksfiles. So after installing, double click any.ksfile to run it.
- The install path can be optionally added to the $PATH varible, so you can run it from the command line from anywhere.
- Download and unzip the zip file from the Releases page.
- CD to the unzipped folder.
- Run
.\Keysharp.exe yourfilename.ahk
- Download and extract the Keysharp installer tarball from the Releases page.
- Run the install.sh script with sudo:
sudo sh ./install.shwhich does the following:- Installs all necessary dependencies except .NET 10 runtime. You need to install that manually.
- Instructions for installing .NET on Linux can be found here.
- Registers Keysharp as the default program to open
.ksfiles. So after installing, double click any.ksfile to run it. - Creates a symlink at
/usr/local/bin/keysharpso you can run it from the command line from anywhere.
- Installs all necessary dependencies except .NET 10 runtime. You need to install that manually.
- Download the latest version of Visual Studio 2022.
- This should install .NET 10. If it doesn't, you need to install it manually from the link above.
- Open Keysharp.sln
- Build all (building the installer is not necessary).
- CD to bin\release\net10.0-windows
- Run
.\Keysharp.exe yourtestfile.ahk
- Install the .NET 10 SDK (not just the runtime) as described in "Installing on Linux"
- In the same parent folder as keysharp, clone the Keysharp branch of Descolada's fork of Eto; if keysharp is at
foo/keysharp, clone Eto tofoo/Etoby runninggit clone -b Keysharp https://github.com/Descolada/Eto.gitfrom withinfoo. - Run
Keysharp.Install/package-linux.sh - A build folder and a tarball of said build folder will be placed in
dist/keysharp-linux-x64anddist/keysharp-linux-x64.tar.gzrespectively. These can then be installed to your system via the steps in "Installing on Linux" above. Note that the folder and tarball are portable so both source repositories can be safely deleted.
Keysharp is a fork and improvement of the abandoned IronAHK project, which itself was a C# re-write of the C++ AutoHotkey project.
The intent is for Keysharp to run on Windows, Linux and eventually Mac. For now, only Windows is supported and partial support for Linux.
This project is in the alpha testing stage and is not yet recommended for production systems.
Some general notes about Keysharp's implementation of the AutoHotkey v2 specification:
-
The syntax is v2 style. While some remnants of V1 will work, it's unintentional and only v2 is supported.
-
The operation of Keysharp is different than AHK. While AHK is an interpreted scripting language, Keysharp actually creates a compiled .NET executable and runs it.
-
The process for reading and running a script is:
- Pass the script to Keysharp.exe which parses it and generates a Document Object Model (DOM) tree.
- The DOM compiler generates C# code for a single program.
- The C# program code is compiled into an in-memory executable.
- The executable is ran in memory as a new process.
- Optionally output the generated C# code to a .cs file for debugging purposes with the
-codeoutoption. - Optionally output the generated executable to an .exe file for running standalone in the future with the
-exeoutoption.
-
Keysharp supports files with the
.ahkextension, however installing it will not register it with that extension. Instead, it will register the other extension it supports,.ks. -
In addition to
Keysharp.exe, there is another executable that ships with the installer namedKeyview.exe. This program can be used to see the C# code that is generated from the corresponding script code.- It gives real-time feedback so you can see immediately when you have a syntax error.
- It is recommended that you use this to write code.
- The features are very primitive at the moment, and help improving it would be greatly appreciated.
Despite our best efforts to remain compatible with the AHK v2 spec, there are differences. Some of these differences are a reduction in functionality, and others are an increase. There are also slight syntax changes.
- Linux support is currently partial.
- Only X11 is supported at the moment, Wayland is not. This may change in the future when Wayland exposes more functionality to automate the desktop.
- Control commands only work on windows created by the running Keysharp process. This is because "controls" don't exist in Linux the same way they do in Windows.
- As an alternative it's recommended to use AtSpi.ks: running it directly displays AtSpiViewer which can be used to inspect windows, and it also contains methods to manipulate windows and controls similarly to Acc/UIA in Windows.
- GUI support is mostly implemented, but some controls are missing or incomplete.
- Registry functions are not supported.
- Keysharp follows the .NET memory model.
- There is no variable caching with strings vs numbers. All variables are C# objects.
- Values not stored in variables are like regular variables, only eligible to be freed once they go out of scope.
FileOpen("test.txt", "w").Write("hello") ; The temporary file object does not get deleted at the end of the line, only possibly at the end of the current scope.
+ Object destructors/finalizers are called at a random point in time, and `Collect()` should be used if they need to be invoked predictably.
+ Object destructors (`__Delete`) are implemented with C# finalizers, which are quite heavy-weight and are not automatically present for all objects. The finalizer state is determined at object creation based on whether `__Delete` is present in the prototype chain, or at the point `__Delete` is defined. If `__Delete` is defined later in the prototype chain then instance finalizers are not automatically activated; the activation can be forced manually by temporarily reassigning a different base for the instance.
+ On script exit all non-local variables are enumerated, finalizers disabled, and `__Delete` called if present. This also includes class static variables.
- AHK says about the inc/dec ++/-- operators on empty variables: "Due to backward compatibility, the operators ++ and -- treat blank variables as zero, but only when they are alone on a line".
- Keysharp breaks this and will instead create a variable, initialize it to zero, then increment it.
- For example, a file with nothing but the line
x++in it, will end with a variable named x which has the value of 1.
- Function objects behave differently in a few ways.
- The underlying function object class is named
FuncObj. This was named so, instead ofFunc, because C# already contains a built in class namedFunc.MsgBox is Funcis still supported though, as isMsgBox is FuncObj. - Function objects can be created by passing the name of the function as as a direct reference or as a string to
Func(). - This can be done by passing the name of the desired function as a direct reference or as a string, and optionally an object and a parameter count like so:
Func(functionName [, object, paramCount]).Func("functionName" [, object, paramCount]).
- Each call to these functions returns a new unique function object. For a given function, it's best to create one object and reference that throughout the script.
- For built-in functions which take a function object as a parameter, there are four ways to call them:
- The underlying function object class is named
Func1() {
}
SetTimer(Func1) ; Pass a direct reference to the function.
SetTimer("Func1") ; Pass the name of the function.
SetTimer(Func(Func1)) ; Pass a direct reference to the function as an argument to Func().
SetTimer(Func("Func1")) ; Pass the name of the function as an argument to Func().
- Error stack traces start from where the error was thrown, not where it was constructed.
StrPtr()works slightly differently because C# strings are constant.StrPtr(variable)returns a customStringBufferobject which is entangled with the original string. When this object is used with DllCall, NumPut etc, then theStringBufferis used as the pointer, and the entangled string is updated after the function call.StrPtr("literal")with a literal string will pin the string from garbage collection and return the actual address of the string. This string must not be modified, and should be freed after use withObjFree().- Instead of
StrPtrit is recommended to use aStringBufferinstance instead.
CallbackCreate()does not support theCDecl/Coption because the program will be run in 64-bit mode.- Passing string pointers to
DllCall()when passing a created callback is recommended against. See explanation above underStrPtr(). - Usage of the created callback will be inefficient, so usage of
CallbackCreate()is discouraged.
- Passing string pointers to
- Deleting a tab via
GuiCtrl.Delete()does not reassociate the controls that it contains with the next tab. Instead, they are all deleted. - The size and positioning of some GUI components will be slightly different than AHK because WinForms uses different defaults.
- There is an additional positioning option
xcandycwhich position the control relative to the container. For example inside a tabxc+10would position the control 10 pixels from the left side of the tab control. - GroupBoxes can be used as containers by calling
GuiObj.UseGroup(groupbox), and to exit the group callGuiObj.UseGroup().
- There is an additional positioning option
- The class name for statusbar/statusstrip objects created by Keysharp is "WindowsForms10.Window.8.app.0.2b89eaa_r3_ad1". However, for accessing a statusbar created by another, non .NET program, the class name is still "msctls_statusbar321".
- Using the class name with
ClassNNon .NET controls gives long, version specific names such as "WindowsForms10.Window.8.app.0.2b89eaa_r3_ad1" for a statusbar/statusstrip.- This is because a simpler class names can't be specified in code the way they can in AHK with calls to
CreatWindowEx(). - These long names may change from machine to machine, and may change for the same GUI if you edit its code.
- There is an new
NetClassNNproperty alongsideClassNN. - The class names of all GUI controls created in Keysharp are prefixed with the string "Keysharp", eg:
KeysharpButton,KeysharpEditetc... NetClassNNwill give values like 'KeysharpButton6' (note that the final digit is the same for theClassNNand theNetClassNN).- Due to the added simplicity,
NetClassNNis preferred overClassNNfor WinForms controls created with Keysharp. - This is used internally in the index operator for the Gui class, where if a control with a matching
ClassNNis not found, then controls are searched for theirNetClassNNvalues.
- This is because a simpler class names can't be specified in code the way they can in AHK with calls to
TrayTip()functions slightly differently.- Muting the sound played by the tip is not supported with the
Muteoption. The sound will be whatever the user has configured in their system settings. - The option
4to use the program's tray icon is not supported. It is always shown in the title of the tip. - The option
32to use the large version of the program's tray icon is not supported. Windows will always show the small version.
- Muting the sound played by the tip is not supported with the
Sleep()works, but usesApplication.DoEvents()internally which is not a good programming practice and can lead to hard to solve bugs.- For this reason, it's recommended that users use timers for repeated execution rather than a loop with calls to
Sleep().
- For this reason, it's recommended that users use timers for repeated execution rather than a loop with calls to
- The Optimization section of the
#HotIfdocumentation doesn't apply to Keysharp because it uses compiled code, thus the expressions are never re-evaluated. - The
#ErrorStdOutdirective will not print to the console unless piping is used. For example:.\Keysharp.exe .\test.ahk | more.\Keysharp.exe .\test.ahk | more > out.txt
- Menu items, whether shown or not, have no impact on threading.
AddStandard()detects menu items by string, instead of ID, because WinForms doesn't expose the ID.ControlMove()andControlSetPos()operate relative to their immediate parent, which may not be the main window if they are contained in a nested control.- Function objects are much slower than direct function calls due to the need to use reflection. So for repeated function calls, such as those involving math, it's best to use the functions directly.
- The
Fileobject is internally namedKeysharpFileso that it doesn't conflict withSystem.IO.File. - In
SetTimer(), the priority is not in the range -2147483648 and 2147483647, instead it is only 0-4. - If a
ComObjectwithVarTypeofVT_DISPATCHand a null pointer value is assinged a non-null pointer value, its type does not change. ThePtrmember remains available. A_LineNumberis not a reliable indicator of the line number because the preprocessor condenses the code before parsing and compiling it.ObjPtr()returns an IUnknownComValuewith the pointer wrapped in it, whereasObjPtrAddRef()returns a raw pointer.- Pointers returned by
StrPtr()must be freed by passing the value to a new function namedObjFree().StrPtr()does not return the address of the string, instead it returns the address of a copy of the bytes of the string.
Sleep()will not do any sleeping if shutdown has been initiated.- The concat-assign operator
.=is not optimized to modify the left operand inplace, meaning calling it in a loop will be very slow. If many concats are required then use aStringBufferinstead. /Debugcommand line switch is not implemented.- If a script is compiled then none of Keysharp or AutoHotkey command parameters apply.
DllCall()has the following caveats:- Use
PtrandStringBufferfor double pointer parameters such asLPTSTR*. This is recommended over the use ofStrPtr().
- Use
ImageSearch()takes an options string as a fifth parameter, rather than inserted in the string before theimageFileparameter.- A leading plus sign on numeric values, such as
+123or+0x123is not supported. It has no effect anyway, so just omit it. - AHK
unsetis implemented asnull.IsSet(x)is equivalent tox == null. - Use of the dereference syntax
%expression%inside functions is highly discouraged. This is because using it will cause every function call to construct an object which captures all local variables, and depending on the number of variables the performance loss may be significant. Gotostatements cannot use any type of variable. They must be labels known at compile time and function just like goto statements in C#.Gotostatements being called as a function likeGoto("Label")are not supported. Instead, just usegoto Label.- The
#Requiresdirective differs in the following ways:- In addition to supporting
AutoHotkey, it also supportsKeysharp. - Sub versions such as -alpha and -beta are not supported. Only the four numerical values values contained in the assembly version in the form of
0.0.0.0are supported.
- In addition to supporting
- Global variables can be accessed from anywhere by using the
Program.prefix:program.a := 123. - For any
__Enum()class method, it should have a parameter value of 2 when returningArrayorMap, since their enumerators have two fields. - RegEx uses PCRE2 engine powered by the PCRE.NET library. There are a few limitations compared to the AutoHotkey implementation:
- The following options are different:
- S: Studies the pattern to try improve its performance.
- This is not supported. All RegEx objects are internally created with the
PcreOptions.Compiledoption specified, so performance should be reasonable.
- This is not supported. All RegEx objects are internally created with the
- u: This new option disables optimizations PCRE2_NO_AUTO_POSSESS, PCRE2_NO_START_OPTIMIZE, and PCRE2_NO_DOTSTAR_ANCHOR. This option can be useful when using callouts, since these optimizations might prevent some callouts from happening.
- S: Studies the pattern to try improve its performance.
- Callouts differ in a few ways:
- The callout function cannot be a closure, it must be a top-level function
- Callouts do not set
A_EventInfo - The callout function must be a top-level function
- A named callout must be enclosed in "", '', or {}
- RegEx operator ~= returns a RegExMatchInfo, which is treated as an integer in comparison or math operations
- The following options are different:
Mapinternally uses a real hashmap, which means item access, insertions and removals are faster, which is especially true for larger datasets. To keep at least partial compatibility with AutoHotkey theMapobject is copied and sorted before enumeration, which means modifying theMapduring enumeration will not have the same effect as in AHK.- A new
HashMapclass has been added which extendsMapand does not perform sorting before enumeration.
- A new
- The spread operator
*may be used multiple times in one function call.MyFunc(arr1*, arr2*)is allowed. - Buffer has an
__Item[]indexer which can be used to read a byte at a 1-based offset. - Buffer has
ToHex(),ToBase64(), andToByteArray()methods which can be used to convert the contents to string (hex or base64), or a byte-array to for example write to a file. - A new class named
StringBufferwhich can be used for passing string memory toDllCall()which will be written to inside of the call.- There are two methods for creating a
StringBuffer:StringBuffer(str := "") => StringBuffer: Creates aStringBufferwith a string ofstrand a capacity of 256.StringBuffer(str, capacity) => StringBuffer: Creates aStringBufferwith a string ofstrand a capacity ofMax(16, capacity).
StringBufferis implicitly castable toString.
- There are two methods for creating a
sb := StringBuffer("hello")
MsgBox(sb) ; Shows "hello".
+ As an alternative to passing a `Buffer` object with type `Ptr` to a function which will allocate and place string data into the buffer, the caller can instead use a `StringBuffer` object to hold the new string.
+ This relieves the caller of having to create a `Buffer` object, then call `StrGet()` on the new string data.
+ `wsprintf()` is one such example.
; Using a Buffer:
ZeroPaddedNumber := Buffer(20)
DllCall("wsprintf", "Ptr", ZeroPaddedNumber, "Str", "%010d", "Int", 432, "Cdecl")
MsgBox(StrGet(ZeroPaddedNumber)) ; Shows "0000000432".
; Using a StringBuffer:
sb := StringBuffer()
DllCall("wsprintf", "Ptr", sb, "Str", "%010d", "Int", 432, "Cdecl")
MsgBox(sb) ; No need to use StrGet() anymore.
+ `StringBuffer` internally uses a `StringBuilder` which is how C# P/Invoke handles string pointers.
- New methods for
Array:Add(value) => Integer: Adds a single element to the array.- This should be more efficient than
Push(values*)when adding a single item because it's not variadic. It also returns the length of the array after the add completes.
- This should be more efficient than
Filter(callback: (value [, index]) => Boolean) => Array: Applies a filter to each element of the array and returns a new array consisting of all elements for whichcallbackreturned true.FindIndex(callback: (value [, index]) => Boolean, startIndex := 1) => Integer: Returns the index of the first element for whichcallbackreturned true, starting atstartIndex. Returns 0 ifcallbacknever returned true.- If
startIndexis negative, the search starts from the end of the array and moves toward the beginning.
- If
IndexOf(value, startIndex := 1) => Integer: Returns the index of the first item in the array which equals value, starting atstartIndex. Returns 0 if value is not found.- If
startIndexis negative, the search starts from the end of the array and moves toward the beginning.
- If
Join(separator := ',') => String: Joins together the string representation of all array elements, separated byseparator.MapTo(callback: (value [, index]) => Any, startIndex := 1) => Array: Maps each element of the array, starting atstartIndex, into a new array where the mapping incallbackperforms some operation.
lam := (x, i) => x * i
arr := [10, 20, 30]
arr2 := arr.MapTo(lam)
+ `Sort(callback: (a, b) => Integer) => this`: Sorts the array in place. The callback should use the usual logic of returning -1 when `a < b`, 0 when `a == b` and 1 otherwise.
-
Hyperbolic versions of the trigonometric functions:
Sinh(value) => DoubleCosh(value) => DoubleTanh(value) => Double
-
A New function
RandomSeed(Integer)to reinitialize the random number generator for the current thread with a specified numerical seed. -
New file functions:
-
FileDirName(filename) => Stringto return the full path to filename, without the actual filename or trailing directory separator character. -
FileFullPath(filename) => Stringto return the full path to filename.
-
-
New window functions:
-
WinFromPoint(x, y)to get the window at a specific screen position. -
WinMaximizeAll()to maximize all windows. -
WinGetAlwaysOnTop([winTitle, winText, excludeTitle, excludeText]) => Integerto determine whether a window will always stay on top of other windows.
-
-
Run/RunWait()can take an extra string for the argument instead of appending it to the program name string. However, the original functionality still works too.- The new signature is:
Run/RunWait(target [, workingDir, options, &outputVarPID, args]).
- The new signature is:
-
When specifying colors for GUI components, the list of supported known colors can be found here.
-
ListViewsupports a new methodDeleteCol(col) => Booleanto remove a column. The value returned indicates whether the column was found and deleted. -
New methods and properties for
Menu:-
HideItem(),ShowItem()andToggleItemVis()which can show, hide or toggle the visibility of a specific menu item. -
MenuItemName()to get the name of a menu item, rather than having to useDllCall(). -
SetForeColor()to set the fore (text) color of a menu item. -
MenuItemCountto get the number of sub items within a menu.
-
-
Picturesupports clearing the picture by setting theValueproperty to empty. -
New options for
UpDown:- These relieve the caller of having to use native Windows API calls.
-
IncrementXXXto specify an increment other than 1.MyGui.Add("UpDown", "x5 y55 vMyNud Increment10", 1)
-
Hexto show the numeric value in hexadecimal.
-
TabControlsupports a new methodSetTabIcon(tabIndex, imageIndex)to relieve the caller of having to useSendMessage(). -
TreeViewsupports a new methodGetNode(nodeIndex) => TreeNodewhich retrieves a raw winforms TreeNode object based on a passed in ID. -
Gui controls support taking a boolean
Autosize(default:false) argument in theAdd()method to allow them to optimally size themselves. -
Guihas a new property namedVisiblewhich get/set whether the window is visible or not. -
A new function
ShowDebug()to show the main window and focus the debug output tab. -
A new function
OutputDebugLine()which is the same asOutputDebug()but appends a linebreak at the end of the string. -
EnvUpdate()is retained to provide for a cross platform way to update environment variables. -
The 40 character limit for hotstring abbreviations has been removed. There is no limit to the length.
-
FileGetSize()supportsGandTfor gigabytes and terabytes. -
DateAdd()andDateDiff()support taking a value of"L"for theTimeUnitsparameter to add miLliseconds or return the elapsed time in milliseconds, respectively.- See the new accessors
A_NowMs/A_NowUTCMs.
- See the new accessors
-
New function
FormatCs()is an alternative to AHKFormat. The syntax used inFormat()is exactly that ofstring.Format()in C#, except with 1-based indexing. Traditional AHK style formatting is not supported.- Full documentation for the formatting rules can be found here.
-
SubStr()uses a default of 1 for the second parameter,startingPos, to relieve the caller of always having to specify it. -
New string functions:
-
Base64Decode(str) => Arrayto convert a Base64 string to a Buffer containing the decoded bytes. -
Base64Encode(value) => Stringto convert a byte array to a Base64 string. -
NormalizeEol(str, eol) => Stringto make all line endings in a string match the value passed in, or the default for the current environment. -
StartsWith(value, token [,comparison]) => BooleanandEndsWith(value, token [,comparison]) => Booleanto determine if the beginning or end of a string start/end with a given string. -
Join(separator, params*) => Stringto join each parameter together as a string, separated byseparator.- Pass params as
params*if it's a collection.
- Pass params as
-
-
New RegEx functions
RegExMatchCs()andRegExReplaceCs()which use the C# style regular expression syntax rather than PCRE2.-
OutputVarinRegExMatchCs()will be of typeRegExMatchInfoCs. - PCRE exceptions are not thrown when there is an error, instead C# regex exceptions are thrown.
- To learn more about C# regular expressions, see here.
- The following options are different:
-
-A: Forces the pattern to be anchored; that is, it can match only at the start of Haystack. Under most conditions, this is equivalent to explicitly anchoring the pattern by means such as
^.- -This is not supported, instead just use
^or\Ain your regex string.
- -This is not supported, instead just use
-
-C: Enables the auto-callout mode.
- -This is not supported. C# regular expressions don't support calling an event handler for each match. You must manually iterate through the matches yourself.
-
-D: Forces dollar-sign ($) to match at the very end of Haystack, even if Haystack's last item is a newline. Without this option, $ instead matches right before the final newline (if there is one). Note: This option is ignored when the
moption is present.- -This is not supported, instead just use
$. However, this will only match\n, not\r\n. To match theCR/LFcharacter combination, include\r?$in the regular expression pattern.
- -This is not supported, instead just use
-
-J: Allows duplicate named subpatterns.
- -This is not supported.
-
-S: Studies the pattern to try improve its performance.
- -This is not supported. All RegEx objects are internally created with the
RegexOptions.Compiledoption specified, so performance should be reasonable.
- -This is not supported. All RegEx objects are internally created with the
-
-U: Ungreedy.
- -This is not supported, instead use
?after:*, ?, +, and {min,max}.
- -This is not supported, instead use
-
-X: Enables PCRE features that are incompatible with Perl.
- -This is not supported because it's Perl specific.
-
`a `n `r: Causes specific characters to be recognized as newlines.- -This is not supported.
-
\Kis not supported, instead, try using(?<=abc).
-
-
-
The v1
MapmethodsMaxIndex()andMinIndex()are still supported. They are also supported forArray. -
New function
ImageCapture(x, y, width, height [, filename]) => Bitmapcan be used to return a bitmap screenshot of an area of the screen and optionally save it to file. -
Rich text boxes are supported by passing
RichEdittoGui.Add(). The same options fromEditare supported with the following caveats:-
Multilineis true by default. -
WantReturnandPasswordare not supported. -
UppercaseandLowercaseare supported, but only for key presses, not for pasting. - The
Gui.Control.Valueproperty will only get/set the displayed text of the control. To get/set the raw rich text, use the new propertyGui.Control.RichText.- Use
AltSubmitwithSubmit()to get the raw rich text. - Attempting to use
Gui.Control.RichTexton any control other thanRichEditwill throw an exception.
- Use
-
-
Loading icons from .NET DLLs is supported by passing the name of the icon resource in place of the icon number.
- To set the tray icon to the built in suspended icon:
TraySetIcon(A_KeysharpCorePath, "Keysharp_s.ico")
- To set a menu item to the same:
parentMenu.SetIcon("Menu caption", A_KeysharpCorePath, "Keysharp_s.ico")
- To set the tray icon to the built in suspended icon:
-
New clipboard functions:
-
CopyImageToClipboard(filename [,options])is supported which copies an image to the clipboard.- Uses the same arguments as
LoadPicture(). - This is a fully separate copy and does not share any handle, or perform any file locking with the original image being read.
- Uses the same arguments as
-
IsClipboardEmpty() => Booleanreturns whether the clipboard is truly empty.
-
-
When sending a string through
SendMessage()using theWM_COPYDATAmessage type, the caller is no longer responsible for creating the specialCOPYDATAstruct.- Instead, just pass
WM_COPYDATA (0x4A)as the message type and the string as thelparam, andSendMessage()will handle it internally. - Note, this will send the string as UTF-16 Unicode. If you need to send to a program which expects ASCII, then you'll need to manually create the
COPYDATAstruct.
- Instead, just pass
-
A new function
Collect()which callsGC.Collect()to force a memory collection.- This rarely ever has to be used in properly written code.
- Calling
Collect()may not always have an immediate effect. For example if an object is assigned to a variable inside a function and then the variable is assigned an empty string then callingCollect()after it will not cause the object destructor to be called. Only after the function has returned will the object be considered to have no references andCollect()starts working. - If an object destructor needs to be called immediately then it may better to call
Object.__Delete()manually.
-
In addition to using
#ClipboardTimeout, a new accessor namedA_ClipboardTimeoutcan be used at any point in the program to get or set that value. -
A compiled script can be reloaded.
- AHK does not support reloading a compiled script.
-
A new function
RunScript(code, callbackOrAsync?, name := "DynamicScript", executable?)which dynamically parses, compiles, and runs the provided code. Optionally provide the script name; whether to run it asynchronously (non-unset non-zerocallbackOrAsynccauses async run without a callback); an executable path to run the compiled assembly (defaults to the current process). IfcallbackOrAsyncis provided a function then it is called after the script has finished with theProcessInfoas the only argument. Over multiple runsRunScriptis faster than running the process manually and writing to StdIn because of assembly and compilation caching.
This function returns aProcessInfoobject encapsulating info and I/O for the process. Available properties:HasExited,ExitCode,ExitTime(YYYYMMDDHH24MISS),StdOut,StdErr,StdIn(asKeysharpFile). Available methods:Kill(). -
A_EventInfois not limited to positive values when reporting the mouse wheel scroll amount.- When scrolling up, the value will be positive, and negative when scrolling down.
-
New accessors:
-
A_AllowTimersreturns whether timers are allowed or not. It's also easier to set this value rather than callThread("NoTimers"). -
A_CommandLinereturns the command line string. This is preferred over passingGetCommandLinetoDllCall()as noted above. -
A_DefaultHotstringCaseSensitivereturns the default hotstring case sensitivity mode. -
A_DefaultHotstringConformToCasereturns the default hotstring case conformity mode. -
A_DefaultHotstringDetectWhenInsideWordreturns the default hotstring word detection mode. -
A_DefaultHotstringDoBackspacereturns the default hotstring backspacing mode. -
A_DefaultHotstringDoResetreturns the default hotstring resetting mode. -
A_DefaultHotstringEndCharRequiredreturns the default hotstring ending character mode. -
A_DefaultHotstringEndCharsreturns the default hotstring ending characters. -
A_DefaultHotstringKeyDelayreturns the default hotstring key delay length in milliseconds. -
A_DefaultHotstringNoMousereturns whether mouse clicks are prevented from resetting the hotstring recognizer because#Hotstring NoMousewas specified. -
A_DefaultHotstringOmitEndCharreturns the default hotstring ending character replacement mode. -
A_DefaultHotstringPriorityreturns the default hotstring priority. -
A_DefaultHotstringSendModereturns the default hotstring sending mode. -
A_DefaultHotstringSendRawreturns the default hotstring raw sending mode. -
A_DirSeparatorreturns the directory separator character which is\on Windows and/elsewhere. -
A_HasExitedreturns whether shutdown has been initiated. -
A_KeysharpCorePathprovides the full path to the Keysharp.Core.dll file. -
A_LoopRegValuewhich makes it easy to get a registry value when usingLoop Reg. -
A_MaxThreadsreturns the valuenspecified with#MaxThreads n. -
A_NoTrayIconreturns whether the tray icon was hidden with #NoTrayIcon. -
A_NowMs/A_NowUTCMsreturns the current local/UTC time formatted to include milliseconds like so "YYYYMMDDHH24MISS.ff".- These can be used with
DateAdd()/DateDiff()using"L"for theTimeUnitsparameter.
- These can be used with
-
A_SuspendExemptreturns whether subsequent hotkeys and hotstrings will be exmpt from suspension because#SuspendExempt truewas specified. -
A_TotalScreenHeightreturns the total height in pixels of the virtual screen. -
A_TotalScreenWidthreturns the total width in pixels of the virtual screen. -
A_UseHookreturns the valuenspecified with#UseHook n. -
A_WinActivateForcereturns whether the forceful method of activating a window is in effect because#WinActivateForcewas specified. -
A_WorkAreaHeightreturns the height of the working area of the primary screen. -
A_WorkAreaWidthreturns the width of the working area of the primary screen.
-
-
Log(number, base := 10)is by default base 10, but it can accept a double as the second parameter to specify a custom base. -
In
SetTimer():- In the callback function,
A_EventInfois set to the function object used to create the timer. - This allows the handler to alter the timer by passing the function object back to another call to
SetTimer(). - Timers are not disabled when the program menu is shown.
- In the callback function,
-
A new timer function
EnabledTimerCount()which returns the number of currently enabled timers in existence. -
Reference parameters for functions using
&are supported with the following improvements and caveats:- Passing class members, array indexes and map values by reference is supported.
func(&classobj.classprop)func(&myarray[5])func(&mymap["mykey"])
- Reference parameters in functions work for class methods, global functions, built in functions, lambdas and function objects.
- Lambdas with a single reference parameter can be declared with no parentheses:
lam := &a => a := (a * 2)
- Lambdas with a single reference parameter can be declared with no parentheses:
- When passing a class member variable as a dynamic reference to a function from within another function of that same class, the
thisprefix must be used:
- Passing class members, array indexes and map values by reference is supported.
class myclass
{
x := 11
y11 := 0
myclassreffunc(&val)
{
}
callmyclassreffunc()
{
myclassreffunc(&this.y%x%) ; Use this.
}
}
- New functions for encrypting/decrypting an object:
- Encrypt or decrypt an object using the AES algorithm:
AES(value, key, decrypt := false) => Array. - Generate hash values using various algorithms:
MD5(value) => String,SHA1(value) => String,SHA256(value) => String,SHA384(value) => String,SHA512(value) => String. - Calculate the CRC32 polynomial of an object:
CRC32(value) => Integer. - Generate a secure cryptographic random number:
SecureRandom(min, max) => Decimal.
- Encrypt or decrypt an object using the AES algorithm:
- New class and functions for managing real threads which are not related to the green threads that are used for the rest of the project.
- A
RealThreadis created by callingStartRealThread().
- A
class RealThread
{
RealThread(Task)
RealThread ContinueWith(funcobj [, params*]) => RealThread ; Call `funcobj` after the task completes, optionally passing `params` to it and return a new `RealThread` object for the continuation thread.
Wait([timeout]) ; Wait until the thread object which was passed to the constructor completes. Optionally return after a specified timeout period in milliseconds elapses.
}
+ `StartRealThread(funcobj [, params*]) => RealThread` Call `funcobj` in a real thread, optionally passing `params` to it, and return a `RealThread` object.
+ `LockRun(lockobj, funcobj [, params*])` Call `funcobj` inside of a lock on `lockobj`, optionally passing `params` to it.
+ `lockobj` must be initialized to some value, such as an empty string.
FuncObj(),IsFunc(),Any.HasProp()andObjBindMethod()take a new optional parameter which specifies the parameter count of the method to search for.- The new signatures are:
ObjBindMethod(obj [, paramCount , method, params]) => FuncObjFuncObj(name, object [, paramCount]) => FuncObjIsFunc(functionName [, paramCount]) => IntegerAny.HasProp(propName [, paramCount]) => Integer- The only properties which can have parameters are the
__Item[]indexer properties.
- The only properties which can have parameters are the
- This is needed to resolve the proper overloaded method. However, overloaded methods are currently not supported, but might be implemented in the future.
- Omit
paramCountor pass -1 to just use the first encountered method on the specified object with the specified name.
- The new signatures are:
KeysharpObjecthas a new methodOwnPropCount()which corresponds to the global functionObjOwnPropCount().ComObjConnect()takes an optional third parameter as a boolean (default:false) which specifies whether to write additional information to the debug output tab when events are received.- New function
Mail(recipients, subject, message, options)to send an email.recipients: A list of receivers of the message.subject: Subject of the message.message: Message body.options: AMapwith any the following optional key/value pairs:- "attachments": A string or
Arrayof strings of file paths to send as attachments. - "bcc": A string or
Arrayof strings of blind carbon copy recipients. - "cc": A string or
Arrayof strings of carbon copy recipients. - "from": A string of comma separated from address.
- "replyto": A string of comma separated reply address.
- "host": The SMTP client hostname and port string in the form "hostname:port".
- "header": A string of additional header information.
- "attachments": A string or
- Preprocessor directives are supported using the familiar syntax of C#.
#if symbolis used to enable a section of code if symbol is defined.- By default, the following are defined:
WINDOWSif you are running the script on Microsoft Windows.LINUXif you are running the script on linux.KEYSHARP
#elsecan be used to take an alternate path if the preceding#ifevaluates to false.#elif symbolcan be used to evaluate another symbol if the preceding#ifor#elifevaluate to false.- All preprocessor blocks must end with an
#endif - New preprocessor symbols can be defined using
#define symbol. - Logical statements can be evaluated using the operators
&&,||and!. - Evaluation of preprocessor statements are case insensitive.
- Some examples are:
#if WINDOWS
MsgBox("Windows")
#elif LINUX
MsgBox("linux")
#else
MsgBox("Unsupported OS")
#endif
#if !(WINDOWS || LINUX)
MsgBox("Unsupported OS")
#endif
#if 1
MsgBox("Always true")
#endif
#if 0
MsgBox("Always false")
#endif
#define NEW_DEFINE
#if NEW_DEFINE
MsgBox("True because of new definition")
#endif
- New preprocessor directives have been added.
#HookMutexName <name>allows renaming the mutex objects created to detect keyboard and mouse hooks in other running scripts. The default name is "Keysharp".- Assembly description attributes may be changed with the following directives (with the desired value as the only argument of the directive):
#AssemblyName#AssemblyDescription#AssemblyConfiguration#AssemblyCompany#AssemblyProduct#AssemblyCopyright#AssemblyTrademark#AssemblyVersion
- Experimental
Clrclass has been added which aims to provide CLR interop with regular AutoHotkey syntax, meaning easy access to CLR libraries.Clr.Load(asmOrPath)loads a CLR assembly from a dll file or assembly name, and returns aManagedAssemblyorManagedNamespaceobject. Example:System := Clr.Load("System")ManagedNamespacecan be accessed with property access syntax to get namespaces and types (ManagedType). Example:linq := System.Linq.EnumerableManagedTypemay be accessed for static methods/properties, or called to create a newManagedInstance.ManagedInstancemay be accessed with normal AutoHotkey syntax for properties, methods, and indexer access. Example:linq.Where(nums, isOdd)- Basic type marshalling between AutoHotkey and CLR is supported (including function objects), more complicated types may not currently work.
Clr.GetNamespaceName(ManagedNamespace)returns the full intenal namespace name of the namespace wrapped byManagedNamespace.Clr.GetTypeName(ManagedType)returns the full internal type name of the type wrapped byManagedType.
- Command line switches may start with either
/(Windows-only),-or--. - Command line switches
--script
Causes a compiled script to ignore its main code and instead executes the provided script. For this to apply,--scriptmust be the first command line argument.
Example:CompiledScript.exe /script /ErrorStdOut MyScript.ahk "Script's arg 1"--version,-v
Displays Keysharp version.--codeout
In addition to running the script, Keysharp outputs a .cs file with the same name as the script containing the code which was used to compile. This is the same code displayed in Keyview.--exeout
In addition to running the script, Keysharp outputs a .exe file which can be ran as standalone from Keysharp (but still requires .NET 9).--minimalexeout
Same as--exeoutbut the number of file dependencies is reduced by embedding them in Scriptname.dll. The resulting program will have five dependencies: Scriptname.exe, Scriptname.dll, Keysharp.Core.dll, Scriptname.deps.json, and Scriptname.runtime.config. To get a truly single-file executable the script must be compiled as a C# project, for example as Keysharp.OutputTest in the Keysharp solution.--validate
Compiles but does not run the script. Can be used to check for load-time errors.--assembly [Type Method]
Reads pre-compiled assembly code from the file or StdIn and runs it. Optionally also provide the entrypoint type and method, but if omitted then the default typeKeysharp.CompiledMain.programand methodMainare used.
ListLines()is non-functional because C# doesn't support it.- The
R,DnorTnparameters inFormatTime()are not supported, except for 0x80000000 to disallow user overrides.- If you want to specify a particular format or order, do it in the format argument. There is no need or reason to have one argument alter the other.
- Here is a list of the C# style DateTime formatters which are supported.
- Static text controls do not send the Windows
API WM_CTLCOLORSTATIC (0x0138)message to their parent controls like they do in AHK. - Double click handlers for buttons are not supported.
- UpDown controls with paired buddy controls are not supported. Keysharp just uses the regular NumericUpDown control in C#.
- The options
16,HorzandWraphave no effect. - The min and max values cannot be swapped.
- The options
IL_Create()only takes one parameter:largeIcons.initialCountandgrowCountare no longer needed because memory is handled internally.LoadPicture()does not accept aGDI+argument as an option.- For slider events, the second parameter passed to the event handler will always be
0because it's not possible to retrieve the method by which the slider was moved in C#. PixelGetColor()ignores themodeparameter.DirSelect():- The
1,3and5options don't apply and the New Folder button will always be shown. - Modality cannot be configured with
Gui.Opt("+OwnDialogs")because the folder select dialog is always modal. - Restricting folder navigation is not supported.
- The
MsgBox():- The modality options are ignored.
- The message box will block the window that launched it by default. If
+OwnDialogsis in effect, then all GUIs in the script are blocked until it is dismissed. - System modal dialog boxes are no longer supported on Windows.
- The help option
16384is ignored.
- Only
Tab3is supported, no older tab functionality is present. - When adding a
ListView, theCountoption is not supported because C# can't preallocate memory for aListView. - The address of a variable cannot be taken using the reference operator.
- It returns a VarRef object as in AHK.
OnMessage()doesn't observe any of the behavior mentioned in the documentation regarding the message check interval because it's implemented in a different way.- A GUI object is required for
OnMessage()to be used.
- A GUI object is required for
- Pausing a script is not supported because a Keysharp script is actually a running program.
- The pause menu item and
Pause()function have been removed.
- The pause menu item and
ObjAddRef()andObjPtrAddRef()do not have an effect for non-COM objects. Instead, use the following:newref := theobj ; adds 1 to the reference countnewref := "" ; subtracts 1 from the reference count
#Warnto enable/disable compiler warnings is not supported yet.- The
/scriptoption for compiled scripts does not apply and is therefore not implemented. - The Help and Window Spy menu items are not implemented yet.
Download()only supports the*0option, and not any other numerical values.- When passing
"Interrupt"as the first argument toThread(), the third argument forLineCountis not supported because Keysharp does not support line level awareness. - Tooltips do not automatically disappear when clicking on them.
- The initial IronAHK developers 2010 - 2015
- Logical string comparison, cddl 1.0
- Cross platform INI file processor
- P/Invoke calls
- Tuple splatter
- Semver version parsing
- PictureBox derivation
- Using SendMessage() with string
- Program icon is a derivative of work by Bamicon
- NAudio
- Scintilla editor for .NET
- Scintilla setup code in Keyview
- Various posts on Stack Overflow
Please make an account here and post a ticket.