I know GetAsyncKeyState() is a function used often in hacks, for navigating menus, detecting key presses in the case of nonmenu hacks and so on, but the fact is a lot of people do not fully understand how it works. So today I will be briefly explaining exactly what GetAsyncKeyState() does and how to use it properly.
Definition: GetAsyncKeyState is a function that returns a SHORT value (on 32bit processors that is a 2 value, half the size of a normal int). The SHORT value will be non-zero (positive) if the key specified is pressed down at the instant the functions is called.
Example:
Code:
GetAsyncKeyState(VK_INSERT);
if the key is pressed down at the exact instant that this function is called the function will return a positive value. Due to automatic type conversion any positive value of any data type when put into an if() statement will return true.
Use in Loops:
Now the function seems simple enough, but this is where a lot of people fail. When used in loops you have to be careful about your timing. The CPU loops through you code 1000's of times per second! Now when a human presses a key on his/her keyboard the program can test that key hundreds of even thousands of times before the human can remove his finger from the button o_O.
Example of bad use:
Code:
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
int i = 0;
while(1) //infinite loop!
{
if(GetAsyncKeyState(VK_DOWN))
{
i--;
cout<<"Selected: " << i <<endl;
}
if(GetAsyncKeyState(VK_UP))
{
i++;
cout<<"Selected: " << i <<endl;
}
}
return 0;
}
I have this code in a infinite loop, but the loop has no controls to slow down the speed of the loop so it could repeat thousands of times before your even humanly able to remove ur finger from the keyboard.
Example of Good Use:
The important thing that makes the difference between a good loop and a bad loop is timing.
This function: Sleep(int timeInMilliseconds); makes a huge difference.
if will slow the speed ur loop repeats to a reasonable human speed, so ur user is actually able to remove their finger before subsequent iterations.
Now a second = 1000 milliseconds so a good amount of time for your program to sleep might be 100 milliseconds or Sleep(100);
Code:
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
int i = 0;
while(1){ //infinite loop!
if(GetAsyncKeyState(VK_DOWN))
{
i--;
cout<<"Selected: " << i <<endl;
}
if(GetAsyncKeyState(VK_UP))
{
i++;
cout<<"Selected: " << i <<endl;
}
Sleep(100); // loop will only start again after 1/10 of a second
}
return 0;
}
See and just like that problem solved. You can compile both of these codes and test to see the difference.
Using GetAsyncKeyState to set values
Usually this the value being set are boolean values. quite a few people think. "Oh well because its just on or off I do not neeed to time the loop. Well this is wrong. Boolean expressions like this are especially troublesome in trainers made by novice or even experience gamehackers:
Example of bad technique:
Code:
#include <iostream>
#include <windows.h>
using namespace std;
void runHack()
{
cout << "Running hack." <<endl;
return;
}
int main()
{
int i = 0;
bool hack = false;
while(1){
if(GetAsyncKeyState(VK_DELETE))
{
if(hack)hack = false; // if true set to false
else hack = true; //if false set to true
cout<<"Hack set to: " << hack <<endl;
}
if(hack) runHack(); //will run if hack is turned on!
else cout<<"Hack is turned off!" <<endl;
}
return 0;
}
Notice there is no sleep time in the above hack! This means that the program could iterate a 100 times before you lift ur finger off the keyboard. Your just as likely to turn off as you are to turn it back on. When you create a hack you don't want to leave ur user with a 50:50 chance like this, plus ur loop is eating up much more CPU time then it needs!
The Right way to set bools
Code:
#include <iostream>
#include <windows.h>
using namespace std;
void runHack()
{
cout << "Running hack." <<endl;
return;
}
int main()
{
int i = 0;
bool hack = false;
while(1){
if(GetAsyncKeyState(VK_DELETE))
{
if(hack)hack = false; // if true set to false
else hack = true; //if false set to true
cout<<"Hack set to: " << hack <<endl;
}
if(hack) runHack(); //will run if hack is turned on!
else cout<<"Hack is turned off!" <<endl;
Sleep(200);
}
return 0;
}
A lot of people for some reason thing that booleans should iterate quicker or that the best hacks have faster clock cycles. This simply not true. The best hacks actually have lower clock cycles, eat up less CPU time and therefore run smoother! Notice I even set the Sleep to 100 here, because it is a boolean expression it needs less monitoring. It only needs to be set to on or off. You could even set it to Sleep(500) with little difference to the user.
Now before I continue on I want to touch on bools a little bit more. A common error I see is poor logic control.
Example of bad logic:
Code:
if(GetAsyncKeyState(VK_DELETE))
{
hack = true; //just sets to true!
cout<<"Hack set to: " << hack <<endl;
}
THis is terrible logic! How is the user supposed to turn the hack off hmmm? o_O
More bad logic:
Code:
if(GetAsyncKeyState(VK_DELETE))
{
if(hack)hack = true; //just sets to true!
cout<<"Hack set to: " << hack <<endl;
}
this says if hack is true then set hack to true... it was a nice attempt, but again fails
Good logic:
Code:
if(GetAsyncKeyState(VK_DELETE))
{
if(hack)hack = false; // if true set to false
else hack = true; //if false set to true
cout<<"Hack set to: " << hack <<endl;
}
finally that's how you do it. This way the bool's value is changed everytime the Del key is pressed!
Pro logic:
Code:
bool bMyVal = false;
if(GetAsyncKeyState(VK_KEYHERE))
bMyVal = !bMyVal; // toggle :)
2 lines of code and does everything you need. Thx HD...
OK. Final chapter
This is the part that many people get confused on. Im sure all of you have seen this at one time or another:
Code:
if(GetAsyncKeyState(VK_DELETE)&0x8000) //tests the most significant bit (msb)
Let me just start by saying for the most part people do this because they don't understand how GetAsyncKeyState works. Let's check MSDN:
Originally Posted by
MSDN
Return Value
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior; for more information, see the Remarks.
Okay a lot of newbies read this and are like "WTF this mean o_O?". And I don't blame you, without a good understanding of programming logic and binary operations this doesn't make a whole lot of sense. So lets walk through this slowly.
GetAsyncKeyState() returns a SHORT. I already touched on this in the beginning of this tutorial, but just to let it really sync in let me explain further. A SHORT value is processor specific. in other words a SHORT on a 16bit processor would be 1 byte long or a char sized value, while a SHORT on our modern 32bit computers are 16 bits or 2 bytes wide. And on the newer 64 bit computers it will be 32 bits wide and so on. The important thing to remember is that it is half the size of an integer always. Now I will use the a 32bit example in this tutorial because at the time of writing this most computers use 32bit processors.
The return value:
The short will have its Most significant bit set if the key is down at the instant the function is called. Now just remember that, because that is all you need to know. if you don't know anything about bits don't worry! All of this is unnecessary. All Im doing is explaining why it is unnecessary
(in fact feel free to end the tutorial here if ur satisfied)
The least significant bit:
"and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior; for more information, see the Remarks."
Pay special attention to that last sentence because here is why. In the days of DOS, programs ran one at a time all in order. In other words windows gave all programs full access to its CPU and if one program wanted to take a particularly long time running and not give up control of the CPU it could. However with modern operating systems Windows only gives programs a set amount of time to run, then it interrupts their process and share the CPU with other programs so that one can't hog all the fun.
With this also came the process of multithreading, now you don't need to know what this is though by all means look it up if you want, but just understand that multithreading creates parallelism which speeds up the execution of code in multiprocessor systems.
What this means is code that was written like this:
Code:
if(GetAsynKeyState(VK_INSERT)); //first
if(GetAsynKeyState(VK_DELETE)&1); //second
can execute like this
Code:
if(GetAsynKeyState(VK_INSERT)); //first
if(GetAsynKeyState(VK_DELETE)&1); //same time
So while this testing the least significant bit thing was okay for 16 bit DOS. It is not okay for modern multithreaded system. Now given it isn't exactly like that. This is more psuedo code thin anything, when ur accessing API functions this could very well be the case, and it is only still there for backwards compatibility.
Removing the least significant bit from the equation means that only the most significant bit is left. And since this:
Code:
if(GetAsynKeyState(VK_INSERT)&0x8000)
Does the same thing as this:
Code:
if(GetAsynKeyState(VK_INSERT))
... There is no longer any need to even mess with MSB or LSB at alll and you misewell save time as well as peace of mind and do it the easy way.
Thanks for reading, why06