Autocomplete anywhere

  • (2 Pages)
  • +
  • 1
  • 2

20 Replies - 2188 Views - Last Post: 31 May 2012 - 03:27 PM Rate Topic: -----

#1 Ahmedn1  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 23
  • View blog
  • Posts: 556
  • Joined: 04-August 09

Autocomplete anywhere

Posted 19 May 2012 - 09:37 AM

Hello DICs,
I want to build a feature that enables me to detect any text editor in the active application to provide the autocomplete feature for the user
I want to do like Microsoft Maren but the problem I searched a lot and I know that User32.dll library will help me with methods like FindWindow
The thing that I need to know is how to detect that the user is writing in a text box or a text editor like (Word text area, Notepad text area and Posting text areas in forums)

After that I will try to find a way to add a list box of autocomplete to the active application

Thanks,

Is This A Good Question/Topic? 0
  • +

Replies To: Autocomplete anywhere

#2 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3551
  • View blog
  • Posts: 11,008
  • Joined: 05-May 12

Re: Autocomplete anywhere

Posted 21 May 2012 - 03:12 AM

I think you will be hard pressed to support "any text editor in the active application". Although most applications will use the handful of text controls available to the Win32 API, not all applications are compelled to use only the Windows controls. If you use any code editor other than Visual Studio, it is very likely that the primary editting surface is not a standard RichEdit or TextEdit control.

Yes, using FindWindow will let you find all the windows (assuming you have the appropriate privileges). If you aren't running with enough privileges, you'll be unable to do anything with applications that are running elevated while you are running as a normal user.

You can detect that the user is writing within a control if that control has the keyboard focus (again something you can determine by calling Win32 APIs), if keys are being pressed, or if the person is pasting text into the control. You can look into Windows hooks if you want to capture the key presses.
Was This Post Helpful? 0
  • +
  • -

#3 Toadill  Icon User is offline

  • D.I.C Regular

Reputation: 45
  • View blog
  • Posts: 401
  • Joined: 08-January 12

Re: Autocomplete anywhere

Posted 21 May 2012 - 05:50 AM

Yes Skydiver makes some valid points I have created something like this in VB 6.0 to automate a server. Using findwindow to hook the window and then findwindowex to enumerate to the textbox you can then focus on the window from there you can use other API's like postmessage(button) or sendmessage to send messages to the control

Although for text editors like office there are COM's that you can use, which is the appropriate way to do this.
Was This Post Helpful? 1
  • +
  • -

#4 Curtis Rutland  Icon User is online

  • (╯□)╯︵ (~ .o.)~
  • member icon


Reputation: 4464
  • View blog
  • Posts: 7,780
  • Joined: 08-June 10

Re: Autocomplete anywhere

Posted 21 May 2012 - 07:47 AM

Doing this in C# is going to be a pain, since you're going to have to P/Invoke all those calls. None of them are managed or wrapped in .NET code, so you'll be doing the wrappers yourself. It might be better to just try this in C++, where you can make those Win32 API calls directly. Toadill's example is a good one, but it's specific to a window you're looking for. In your case, it's going to be much harder, since you're going to have to enumerate all windows, then find any textbox controls, then find if they're focused, then run your code.
Was This Post Helpful? 0
  • +
  • -

#5 Ahmedn1  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 23
  • View blog
  • Posts: 556
  • Joined: 04-August 09

Re: Autocomplete anywhere

Posted 23 May 2012 - 09:01 AM

View PostToadill, on 21 May 2012 - 02:50 PM, said:

Yes Skydiver makes some valid points I have created something like this in VB 6.0 to automate a server. Using findwindow to hook the window and then findwindowex to enumerate to the textbox you can then focus on the window from there you can use other API's like postmessage(button) or sendmessage to send messages to the control

Although for text editors like office there are COM's that you can use, which is the appropriate way to do this.


