Aus einer Produktion der langeweile entsteht heute abend ein Tutorial über ein GUI Menu.
Zu erst überlegen wir uns was wir benötigen.
- Structuren die die Daten speichern
- Funktionen die die Daten wiedergeben
- Ein Key- und Mouse-Handling
Nun machen wir uns über die Umsetzung gedanken.
also was müssen die Structuren alles Speichern ?
- Position des Menus (x,y)
- Text in dem Menu
- Buttons und Beschriftung
- Ob die Maus über dem Menu ist und welche Taste gedrück wird
So nun haben wir die Structuren weiter zu den Funktionen.
Was erwarten wir von den Funktionen ?
- Die Daten aus den Structuren müssen verarbeitet werden
- Möglichst viel Arbeitserleichterung
Nun zu dem Keyhandling was erwarten wir davon ?
- Verarbeiten des Userinputs
- Möglichst unkompliziert und präzise
Soviel zur Theorie nun mal ein paar kleine Gedanken und Funktionen
Zuerst müssen wir die WindowProc, GetCursorPos und SetCursorPos hooken.Die gehooketen Funktionen sehen dann in etwa so aus.
Code:
int APIENTRY newGetCursorPos(LPPOINT lpPoint)
{
int ret = GetCursorPos(lpPoint);
if(draw.menu) // wenn das Menu aktive ist beeinflussen wir die Maus
{
mousepos[0] = (float)lpPoint->x; // Speichern die Position der maus
mousepos[1] = (float)lpPoint->y;
lpPoint->x = (long)(vp[2]/2); // Und täuschen vor das die Maus in der Mitte des Screens ist
lpPoint->y = (long)(vp[3]/2); // Denn sonst würde HL den Cursor in die Mitte setzten
}
return ret;
}
Code:
int APIENTRY newSetCursorPos(int x, int y)
{
if(draw.menu) // Wenn das Menu AKtive ist beantworten wir sämtliche aufrufe der Funktion von HL mit true
return 1;
return SetCursorPos(x, y);
}
Code:
LRESULT CALLBACK HookedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg == WM_KEYDOWN) // Wenn eine Taste gedrückt wird bis auf Tasten der Maus
{
KeyHandle(wParam); // Führen wir unsere KeyHanlde Funktion aus
}
if (((uMsg==513) || (uMsg==516))) // Wenn Mouse 1 oder Mouse 2 gedrückt werden
{
if (mouse.pressed != 1) // Und die Maus nicht schon gedrückt ist
{
mouse.pressed = 1; // Speichern wir in der mouse-Structur das sie gedrückt ist
mouse.button = wParam; // und Welche Taste gedrück wird 1 oder 2
mouse.posbx = mousepos[0]; // Speichern die Position der Maus
mouse.posby = mousepos[1]; // Was wir später brauchen um das Menu moven zu können
}
}
if (((uMsg==514) || (uMsg==517)) && (wParam == 0)) // Wenn die Tasten wieder losgelassen werden
{
mouse.pressed = -1; //Setzten wir alles weider zurück
mouse.button = -1;
if (draw.menu) // und wenn das Menu aktive ist setzten wir auch die Menuspezifischen sachen zurück
{
mouse.menu = -1;
mouse.hover = -1;
}
}
if(uMsg==WM_MOUSEMOVE) // Wenn die Maus bewegt wird
{
mousep = MAKEPOINTS(lParam);
mousepos[0] = mousep.x; // speichern wir die Position der Maus
mousepos[1] = mousep.y;
}
if (draw.menu) // Und wenn das Menu Aktive ist sagen wir HL immer das alles ok ist und returnen True
return true;
return CallWindowProc(orig_WindowProc, hwnd, uMsg, wParam, lParam);// else retval=true;
}
Code:
void KeyHandle(int Key) { // Die Funktion wird aufgerufen wenn eine Taste gedrückt wird
if (Key == cvar.menukey) // Wenn die gedrückte Taste das Menu öffnen soll
{
hCursor = LoadCursor(NULL, IDC_ARROW);
SetCursor(hCursor); // Ihr könnt den Cursor darstellen wie ihr wollt ich aber bevorzuge den Windos Cursor also benutz ich auch die Windows Cursor Funktionen
draw.menu=!draw.menu;
if (draw.menu)
ShowCursor(true);
else
{
SetCursorPos(vp[2]/2,vp[3]/2);
SetCursor(NULL);
}
}
}
Dann können wir die Structuren anlegen die wir uns weiter oben ausgedacht haben.
Code:
typedef struct {
int style; // Wenn wir verschiedene Styles benötigen z.B. mit Header oder ohne
int button; // die Anzahl der Burrons die in dem Menu vorhanden sind
int textcount; // Die Anzahl der textfelder
float posx; // Die Position
float posy;
float width; // Breite und Höhe des Menus
float height;
float r; // Die farbe des Menus so wie der Alphawert
float g;
float b;
float a;
bool active; // Ist das Menu Aktive sprich soll es dargestellt werden
bool border; // Soll es einen Rahmen bekommen ?
char title[100]; // Der Titel
} menu_s;
Code:
typedef struct {
float posx; // Dir Position Innerhalb des Menus
float posy;
float width;
float height;
char text[100];
float r;
float g;
float b;
float a;
} menu_button_s;
Code:
typedef struct {
char text[255]; // Der text Selbst
float r; // Die Farbe
float g;
float b;
float posx; // Die Position innerhalb des Menus
float posy;
} menu_text_s;
Code:
typedef struct {
float posx; // Position der Maus
float posy;
float posbx; // Position beim Drüken einer der Maustasten
float posby;
int pressed; // Ist eine der beiden Maustasten gedrückt ? ja 1 nein 0
int hover; // Für das Menu ist die Maus über einem Button ?
int menu; // Zu welchem Menu gehört der Button
int button; // Und welcher button ist es ?
} mouse_s;
So nun haben wir auch die Structuren was uns nun noch Fehlt sind die Funktionen zum wiedergeben der Daten.
Code:
void ButtonHandle(int menunum, int buttonnum, int mousebutton)
{
switch (menunum)
{
case 0: // Menu 0
{
switch (buttonnum) // Switch durch die Buttons
{
case 0: // Button 0
{
// Hier die Funktionen der Button
//mouse.pressed = -1; // Wenn der Button danach nicht mehr als gedrückt gelten soll z.B. bei normalen Buttons hingegen beim Move-Button darf man das nciht machen
// Hier z.B. ein Move-Button
menu[menunum].posx = mouse.posx+(mousepos[0]-mouse.posbx);
menu[menunum].posy = mouse.posy+(mousepos[1]-mouse.posby);
break;
}
case 1: // Button 1
{
// Hier die Funktion zu dem Button
mouse.pressed = -1;
break;
}
}
break;
}
}
}
Code:
void DrawMenu(void)
{
glGetFloatv(GL_CURRENT_COLOR, color);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
DrawAdver();
glDisable(GL_TEXTURE_2D);
// Draw Background
glColor4f(0.0f/255,0.0f/255,0.0f/255,120.0f/255); // Hier verdunkeln wie den Background
DrawBox(0.0f,0.0f,vp[2],vp[3]);
// Draw Menu
RefreshMenu(); // Ist eine Funktion die die Beschriftung der Buttons aktuallisiert
for(int i=0;i < 11;i++) // Ich habe hier die Anzahl der Menus auf 10 beschrenkt
{
if (menu[i].active) // Wenn das Menu als aktive gekennzeichnes ist wird es gemalt
{
glColor4f(menu[i].r/255,menu[i].g/255,menu[i].b/255,menu[i].a/255); // Die farbe des Menus ich hätte hier auch glColor4ub benutzten können jedoch hab ich es mir so angewöhnt
switch (menu[i].style) // Die unterscheidung de Styles
{
case 0:
{
DrawMenuBody(menu[i].posx,menu[i].posy,menu[i].width,menu[i].height,menu[i].border,menu[i].r,menu[i].g,menu[i].b,menu[i].a);
glPrint(menu[i].posx+10.0f,menu[i].posy+12.0,0.0f,false,1.0,1.0,1.0,"%s",menu[i].title);
break;
}
case 1:
{
DrawBox(menu[i].posx,menu[i].posy,menu[i].width,menu[i].height);
break;
}
}
for (int x=0;x < menu[i].textcount;x++)
{
glPrint(menu[i].posx+menu_text[i][x].posx,menu[i].posy+menu_text[i][x].posy,0.0f,false,menu_text[i][x].r,menu_text[i][x].g,menu_text[i][x].b,"%s",menu_text[i][x].text);
}
for (int y=0;y < menu[i].button;y++)
{
// Wenn Der Button gedrück st vertauscht er die Farben damit der druck effekt entsteht
if ((mouse.pressed == 1) && (mouse.hover == y) && (mouse.menu == i))
DrawButton(menu[i].posx+menu_button[i][y].posx,menu[i].posy+menu_button[i][y].posy,menu_button[i][y].width,menu_button[i][y].height,menu_button[i][y].r,menu_button[i][y].g,menu_button[i][y].b,menu_button[i][y].a,true);
else
DrawButton(menu[i].posx+menu_button[i][y].posx,menu[i].posy+menu_button[i][y].posy,menu_button[i][y].width,menu_button[i][y].height,menu_button[i][y].r,menu_button[i][y].g,menu_button[i][y].b,menu_button[i][y].a,false);
if ((mouse.pressed != 1) && (mousepos[0] > menu[i].posx+menu_button[i][y].posx) && (mousepos[0] < menu[i].posx+menu_button[i][y].posx+menu_button[i][y].width) && (mousepos[1] > menu[i].posy+menu_button[i][y].posy) && (mousepos[1] < menu[i].posy+menu_button[i][y].posy+menu_button[i][y].height))
{ // Wenn die Maus nicht gedrück wird soll er gucken ob sich die Maus über einem Objekt befindet
mouse.hover = y;
mouse.menu = i;
mouse.posx = menu[i].posx;
mouse.posy = menu[i].posy;
}
else if ((mouse.hover == y) && (mouse.menu == i) && (mouse.pressed != 1))
{ // Wenn der Mousehover auf dem Aktuellen Menu steht jedoch die vorige if abfrage nicht true ist dann ist derCursor ausserhalb des Buttons
mouse.hover = -1;
mouse.menu = -1;
}
if ((mouse.pressed == 1) && (mouse.hover != -1) && (mouse.menu != -1) )
{
ButtonHandle(mouse.menu,mouse.hover,mouse.button); // hier rufen wir den Buttonhandle auf
}
// Berechnung das der Buttontext auch etwa in der Mitte des Buttons ist
glPrint(menu[i].posx+menu_button[i][y].posx+((menu_button[i][y].width-(strlen(menu_button[i][y].text)*6.5))/2),
menu[i].posy+menu_button[i][y].posy+((menu_button[i][y].height/2)+4),
0.0,false,1.0,1.0,1.0,"%s",menu_button[i][y].text);
}
}
}
glDisable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
// Draw spieletermine networks
}
Code:
void RefreshMenu(void) // So kann die RefreshMenu gestaltet sein
{
int i=0,y=0;
// Menu 0
// Menu 1
i++;
y=0;
// Button 0
// Button 1
y++;
// Button 2
y++;
sprintf(menu_button[i][y].text,"%s",aim.active?"on":"off");
// Menu 2
i++;
y=0;
// Button 0
// Button 1
y++;
// Button 2
y++;
if (cvar.wall == 0)
sprintf(menu_button[i][y].text,"off");
else if (cvar.wall == 1)
sprintf(menu_button[i][y].text,"XQZ");
else if (cvar.wall == 2)
sprintf(menu_button[i][y].text,"Asus");
else if (cvar.wall == 3)
sprintf(menu_button[i][y].text,"Wireframe");
else if (cvar.wall == 4)
sprintf(menu_button[i][y].text,"Model");
else if (cvar.wall == 5)
sprintf(menu_button[i][y].text,"ViewPort");
}
Code:
void InitMenu(void)
{
mouse.hover = -1; // Wir setzten die Werte auf -1
mouse.pressed = -1;
int i=0,y=0;
// Set Menu 0
menu[i].active = true; // Und setzten die Menueinträge
menu[i].posx = 0.0f;
menu[i].posy = vp[3]-24.0;
menu[i].width = vp[2];
menu[i].height = 24.0;
menu[i].r = 76.0f;
menu[i].g = 88.0f;
menu[i].b = 68.0f;
menu[i].a = 209.1f;
menu[i].border = false;
menu[i].style = 1;
sprintf(menu[i].title,"");
// Set Buttons
menu_button[i][y].posx = 1.0f;
menu_button[i][y].posy = 2.0f;
menu_button[i][y].width = 100.0f;
menu_button[i][y].height = 20.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 255.0f;
sprintf(menu_button[i][y].text,"Aimbot");
y++;
menu_button[i][y].posx = 105.0f;
menu_button[i][y].posy = 2.0f;
menu_button[i][y].width = 100.0f;
menu_button[i][y].height = 20.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 255.0f;
sprintf(menu_button[i][y].text,"Visual");
y++;
menu_button[i][y].posx = 210.0f;
menu_button[i][y].posy = 2.0f;
menu_button[i][y].width = 100.0f;
menu_button[i][y].height = 20.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 255.0f;
sprintf(menu_button[i][y].text,"Hud");
menu[i].button = y+1; // Hier speichern wir die Anzahl der Buttons
i++;
y=0;
//===============================================================================================
// Set Menu 1
//===============================================================================================
menu[i].active = false;
menu[i].posx = 350.0f;
menu[i].posy = 400.0f;
menu[i].width = 200.0f;
menu[i].height = 300.0;
menu[i].r = 50.0f;
menu[i].g = 30.0f;
menu[i].b = 20.0f;
menu[i].a = 200.0f;
menu[i].border = true;
menu[i].style = 0;
sprintf(menu[i].title,"HUD");
//=========================================
// Set Menu Button
//=========================================
// Set Button 0
menu_button[i][y].posx = 0.0f;
menu_button[i][y].posy = 0.0f;
menu_button[i][y].width = 180.0f;
menu_button[i][y].height = 14.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 0.0f;
sprintf(menu_button[i][y].text,""); // Der Text wird in der RefreshMenu gesetzt
y++;
// Set Button 1
menu_button[i][y].posx = 185.0f;
menu_button[i][y].posy = 3.0f;
menu_button[i][y].width = 10.0f;
menu_button[i][y].height = 10.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 255.0f;
sprintf(menu_button[i][y].text,"");
y++;
// Set Button 2
menu_button[i][y].posx = 110.0f;
menu_button[i][y].posy = 20.0f;
menu_button[i][y].width = 80.0f;
menu_button[i][y].height = 16.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 255.0f;
sprintf(menu_button[i][y].text,"off");
y++;
// Set Button 3
menu_button[i][y].posx = 110.0f;
menu_button[i][y].posy = 40.0f;
menu_button[i][y].width = 80.0f;
menu_button[i][y].height = 16.0f;
menu_button[i][y].r = 51.0f;
menu_button[i][y].g = 51.0f;
menu_button[i][y].b = 51.0f;
menu_button[i][y].a = 255.0f;
sprintf(menu_button[i][y].text,"off");
menu[i].button = y+1;
//=========================================
// Set Menu Button Text
//=========================================
y=0;
menu_text[i][y].posx = 5.0f; // Und hier erstellen wir gerade ein Textfeld
menu_text[i][y].posy = 32.0f;
menu_text[i][y].r = 1.0f;
menu_text[i][y].g = 1.0f;
menu_text[i][y].b = 1.0f;
sprintf(menu_text[i][y].text,"HUD:");
y++;
menu_text[i][y].posx = 5.0f;
menu_text[i][y].posy = 52.0f;
menu_text[i][y].r = 1.0f;
menu_text[i][y].g = 1.0f;
menu_text[i][y].b = 1.0f;
sprintf(menu_text[i][y].text,"Crosshair:");
menu[i].textcount = y+1; // Und Speichern auch die Anzahl der textfelder in der Structur
}
So die Draw Funktionen kann sich jeder der dem Tutorial bis hierhin folgen konnte selber erstellen. Ich hoffe es hat euch geholfen und das wir in naher zukunft viele GUI Menus auch in OGL Hacks sehen werden
greez to tabris from gd.com :)
mfg Suxx :)