如何通过辅助功能 API 获取当前所选文本的全局屏幕坐标。

发布于 2024-11-17 18:55:48 字数 258 浏览 3 评论 0原文

我需要帮助来了解字典应用程序如何在任何应用程序上按 CMD+CTRL+D 时显示所选文本的以下弹出对话框。我想实施 我的可可应用程序具有相同的功能,我的应用程序将在后台运行,并显示有关所选文本的一些热键的建议。

词典应用热键建议对话框

我已经实现了热键捕获,我只需要有代码来获取矩形区域在屏幕上选择文本,这样我就可以像字典应用程序一样显示对话框。

谢谢

I need help to find out, how Dictionary app showing following popup dialog for selected text on pressing CMD+CTRL+D on any application. I want to implement
the same kind of functionality for my cocoa app, where my app will run in background and showing suggestions on some hot key press for the selected text.

Dictionary app hot key suggestion dialog

I have already implemented hot key capturing, i just need to have code to get the rectangle area of selected text on screen, so i can show the dialog like dictionary app.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

缪败 2024-11-24 18:55:48

您可以为此使用辅助功能 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);

You can use the accessibility APIs for that. Make sure that the "Enable access for assistive devices" setting is checked (in System Preferences / Universal Access).

The following code snippet will determine the bounds (in screen coordinates) of the selected text in most applications. Unfortunately, it doesn't work in Mail and Safari, because they use private accessibility attributes. It's probably possible to get it to work there as well, but it requires more work and possibly private API calls.

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);
桃扇骨 2024-11-24 18:55:48

在这里你可以用 Swift 获取 @omz 答案

let systemWideElement = AXUIElementCreateSystemWide()
var focusedElement : AnyObject?

let error = AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute as CFString, &focusedElement)
if (error != .success){
    print("Couldn't get the focused element. Probably a webkit application")
} else {
    var selectedRangeValue : AnyObject?
    let selectedRangeError = AXUIElementCopyAttributeValue(focusedElement as! AXUIElement, kAXSelectedTextRangeAttribute as CFString, &selectedRangeValue)
    if (selectedRangeError == .success){
        var selectedRange : CFRange?
        AXValueGetValue(selectedRangeValue as! AXValue, AXValueType(rawValue: kAXValueCFRangeType)!, &selectedRange)
        var selectRect = CGRect()
        var selectBounds : AnyObject?
        let selectedBoundsError = AXUIElementCopyParameterizedAttributeValue(focusedElement as! AXUIElement, kAXBoundsForRangeParameterizedAttribute as CFString, selectedRangeValue!, &selectBounds)
        if (selectedBoundsError == .success){
            AXValueGetValue(selectBounds as! AXValue, .cgRect, &selectRect)
            //do whatever you want with your selectRect
            print(selectRect)
        }
    }
}

Here you go for @omz answer in Swift

let systemWideElement = AXUIElementCreateSystemWide()
var focusedElement : AnyObject?

let error = AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute as CFString, &focusedElement)
if (error != .success){
    print("Couldn't get the focused element. Probably a webkit application")
} else {
    var selectedRangeValue : AnyObject?
    let selectedRangeError = AXUIElementCopyAttributeValue(focusedElement as! AXUIElement, kAXSelectedTextRangeAttribute as CFString, &selectedRangeValue)
    if (selectedRangeError == .success){
        var selectedRange : CFRange?
        AXValueGetValue(selectedRangeValue as! AXValue, AXValueType(rawValue: kAXValueCFRangeType)!, &selectedRange)
        var selectRect = CGRect()
        var selectBounds : AnyObject?
        let selectedBoundsError = AXUIElementCopyParameterizedAttributeValue(focusedElement as! AXUIElement, kAXBoundsForRangeParameterizedAttribute as CFString, selectedRangeValue!, &selectBounds)
        if (selectedBoundsError == .success){
            AXValueGetValue(selectBounds as! AXValue, .cgRect, &selectRect)
            //do whatever you want with your selectRect
            print(selectRect)
        }
    }
}
圈圈圆圆圈圈 2024-11-24 18:55:48

您正在寻找的是服务。
通过服务,您的应用程序甚至不必运行或捕获全局热键。

例如,您描述的词典应用程序的功能实际上是一项服务,可以在“服务”菜单中观察到。

词典服务菜单

Apple 的 服务实现指南可能是有关服务的最佳信息。

What you're looking for is a Service.
With services, your app doesn't even have to be running or capture global hotkeys.

For example, the functionality of the dictionary app you described is actually a service, observable in the Services menu.

Dictionary Service Menu

Apple's Service Implementation Guide is probably the best info on services out there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文