I have a code to get the active window using FindWindow and some Enumeration
So, hot to get to the text editor of this window as you did using FindWindowEx ?
Was This Post Helpful? 0
  • +
  • -

#6 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3551
  • View blog
  • Posts: 11,008
  • Joined: 05-May 12

Re: Autocomplete anywhere

Posted 23 May 2012 - 12:59 PM

If you have the code to get the active window using FindWindow(), then you should take time to understand what it does.

Hint: The first parameter to FindWindow() is the class name. What are the class names for text boxes and rich edit controls?

Building on that hint, this is why it becomes very hard to do what you want for any application. The class names for text boxes and rich edit controls are well documented and guaranteed to stay the same for all versions of Windows. But if you run into "My XYZ Word Processor", how would you find the class name of their editing surface in an automated manner?
Was This Post Helpful? 0
  • +
  • -

#7 Ahmedn1  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 23
  • View blog
  • Posts: 556
  • Joined: 04-August 09

Re: Autocomplete anywhere

Posted 23 May 2012 - 02:32 PM

View PostSkydiver, on 23 May 2012 - 09:59 PM, said:

If you have the code to get the active window using FindWindow(), then you should take time to understand what it does.

Hint: The first parameter to FindWindow() is the class name. What are the class names for text boxes and rich edit controls?

Building on that hint, this is why it becomes very hard to do what you want for any application. The class names for text boxes and rich edit controls are well documented and guaranteed to stay the same for all versions of Windows. But if you run into "My XYZ Word Processor", how would you find the class name of their editing surface in an automated manner?


yes that's what I'm asking about
I thought toadill had a way to get any text box control in any window
Was This Post Helpful? 0
  • +
  • -

#8 Toadill  Icon User is offline

  • D.I.C Regular

Reputation: 45
  • View blog
  • Posts: 401
  • Joined: 08-January 12

Re: Autocomplete anywhere

Posted 24 May 2012 - 07:02 AM

Okay there is a way to do this, there is a tool called Spy++ that comes with the older versions of the visual studio. I believe you can also download it for free. What this does is allow you to get the handle and or caption for the window, which is what is used in the API as a parameter to hook the window. Spy++ is easy to use all you do is hit the button in the spy program then click the window you want the handle for. You will have to do this for the form window and the textbox so that you can findwindowEx to the textbox.
The spy program will then give you both the caption and the handle. Also when using the findow function you can null out either of the parameters or use just one or the other to hook the window. This is useful because some times programs have the same handle name if programmed that way. In this situation you could use the caption of the program instead. In other situations the caption of the program could change so you have to really test things to decide which is the best approach. Also just so you don't get confused you will have to use findwindowEx to get to the textbox control findwindow only gets the main window, you must enum in order to get the control.
once you enum to the textbox you can use the sendmessage, or postmessage API's.

This post has been edited by Toadill: 24 May 2012 - 07:23 AM

Was This Post Helpful? 0
  • +
  • -

#9 Toadill  Icon User is offline

  • D.I.C Regular

Reputation: 45
  • View blog
  • Posts: 401
  • Joined: 08-January 12

Re: Autocomplete anywhere

Posted 24 May 2012 - 07:20 AM

Here is a example of this in C
This will open notepad and enter a letter in the text box

#include <windows.h>
#include <stdio.h>

void main(void) 
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    HWND mainwnd,editwnd;
    char c;
    si.cb=sizeof(si);
    si.lpReserved=NULL;
    si.lpDesktop=NULL;
    si.lpTitle=NULL;
    si.dwFlags=0;
    si.cbReserved2=0;
    si.lpReserved2=NULL;
    if(!CreateProcess("c:\\windows\\notepad.exe",NULL,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) {
        printf("Failed to run app");
        return;
    }
    WaitForInputIdle(pi.hProcess,INFINITE);
    mainwnd=FindWindow(NULL,"Untitled - Notepad");
    if(!mainwnd) {
        printf("Main window not found");
        return;
    }
    editwnd=FindWindowEx(mainwnd,NULL,"Edit","");
    if(!editwnd) {
        printf("Edit window not found");
        return;
    }
    for(c='1';c<='9';c++) {
        PostMessage(editwnd,WM_CHAR,c,1);
        Sleep(100);
    }
}




