#java #macos #jna
#java #macos #jna
Вопрос:
Я использовал библиотеку JNA для получения всех видимых дескрипторов окон в Windows. Мне нужно сделать что-то подобное в macOS с использованием JNA.
Вот код для получения всех дескрипторов окон в Windows:
public static List<HWND> findAll() {
final List<HWND> windows = new LinkedList<>();
User32.INSTANCE.EnumWindows(new User32.WNDENUMPROC() {
@Override
public boolean callback(HWND hWnd, Pointer arg) {
if (User32.INSTANCE.IsWindowVisible(hWnd)) {
windows.add(hWnd);
}
return true;
}
}, null);
return windows;
}
Какой эквивалентный код в macOS?
Ответ №1:
Вам нужно будет отобразить части Core Graphics Framework. Вы можете составить список окон, используя функцию CGWindowListCopyWindowInfo().
Для загрузки фреймворка вам нужно сопоставить CoreGraphics
интерфейс, расширяющий Library
класс JNA, и сопоставить нужную вам функцию:
public interface CoreGraphics extends Library {
CoreGraphics INSTANCE = Native.load("CoreGraphics", CoreGraphics.class);
CFArrayRef CGWindowListCopyWindowInfo(int option, int relativeToWindow);
}
CFArrayRef
Тип уже отображен в JNA в CoreFoundation
классе. Выберите соответствующий параметр списка окон (вероятно kCGWindowListOptionAll
, = 0). Если у вас уже был номер окна, вы могли бы использовать относительные ссылки, в противном случае вы будете использовать kCGNullWindowID
(0) для второго параметра. Вызов его из вашего кода должен быть простым:
CFArrayRef windowInfo = CoreGraphics.INSTANCE.CGWindowListCopyWindowInfo(0, 0);
Это даст вам массив CFDictionaryRef
объектов, представляющих окна. Вы можете выполнить итерацию массива, а затем использовать дополнительные методы в CFDictionaryRef
классе для изучения этих объектов словаря: вы создадите CFString
для ключей. Список обязательных ключей задокументирован здесь, а дополнительные ключи — здесь. Строки констант соответствуют имени переменной.
Это должно дать вам CFNumberRef
для каждого номера окна (эквивалент «дескриптора»):
// Set up keys for dictionary lookup
CFStringRef kCGWindowNumber = CFStringRef.createCFString("kCGWindowNumber");
CFStringRef kCGWindowOwnerPID = CFStringRef.createCFString("kCGWindowOwnerPID");
// Note: the Quartz name is rarely used
CFStringRef kCGWindowName = CFStringRef.createCFString("kCGWindowName");
CFStringRef kCGWindowOwnerName = CFStringRef.createCFString("kCGWindowOwnerName");
// Iterate the array
int numWindows = windowInfo.getCount();
for (int i = 0; i < numWindows; i ) {
// For each array element, get the dictionary
Pointer result = windowInfo.getValueAtIndex(i);
CFDictionaryRef windowRef = new CFDictionaryRef(result);
// Now get information from the dictionary.
// Get a pointer to the result, in this case a CFNumber
result = windowRef.getValue(kCGWindowNumber);
// "Cast" the pointer to the appropriate type
CFNumberRef windowNumber = new CFNumberRef(result);
// CoreFoundation.INSTANCE.CFNumberGetType(windowNumber)
// --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()
// Get a pointer to the result, in this case a CFNumber
result = windowRef.getValue(kCGWindowOwnerPID);
// "Cast" the pointer to the appropriate type
CFNumberRef windowOwnerPID = new CFNumberRef(result);
// CoreFoundation.INSTANCE.CFNumberGetType(windowOwnerPID)
// --> 4 = kCFNumberSInt64Type, signed 64 bit so use getLong()
// Get a pointer to the result, in this case a CFString
result = windowRef.getValue(kCGWindowName);
// "Cast" the pointer to the appropriate type
// Optional key, check for null
String windowName = result == null ? "" : new CFStringRef(result).stringValue();
// Get a pointer to the result, in this case a CFString
result = windowRef.getValue(kCGWindowOwnerName);
// "Cast" the pointer to the appropriate type
// Optional key, check for null
String windowOwnerName = result == null ? "" : new CFStringRef(result).stringValue();
// ... look up other keys if needed ...
// use ProcessHandle with the PID to get start time
// Output or add to List, etc.
System.out.println(windowNumber.longValue()
" (" windowOwnerName ", pid="
windowOwnerPID.longValue()
"): " windowName);
}
// CF references from "Copy" or "Create" must be released
// release the created key references
kCGWindowNumber.release();
kCGWindowOwnerPID.release();
kCGWindowName.release();
kCGWindowOwnerName.release();
// release the array
windowInfo.release();
Комментарии:
1. Как насчет CoreGraphics? CoreGraphics также есть в JNA?
2. Вы создадите свой собственный класс extending
Library
. Я включил синтаксис в свой ответ.3. Как я могу получить название окна (title), имя процесса, идентификатор процесса и время запуска процесса?
4. Название окна находится в этом информационном словаре с использованием ключа
kCGWindowName
. Имя процесса-владельца указано в ключеkCGWindowOwnerName
. Идентификатор процесса-владельца находится вkCGWindowOwnerPID
. Чтобы узнать время начала, вы должны использовать PID для полученияProcessHandle
в Java 9 .5. Спасибо за помощь и время .. Надеюсь, это сработает на mac @Daniel Widdis