Как получить глобальные экранные координаты текущего выделенного текста с помощью API доступности.

Мне нужна помощь, чтобы узнать, как приложение Dictionary показывает следующий всплывающий диалог для выбранного текста при нажатии CMD + CTRL + D на любом приложении. Я хочу реализовать такая же функциональность для моего приложения cocoa, где мое приложение будет работать в фоновом режиме и покажет предложения по нажатию какой-либо горячей клавиши для выбранного текста.

Dictionary app hot key suggestion dialog

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

Спасибо

Ответ 1

Для этого вы можете использовать API-интерфейсы доступности. Убедитесь, что установлен параметр "Включить доступ для вспомогательных устройств" (в разделе "Системные настройки/Универсальный доступ" ).

Следующий фрагмент кода определит границы (в координатах экрана) выбранного текста в большинстве приложений. К сожалению, он не работает в Mail и Safari, поскольку они используют атрибуты частной доступности. Вероятно, возможно, он также будет работать там, но для этого требуется больше работы и, возможно, частные вызовы API.

AXUIElementRef systemWideElement = AXUIElementCreateSystemWide();
AXUIElementRef focussedElement = NULL;
AXError error = AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute, (CFTypeRef *)&focussedElement);
if (error != kAXErrorSuccess) {
    NSLog(@"Could not get focussed element");
} else {
    AXValueRef selectedRangeValue = NULL;
    AXError getSelectedRangeError = AXUIElementCopyAttributeValue(focussedElement, kAXSelectedTextRangeAttribute, (CFTypeRef *)&selectedRangeValue);
    if (getSelectedRangeError == kAXErrorSuccess) {
        CFRange selectedRange;
        AXValueGetValue(selectedRangeValue, kAXValueCFRangeType, &selectedRange);
        AXValueRef selectionBoundsValue = NULL;
        AXError getSelectionBoundsError = AXUIElementCopyParameterizedAttributeValue(focussedElement, kAXBoundsForRangeParameterizedAttribute, selectedRangeValue, (CFTypeRef *)&selectionBoundsValue);
        CFRelease(selectedRangeValue);
        if (getSelectionBoundsError == kAXErrorSuccess) {
            CGRect selectionBounds;
            AXValueGetValue(selectionBoundsValue, kAXValueCGRectType, &selectionBounds);
            NSLog(@"Selection bounds: %@", NSStringFromRect(NSRectFromCGRect(selectionBounds)));
        } else {
            NSLog(@"Could not get bounds for selected range");
        }
        if (selectionBoundsValue != NULL) CFRelease(selectionBoundsValue);
    } else {
        NSLog(@"Could not get selected range");
    }
}
if (focussedElement != NULL) CFRelease(focussedElement);
CFRelease(systemWideElement);

Ответ 2

То, что вы ищете, это Сервис. С помощью сервисов ваше приложение даже не нужно запускать или захватывать глобальные горячие клавиши.

Например, функциональность описанного вами словарного приложения фактически является сервисом, наблюдаемым в меню "Службы".

Dictionary Service Menu

Apple Руководство по внедрению служб, вероятно, является лучшей информацией об услугах.