The difference between postmessage and sendmessage is that postmessage returns immediately while sendmessage waits until things finish processing.
Also in order to get the text in the editor you will also need to use GetWindowText to retrieve and change data
Another useful API would be GetWindowTextLength which would be needed to decide the string size for GetWindowText


example

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);



public static string GetText(IntPtr hWnd)
{
    // Allocate correct string length first
    int length       = GetWindowTextLength(hWnd);
    StringBuilder sb = new StringBuilder(length + 1);
    GetWindowText(hWnd, sb, sb.Capacity);
    return sb.ToString();
}




You can see how StringBuilder would be very useful for what you are trying to accomplish

This post has been edited by Toadill: 24 May 2012 - 07:48 AM

Was This Post Helpful? 1
  • +
  • -

#10 Ahmedn1  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 23
  • View blog
  • Posts: 556
  • Joined: 04-August 09

Re: Autocomplete anywhere

Posted 24 May 2012 - 08:38 AM

Toadill I know Spy++ tool
but the point is I don't want my app to work only for a specific app/window
I wanted it to be global
but now it seems to be not possible

Thanks for helping
Was This Post Helpful? 0
  • +
  • -

#11 Toadill  Icon User is offline

  • D.I.C Regular

Reputation: 45
  • View blog
  • Posts: 401
  • Joined: 08-January 12

Re: Autocomplete anywhere

Posted 24 May 2012 - 08:47 AM

This is what I was getting at you can build a program that excepts the most common types of editors, such as notepad, word, and all the rest but the applications are individual and with their own handles
one thing you could do that I have done in the past is allow the user to add the handles at run time and pass the values entered to findwindow. I did this by creating a .dat file that stored the handles they entered. I did this because the game server I was building tools for was constantly being changed and updated and there were many different version of the server therefore I added this feature so that I would not have to rebuild the program every time a new server came out. Instead I could just add the handles and captions of the new server and it would run just like it did before.

The way to make this work is to use variables in place of your constant handle and caption values this way when the user enters the information you can use that to hook the window.

Here is a video of it in action

Universal server launcher

Download

I just realized in the video I did not add this feature yet but if you download the program and hit the down arrow you can see the section where it says server version set it to custom and hit set then take a program you want to test it on and get its handle and caption and enter them in. this uses the API's to click a button rather then edit text but it does use the same functionality.

This post has been edited by Toadill: 24 May 2012 - 09:21 AM

Was This Post Helpful? 1
  • +
  • -

#12 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3551
  • View blog
  • Posts: 11,008
  • Joined: 05-May 12

Re: Autocomplete anywhere

Posted 24 May 2012 - 02:11 PM

View PostAhmedn1, on 24 May 2012 - 08:38 AM, said:

Toadill I know Spy++ tool
but the point is I don't want my app to work only for a specific app/window
I wanted it to be global
but now it seems to be not possible

Thanks for helping


Then use EnumWindows to enumerate through all the windows and find the windows you are interested in.

Or a brute force approach is to install a Windows hook. (Search Code Project if you think you want to go with this approach.)
Was This Post Helpful? 0
  • +
  • -

#13 Toadill  Icon User is offline

  • D.I.C Regular

Reputation: 45
  • View blog
  • Posts: 401
  • Joined: 08-January 12

Re: Autocomplete anywhere

Posted 29 May 2012 - 12:34 PM

Here is a C++ example that Skydiver and I came up with
This retrieves the data in a notepad

#include <iostream>
#include <Windows.h>
//Avoid unicode due to windows 7 problems
#define SendMessage SendMessageA


using namespace std;

