Objective c 如何在MacBook键盘上轻触(挂钩)F7至F12并开机/弹出
这个问题源自 到目前为止,我可以使用以下方法轻触修改器键和大多数其他键:Objective c 如何在MacBook键盘上轻触(挂钩)F7至F12并开机/弹出,objective-c,macos,keyboard-events,tap,Objective C,Macos,Keyboard Events,Tap,这个问题源自 到目前为止,我可以使用以下方法轻触修改器键和大多数其他键: _eventTap = CGEventTapCreate( kCGHIDEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, CGEven
_eventTap = CGEventTapCreate( kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit( kCGEventKeyDown )
| CGEventMaskBit( kCGEventFlagsChanged )
,
(CGEventTapCallBack)_tapCallback,
(__bridge void *)(self));
值得注意的是,F3
在采取行动之前正确报告一个键码(160)。i、 我可以通过让我的事件处理程序返回NULL(从而无法传播事件)来禁用该操作
但是,F7到F12和弹出/启动不会触发回调
如果我加上:
| CGEventMaskBit( NSSystemDefined )
。。。现在剩下的Fx键确实触发了回调(尽管Power/Eject仍然没有),但我无法访问事件的keyCode方法
它会产生一个错误:
2015-05-21 12:30:02.044 tap_k[16532:698660]NSSystemDefined:0
2015-05-21 12:30:02.044 tap_k[16532:698660]*在中的断言失败
-[NSEvent keyCode],/SourceCache/AppKit/AppKit-1347.57/AppKit.subproj/NSEvent.m:2471
2015-05-21 12:30:02.045由于以下原因终止应用程序:
未捕获异常“NSInternalInconsistencyException”,原因:
“发送到事件”NSEvent:type=SysDefined loc=(882687)的“无效消息”
时间=118943.3标志=0 win=0x0 winNum=0 ctxt=0x0子类型=8 data1=2560
数据2=-1“'
所以要么:(1) 我需要从NSEvent中提取某些唯一标识符的其他方法,或
(2) 我需要在一个较低的层次上轻敲/钩住 使用(1)时,我注意到NSEvent有一个data1属性。以十六进制记录这一点可以提供:
2015-05-21 12:40:05.428 tap_k[16576:704298] NSSystemDefined: 140b00
2015-05-21 12:40:06.914 tap_k[16576:704298] NSSystemDefined: 100a00
2015-05-21 12:40:06.992 tap_k[16576:704298] NSSystemDefined: 100b00
2015-05-21 12:40:07.600 tap_k[16576:704298] NSSystemDefined: 130a00
2015-05-21 12:40:07.690 tap_k[16576:704298] NSSystemDefined: 130b00
2015-05-21 12:40:08.219 tap_k[16576:704298] NSSystemDefined: 70a00
2015-05-21 12:40:08.277 tap_k[16576:704298] NSSystemDefined: 70b00
2015-05-21 12:40:09.062 tap_k[16576:704298] NSSystemDefined: 10a00
2015-05-21 12:40:09.186 tap_k[16576:704298] NSSystemDefined: 10b00
2015-05-21 12:40:09.637 tap_k[16576:704298] NSSystemDefined: a00
2015-05-21 12:40:09.726 tap_k[16576:704298] NSSystemDefined: b00
。。当我按下/按下F6 F7 F8 F9 F10 F11 F12键时
(此外,对于重复,最后一个值更改为1)
所以我想我可以只吃带有这些值的事件,然后传递其他NSSystemDefined事件
它仍然不能解决捕获弹出/电源的问题
但是有没有更干净/更好的方法
如果有人有兴趣玩,以下是完整的代码:
// compile and run from the commandline with:
// clang -fobjc-arc -framework Cocoa ./foo.m -o foo
// sudo ./foo
#import <Foundation/Foundation.h>
#import <AppKit/NSEvent.h>
typedef CFMachPortRef EventTap;
// - - - - - - - - - - - - - - - - - - - - -
@interface KeyChanger : NSObject
{
@private
EventTap _eventTap;
CFRunLoopSourceRef _runLoopSource;
CGEventRef _lastEvent;
}
@end
// - - - - - - - - - - - - - - - - - - - - -
CGEventRef _tapCallback(
CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
KeyChanger* listener
);
// - - - - - - - - - - - - - - - - - - - - -
@implementation KeyChanger
- (BOOL)tapEvents
{
if (!_eventTap) {
NSLog(@"Initializing an event tap.");
// kCGHeadInsertEventTap -- new event tap should be inserted before any pre-existing event taps at the same location,
_eventTap = CGEventTapCreate( kCGHIDEventTap, // kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit( kCGEventKeyDown )
| CGEventMaskBit( kCGEventFlagsChanged )
| CGEventMaskBit( NSSystemDefined )
,
(CGEventTapCallBack)_tapCallback,
(__bridge void *)(self));
if (!_eventTap) {
NSLog(@"unable to create event tap. must run as root or "
"add privlidges for assistive devices to this app.");
return NO;
}
}
CGEventTapEnable(_eventTap, TRUE);
return [self isTapActive];
}
- (BOOL)isTapActive
{
return CGEventTapIsEnabled(_eventTap);
}
- (void)listen
{
if( ! _runLoopSource ) {
if( _eventTap ) { //dont use [self tapActive]
_runLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault,
_eventTap, 0);
// Add to the current run loop.
CFRunLoopAddSource( CFRunLoopGetCurrent(), _runLoopSource,
kCFRunLoopCommonModes);
NSLog(@"Registering event tap as run loop source.");
CFRunLoopRun();
}else{
NSLog(@"No Event tap in place! You will need to call "
"listen after tapEvents to get events.");
}
}
}
- (CGEventRef)processEvent:(CGEventRef)cgEvent
{
NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
NSUInteger modifiers = [event modifierFlags] &
(NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask);
enum {
kVK_ANSI_3 = 0x14,
};
switch( event.type ) {
case NSFlagsChanged:
NSLog(@"NSFlagsChanged: %d", event.keyCode);
break;
case NSSystemDefined:
NSLog(@"NSSystemDefined: %x", event.data1);
return NULL;
case kCGEventKeyDown:
NSLog(@"KeyDown: %d", event.keyCode);
break;
default:
NSLog(@"WTF");
}
// TODO: add other cases and do proper handling of case
if (
//[event.characters caseInsensitiveCompare:@"3"] == NSOrderedSame
event.keyCode == kVK_ANSI_3
&& modifiers == NSShiftKeyMask
)
{
NSLog(@"Got SHIFT+3");
event = [NSEvent keyEventWithType: event.type
location: NSZeroPoint
modifierFlags: event.modifierFlags & ! NSShiftKeyMask
timestamp: event.timestamp
windowNumber: event.windowNumber
context: event.context
characters: @"#"
charactersIgnoringModifiers: @"#"
isARepeat: event.isARepeat
keyCode: event.keyCode];
}
_lastEvent = [event CGEvent];
CFRetain(_lastEvent); // must retain the event. will be released by the system
return _lastEvent;
}
- (void)dealloc
{
if( _runLoopSource ) {
CFRunLoopRemoveSource( CFRunLoopGetCurrent(), _runLoopSource, kCFRunLoopCommonModes );
CFRelease( _runLoopSource );
}
if( _eventTap ) {
//kill the event tap
CGEventTapEnable( _eventTap, FALSE );
CFRelease( _eventTap );
}
}
@end
// - - - - - - - - - - - - - - - - - - - - -
CGEventRef _tapCallback(
CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
KeyChanger* listener
)
{
//Do not make the NSEvent here.
//NSEvent will throw an exception if we try to make an event from the tap timout type
@autoreleasepool {
if( type == kCGEventTapDisabledByTimeout ) {
NSLog(@"event tap has timed out, re-enabling tap");
[listener tapEvents];
return nil;
}
if( type != kCGEventTapDisabledByUserInput ) {
return [listener processEvent:event];
}
}
return event;
}
// - - - - - - - - - - - - - - - - - - - - -
int main(int argc, const char * argv[])
{
@autoreleasepool {
KeyChanger* keyChanger = [KeyChanger new];
[keyChanger tapEvents];
[keyChanger listen];//blocking call.
}
return 0;
}
//使用以下命令行编译和运行:
//叮当声-fobjc弧-framework-Cocoa./foo.m-o foo
//sudo./foo
#进口
#进口
typedef CFMachPortRef EventTap;
// - - - - - - - - - - - - - - - - - - - - -
@接口密钥转换器:NSObject
{
@私人的
事件点击(EventTap);
CFRunLoopSourceRef\u runLoopSource;
CGEventRef_lastEvent;
}
@结束
// - - - - - - - - - - - - - - - - - - - - -
CGEventRef\u tapCallback(
CGEventTapProxy代理,
CGEventType类型,
CGEventRef事件,
换键器*监听器
);
// - - - - - - - - - - - - - - - - - - - - -
@键盘转换器的实现
-(BOOL)tapEvents
{
如果(!\u事件点击){
NSLog(@“初始化事件点击”);
//kCGHeadInsertEventTap——应在同一位置的任何预先存在的事件抽头之前插入新的事件抽头,
_eventTap=CGEventTapCreate(kCGHIDEventTap,//kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown)
|CGEventMaskBit(kCGEventFlagsChanged)
|CGEventMaskBit(NSSystemDefined)
,
(CGEventTapCallBack)\ u tapCallback,
(uu桥空*)(自));
如果(!\u事件点击){
NSLog(@“无法创建事件跟踪。必须以root或”
“将辅助设备的权限添加到此应用程序。”);
返回否;
}
}
cgEventTapeEnable(_eventTap,TRUE);
返回[自激活];
}
-(BOOL)ISTActive
{
返回CGEventTapIsEnabled(_eventTap);
}
-(空)听
{
if(!\u runLoopSource){
如果(_eventTap){//不使用[self-tappactive]
_runLoopSource=CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
_eventTap,0);
//添加到当前运行循环。
CFRunLoopAddSource(CFRunLoopGetCurrent(),_runLoopSource,
KCFRUNLOP模式);
NSLog(@“将事件点击注册为运行循环源”);
CFRunLoopRun();
}否则{
NSLog(@“无事件点击到位!您需要呼叫”
“在磁带事件之后收听以获取事件。”);
}
}
}
-(CGEventRef)processEvent:(CGEventRef)cgEvent
{
NSEvent*event=[NSEvent eventWithCGEvent:cgEvent];
NSU整数修饰符=[event modifierFlags]&
(NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask);
枚举{
kVK_ANSI_3=0x14,
};
开关(event.type){
案件编号:
NSLog(@“NSFlagsChanged:%d”,event.keyCode);
打破
案例定义:
NSLog(@“NSSystemDefined:%x”,事件数据1);
返回NULL;
案例kCGEventKeyDown:
NSLog(@“KeyDown:%d”,event.keyCode);
打破
违约:
NSLog(“WTF”);
}
//TODO:添加其他案例并正确处理案例
如果(
//[event.characters caseInsensitiveCompare:@“3”]==传感器名称
event.keyCode==kVK_ANSI_3
&&修饰符==NSSHIFTKEYSMASK
)
{
NSLog(@“获得班次+3”);
event=[NSEvent keyEventWithType:event.type
地点:NSZeroPoint
modifierFlags:event.modifierFlags&!NSShiftKeyMask
timestamp:event.timestamp
windowNumber:event.windowNumber
上下文:event.context
字符:@“#”
CharacterSigningModifiers:@“#”
isARepeat:event.isARepeat
keyCode:event.keyCode];
}
_拉斯蒂夫
// compile and run from the commandline with:
// clang -framework coreFoundation -framework IOKit ./HID.c -o hid
// sudo ./hid
// This code works with the IOHID library to get notified of keys.
// Still haven't figured out how to truly intercept with
// substitution.
#include <IOKit/hid/IOHIDValue.h>
#include <IOKit/hid/IOHIDManager.h>
void myHIDKeyboardCallback( void* context, IOReturn result, void* sender, IOHIDValueRef value )
{
IOHIDElementRef elem = IOHIDValueGetElement( value );
if (IOHIDElementGetUsagePage(elem) != 0x07)
return;
uint32_t scancode = IOHIDElementGetUsage( elem );
if (scancode < 4 || scancode > 231)
return;
long pressed = IOHIDValueGetIntegerValue( value );
printf( "scancode: %d, pressed: %ld\n", scancode, pressed );
}
CFMutableDictionaryRef myCreateDeviceMatchingDictionary( UInt32 usagePage, UInt32 usage )
{
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0
, & kCFTypeDictionaryKeyCallBacks
, & kCFTypeDictionaryValueCallBacks );
if ( ! dict )
return NULL;
CFNumberRef pageNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, & usagePage );
if ( ! pageNumberRef ) {
CFRelease( dict );
return NULL;
}
CFDictionarySetValue( dict, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef );
CFRelease( pageNumberRef );
CFNumberRef usageNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, & usage );
if ( ! usageNumberRef ) {
CFRelease( dict );
return NULL;
}
CFDictionarySetValue( dict, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef );
CFRelease( usageNumberRef );
return dict;
}
int main(void)
{
IOHIDManagerRef hidManager = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone );
CFArrayRef matches;
{
CFMutableDictionaryRef keyboard = myCreateDeviceMatchingDictionary( 0x01, 6 );
CFMutableDictionaryRef keypad = myCreateDeviceMatchingDictionary( 0x01, 7 );
CFMutableDictionaryRef matchesList[] = { keyboard, keypad };
matches = CFArrayCreate( kCFAllocatorDefault, (const void **)matchesList, 2, NULL );
}
IOHIDManagerSetDeviceMatchingMultiple( hidManager, matches );
IOHIDManagerRegisterInputValueCallback( hidManager, myHIDKeyboardCallback, NULL );
IOHIDManagerScheduleWithRunLoop( hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode );
IOHIDManagerOpen( hidManager, kIOHIDOptionsTypeNone );
CFRunLoopRun(); // spins
}