OSX:检测全系统键盘事件?
-
13-10-2019 - |
题
我正在为Mac OSX的打字器应用程序进行打字,该应用程序需要将键击向它转发到它,即使该应用程序不重视。
有没有办法通过NSDistributedNotificationCenter将系统转发到该应用程序?我已经谷歌搜索了自己很愚蠢的,但是找不到答案...
编辑: 下面的示例代码.
感谢@nsgod将我指向正确的方向 - 我最终添加了一个 全球事件监视器 使用该方法 addGlobalMonitorForEventsMatchingMask:handler:
, ,工作得很好。为了完整,我的实施看起来像这样:
// register for keys throughout the device...
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
handler:^(NSEvent *event){
NSString *chars = [[event characters] lowercaseString];
unichar character = [chars characterAtIndex:0];
NSLog(@"keydown globally! Which key? This key: %c", character);
}];
对我来说,棘手的部分是使用块,所以我会提供一些描述,以防万一它可以帮助任何人:
关于上述代码的要注意的是全部 一个方法调用 在nsevent上。该块是作为参数提供的,直接 至 功能。您可以想到这是一个内联代表方法。仅仅因为这花了一段时间才为我沉没,我将在这里逐步进行逐步进行:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
这是没有问题的。您正在调用NSEVENT上的类方法,并告诉您您要监视哪个事件,在这种情况下为NSKeyDownMask。一个 支持事件类型的面具列表 可以被找寻到 这里.
现在,我们来到了棘手的部分:Handler,期望一个障碍:
handler:^(NSEvent *event){
我花了一些编译错误才能正确解决这个问题,但是(谢谢Apple)它们是非常建设性的错误消息。首先要注意的是克拉 ^。这标志着块的开始。之后,在括号内,
NSEvent *event
它声明您将在块中使用的变量来捕获事件。你可以称呼它
NSEvent *someCustomNameForAnEvent
没关系,您只是在块中使用该名称。然后,这几乎就是它。确保关闭卷发支架,然后支架完成方法调用:
}];
你完成了!这确实是一个“单线”。在应用程序中执行此调用的何处都没关系 - 我在AppDelegate的ApplicationDidfinishLaunching方法中进行操作。然后,在块中,您可以在应用程序中调用其他方法。
解决方案
如果您对OS X 10.6+的最低要求还可以,并且可以使用“仅阅读”访问事件的访问,则可以在可可中安装全局事件监视器:可可活动处理指南:监视事件.
如果您需要支持OS X 10.5及更早的OS X,并且仅阅读访问是可以的,并且不介意与Carbon Event Manager合作,则基本上可以使用碳等于 GetEventMonitorTarget()
. 。 (虽然您很难找到有关该方法的任何(官方)文档)。我相信,该API首先在OS X 10.3中使用。
如果您需要对事件流进行阅读 - 写入访问,则需要查看稍低的API,该API是ApplicationsEvceServices> CoreGraphics的一部分:CGEventTapCreate()
和朋友。这首先在10.4中提供。
请注意,所有3种方法都将要求用户在系统首选项中启用启用辅助设备的访问权限>通用访问偏好窗格(至少对于关键事件)。
其他提示
我正在发布适合我案件的代码。
应用程序启动后,我将添加全球活动处理程序。我的快捷方式使CTRL+ALT+CMD+T打开我的应用程序。
- (void) applicationWillFinishLaunching:(NSNotification *)aNotification
{
// Register global key handler, passing a block as a callback function
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
handler:^(NSEvent *event){
// Activate app when pressing cmd+ctrl+alt+T
if([event modifierFlags] == 1835305 && [[event charactersIgnoringModifiers] compare:@"t"] == 0) {
[NSApp activateIgnoringOtherApps:YES];
}
}];
}
我发现的问题是,另一个应用程序在全球登记的任何密钥都不会被关注……或者至少在我的情况下,也许我做错了什么。
如果您的程序需要显示所有键,例如“ Command-Shift-3”,则不会看到它显示出来...因为它被OS占用。
还是有人弄清楚了?我很想知道...
正如NSGOD已经指出的那样,您也可以使用CoreGraphics。
在您的班级中(例如,Init):
CFRunLoopRef runloop = (CFRunLoopRef)CFRunLoopGetCurrent();
CGEventMask interestedEvents = NSKeyDown;
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
0, interestedEvents, myCGEventCallback, self);
// by passing self as last argument, you can later send events to this class instance
CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
eventTap, 0);
CFRunLoopAddSource((CFRunLoopRef)runloop, source, kCFRunLoopCommonModes);
CFRunLoopRun();
班级外,但在同一.m文件中:
CGEventRef myCGEventCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
if(type == NX_KEYDOWN)
{
// we convert our event into plain unicode
UniChar myUnichar[2];
UniCharCount actualLength;
UniCharCount outputLength = 1;
CGEventKeyboardGetUnicodeString(event, outputLength, &actualLength, myUnichar);
// do something with the key
NSLog(@"Character: %c", *myUnichar);
NSLog(@"Int Value: %i", *myUnichar);
// you can now also call your class instance with refcon
[(id)refcon sendUniChar:*myUnichar];
}
// send event to next application
return event;
}