int main()
{
	HWND Handle_NotePad = 0;
	HWND TextBox_ = 0;
	int messReturn = 0;
	const int MAXSIZE = 2048;
	char szBuf[MAXSIZE];
	 
	Handle_NotePad = FindWindow(TEXT("NotePad"),NULL);

	if (Handle_NotePad != 0)
	{
		cout << "Note Pad Hooked!" << endl;
		TextBox_ = FindWindowEx(Handle_NotePad, TextBox_, TEXT("Edit"), NULL);
	}
	else
	{
		cout << "Note Pad Not found" << endl;
	}

	if (TextBox_ != 0)
	{
		cout << "Text Pad Hooked!" << endl;
		messReturn = SendMessage(TextBox_, WM_GETTEXT, (WPARAM)(sizeof( szBuf ) / sizeof( szBuf[0] )), (LPARAM)szBuf );
	}
	else
	{
		cout << "Text Pad Not found" << endl;
	}

	for (int n = 0; n < MAXSIZE -1; n++)
	{
		cout << szBuf[n];
	}
	cout << endl;


	system("pause");
	return 0;
}


This post has been edited by Toadill: 29 May 2012 - 12:39 PM

Was This Post Helpful? 1
  • +
  • -

#14 Toadill  Icon User is offline

  • D.I.C Regular

Reputation: 45
  • View blog
  • Posts: 401
  • Joined: 08-January 12

Re: Autocomplete anywhere

Posted 29 May 2012 - 12:48 PM

My thoughts are you could retrieve any text that does not contain spaces(the last word typed) and compare it to the programs database or list of words(dictionary) finding the closest word to the spelling within your dictionary and displaying it on a label(could go as far as making a form invisible and placing a label on it so you can see the editor and the program, you would also need to to make your program stay on top). Once a word is select the user could press a programmed key to trigger replacement of the word being typed with the auto-complete word in the dictionary.

For example you type the letter "j" the letter "j" would be retrieved and compared. Now I add the letter "a" which gives me "ja" this would be retrieved and compared. Finally I type "m" and hit space therefore I have the word "jam" when space is hit the program should stop retrieving and comparing until another letter is pressed to save memory. Once a letter is pressed this process would start all over again.
Therefore each time a word is completed with autocomplete it should also add a space.

This post has been edited by Toadill: 29 May 2012 - 12:54 PM

Was This Post Helpful? 1
  • +
  • -

#15 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3551
  • View blog
  • Posts: 11,008
  • Joined: 05-May 12

Re: Autocomplete anywhere

Posted 29 May 2012 - 01:43 PM

Actually, it is not a Windows 7 problem, it's a Unicode/ANSI mismatch.

Here's is a more ANSI/UNICODE portable version:

#include <iostream>
#include <Windows.h>
#include <tchar.h>

using namespace std;

int _tmain()
{
	HWND hwndNotePad = FindWindow(_T("NotePad"), NULL);
	if (!hwndNotePad)
	{
		cout << "Note Pad Not found" << endl;
		return -1;
	}
	_tprintf(_T("NotePad Found!\n"));

	HWND hwndEdit = FindWindowEx(hwndNotePad, NULL, _T("Edit"), NULL);
	if (!hwndEdit)
	{
		cout << "Text Pad Not found" << endl;
		return -1;
	}
	_tprintf(_T("Edit Control Found!\n"));

	const int MAXSIZE = 2048;
	TCHAR szText[MAXSIZE];
	szText[0] = 0;

	const int cchMax = sizeof(szText) / sizeof(szText[0]);
	const int cchReturned = SendMessage(hwndEdit,
										WM_GETTEXT, 
										static_cast<WPARAM>(cchMax),
										reinterpret_cast<LPARAM>(szText));

	_tprintf(_T("SendMessage() returned %d chars for a buffer of size %d chars\n"), cchReturned, cchMax);
	_tprintf(_T("Buffer contents:\n%s\n"), szText);

	system("pause");
	return 0;
}


Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2