可可事件点击

时间:2014-08-11 09:43:42

标签: objective-c macos cocoa core-graphics cgeventtap

我正在尝试在OS X上使用Quartz Event Services,特别是事件点击来捕获由连接到剥离键盘PCB的被动红外传感器生成的模拟按键。从理论上讲,通过事件点击,我可以选择吞下并忽略按键操作,只需使用键盘输入“唤醒”计算机即可。我也可以使用事件点击(只有一个“键”接线,因此运动检测器总是发送“0”)来修改任意键或键组合的输入,这将反过来调用主机上的任意功能。为了使事情变得更复杂,终端主机是旧的G4 Powerbook(PPC),除了OS X 10.4之外无法真正运行任何东西,而我当前的开发机器是一个更新的基于Intel的iMac,运行10.9并使用Xcode 5.1。 1。

我从答案here找到了以下代码,看起来它会很完美。如果我在Cocoa中创建一个终端应用程序,我可以基本按原样使用代码。我还尝试创建一个基于窗口的Cocoa应用程序,以防将此应用程序添加到可以在安全/隐私首选项下“控制”计算机的辅助功能应用程序列表(在小牛队中不推荐启用辅助设备访问)。 app-type都没有完全运作。我能够实现的最好的方法是让程序识别按键修改键(命令,选项,移位,ctl等),但我无法通过按键“常规”键盘键获得任何响应,而我似乎无法实际改变捕获的键事件。此外,似乎鼠标事件,特别是鼠标点击,注册为KeyUp和KeyDown事件 - 即使我将事件掩码从'AllEvents更改为'KeyUp或'KeyDown。

这是我原始代码的略微修改版本,适用于尝试符合Xcode 5约定。正如您所看到的那样,繁重的工作在applicationDidFinishLaunching方法中,而不是原始的main()。显然,我必须在AppDelegate.h文件中创建一个方法声明,它也不是原始代码的一部分。

#import "AppDelegate.h"
#import <Cocoa/Cocoa.h>
#import <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>


@implementation AppDelegate

CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    NSLog(@"In the callback");
    //0x0b is the virtual keycode for "b"
    //0x09 is the virtual keycode for "v"
    if ((type != kCGEventKeyDown) && (type != kCGEventKeyUp))
        NSLog(@"event: %@", event);
    if (CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == kVK_ANSI_S) {
        NSLog(@"event matched");
        CGEventSetIntegerValueField(event, kCGKeyboardEventKeycode, kVK_ANSI_1);
    }

    return event;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSLog(@"Hello?");

    CFRunLoopSourceRef runLoopSource;

    CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventMaskForAllEvents, myCGEventCallback, NULL);

    if (!eventTap) {
        NSLog(@"Couldn't create event tap!");
        exit(1);
    }

    runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

    CGEventTapEnable(eventTap, true);

    CFRunLoopRun();

    CFRelease(eventTap);
    CFRelease(runLoopSource);

    NSLog(@"goodbye");
}

@end

此时,在我尝试向后兼容到10.4兼容性之前,我只是试图将10.9上的某些东西作为概念验证。对不起,很长的帖子。第一次在这里寻求帮助,并试图彻底。提前感谢任何和所有回复!

1 个答案:

答案 0 :(得分:2)

好的,所以我对解决方案的追求导致我发现堆栈溢出this。特别感兴趣的是以下代码突出显示。

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);

这是10.9 Mavericks中新API的一部分。将它添加到混合中导致出现Sys Pref / Deny提示符,最终,Xcode本身被添加到列表中,而不是我正在处理的已编译应用程序(这从未让我想到)。即使在对此代码进行评论之后,它仍然有效,显然因为Xcode现在位于白名单中,所以这只需要完成一次。所以概念验证就在其中。

它似乎也在10.4上工作。有几个错误。我不确定这部分是否必要,但是我在Powerbook上下载并安装了Xcode 2.5,并直接在主机上创建和编译了应用程序。两个问题似乎与常数有关。来自CGEventTapCreate函数的kCGEventTapOptionDefault常量(似乎它可以很容易地是BOOL而不是uINT)在10.4框架头文件中没有定义,所以除非你将它改为0或1,否则会有错误。这似乎适用于在较新系统上的碳标头中定义的kVC虚拟键代码常量。相反,我只是坚持使用十六进制值。最后,请鼓励,不要试图让远程桌面按键在远程系统上注册为KeyUp或KeyDown事件。它没有工作,所以最后我有一个明智的想法,走到G4并插入一个键盘(G4向后弯曲一半并挂在墙上,所以,从前面看,它只是一个液晶显示器安装在墙)。瞧。完美。