-=[ INTRO ]=-
UC-FORUM ONLY RELEASE
(Please do not post this tutorial on ANY other website. You may link to it, but not post it elsewhere)
Hey all! Had this console finished now for a while but never got around to releasing it – I still don’t think I will, I simply don’t have the time. Anyway, I’ve decided to make a tutorial from it so hopefully it can help someone out there!
This is my first DirectX/C++ tutorial so go easy on me
Before we start I’d like to get the greetz in:
- AlexAk92
- SEGnosis
- Kiwidog (First DirectX-Hooking source I could actually understand)
And since there is a portion from the QTS, thanks to:
This tutorial assumes you already know the basics of C++ and DirectX, so I won’t cover these (hooking, drawing, etc). It’s written in a “step-by-step” form, which will hopefully be easier to learn from – though it will be long.
This is what the finished product will (hopefully) look like for you:
Some things are optional – they are geared towards coding an ingame console for Modern Warfare 2. They can be easily adapted for other games, or completely ignored if all you want is a textbox. I will colour these items in
red to make them stand out, and be easier to skip if you don’t need/want them.
Anyway, let’s get this started.
-=[ TUTORIAL ]=-
Firstly you’ll need to think logically about what needs to be done for a textbox. What will we need to do to create one? Here I’ve taken a screenshot of one and I’ll explain each thing we need:
Okay! So there are 3 main things that need to be done – the background, the text, and the caret. I’ll explain them in the order they should be done.
The background will be easy – we will simply draw a rectangle, and if you like you can also give it a border. We do this first as everything else will be drawn on top of it.
What is text really? The text is a variable just like any other – we’ll have to store it as such. Nothing overly complicated, just a string variable. Then we simply draw the text over the background. Easy!
The caret is a simple enough concept, but not as simple to implement fully. A caret basically shows where we will be inserting or removing text from. In this tutorial we’ll use a fixed-width font (Courier), which will make coding our caret MUCH easier. We’ll need 3 variables for this – an integer storing the caret’s position, an integer for a tick count for the caret, and a Boolean whether to show it or not (I’ll explain these later).
So in a textbox we have 3 main things to worry about – the background, the text, and the caret.
Well now that we have an idea what’s going to be done, let’s get started coding! I created this as a class so that anything can call, but you can do it however you like.
Firstly, let’s actually create the class. We’ll create a file called “console.h”, in which we’ll store it:
Code:
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#include "O_Drawing.h"
#include <string>
#include <vector>
using namespace std;
#define ADDR_CONSOLE 0x4393E0 // MW2 v1.2.208
class MW2_Console
{
public:
void Render(int x, int y, int width, LPDIRECT3DDEVICE9 pDevice);
void takeInput(WPARAM wParam);
void Init();
void Send(string cmd);
string command;
vector<string> prevCommands;
int caretPos,caretTick,cmdCount,currCmd;
bool showCaret,handled;
}Console;
#endif
Okay, so what’s actually happening here?
Firstly we include “O_Drawing.h” – this is my drawing class. It contains the functions required for drawing things. Since this tutorial assumes you know the basics of DirectX, you should already have your own. Just replace "O_Drawing.h" with your class.
Next we include “string”, and
“vector”. String contains classes and functions that make it easier to work with strings, and vector allows us to store data nicely.
Then we define “ADDR_CONSOLE”. ADDR_CONSOLE is the address in Modern Warfare 2 for the SendCommandToConsole() function. This allows us to easily change the address if required, rather than searching through the source for the function to change the address.
The last thing we do here is define the class and its functions/variables.
The Render function will draw everything – the background, the text, and the caret.
The TakeInput function will take the input from the user and input it into the string. This function should be called from a WM_CHAR message hook. See SEGnosis’ Quick Tip Series at
http://www.unknowncheats.me/forum/c-...ip-series.html to see how to hook windows messages.
The Init function will reset all the variables, making them easy to use from the get-go.
The Send() function, will send the specified command to the console. It will also split up commands written in the format “command1;command2;command3”, because these need to be sent separately to work.
Lastly we declare our variables:
- “command” is our string variable. It contains the string that’s shown in our textbox. We use a string rather than a char * or other variable due to the easy to use functions of the string class, for inserting characters, removing them, and editing them.
- “prevCommands” is a vector variable. It is a vector of string variables, which can be re-used and called later. When we send a command to the console, we add it to prevCommands, allowing the user to cycle through old commands, rather than having to type them out every time.
Next we declare a bunch of integer variables. I’ll explain each of them individually:
- caretPos stores the position of our caret. This allows us to accurately draw it, and insert/delete text at the specified position.
- caretTick is for our make-shift timer. If you have ever used a textbox, you’ll know that the caret is not always visible. It “flashes” on and off. We make our own timer for this, and caretTick is the variable used for this.
- cmdCount is used to store the count of how many commands have been sent/stored. This makes it easy to reference prevCommands without going too far (ie. Out of the size of it, which would likely cause a crash, or at least output pure gobbledygook to the user).
- currCmd is used to store what our current index in prevCommands is, so that we can show the next, or previous command sent, rather than always just the first one on the list.
And finally we have our two Booleans:
- showCaret is linked with caretTick. If showCaret is true then the caret will be drawn. Otherwise it won’t be drawn.
- Handled is a variable which decides whether input has already been handled by the DLL’s main function. If it has, then our console won’t take the input. (For example I have ESC as a key in the main function to close the console. If handled weren’t set to true, the console would also take that input and make a weird character out of it.)
Okay now that we have a class, we can start building up the functions to get this working!
For the sake of easiness I’ll just do these in the order they appear in the class definition, then at the end show how to use them all.
So, firstly we’ll create our Render function:
Code:
void MW2_Console::Render(int x, int y, int width, LPDIRECT3DDEVICE9 pDevice)
{
// Draw box with border
Draw.FullRectBordered(x,y,width,20,2,D3DCOLOR_ARGB( 155, 000, 000, 000 ),D3DCOLOR_ARGB( 255, 000, 000, 000 ),pDevice);
// Draw command
Draw.Text(x+2,y+2,D3DCOLOR_ARGB( 255, 255, 165, 0 ),">",pDevice);
Draw.Text(x+10,y+2,D3DCOLOR_ARGB( 255, 255, 255, 0 ),command.c_str(),pDevice);
caretTick+=1;
if ( caretTick >= 25)
{
caretTick=0;
showCaret=!showCaret;
}
if(showCaret)
Draw.Text(x+6+(caretPos*8),y+2,D3DCOLOR_ARGB( 255, 255, 165, 0 ),"|",pDevice);
}
Okay so let’s explain how this is done. In our EndScene function we have a call to this, if the console is supposed to be visible:
Code:
if(console)
Console.Render(10,10,Viewport.Width-20,pDevice);
So that will render our console at (10,10), with a width that is 10px from the right (so it’ll always be 10px from either side of the screen).
So what actually happens in the render function?
Firstly we draw our background – it’s simply a box with a border. The box is semitransparent, and the border is full black. Just so you know what each of the paramaters are, here’s the prototype of my FullRectBordered function:
Code:
void FullRectBordered(float x, float y, int width, int height, int borderThickness, D3DCOLOR fillColor, D3DCOLOR borderColor, LPDIRECT3DDEVICE9 pDevice);
Next, we draw our text. I draw a > character in Orange in front, just for the sake of sexiness, then draw the text in Yellow. We draw command.c_str() rather than command because my Text function takes a char * rather than a string:
Code:
void Text( int x, int y, D3DCOLOR Color, const char *str, LPDIRECT3DDEVICE9 pDevice);
The last thing we do is the caret. Here we have our makeshift timer:
Code:
caretTick+=1;
if ( caretTick >= 25)
{
caretTick=0;
showCaret=!showCaret;
}
Basically what’s done here is caretTick is increased by 1. If it is greater than or equal to 25, then it is reset to 0, and we toggle showCaret. I’ve found 25 looks fairly good, but you can change it around for longer or shorter intervals if you wish – or even remove it altogether to have an always-visible caret.
Then we have
Code:
if(showCaret)
Draw.Text(x+6+(caretPos*8),y+2,D3DCOLOR_ARGB( 255, 255, 165, 0 ),"|",pDevice);
This checks is showCaret is true. If it is, then we draw it. The font we are using for all of this is Courier, at 14pt.
For the “x” position of our caret, we have x+6+(caretPos*8). Why?
Well we add 6 to the rendering x position due to the sexy > character which is drawn first, then caretPos*8. We multiply caretPos by 8, because (from my calculations), Courier @ 14pt has characters of width about 8px. So the 2nd character of the string would be 16px in, for example.
Next we take our input:
Code:
void MW2_Console::takeInput(WPARAM wParam)
{
if(handled)
{
handled=false;
return;
}
switch(wParam)
{
case '\b': // backspace
{
if(caretPos>0)
{
command.erase(caretPos-1,1);
caretPos-=1;
}
}
break;
case '\r': // return/enter
{
prevCommands.push_back(command);
Send(command);
command="";
caretPos=0;
cmdCount=prevCommands.size();
currCmd=cmdCount;
}
break;
case '\t': // tab
{
if(cmdCount>0)
{
if(currCmd>0)
{
currCmd-=1;
command=prevCommands.at(currCmd);
caretPos=command.length();
}
else
{
currCmd=cmdCount-1;
command=prevCommands.at(currCmd);
caretPos=command.length();
}
}
}
break;
default:
command.insert(caretPos,1,(char)wParam);
caretPos+=1;
break;
} // switch(wParam)
}
Okay this function is much larger than the last and may seem a bit complicated, but it’s simple enough logic once you go through it step by step.
Firstly we check if input has already been handled (See my ESC example in the variable explanations). If it has, then we return, skipping the rest of the function. Otherwise, we continue.
Our first check in the switch is for the character ‘\b’. This character is what is received after the user presses a backspace, so we remove a character.
Code:
if(caretPos>0)
{
command.erase(caretPos-1,1);
caretPos-=1;
}
This is where our nice string functions start to come into play. Firstly we check that caretPos is greater than 0. If it were 0 there would be nothing to delete before the caret!
If it is greater than 0, there will be a character to remove, so we remove it. We erase the character just before caretPos, with a “length” of 1. This means we only delete 1 character. When you backspace, your caret will obviously move back too, so we put the caretPos back 1.
Next we check for ‘\r’. This character is received when the user presses enter/return. Firstly we save the command to our vector prevCommands, allowing it to be called again in the future if you wish. It then calls the Send() function, which will split it up if required, then send to MW2’s console. Then, we reset our variables to their required values – command is emptied, caretPos is reset to 0, cmdCount is set to the size of prevCommands, as is currCmd.
Our next check is ‘\t’, which is what is sent when the user presses the Tab key.
Code:
if(cmdCount>0)
{
if(currCmd>0)
{
currCmd-=1;
command=prevCommands.at(currCmd);
caretPos=command.length();
}
else
{
currCmd=cmdCount-1;
command=prevCommands.at(currCmd);
caretPos=command.length();
}
}
Firstly we check the cmdCount is greater than 0, ie. There is a stored command to go to. If there is we check what currCmd is. If it’s greater than 0, then we take 1 from it, showing an older command. If however it’s 0 or less than 0, we reset it back to the newest command that was stored, a kind of “wrap around”.
Don’t forget of course to set the new caretPos!
Finally we have our default case. This is called when the sent character has not already been handled, is not return or tab or any other key that is used by other parts of the hack – ie. It is in fact text input!
Code:
default:
command.insert(caretPos,1,(char)wParam);
caretPos+=1;
break;
We insert the character at the position of the caret, and increase the caret position. Don’t forget to use (char)wParam, as this actually converts it to a character properly.
Now back to something quick and easy – the init function:
Code:
void MW2_Console::Init()
{
command="";
caretPos=0;
cmdCount=0;
currCmd=0;
}
This one is pretty basic – all it does is reset all the required variables.
Next, our Send() function:
Code:
// SendCommandToConsole(1,1,"Command");
void (__cdecl *SendCommandToConsole)(int a1,int a2,const char *cvar)=(void (__cdecl *)(int,int,const char *))ADDR_CONSOLE;
void MW2_Console::Send(string cmd)
{
size_t scPos,len; // scPos = semicolon position. Len = length of cmd.
char tmp[50]; // temporary char array for splitting multiple commands
string cmdToSend; // The command to be sent. Used for splitting multiple commands
int i=0;
do
{
cmd.begin();
scPos=cmd.find(';');
if (scPos!=string::npos) // There was an ;. More than one command.
{
len=cmd.copy(tmp,int(scPos),0); // Copy the first command to tmp
tmp[len]='\0'; // End tmp "string"
cmdToSend=tmp; // Assign tmp as the command to be sent
cmdToSend+='\n';
SendCommandToConsole(1,1,cmdToSend.c_str());
cmd.erase(0,int(scPos)+1); // Erase the just-sent command, and the ;
}
else // There was no ;. Just a single command.
{
cmd+='\n';
SendCommandToConsole(1,1,cmd.c_str());
}
}while(scPos!=string::npos); // Only loop again if a ; was found in the last iteration.
}
Firstly we have the declaration of SendCommandToConsole(). This allows us to send a command to the console (no way!) of MW2.
The source is pretty heavily commented here so it’s fairly obvious what’s going on – basically what it does is search for a “;”. If one doesn’t exist, then send the command. Otherwise, split up the command, and send it piece by piece, until it’s all been sent.
We use a do..while loop so that it’s always called at least once, and if required will wrap back around.
So yeah, there you have it, a working textbox class. But are we done?
No.
If you have actually read through this and didn’t scroll to the end to look for full source then lucky you.
Here’s my command.h :P
Okay, so now we have a class, and the majority of the functions we need to have a pretty nice textbox going, but what more do we need?
Well there are other things than text which are required to have a good textbox. We must also control, for example, the left/right keys to move the caret, escape to quickly close the console, and the DEL key to delete text IN FRONT of the caret.
I coded this function in my main.cpp, but you could easily implement this directly to the console class. I call this from the WM_KEYDOWN message.
Code:
void KeyPressed(WPARAM wParam)
{
Console.handled=false; // in case it's still true
if(wParam==VK_SHIFT) // allows us to use combinations such as Shift+(key)
shift=true;
if(wParam==VK_F1) // F1 is our show/hide hotkey
{
Console.handled=true;
if(console)
{
Console.Send("con_minicon 0"); // This is my lazy way of getting "feedback" from the console
console=false;
}
else
{
Console.Send("con_minicon 1");
console=true;
}
}
if(console) // If the console is visible, take input.
{
switch(wParam)
{
case VK_LEFT:
if(Console.caretPos>0) Console.caretPos-=1; // Left key. Move the caret back 1 if it's not already at 0.
break;
case VK_RIGHT:
if(Console.caretPos<(int)Console.command.length()) Console.caretPos+=1; // Right key. Move the caret forward one if it's not already at the end of the string.
break;
case VK_DELETE:
if(shift) // Shift+DEL are pressed.
{
Console.command=""; // Empty the string
Console.caretPos=0; // Reset Caret
}
else
{
// Delete the character in front of the caret if it's not at the end of the string
// (Note that the caret stays in the same position)
if(Console.caretPos<(int)Console.command.length()) Console.command.erase(Console.caretPos,1);
}
break;
case VK_ESCAPE:
{
Console.handled=true;
console=false; // Hide the console.
}
break;
} // switch(wParam)
} // if(console)
}
Now this is already pretty commented, so it’s pretty self explanatory.
All that you need to know is that console is a boolean for whether to show the console or not, and shift is a boolean for whether the shift key is up or down.
The shift boolean is nice as it allows WM_KEYDOWN to handle Shift+(KEY). Basically, if shift is down, then shift=true. On WM_KEYUP, if the key going up is Shift, then shift = false:
Code:
case WM_KEYUP:
if(wParam==VK_SHIFT)
shift=false;
break;
The con_minicon lines are just plain laziness on my part – rather than actually reading the feedback from the game’s console, I get the game to display it itsself. Pretty nifty.
Just to give you an idea of my Windows Messages handler, here’s the switch statement:
Code:
switch( lpmsg->message )
{
case WM_KEYUP:
if(wParam==VK_SHIFT)
shift=false;
break;
case WM_KEYDOWN:
KeyPressed(wParam);
if(console) return true;
break;
case WM_CHAR:
if(console)
{
Console.takeInput(wParam);
return true;
}
break;
}
As you can see for WM_KEYDOWN and WM_CHAR, if console is true, then I return true. This tells the game that the messages have already been handled, and as such won’t take them (so you won’t run around randomly ingame, or send stupid text messages while the console is showing).
So my last thing to show you is how to call everything and get your wonderful textbox going.
Wherever you init the rest of your hack, where you init your drawing class, etc. Call Console.Init();.
Call the render function in your EndScene hook, eg:
Code:
if(console)
Console.Render(10,10,Viewport.Width-20,pDevice);
Call KeyPressed() and takeInput() from your Windows Messages hook (see above).
That’s it! You now have a beautiful textbox to use for…whatever you want in your DirectX projects
The concepts covered in this tutorial are most certainly not limited to DirectX – the only things in this that rely on DirectX are the drawing functions! Since you’ll be using your own, you could port this to any graphics library or project EXTREMELY easily.
Obviously this textbox is quite basic. There is a lot you could do to expand it if you liked – here are some ideas to get you thinking:
- Create a multiline textbox
- Allow users to have text input in your hack, eg have an aimbot focus on “Player X”
- For a console, have command suggestions
- For a console, have feedback
- Instead of Tab, use the up and down keys to cycle through old messages/commands.
- …
- ..
- .
The possibilities are…for a textbox at least, endless!
If you’ve physically read through all of this, then I salute you! Well done
Anyway, I hope you enjoyed the tutorial, found it easy to follow and most importantly learned from it! Please comment if you have any suggestions or spot any mistakes or whatnot.
Cheers,
0rbit