Note for new readers: If you’re new to AutoHotkey, you may want to check out this Introduction to AutoHotkey: A Review and Guide for Beginners.
* * *
Hi Jack, I would like to ask you to teach us some advanced autohotkey topic, like API calls. It would be very appreciated by us all.
* * *
Thanks for the question. Using Windows API calls in AutoHotkey is certainly an advanced topic which deserves some attention. Through the use of these functions much of the power of Windows can be accessed directly. The problem is that figuring out how to use them can be pretty cryptic—and I’m certainly no expert.
I’ve used the Windows API (Application Program Interface) tools in a number of AutoHotkey scripts, but I usually find the code at another location and change the pertinent parts. I’ve found that this technique is pretty effective—especially for novice script writers. However, it may be time for me to dig a little deeper. With this blog I will start this journey into the unknown.
The First Steps on a Journey of Exploration
My usual approach to any topic is to create (or find) useful applications and highlight them. This helps both the reader (and myself) to understand the workings of a script. I plan to approach Windows API calls in AutoHotkey in the same manner. I will not be able to immediately give a complete tutorial since I find a great deal of the topic mystifying. I’ve read some of the online introductions and must admit that while it seems to make sense, a great deal of the terminology is new to me. That means I will need to develop a clear understanding of the inner workings of the system’s bits and pieces before I can pass much along. This will take some time. In the meantime, I will look for examples which can provide immediate results—even if we don’t truly understand what’s going on. I will chronicle the journey in this blog (occasionally taking a side trip or two on the way). I can only clarify those aspects of API calls which are clear to me leaving many questions unanswered until a later time. I suspect that I will experience a few “Aha!” moments along the way, but it’s impossible to predict when they will occur. In the meantime, we will compile a bunch of useful little AutoHotkey apps.
This is what happened when I traveled the road which culminated in A Beginner’s Guide to Using Regular Expressions with AutoHotkey. You could say that the book was written inside out. I started working with AutoHotkey scripts which used the RegEX functions while I was still in the haze of partial understanding. About halfway through, I had a couple of epiphanies about how to properly understand and use those specialized functions. I started to see how the book should come together—writing the beginning parts last.
Slowing Down Mouse Cursor Movement
The first example is a simple trick for temporarily slowing down the mouse cursor. While many people may never need this app, people who engage in detailed graphic work may find it useful. The problems is that when trying to land the mouse cursor on a specific pixel, the speed setting may be too fast causing the cursor to jump past the mark. But what if there was a key that you could press which would temporarily slowdown the cursor—thus allowing exact pixel placement? That is the purpose of the following example which was taken from the online documentation for the AutoHotkey function DLLCall():
; Example: This is a hotkey that temporarily reduces the mouse cursor's speed, which facilitates precise positioning. ; Hold down the F1 key to slow down the cursor. Release it to return to original speed. F1:: SPI_GETMOUSESPEED = 0x70 SPI_SETMOUSESPEED = 0x71 ; Retrieve the current speed so that it can be restored later: DllCall("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0) ; Now set the mouse to the slower speed specified in the next-to-last parameter (the range is 1-20, 10 is default): DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, Ptr, 3, UInt, 0) KeyWait F1 ; This prevents keyboard auto-repeat from doing the DllCall repeatedly. return F1 up::DllCall("SystemParametersInfo", UInt, 0x71, UInt, 0, Ptr, OrigMouseSpeed, UInt, 0) ; Restore the original speed.
You can quickly cut-and-paste this script into a text file with the AHK extension (i.e. MouseSlow.ahk) and run it to test this simple app.
The AutoHotkey DllCall() Function
Many of the internal features of Windows are stored in systems files. Some of the most important files are the DLLs (files with .dll extensions) containing the functions which read and alter various settings. If you know the right function, then you can change the setting directly with AutoHotkey.
The AutoHotkey DllCall() function “calls a function inside a DLL, such as a standard Windows API function.” DLL (Dynamic-Link Library) files are utility library files containing “code, data, and resources, in any combination.” There are Windows system DLL files (our primary interest) and other DLL files associated with other programs. The AutoHotkey DllCall() function can be used to either access Windows system functions (by default) or any other named DLL file. There are literally hundreds of functions included in the Windows API. I usually scan the possible options in the documentation, but reviewing the Microsoft pages quickly became overwhelming without adding much clarity. For now, it’s better to concentrate on specific examples. I’ll use a reverse engineering approach and parse the uses of DllCall() in the code above—the first of which is:
DllCall(“SystemParametersInfo”, UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
The first parameter in the DllCall() function is always the filename/function name. If there is no filename, then it is assumed to be a function located in one of the system files—as is the case here (SystemParametersInfo). SystemParametersInfo is automatically accessed using specific parameters in pairs. The first parameter of the pair designates the type of the second parameter in the pair, such as a string, integer, floating decimal, etc. The second parameter is the value sent to the function. The number of pairs depends upon the definition of the function. In this case, there are four pairs, only two of which we will need or attempt to understand. One of the most common errors I’ve seen noted is not using the proper variable type with the second parameter.
The first pair is UInt, SPI_GETMOUSESPEED. UInt is the type for SPI_GETMOUSESPEED. As far as I can tell, all Int means is that the next parameter value will be an integer. Here it describes the action of recording the current setting for mouse speed. The preceding U merely means it is unsigned, but that seems to rarely make a difference. (To tell the truth, I don’t yet know the importance of the difference between unsigned UInt and signed Int variables.) In any case, the value of SPI_GETMOUSESPEED is an integer with the hexadecimal value of 0x70 (assigned by SPI_GETMOUSESPEED = 0x70 in the line of code above).
I’m not sure whether the name SPI_GETMOUSESPEED is anything more than a way of describing the function setting accessed by the associated integer. If you look it up in the SystemParametersInfo page, it gives you the hexadecimal number to call it and how it works, but other than as a reference, the name is not needed to make the script work. For example, you can directly use the integer in the DllCall() function and get the same result:
DllCall(“SystemParametersInfo”, UInt, 0x70, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
In fact, the decimal equivalent (0x70 converts to 112 decimal) also gives the same result:
DllCall(“SystemParametersInfo”, UInt, 112, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
What’s important is that this first parameter pair of the SystemParametersInfo function tells the function which Windows setting to access. The current setting of the mouse speed is called with the integer in hex (0x70) or its decimal equivalent (112) so we can later reset it back to that same value. It can either be a variable which contains the correct integer (SPI_GETMOUSESPEED) or the integer itself.
While the SystemParametersInfo function designates four pairs of parameters, often only two pairs are used—as in this example. It is more important to know the position of the parameter than the name. The other pairs are often set to zero. In the case of SPI_GETMOUSESPEED the third pair sets up the variable for saving the value of the mouse speed (UIntP, OrigMouseSpeed). I don’t fully comprehend the type UIntP used here, but suffice it to say the current value will be an integer and saved in the variable OrigMouseSpeed.
Slowing Down the Mouse Cursor Speed
The next use of the DllCall() function accesses the SystemParametersInfo Windows function setting for changing the mouse speed (SPI_SETMOUSESPEED):
DllCall(“SystemParametersInfo”, UInt, SPI_SETMOUSESPEED, UInt, 0, Ptr, 3, UInt, 0)
Other than the system parameter SPI_SETMOUSESPEED equaling 0x71 (or 113 in decimal), the primary difference here is that the third pair of parameters sets the new mouse speed to a slow 3. (I studied the Ptr type for a while, but never settled into understanding it. It may have something to do with the fact that we are designating a new value. For now, we just need to know that it works.)
If for some reason you wanted to speed up the mouse rather than slow it down, then change the value 3 to something higher such as 18. (The range is 1 to 20.)
Restoring the Original Value
Upon releasing the F1 key (F1 up), the mouse speed is returned to its original value (OrigMouseSpeed):
F1 up::DllCall(“SystemParametersInfo”, UInt, 0x71, UInt, 0, Ptr, OrigMouseSpeed, UInt, 0)
Notice that this time the example did not bother to use the variable SPI_SETMOUSESPEED and directly inserted the hex equivalent (0x71).
While there is still a good deal of mystery surrounding these type of DllCall() functions, I now know how to change the mouse cursor speed on the fly. The SystemParametersInfo function “is intended for use with applications that allow the user to customize the environment.” I looked over the other available settings on the Microsoft page, but was not immediately inspired for more possible applications. In fact, the only example at the end of the Microsoft page was one that changed the same mouse speed. That doesn’t mean we won’t find many more practical uses for the SystemParametersInfo function. I just don’t know what they are yet.
This is merely the first step in a long journey, so I don’t expect to get it all at once. More to the point, I’m coming to realized that we may find many examples of API calls which—even though we don’t completely understand them—we can use them in our AutoHotkey applications. What’s important is to know which parameters to change in the functions and which to leave untouched.