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

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

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

Post 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
mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Post 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
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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.
Use the source, Luke!
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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.
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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.
Use the source, Luke!
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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));
}
}
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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 ?
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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);
}
Use the source, Luke!
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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?
User avatar
doublemax
Moderator
Moderator
Posts: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post 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.
Use the source, Luke!
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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.
mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Post 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])){
}
mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Post 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
Komerad
Earned a small fee
Earned a small fee
Posts: 15
Joined: Tue Mar 03, 2009 9:42 pm

Post 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)
Locked