简体   繁体   English

可可事件水龙头

[英]Cocoa Event Taps

I'm trying to use Quartz Event Services, specifically event taps, on OS X to capture simulated key presses generated by a passive infrared sensor wired to a stripped keyboard PCB.我正在尝试在 OS X 上使用 Quartz 事件服务,特别是事件点击来捕获由连接到剥离键盘 PCB 的被动红外传感器生成的模拟按键。 Theoretically, with event taps I can choose to swallow and ignore the key presses and simply use the keyboard input to "wake" the computer.从理论上讲,通过事件点击,我可以选择吞下并忽略按键,只需使用键盘输入来“唤醒”计算机。 I can also use the event tap (only one "key" is wired so the motion detector always sends a "0") to modify the input to an arbitrary key or key combination that will, in turn, invoke arbitrary functionality on the host machine.我还可以使用事件点击(只连接一个“键”,因此运动检测器始终发送“0”)来修改任意键或组合键的输入,进而调用主机上的任意功能. To make things more complicated, the end host machine is an old G4 Powerbook (PPC) that can't really run anything beyond OS X 10.4, and my current development machine is a much newer Intel-based iMac running 10.9 and using Xcode 5.1.1.更复杂的是,最终主机是旧的 G4 Powerbook (PPC),它不能真正运行 OS X 10.4 以外的任何东西,而我目前的开发机器是运行 10.9 并使用 Xcode 5.1 的更新的基于 Intel 的 iMac。 1.

I found the following code from an answer here , and it seems like it would be perfect.我从这里的答案中找到了以下代码,看起来很完美。 If I create a terminal application in Cocoa, I can use the code basically as-is.如果我在 Cocoa 中创建一个终端应用程序,我基本上可以按原样使用代码。 I also tried creating a window-based Cocoa application in case this was necessary for adding the application to the list of Accessibility apps that can "control" the computer under the Security/Privacy Preferences (Enable Access for Assistive Devices is deprecated in Mavericks).我还尝试创建一个基于窗口的 Cocoa 应用程序,以防万一这是将应用程序添加到可以在安全/隐私首选项下“控制”计算机的辅助功能应用程序列表中所必需的(在 Mavericks 中不推荐使用“启用辅助设备访问”)。 Neither app-type worked completely.两种应用程序类型都不能完全正常工作。 The best I have been able to achieve is to get the program to recognize key presses of modifier keys (command, option, shift, ctl, etc), but I cannot get any response from key presses of "regular" keyboard keys, and I cannot seem to enact actually changing the captured key event.我能够实现的最好方法是让程序识别修饰键(命令、选项、shift、ctl 等)的按键,但是我无法从“常规”键盘键的按键中得到任何响应,并且我似乎无法实际更改捕获的关键事件。 Furthermore, it seems like mouse events, specifically,mouse clicks, register as KeyUp and KeyDown events - even if I change the event mask from 'AllEvents to just 'KeyUp or 'KeyDown.此外,似乎鼠标事件,特别是鼠标点击,注册为 KeyUp 和 KeyDown 事件——即使我将事件掩码从“AllEvents”更改为“KeyUp”或“KeyDown”。

Here is my slightly modified version of the original code that is adapted to try to conform to Xcode 5 conventions.这是我对原始代码稍加修改的版本,该版本适合尝试符合 Xcode 5 约定。 As you can see the heavy lifting is in the applicationDidFinishLaunching method rather than main() as in the original.正如您所看到的,繁重的工作在 applicationDidFinishLaunching 方法中,而不是在原始方法中的 main() 中。 Obviously, I had to create a method declaration in the AppDelegate.h file, which is also not part of the original code.显然,我必须在 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

At this point, I'm just trying to get something working on 10.9 as a proof of concept before I attempt to backport to 10.4 compatibility.在这一点上,在尝试向后移植到 10.4 兼容性之前,我只是想在 10.9 上做一些工作作为概念证明。 Sorry for the long post.抱歉,帖子太长了。 First time asking for help here and just trying to be thorough.第一次在这里寻求帮助,只是想做到彻底。 Thanks in advance for any and all responses!在此先感谢您的任何回复!

OK, so my quest for a solution lead me to this post on stack overflow.好的,所以我对解决方案的追求使我看到了这篇关于堆栈溢出的帖子。 Of particular interest is the following code highlighted there.特别有趣的是下面突出显示的代码。

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

This is part of a new API in 10.9 Mavericks.这是 10.9 Mavericks 中新 API 的一部分。 Adding this into the mix caused the Sys Pref/Deny prompt to appear and, ultimately, Xcode itself was added to the list, not the compiled app I was working on (this never crossed my mind).将此添加到组合中会导致出现 Sys Pref/Deny 提示,最终,Xcode 本身被添加到列表中,而不是我正在处理的已编译应用程序(这从来没有想过我)。 Even after commenting this code out, it still works, obviously since Xcode is now in the white list and this only needs to be done once.即使在注释掉这段代码之后,它仍然有效,很明显,因为 Xcode 现在在白名单中,这只需要做一次。 So the proof of concept is in the bag.所以概念证明就在袋子里。

It seems to be working on 10.4 too.它似乎也适用于 10.4。 There were several mistakes.有几个错误。 I'm not sure if this part was necessary, but I downloaded and installed Xcode 2.5 on the Powerbook and created and compiled the app directly on the host machine.我不确定这部分是否必要,但我在 Powerbook 上下载并安装了 Xcode 2.5,并直接在主机上创建和编译了应用程序。 Two issues seem to be related to constants.有两个问题似乎与常量有关。 The kCGEventTapOptionDefault constant from the CGEventTapCreate function (seems like it could just as easily have been a BOOL instead of a uINT) is not defined in the 10.4 framework headers so unless you change it to a 0 or 1 there will be errors.来自 CGEventTapCreate 函数的 kCGEventTapOptionDefault 常量(似乎它可以很容易地是一个 BOOL 而不是 uINT)在 10.4 框架头文件中没有定义,所以除非你将它更改为 0 或 1,否则会出现错误。 The same seems to apply to the kVC virtual key code constants which are defined in the Carbon headers on newer systems.这似乎同样适用于在较新系统上的 Carbon 头文件中定义的 kVC 虚拟键代码常量。 Instead, I just stuck with the hex values.相反,我只是坚持使用十六进制值。 Finally, drumroll please, don't make the mistake of trying to get Remote Desktop key presses to register as KeyUp or KeyDown events on the remote system.最后,请不要犯错误,试图让远程桌面按键在远程系统上注册为 KeyUp 或 KeyDown 事件。 It wasn't working so finally I had the bright idea of walking over to the G4 and plugging in a keyboard (G4 is bent in half backwards and hanging on the wall so, from the front, it looks like it's just an LCD mounted on the wall).它不起作用,所以最后我有了一个聪明的主意,走到 G4 并插入键盘(G4 向后弯成两半并挂在墙上,所以从前面看,它看起来只是一个安装在上面的 LCD墙)。 Voila.瞧。 Perfect.完美的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM