Как обрабатывать событие со стрелкой в ​​Cocoa приложении?

(Примечание к решению)

Как обрабатывать событие со стрелкой в ​​ Cocoa приложении?

Ответ 1

Смотрите этот код. Я предположил, что класс является подклассом NSView.

#pragma mark    -   NSResponder

- (void)keyDown:(NSEvent *)theEvent
{
    NSString*   const   character   =   [theEvent charactersIgnoringModifiers];
    unichar     const   code        =   [character characterAtIndex:0];

    switch (code) 
    {
        case NSUpArrowFunctionKey:
        {
            break;
        }
        case NSDownArrowFunctionKey:
        {
            break;
        }
        case NSLeftArrowFunctionKey:
        {
            [self navigateToPreviousImage];
            break;
        }
        case NSRightArrowFunctionKey:
        {
            [self navigateToNextImage];
            break;
        }
    }
}

Представление должно быть первым ответчиком для получения событий. Возможно, этот код будет необходим для поддержки этого.

#pragma mark    -   NSResponder
- (BOOL)canBecomeKeyView
{
    return  YES;
}
- (BOOL)acceptsFirstResponder
{
    return  YES;
}

Чтобы использовать этот метод, класс должен быть подклассом NSResponder. См. Другую обработку ответов без подкласса NSResponder.

Ответ 2

Но, но... но я не хочу быть подклассом NSResponder.

@interface AMonitorNotAResponder : NSObject 
@end

@implementation AMonitorNotAResponder
{
    id eventMonitor;   // An event monitor object; instance of
                       // private class _NSLocalEventObserver
}

- (id)init 
{
    self = [super init];
    if( !self ) return nil;

    NSEvent * (^monitorHandler)(NSEvent *);
    monitorHandler = ^NSEvent * (NSEvent * theEvent){

        switch ([theEvent keyCode]) {
            case 123:    // Left arrow
                NSLog(@"Left behind.");
                break;
            case 124:    // Right arrow
                NSLog(@"Right as always!");
                break;
            case 125:    // Down arrow
                NSLog(@"Downward is Heavenward");
                break;
            case 126:    // Up arrow
                NSLog(@"Up, up, and away!");
                break;
            default:
                break;
        }
        // Return the event, a new event, or, to stop 
        // the event from being dispatched, nil
        return theEvent;
    };

    // Creates an object we do not own, but must keep track
    // of so that it can be "removed" when we're done
    eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask 
                                                         handler:monitorHandler];

    return self;
}

- (void)dealloc 
{
    [NSEvent removeMonitor:eventMon];
}

@end

Руководство по обработке событий дает некоторые возможные варианты использования. Кажется, это дружественная Cocoa версия CGEventTap или способ обойти цепочку респондентов для определенной цели. Там ограниченный выбор типов событий, которые можно контролировать, например, только клавиши вниз, а не вверх. В docs есть список.

Также доступно: проверять события, поступающие в любое другое приложение (без возможности их изменения) с помощью addGlobalMonitorForEventsMatchingMask:handler:. Подобно событиям, этот метод требует включения доступности.

Ответ 3

В моем случае я хотел, чтобы представленный подкласс NSViewController мог прослушивать события со стрелкой для навигации с минимальными усилиями. Здесь лучшее решение, которое я нашел, небольшое изменение ответа Джоша Казуэлла.

Определить монитор событий (необязательно), может быть локально в подклассе NSViewController.m

id keyMonitor;

Затем запустите мониторинг событий, например, в viewDidLoad.

keyMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:^(NSEvent *event) {

    unichar character = [[event characters] characterAtIndex:0];
    switch (character) {
        case NSUpArrowFunctionKey:
            NSLog(@"Up");
            break;
        case NSDownArrowFunctionKey:
            NSLog(@"Down");
            break;
        case NSLeftArrowFunctionKey:
            NSLog(@"Left");
            break;
        case NSRightArrowFunctionKey:
            NSLog(@"Right");
            break;
        default:
            break;
    }
    return event;
}];

Чтобы удалить монитор, если это не требуется (если вы его определили)

[NSEvent removeMonitor:keyMonitor];