IMKit捕获NSKeyup事件 [英] IMKit to catch NSKeyup event
问题描述
作为一个实验,我试图实现以下:
- 让空格键作为修饰键 - 其中按住空格键和打字键打印不同的字母。释放空格键会将状态恢复正常,只需按下它就像一个正常的空格键。
keydown和keyup事件,但在 handleEvent:client: /IMKServerInput_Additions/Reference/IMKServerInput.htmlAddions/Reference/IMKServerInput.html#//apple_ref/doc/uid/TP40006161-CH3-SW4rel =nofollow> IMKServerInput协议似乎只捕获键向下和鼠标事件。
没有太多的可可经验,我尝试了一些没有成功的方法:
- 技术说明2128 via互联网档案,这给了我合理的解释plist项目。
- 尝试向 recognizedEvents:添加NSKeyUpMask。 com / library / mac / documentation / Cocoa / Reference / IMKStateSetting_Protocol / Reference / IMKStateSetting_Ref.html#// apple_ref / doc / uid / TP40006159-CH3-DontLinkElementID_2rel =nofollow> IMKStateSetting Protocol ,似乎也捕获了该事件。
- 测试了 addLocalMonitorForEventsMatchingMask:handler:,但没有任何反应。
- 未能找到使用空格键来使
NSFlagsChanged
事件触发的方法。 - 阅读关于 Quartz Event Service 和
CGEventTap
这似乎处理较低级别的用户输入。 - IOHIDManager ?
我得出结论,IMKit只能的被动接收事件。
因为它不是一个应用程序,没有 keyUp:
方法覆盖 - AFAIK,IMKit不继承 NSResponder
class。
不幸的是,可可太宽泛了,对于像我这样的新手来说,
我试过全部可能的替代方案一个一个,并最终通过创建一个全局EventTap
与 CGEventTap
。
代码基本上看起来像这样:
//创建事件点击。
CGEventMask eventMask =((1 CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
0,
eventMask,
myCGEventCallback,
NULL);
if(!eventTap){
NSLog(@无法创建事件tap \\\
);
return NO;
} else {
//创建一个运行循环源。
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,eventTap,0);
//添加到当前运行循环。
CFRunLoopAddSource(CFRunLoopGetCurrent(),runLoopSource,kCFRunLoopCommonModes);
//启用事件点击。
CGEventTapEnable(eventTap,true);
return YES;
}
其中 myCGEventCallback
同时这里是我发现的一些:
- 根据键输入消息序列文档中,应用程序仅将链接事件传递到输入法工具包,之后尝试链中的其他堆处理程序。你不能让
IMKServerInput
'catch'NSKeyUp事件。只需向recognizedEvents:
添加NSKeyUpMask
就不起作用。 -
addLocalMonitorForEventsMatchingMask:handler:
和CGEventTapCreateForPSN
不会捕获事件。我想这是因为虽然输入法可能作为一个单独的进程运行,事件本身是从应用程序,像TextEdit,并移交给输入`方法。 - <$
- 创建一个全局EventTap需要运行具有sudo权限的进程 - 复制一个新的硬件设备和制作驱动程序。输入方法
/ Library /输入方法
不使用sudo权限运行,或将应用程序注册到辅助功能控件。这是在系统偏好→安全&隐私权&rarr隐私标签→辅助功能,在小牛。
As an experiment, I am trying to achieve the following:
- Let spacebar work as a modifier key - like the Shift key - where holding the spacebar key down and typing keys print different letters. Releasing the spacebar would set the state back to normal, and just pressing it behaves like a normal space key.
I was thinking of handling the keydown and keyup event, but apparently handleEvent:client:
in IMKServerInput Protocol seems to only catch key down and mouse events.
Without much experience with cocoa, I’ve tried some methods with no success:
- went through the Technical Note 2128 via internet archive, which gave me the suitable explanations of plist items. Still, nothing about keyup.
- tried adding NSKeyUpMask to
recognizedEvents:
in IMKStateSetting Protocol, but that didn’t seem to catch the event either. - tested a bit with addLocalMonitorForEventsMatchingMask:handler: but nothing happens.
- failed to find a way to make
NSFlagsChanged
event fire with spacebar. - read about Quartz Event Service and
CGEventTap
which seems to handle user inputs in lower level. Didn’t go further to this route, yet. - IOHIDManager?
I reached to a conclusion that IMKit is only capable of passively receiving events.
Since it is not an application, there is no keyUp:
method to override - AFAIK, IMKit does not inherit NSResponder
class.
Unfortunately cocoa is way too broad and has much less (or overflowed with non-helping) documentations for a novice like me to dive in.
Can anyone help me to the right direction?
I tried all possible alternatives one by one, and eventually achieved it by creating a global EventTap
with CGEventTap
.
The code basically looks like this:
// Create an event tap.
CGEventMask eventMask = ((1 << kCGEventKeyDown) | (1 << kCGEventKeyUp));
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
0,
eventMask,
myCGEventCallback,
NULL);
if (!eventTap) {
NSLog(@"failed to create event tap\n");
return NO;
} else {
// Create a run loop source.
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
// Add to the current run loop.
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
// Enable the event tap.
CGEventTapEnable(eventTap, true);
return YES;
}
where myCGEventCallback
handles the global states.
Meanwhile here are some of what I've found out:
- According to The Key-Input Message Sequence document, the application only passes the keydown event to the Input Method Kit, after trying other bunch of handlers in the chain. You cannot let
IMKServerInput
'catch' the NSKeyUp event. Just adding anNSKeyUpMask
torecognizedEvents:
would not work. addLocalMonitorForEventsMatchingMask:handler:
andCGEventTapCreateForPSN
would not catch the event. I suppose this is because though an Input Method may run as a separate process, the event itself is fired from the application, like TextEdit, and handed over to the Input `Method.IOHIDManager:
is for adding new hardware devices and making drivers.- Creating a global EventTap requires either running the process with sudo privilege -- copying the Input Method to
/Library/Input Methods
does not run with sudo privilege --, or registering the application to the Accessibility control. That's in System Preferences → Security & Privacy → Privacy tab → Accessibility, in Mavericks.
这篇关于IMKit捕获NSKeyup事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!