Page 1 of 2

Send pre defined 'keystrokes' + string (txt) to window

Posted: Fri May 15, 2009 5:58 pm
by Komerad
Purpose :
I want to make a recruiting tool for mmorpgs wich sends the recruiting info to ingame chat with configurable intervals.

Tool should receive a string trough textctrl from the user. When the button is pressed it passes on the content from the string to another windows wich is not controled.

Problem :
I did some searching on the internet and found some basic info about how to do send txt to notepad.. wich works. Porting this to guildwars it does not work anymore, even if I have chat open ready for input (as a way of step by step testing). I so ran into spy++ wich helped me determing the window class of guildwars to use.
Notepad window name = notepad
Notepad textfield = edit
Sadly enough guildwars doesnt seem to show me enough information trough spy++.. and the text doesnt apear in guildwars. Not even the keystroke (I tested with 'a' key wich if it doesnt end up in as character a in the chat should make the camera view rotate)

I currently don't have the code right here and look deeper into it soon.

If anyone had something similar i'd like to know :)

Regards

Posted: Fri May 15, 2009 6:35 pm
by mc2r
At a guess, guildwars isn't using a text box with a an HWND, but some gui element of their own design.

You don't post any code but I assume you are doing something like

Code: Select all

SendMessage(hNotepad, WM_CHAR, (TCHAR) 'H', 0);
SendMessage(hNotepad, WM_CHAR, (TCHAR) 'E', 0);
SendMessage(hNotepad, WM_CHAR, (TCHAR) 'L', 0);
SendMessage(hNotepad, WM_CHAR, (TCHAR) 'L', 0);
SendMessage(hNotepad, WM_CHAR, (TCHAR) 'O', 0);
to send the message to notepad?

You could try sending the event to the top level window for GuildWars. Maybe FindWindow or EnumWindows will help with that.

Oh and this isn't really much of a wxWidgets question. Also, a bit spam'y don't you think? Not sure what guildwars AUP says about this.

-Max

Posted: Fri May 15, 2009 6:56 pm
by Komerad
Yes sir I do, I don't have the code right here (ain't home atm)

Sending to the top level does not work.

I tought it is not realy a wx question altho i would not be surprised there would have been some wxclass around for this, its just so that I use wxwidgets for all almost all the stuff I do. As for guildwars besides that guildwars blocks messages that add up to fast as a way of spamprotection I do NOT have the intention to realy 'spam' I have 2 computers with 3 screens and run 3 accounts at once, and I just want to fully utilize them (i'm short on arms, hands and fingers to do so). Also I am behind those computers, no use to recruit, wts or wtb if you can's answer pm's and such. I'm not following c++ lessons to abuse things, just to make things easyer :)

Thx for info.

Posted: Fri May 15, 2009 7:40 pm
by doublemax
you could use low-level keyboard emulation. wxWidgets has no functions for that, but under Windows it's pretty easy using SendInput.

The target application of course needs to have keyboard focus for this to work.

Posted: Sun May 17, 2009 12:50 pm
by Komerad
Thx for the direction, that seems to be the only way to do this job, first tests look fine just need to write a routine to translate characters from string to vkey codes.

Thx.

To ADMIN : I accepted last reply instead of the one just above. Can you pls correct is. Sorry.

Posted: Sun May 17, 2009 1:29 pm
by doublemax
first tests look fine just need to write a routine to translate characters from string to vkey codes.
VkKeyScan

There are other related Win32 API functions that might be useful for you as well.

Posted: Mon May 18, 2009 12:36 pm
by Komerad
Well the sending a declared char, the amount = the length did work fine..

Code: Select all

wxString SENDTXT = TextCtrl1->GetValue();
const char *ch1 = TextCtrl1->GetValue();
int Lengte = strlen(SENDTXT);
///////////////////////////////////////////////
// Stuur string inhoud
///////////////////////////////////////////////
for(int letternr = 0 ; letternr <= Lengte ; letternr++){

wxString LETTER = SENDTXT.substr(0, letternr);
//char ch2 = SENDTXT.substr(0, letternr);
TextCtrl2->SetValue(ch1[letternr]);
TextCtrl1->SetValue(LETTER);


char ch = ch1[letternr]; // Getting this to work is a PIMA
//char ch = 'A';
// STUUR LETTE a //
KEYBDINPUT kb={0};
INPUT Input={0};
// down
kb.wVk = ch; // 'A';
Input.type = INPUT_KEYBOARD;
Input.ki = kb;
::SendInput(1,&Input,sizeof(Input));
// up
::ZeroMemory(&kb,sizeof(KEYBDINPUT));
::ZeroMemory(&Input,sizeof(INPUT));
kb.dwFlags = KEYEVENTF_KEYUP;
kb.wVk = ch; // 'A';
Input.type = INPUT_KEYBOARD;
Input.ki = kb;
::SendInput(1,&Input,sizeof(Input));
}
}

Posted: Mon May 18, 2009 4:45 pm
by Komerad
Another test :

Code: Select all

wxString SENDTXT = TextCtrl1->GetValue();
const char *ch1 = TextCtrl1->GetValue();
int Lengte = strlen(SENDTXT);
///////////////////////////////////////////////
// Stuur string inhoud
///////////////////////////////////////////////
for(int letternr = 0 ; letternr <= Lengte ; letternr++){
keybd_event( ch1[letternr], 0, 0, 0 );
keybd_event( ch1[letternr], 0, KEYEVENTF_KEYUP, 0 );
Sleep(100);
}}
This method comes close as well.. but somehow it skips characters randomly, thats why i included the sleep command, even at 1 second sleep it keeps skipping...

