写个小工具,需要用到键盘快捷键。但是我对于mac os 开发,目前来讲还是个小白。网上一番搜索,得到一些了解,到这里记录一下,便于后来者翻阅。
在mac os中,事件大概有以下几种方式可以捕获进行操作:
1.注册全局事件
2.事件监控回调函数
3.基于NSResponder的回调。
1.注册全局事件
不废话了,直接上代码。
1.使用的是Carbon库,所以需要项目导入Carbon库。
2.在某个地方调用注册代码
#import <Carbon/Carbon.h>
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[SomeClass addGlobalHotKey:kVK_ANSI_1];//注册数字按钮1
[SomeClass addGlobalHotKey:kVK_ANSI_2];//注册数字按钮2
[SomeClass addGlobalHotKey:kVK_ANSI_3];//注册数字按钮3
}
/**
* 添加全局的快捷键
**/
+(void)addGlobalHotKey:(NSInteger)keyCode{
EventHotKeyRef gMyHotKeyRef;
EventHotKeyID gMyHotKeyID;
EventTypeSpec eventType;
eventType.eventClass = kEventClassKeyboard;
eventType.eventKind = kEventHotKeyPressed;
InstallApplicationEventHandler(&GlobalHotKeyHandler,1,&eventType,NULL,NULL);
gMyHotKeyID.signature = 'abcdef';
gMyHotKeyID.id = keyCode;
RegisterEventHotKey(keyCode, 0, gMyHotKeyID,GetApplicationEventTarget(), 0, &gMyHotKeyRef);
// RegisterEventHotKey(keyCode, cmdKey+optionKey, gMyHotKeyID,GetApplicationEventTarget(), 0, &gMyHotKeyRef);
}
上面里面需要注意的:keyCode 是Carbon/HIToolbox/Events.h 文件里面定义好的键盘值,可以自己去看一下。
enum {
kVK_ANSI_A = 0x00,
kVK_ANSI_S = 0x01,
kVK_ANSI_D = 0x02,
kVK_ANSI_F = 0x03,
kVK_ANSI_H = 0x04,
kVK_ANSI_G = 0x05,
kVK_ANSI_Z = 0x06,
kVK_ANSI_X = 0x07,
kVK_ANSI_C = 0x08,
kVK_ANSI_V = 0x09,
kVK_ANSI_B = 0x0B,
kVK_ANSI_Q = 0x0C,
kVK_ANSI_W = 0x0D,
kVK_ANSI_E = 0x0E,
kVK_ANSI_R = 0x0F,
kVK_ANSI_Y = 0x10,
kVK_ANSI_T = 0x11,
kVK_ANSI_1 = 0x12,
kVK_ANSI_2 = 0x13,
kVK_ANSI_3 = 0x14,
kVK_ANSI_4 = 0x15,
kVK_ANSI_6 = 0x16,
kVK_ANSI_5 = 0x17,
kVK_ANSI_Equal = 0x18,
kVK_ANSI_9 = 0x19,
kVK_ANSI_7 = 0x1A,
kVK_ANSI_Minus = 0x1B,
kVK_ANSI_8 = 0x1C,
kVK_ANSI_0 = 0x1D,
kVK_ANSI_RightBracket = 0x1E,
kVK_ANSI_O = 0x1F,
kVK_ANSI_U = 0x20,
kVK_ANSI_LeftBracket = 0x21,
kVK_ANSI_I = 0x22,
kVK_ANSI_P = 0x23,
kVK_ANSI_L = 0x25,
kVK_ANSI_J = 0x26,
kVK_ANSI_Quote = 0x27,
kVK_ANSI_K = 0x28,
kVK_ANSI_Semicolon = 0x29,
kVK_ANSI_Backslash = 0x2A,
kVK_ANSI_Comma = 0x2B,
kVK_ANSI_Slash = 0x2C,
kVK_ANSI_N = 0x2D,
kVK_ANSI_M = 0x2E,
kVK_ANSI_Period = 0x2F,
kVK_ANSI_Grave = 0x32,
kVK_ANSI_KeypadDecimal = 0x41,
kVK_ANSI_KeypadMultiply = 0x43,
kVK_ANSI_KeypadPlus = 0x45,
kVK_ANSI_KeypadClear = 0x47,
kVK_ANSI_KeypadDivide = 0x4B,
kVK_ANSI_KeypadEnter = 0x4C,
kVK_ANSI_KeypadMinus = 0x4E,
kVK_ANSI_KeypadEquals = 0x51,
kVK_ANSI_Keypad0 = 0x52,
kVK_ANSI_Keypad1 = 0x53,
kVK_ANSI_Keypad2 = 0x54,
kVK_ANSI_Keypad3 = 0x55,
kVK_ANSI_Keypad4 = 0x56,
kVK_ANSI_Keypad5 = 0x57,
kVK_ANSI_Keypad6 = 0x58,
kVK_ANSI_Keypad7 = 0x59,
kVK_ANSI_Keypad8 = 0x5B,
kVK_ANSI_Keypad9 = 0x5C
};
如果是组合键需要在RegisterEventHotKey的第二个参数加cmdKey+optionKey 这样子。表示 cmdKey+optionKey+keyCode 键盘上3个按钮同时按下。
RegisterEventHotKey(keyCode, cmdKey+optionKey, gMyHotKeyID,GetApplicationEventTarget(), 0, &gMyHotKeyRef);
另外参数重需要传递一个回调函数过去,也就是InstallApplicationEventHandler这个方法的第一个参数&GlobalHotKeyHandler,所以我们要在文件前面申明这个回调函数。
OSStatus GlobalHotKeyHandler(EventHandlerCallRef nextHandler,EventRef theEvent,
void *userData)
{
EventHotKeyID hkCom;
GetEventParameter(theEvent,kEventParamDirectObject,typeEventHotKeyID,NULL,
sizeof(hkCom),NULL,&hkCom);
int l = hkCom.id;
switch (l) {
case kVK_ANSI_1: //do something
NSLog(@"kVK_ANSI_1按下");
break;
case kVK_ANSI_2:
NSLog(@"kVK_ANSI_2按下");
break;
case kVK_ANSI_3:
NSLog(@"kVK_ANSI_3按下");
break;
}
return noErr;
}
在对应的case里,可以发送全局通知,呼起业务逻辑。
2.事件监控回调函数
事件监控就是2个简单的函数:
+(void)addMonitorForEvent{
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged handler:^NSEvent * _Nullable(NSEvent * event) {
NSUInteger flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if (flags == NSEventModifierFlagCommand) {
// handle it
NSLog(@"NSCommandKeyMask");
}
NSLog(@"addLocalMonitorForEventsMatchingMask %@",event);
return event;
}];
[NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged handler:^(NSEvent *event){
NSUInteger flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
if (flags == NSEventModifierFlagCommand) {
// handle it
}
NSLog(@"addGlobalMonitorForEventsMatchingMask %@",event);
}];
}
如果app是激活状态按下cmd按钮,则会调用local方法。如果是在非激活状态按下,则会调用global方法。
这个addMonitorForEvent 也是可以在app加载的时候就直接初始化。
3.基于NSResponder的回调。
这个应该是最常用的快捷键了,就是重写view的NSResponder对应的事件函数,达到捕获按键事件处理的效果。
在自己的视图(NSView)上面直接写2个函数,如下:
//需要捕获command + 1234567890事件
- (void)keyDown:(NSEvent *)theEvent{
NSString *key = [theEvent charactersIgnoringModifiers];
if([self.numKeyStrArray containsObject:key]){
if([theEvent modifierFlags] & NSEventModifierFlagCommand){//command+num
[self pressNum:key];
}
}
[super keyDown:theEvent];
}
-(void)keyUp:(NSEvent *)theEvent {
}
-(void)pressNum:(NSString *)numStr{
NSLog(@" 按下 commnd + %@",numStr);
}
- (BOOL)acceptsFirstResponder{
return YES;
}
有补充的欢迎留言。