我有一个非常基本的小命令行应用程序,下次单击鼠标时会捕获鼠标坐标。
#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文件,因此我很难弄清楚将其放在哪里。
修改
此应用程序只是抓住屏幕区域的左上角,以馈送到第二个应用程序,该应用程序将屏幕的该区域流式传输到第二个设备。流媒体的代码在Win / Linux / MacOS上很常见,因此请尝试将屏幕坐标集合完全分开
答案 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)
但是我认为这不适用于鼠标事件。