Слежение за развитием событий

Платформа AppKit позволяет Вам устанавливать монитор события, объект, ищущий события ввода данных пользователем определенного типа (или типы), поскольку приложение диспетчеризирует их в sendEvent: метод. Например, монитор мог искать мышь, ключ вниз, или события сильно-ударять-жеста, или даже все события.

Существует два вида мониторов события, каждый отличающийся по контролирующему объему и возможностям:

Параметры обоих методов установки монитора почти идентичны. Первый параметр является маской события для указания мероприятий типом. Второй параметр определяет блок, выполняющий обработку следивших за развитием событий; это вызывают для каждого нового события, соответствующего один из указанных типов. Для обоих методов, NSEvent объект является единственным параметром блока. Однако блочный обработчик для addLocalMonitorForEventsMatchingMask:handler: вводится для возврата NSEvent возразите в то время как блочный обработчик для возвратов глобального метода void. Обработчики всегда вызывают на основном потоке. Оба метода класса возвращают объект монитора, которым вызывающий объект не владеет (и таким образом не имеет никакой потребности сохранить или выпустить).

Существует много сценариев, где монитор события мог бы быть полезен для приложения. Одним примером является всплывающее окно, действующее как меню. Приложение хочет знать, когда пользователь щелкает за пределами того окна, таким образом, это может отклонить его. Это также хочет знать, нажимает ли пользователь Клавишу выхода (для отклонения его, не сохраняя изменения) или если пользователь нажимает клавишу Enter (чтобы отклонить его и сохранить изменения). Проект примера кода AnimatedTableView устанавливает локальный монитор события (в ATColorTableController.m) это выполняет эти функции. Перечисление 9-1 показывает, как оно делает это.

Перечисление 9-1  , Устанавливающее локальный монитор события

- (void)editColor:(NSColor *)color locatedAtScreenRect:(NSRect)rect {
 
    // code unrelated to event monitoring deleted here.....
 
    // Start watching events to figure out when to close the window
    NSAssert(_eventMonitor == nil, @"_eventMonitor should not be created yet");
    _eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:
            (NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | NSKeyDownMask)
            handler:^(NSEvent *incomingEvent) {
        NSEvent *result = incomingEvent;
        NSWindow *targetWindowForEvent = [incomingEvent window];
        if (targetWindowForEvent != _window) {
            [self _closeAndSendAction:NO];
        } else if ([incomingEvent type] == NSKeyDown) {
            if ([incomingEvent keyCode] == 53) {
                // Escape
                [self _closeAndSendAction:NO];
                result = nil; // Don't process the event
            } else if ([incomingEvent keyCode] == 36) {
                // Enter
                [self _closeAndSendAction:YES];
                result = nil;
            }
        }
        return result;
    }];
}

Когда окно закрывается, приложение больше не имеет потребности в мониторе события. Таким образом, это отправляет уведомление, когда это закрывает окно. Метод в Перечислении 9-2 вызывается в результате этого уведомления, и класс реализует его для удаления монитора события (среди прочего).

Перечисление 9-2  , Демонтирующее монитор события

- (void)_windowClosed:(NSNotification *)note {
    if (_eventMonitor) {
        [NSEvent removeMonitor:_eventMonitor];
        _eventMonitor = nil;
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:_window];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidResignActiveNotification object:nil];
}

Несмотря на то, что контроль события может быть идеальным решением для некоторых проблем, это не могло бы быть лучшим для других. Например, приложение AnimatedTableView устанавливает локальный монитор события, который может обнаружить события от нажатия мыши, отправленные в приложение, но не может обнаружить события от нажатия мыши, отправленные в другие приложения. Если пользователь щелкает в другом приложении, но приложение должно отклонить окно. Чтобы сделать это, AnimatedTableView наблюдает NSApplicationDidResignActiveNotification уведомление вместо того, чтобы установить глобальный монитор события. Глобальный монитор события не был бы в состоянии обнаружить Вкладку команды или системное предупреждение, оба из которых должны заставить окно быть отклоненным. Мониторы события должны использоваться только, когда нет никакого другого способа решить Вашу проблему.