Я не могу напрямую дать вам решение, но я возился с некоторым кодом и, возможно, смогу указать вам правильное направление.
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