2

我正在尝试在 OS X 上使用 Quartz 事件服务,特别是事件点击来捕获由连接到剥离键盘 PCB 的无源红外传感器生成的模拟按键。从理论上讲,通过事件点击,我可以选择吞下并忽略按键,只需使用键盘输入来“唤醒”计算机。我还可以使用事件点击(仅连接一个“键”,因此运动检测器始终发送“0”)将输入修改为任意键或组合键,进而调用主机上的任意功能. 更复杂的是,最终主机是一台旧的 G4 Powerbook (PPC),它不能真正运行 OS X 10.4 以外的任何东西,而我目前的开发机器是一台更新的基于 Intel 的 iMac,运行 10.9 并使用 Xcode 5.1。 1.

我从这里的答案中找到了以下代码,而且看起来会很完美。如果我在 Cocoa 中创建一个终端应用程序,我基本上可以按原样使用代码。我还尝试创建一个基于窗口的 Cocoa 应用程序,以防有必要将应用程序添加到可在安全/隐私首选项下“控制”计算机的辅助功能应用程序列表(在小牛队中不推荐使用启用辅助设备访问)。两种应用程序类型都不能完全正常工作。我能做到的最好的事情是让程序识别修饰键(命令、选项、shift、ctl等)的按键,但是我无法从“常规”键盘键的按键中得到任何响应,而且我似乎无法制定实际更改捕获的关键事件。此外,它似乎是鼠标事件,特别是鼠标点击,

这是我对原始代码稍作修改的版本,它适用于尝试符合 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 上进行一些工作作为概念证明。对不起,很长的帖子。第一次在这里寻求帮助,只是想彻底。在此先感谢您的所有回复!

4

1 回答 1

2

好的,所以我对解决方案的追求导致我看到这篇关于堆栈溢出的帖子。特别感兴趣的是那里突出显示的以下代码。

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,否则将出现错误。这似乎同样适用于在较新系统上的 Carbon 标头中定义的 kVC 虚拟键代码常量。相反,我只是坚持使用十六进制值。最后,请不要错误地尝试让远程桌面按键注册为远程系统上的 KeyUp 或 KeyDown 事件。它不是 t 工作所以最后我想到了走到 G4 并插入键盘的好主意(G4 向后弯曲一半并挂在墙上,所以从前面看,它看起来只是一个安装在墙上的 LCD) . 瞧。完美的。

于 2014-08-12T18:47:41.777 回答