Java-поиск текстового поля на экране

Я пытаюсь создать программу, которая автоматически ищет текстовое поле на экране и повторно вводит слово в это текстовое поле. Есть ли класс, который может найти текстовое поле? Или есть способ найти текстовое поле? Поскольку я знаю, что класс Robot может набирать текст, мне просто нужно либо поместить курсор в текстовое поле, либо использовать методы mousePress() и mouseRelease().

Спасибо


person Bl H    schedule 02.08.2012    source источник
comment
Где находится текстовое поле. Это на веб-странице или в каком-то графическом интерфейсе на основе Java Swing.   -  person Ajay George    schedule 02.08.2012
comment
текстовое поле находится на веб-странице или как в операционной системе, текстовое поле — это любое возможное место, где вы можете печатать на экране   -  person Bl H    schedule 02.08.2012
comment
если это веб-страница, вы можете использовать селен, это действительно тестовая среда, но ее можно использовать для этого. Если это вариант, вы можете просто пропустить текстовое поле и все вместе и просто сделать запрос прямо на сервер, если это ваша цель.   -  person G-Man    schedule 02.08.2012
comment
Если текстовое поле находится в Java-программе, вам поможет abbot.sf.net.   -  person technomage    schedule 03.08.2012


Ответы (3)


Я не могу напрямую дать вам решение, но я возился с некоторым кодом и, возможно, смогу указать вам правильное направление.

Java, как вы, наверное, знаете, работает в JVM. Это позволяет выполнять его в любой операционной среде. Каждая операционная среда (Windows, Mac и т. д.) имеет свою собственную систему для обработки полей редактирования и установки фокуса на нужное окно и еще много чего. Следующий пример кода предназначен для использования только в Windows, что не соответствует духу языка Java. Как указал Адриан, для такого рода вещей существуют и другие языки, но МОЖНО (до некоторой степени) выполнить только с помощью Java.

В Windows вы должны понимать, как управляются все активные окна и что все, что вы видите (включая поля редактирования), рассматривается ОС Windows как «окно». Я действительно не понимаю, как все работает под капотом, поэтому я не могу предоставить гораздо больше информации, чем это. В родном языке, таком как C++, есть несколько функций, предоставляемых API ОС Windows, которые можно использовать для достижения вашей цели. А именно, EnumWindows(), EnumChildWindows(), GetClassName() и SetForegroundWindow(). Вы можете найти документацию о том, как использовать эти функции на родном языке, выполнив поиск в библиотеке документации MSDN.

Таким образом, вам НУЖНО иметь возможность вызывать эти функции из Java. В обычных условиях вызов этих собственных методов невозможен. Однако есть библиотека, которая поможет вам: библиотека JNA. JNA расшифровывается как Java Native Access и позволяет вам работать с блестящими новыми функциями, о которых я упоминал ранее.

Таким образом, чтобы достичь своей цели на родном языке, обычно нужно начинать с вызова toEnumWindows() для возврата списка всех родительских окон, о которых знает ОС. Этот список будет содержать дескрипторы родительских окон — окон с названиями «MSN», «Eclipse», «Microsoft Office» и т. д. Каждое из этих окон, как родитель, имеет дочерние элементы. Именно в этом списке дочерних элементов вы найдете «элемент управления», который ищете: элемент управления Edit. Теперь многие приложения используют разные библиотеки и нестандартные вещи для текстовых полей — например, Pidgin, приложение для обмена сообщениями, с которым я тестировал соответствующий код, имеет каждый элемент управления с именем «gdkWindowChild», который точно не говорит нам, какой элемент управления на самом деле является EditBox или в противном случае место, которое позволяет нам вводить текст. Это главная проблема с вашей идеей; вы не всегда можете точно сказать, на каком элементе управления вы хотите сфокусироваться, чтобы вы могли вводить текст. Несмотря ни на что, мы продолжим:

После нахождения соответствующего родительского окна с помощью EnumWindows() вызов EnumChildWindows() даст нам все подокна и другие «элементы управления» (включая потенциальные поля редактирования), принадлежащие родительскому. EnumChildWindows() вызывает функцию обратного вызова для каждого найденного подокна, поэтому довольно легко "выполнить поиск" по списку дочерних окон - используя GetClassName() для поиска имени элемента управления - потенциально найти HWND (дескриптор окна) элемента управления вы хотите.

После того, как вы нашли правильный HWND поля редактирования (это, конечно, является сложной частью, учитывая общий объем вашего вопроса), простой вызов SetForegroundWindow(targetHWND) должен вывести элемент управления на передний план и установить ваш курсор в готовом виде. поле ввода типа.

Вот некоторый рабочий пример кода, который я написал, чтобы вы начали. Этот код будет перебирать все активные окна, используя EnumWindows(), а затем вызывать EnumChildWindows() для каждого родителя, выводя все найденные элементы управления. Обратите внимание, что этот код требует запуска библиотеки JNA.

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.examples.win32.W32API.HWND;
import com.sun.jna.examples.win32.W32API.LPARAM;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;


