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

时间:2011-07-01 06:19:24

标签: objective-c cocoa screen accessibility selectedtext

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

Dictionary app hot key suggestion dialog

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

由于

3 个答案:

答案 0 :(得分:15)

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

答案 1 :(得分:1)

在这里您需要在Swift中获取@omz答案

import 'dart:async';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Setting BuildContext to null',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Setting BuildContext to null'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  AsyncClass _asyncClass = AsyncClass();
  Duration duration = const Duration(seconds: 5);
  void toggleContext(BuildContext context){
    Timer.periodic(duration, (_){
      print("Setting context to null");
      context = null;

    });
  }

  @override
  Widget build(BuildContext context) {
    toggleContext(context);
    _asyncClass.asyncFunc(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(),
    );
  }
}

class AsyncClass{
  void asyncFunc(BuildContext context){
    const duration = const Duration(seconds: 1);
    Timer.periodic(duration, (_){
      if(context==null){
        print("Context is null");
      } else {
        print("Context is not null");
      }

    });
  }
}

答案 2 :(得分:0)

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

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

Dictionary Service Menu

Apple的Service Implementation Guide可能是有关服务的最佳信息。