在Mojave上获取鼠标坐标

时间:2019-01-04 10:26:16

标签: macos cocoa macos-mojave

我有一个非常基本的小命令行应用程序,下次单击鼠标时会捕获鼠标坐标。

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    CGFloat displayScale = 1.0f;
    if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)])
    {
        displayScale = [NSScreen mainScreen].backingScaleFactor;
    }

    CGPoint loc = CGEventGetLocation(event);
    CFRelease(event);
    printf("%dx%d\n", (int)roundf(loc.x * displayScale), (int)roundf(loc.y * displayScale) );
    exit(0);
    return event;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        CFMachPortRef eventTap;
        CGEventMask eventMask;
        CFRunLoopSourceRef runLoopSource;
        eventMask = 1 << kCGEventLeftMouseDown;
        eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
                                    1, eventMask, myCGEventCallback, @"mydata");

        runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
                           kCFRunLoopCommonModes);
        CGEventTapEnable(eventTap, true);
        CFRunLoopRun();
    }
    return 0;
}

我正在使用带有以下文件的cmake进行构建:

cmake_minimum_required(VERSION 3.0.0)


project (location)

set(CMAKE_C_FLAGS "-arch x86_64 -mmacosx-version-min=10.12 -std=gnu11 -fobjc-arc -fmodules")

在升级到Mojave之前,一切正常。

仔细研究一下,可以看出这是最新的安全更新集,还有一些hints(除了CGEventTapCreate()不返回null)有关设置Info.plist中的某些值以允许该应用程序以使用可访问性API。但是,由于我只有一个带有代码的.m文件,因此我很难弄清楚将其放在哪里。

修改

  • 这需要以非root用户身份运行(公司政策)
  • 如果是获取许可的唯一途径,则可以将其扩展为具有最小UI的“ GUI”应用

此应用程序只是抓住屏幕区域的左上角,以馈送到第二个应用程序,该应用程序将屏幕的该区域流式传输到第二个设备。流媒体的代码在Win / Linux / MacOS上很常见,因此请尝试将屏幕坐标集合完全分开

2 个答案:

答案 0 :(得分:0)

在您猜测时,如果没有访问权限,事件水龙头将无法在Mojave上使用。来自documentation

  

如果满足以下任一条件,则事件点击会接收按键上升和按键下降事件   条件为true:当前进程以root用户身份运行。   启用辅助设备的访问权限。在OS X v10.4中,您可以启用   使用“系统偏好设置”,“通用访问”面板,   键盘视图。

GUI应用程序会在第一次需要时提示用户启用可访问性,但看起来CLI应用程序却没有这样做(这很有意义)。

无法以编程方式或通过脚本启用此功能;用户必须自己做。

root运行工具应该可以-您可以强制执行该操作吗?

否则,您可以将用户定向到“系统偏好设置”中的正确位置:

tell application "System Preferences"
    reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"
    activate
end tell

如果您的应用未沙箱化,则可以使用Carbon

最后,一个快速测试表明,至少使用IOHID可以做到这一点。我从此answer借用了KeyboardWatcher类。然后,修改设备类型:

[self watchDevicesOfType:kHIDUsage_GD_Keyboard];

进入:

[self watchDevicesOfType:kHIDUsage_GD_Mouse];

最后,我的回调如下:

static void Handle_DeviceEventCallback (void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef value)
{
    IOHIDElementRef element = IOHIDValueGetElement(value);
    IOHIDElementType elemType = IOHIDElementGetType(element);

    if (elemType == kIOHIDElementTypeInput_Button)
    {
        int elementValue = (int) IOHIDValueGetIntegerValue(value);
        // 1 == down 0 == up
        if (elementValue == 1)
        {
            CGEventRef ourEvent = CGEventCreate(NULL);
            CGPoint point = CGEventGetLocation(ourEvent);
            printf("Mouse Position: %.2f, y = %.2f \n", (float) point.x, (float) point.y);
        }
    }
}

这确实是一项快速的黑客工作,但它证明了这是可能的,并希望您可以根据需要对其进行完善。

答案 1 :(得分:0)

我发现CGEventTap文档从Mojave开始已经过时了。以root身份运行通常会绕过某些权利,但是在Mojave中,这种情况已得到严格处理。正如您所注意到的,一个奇怪的副作用是,根仍然可以获取水龙头的马赫数。只是无法从中读取任何事件。如果您在没有以root用户身份运行的情况下尝试应用程序,则应该出现预期的弹出窗口,以请求权限。

如果没有弹出窗口,或者出于其他目的需要以root用户身份运行,则可以通过SystemPreferences -> Security & Privacy -> Privacy -> Accessibility手动将应用程序添加到受信任的TCC数据库中

  

在Info.plist中设置一些值,以允许应用使用辅助功能API

我相信您的意思是添加权利(也是plist)。允许应用程序使用Accessibility API的权利为com.apple.private.tcc.allow权利(值为kTCCServiceAccessibility)。您可能会从名称中猜到它仅在Apple签名的二进制文件中被允许。

如果禁用系统完整性保护(SIP)并使用选项amfi_get_out_of_my_way=1引导内核,则可以将这些权利添加到自己的应用程序中,但我不建议这样做(当然,您的任何客户都不会这样做)不想)。在仅禁用SIP的情况下,您可以手动将条目添加到TCC数据库中以授予特权,但是仍然不建议这样做。

可能的选择

您可以使用事件监视器:

NSEventMask mask = (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask);
mouseEventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask: mask
                     handler:^(NSEvent *event){
                         // get the current coordinates with this
                         NSPoint coords = [NSEvent mouseLocation];
                         // event cooordinates would be event.absoluteX and event.absoluteY
                         ... do stuff
                     }];

文档中确实提到:

  

仅在启用辅助功能或信任您的应用程序可访问性的情况下,才可以监视与密钥相关的事件。(pXI)

但是我认为这不适用于鼠标事件。