public class IterateChildWindows {
    public interface User32 extends StdCallLibrary {
        User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);

        HWND FindWindow(String lpClassName, String lpWindowName);
        int GetWindowRect(HWND handle, int[] rect);
        int SendMessage(HWND hWnd, int msg, int wParam, byte[] lParam); 
        HWND FindWindowEx(HWND parent, HWND child, String className, String window);

        boolean EnumWindows(WNDENUMPROC lpEnumFunc, Pointer arg);
        boolean EnumChildWindows(HWND parent, WNDENUMPROC callback, LPARAM info);

        interface WNDENUMPROC extends StdCallCallback {
            boolean callback(HWND hWnd, Pointer arg);
        }

        int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);
        long GetWindowLong(HWND hWnd, int index);
        boolean SetForegroundWindow(HWND in);
        int GetClassNameA(HWND in, byte[] lpString, int size);
    }

    public static void main(String[] args) {        
        User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() {
            public boolean callback(HWND hWnd, Pointer userData) { // this will be called for each parent window found by EnumWindows(). the hWnd parameter is the HWND of the window that was found.
                byte[] textBuffer = new byte[512];
                User32.INSTANCE.GetWindowTextA(hWnd, textBuffer, 512);
                String wText = Native.toString(textBuffer);
                System.out.println("Window found: " + wText);

                // now call EnumChildWindows() giving the previously found parent window as the first parameter
                User32.INSTANCE.EnumChildWindows(hWnd, new User32.WNDENUMPROC() {
                    public boolean callback(HWND hWnd, Pointer userData) { // this is called for each child window that EnumChildWindows() finds - just like before with EnumWindows().
                        byte[] textBuffer = new byte[512];
                        User32.INSTANCE.GetClassNameA(hWnd, textBuffer, 512);
                        System.out.println(" - Found sub window / control class: " + new String(textBuffer).trim());
                        return true;
                    }
                }, null);
                return true;
            }
        }, null);
    }
}

Вот выдержка из вывода, предоставленного этим кодом:

Window found: Pidgin
 - Found sub window / control class: gdkWindowChild
 - Found sub window / control class: gdkWindowChild
 - Found sub window / control class: gdkWindowChild
 - Found sub window / control class: gdkWindowChild
Window found: Malwarebytes Anti-Malware
 - Found sub window / control class: Static
 - Found sub window / control class: Static
 - Found sub window / control class: Button
 - Found sub window / control class: Button
 - Found sub window / control class: Button

Отправка сообщений непосредственно в HWND элементов управления через PostMessage() и SendMessage(), например, в класс MalwareBytes Button, вызовет нажатие кнопки в самой программе, очень похоже на то, как SetForegroundWindow() должен выводить элемент управления в стиле поля редактирования на передний план, давая вы способность печатать. Интересный материал для игр :)

Если вы хотите визуализировать, что я имею в виду, когда говорю «родитель», «дети» и «контроль», вам может пригодиться эта программа: Управление просмотром. Он может показать вам каждый элемент управления и выделить его в окне приложения и многое другое - очень полезный инструмент.

Извините, если этот пост оставил зону комфорта, которую предоставляет java, но на самом деле нет другого способа достичь вашей цели в таком общем объеме.

Надеюсь, я хотя бы показал вам, что необходимо для достижения вашей цели, и направил вас в правильном направлении. Я не бог, когда дело доходит до нативных API Windows, поэтому я могу ошибаться в каком-то месте, однако код работает. Удачи :)

person Alex Lynch    schedule 02.08.2012
comment
Вы правы насчет зоны комфорта, я новичок в родном коде ОС Windows, который вы описали выше;) Я попробую, это должно быть весело, по крайней мере, я понимаю вашу методологию поиска поле редактирования. Спасибо. Однако, читая ваш код, где можно приобрести пакет com.sun.jna и остальные классы, показанные в примере кода? - person Bl H; 02.08.2012
comment
@BlH Я думаю, что JNA недавно обновила и устарела пакет примеров, поэтому вот файлы, которые я использую: dl.dropbox.com/u/13849688/jna.zip просто добавьте их в путь к классам, и пример должен работать. - person Alex Lynch; 02.08.2012

друг мой, класс Robot может имитировать написание текста.

private static void typeOut(String s,Robot bot)
{
try
{
char [] chars = s.toCharArray();
for (char c : chars) 
{
bot.keyPress((int)c);
bot.keyRelease((int)c);
}
}
catch (Exception e) 
{
System.out.println(e.getMessage());
}
}

и вы можете использовать этот метод

Robot bot=new Robot();    
typeOut("WWW.GOOGLE.COM", bot);

и если вы каким-либо образом хотите прочитать текст или написать текст в текстовое поле в браузере, я бы посоветовал вам использовать селен.

person tewari2312    schedule 28.12.2012