My test I entered : ABCDEFGH..
The return : abef..

Can you pls tell how to use : VkKeyScan ?

Posted: Mon May 18, 2009 9:34 pm
by doublemax
try something like this (untested):

Code: Select all

wxString SENDTXT = TextCtrl1->GetValue();
for(int letternr = 0 ; letternr<SENDTXT.Len() ; letternr++){
  short keycode=VkKeyScan(SENDTXT[letternr])&0xff; // ignore modifier states for this test
  keybd_event( keycode, 0, 0, 0 );
  Sleep(10);
  keybd_event( keycode, 0, KEYEVENTF_KEYUP, 0 );
  Sleep(10);
}

Posted: Tue May 19, 2009 9:30 am
by Komerad
Thx, this comes very close, it even recognises '=' wich i did not even find the vkey code for.

It does not recon the numbers but there are only 10 numbers so if needed i'll just write a routine for those.

It neither does recon the difference between capital or minor, i've did some tests also with vkey'ing the capslock bit that did not work out.. this is a minor issue i can live with tho.

Can you pls tell what the

Code: Select all

&0xff
stands for?

Posted: Tue May 19, 2009 9:43 am
by doublemax
Komerad wrote:Thx, this comes very close, it even recognises '=' wich i did not even find the vkey code for.

It does not recon the numbers but there are only 10 numbers so if needed i'll just write a routine for those.

It neither does recon the difference between capital or minor, i've did some tests also with vkey'ing the capslock bit that did not work out.. this is a minor issue i can live with tho.

Can you pls tell what the

Code: Select all

&0xff
stands for?
VkKeyScan returns the shift/ctrl/alt state for this key in the upper byte, the "&0xff" deletes these upper bits.

This should also answer what you have to do to support Capital letters: Check the upper bits and emulate pressing shirt/ctrl/alt keys respectively.

Posted: Tue May 19, 2009 12:13 pm
by Komerad
Thx a lot for the help it now does what it should do, here's the code :

Code: Select all


for(int letternr = 0 ; letternr<SENDTXT.Len()  ; letternr++){
short keycode=VkKeyScan(SENDTXT[letternr]) &0xff;

////////////////////////////////////////////////
// Check for Upper cases
////////////////////////////////////////////////
if(isupper(SENDTXT[letternr])){
  keybd_event( VK_LSHIFT, 0xA0, 0, 0 );
  Sleep(10);
  keybd_event( keycode, 0, 0, 0 );
  Sleep(10);
  keybd_event( keycode, 0, KEYEVENTF_KEYUP, 0 );
  Sleep(10);
  keybd_event( VK_LSHIFT, 0xA0, KEYEVENTF_KEYUP, 0 );
  Sleep(10);
}
////////////////////////////////////////////////
// Check for numbers
////////////////////////////////////////////////

else if(isdigit(SENDTXT[letternr])){
  keybd_event( VK_LSHIFT, 0xA0, 0, 0 );
  Sleep(10);
  keybd_event( keycode, 0, 0, 0 );
  Sleep(10);
  keybd_event( keycode, 0, KEYEVENTF_KEYUP, 0 );
  Sleep(10);
  keybd_event( VK_LSHIFT, 0xA0, KEYEVENTF_KEYUP, 0 );
}
////////////////////////////////////////////////
// All the rest
////////////////////////////////////////////////
else{
  keybd_event( keycode, 0, 0, 0 );
  Sleep(10);
  keybd_event( keycode, 0, KEYEVENTF_KEYUP, 0 );
  Sleep(10);
}}

What did not work to my surprise was combining the isupper with the isdigit :

Code: Select all

if(isupper(SENDTXT[letternr] || isdigit(SENDTXT[letternr])){
}
Resulted in not showing numbers nor upper cases, just nothing
so i had to split that one up.

Again THX!

EDIT :
Stuck again altho one of all the methods i tried did manage to send keys as they are to guildwars this method seems unable to send the 'enter' or 'return' keys..

Works fine in notepad doesnt work with guildwars. If the chat is opened the text is sended flawless now but opening and closing doesnt work.

Posted: Tue May 19, 2009 3:17 pm
by mc2r
Komerad wrote:What did not work to my surprise was combining the isupper with the isdigit :

Code: Select all

if(isupper(SENDTXT[letternr] || isdigit(SENDTXT[letternr])){
}
Resulted in not showing numbers nor upper cases, just nothing
so i had to split that one up.
I think you have a missing paren. Not sure if that was an error entering it here or actually one in your code.

Code: Select all

if(isupper(SENDTXT[letternr]) || isdigit(SENDTXT[letternr])){
}

Posted: Tue May 19, 2009 3:26 pm
by mc2r
One other thought before I get to working on my own buggy code. You could google for "guild wars bot" and see if you can find one with source code. Might be able to figure out how to interact with the game through some already written code.

-Max

Posted: Tue May 19, 2009 3:44 pm
by Komerad
I did that, besides of it being a good lesson as apprentice promgrammer thats the main reason why i just want to write one myself.

One of all methods i posted managed to send keys to guilwars.. yet the method used lastly (code above) seemed a much better sollution for handling the input correctly.

All i need to figure out now : How to send an 'ENTER' to guildwars or better.. in a way that guildwars will accept it as an enter..

(as for the code it was indeed a missing paren have been looking over it, did not got any error on it neither)