Слежение за развитием событий
Платформа AppKit позволяет Вам устанавливать монитор события, объект, ищущий события ввода данных пользователем определенного типа (или типы), поскольку приложение диспетчеризирует их в sendEvent:
метод. Например, монитор мог искать мышь, ключ вниз, или события сильно-ударять-жеста, или даже все события.
Существует два вида мониторов события, каждый отличающийся по контролирующему объему и возможностям:
Глобальный монитор события ищет события ввода данных пользователем, диспетчеризированные приложениям кроме того, в котором он установлен. Монитор не может изменить событие или предотвратить его нормальную поставку. И это может только следить за развитием ключевых событий, если доступность включена или если приложению доверяют для доступности.
Вы устанавливаете глобальный монитор события с
NSEvent
метод классаaddGlobalMonitorForEventsMatchingMask:handler:
.Локальное событие контролирует взгляды на события ввода данных пользователем, диспетчеризирующиеся приложению, в котором установлен монитор. Для данного объекта-события интереса локальный монитор может возвратить неизмененный объект, создать и возвратить новое
NSEvent
объект или возвратnil
остановить диспетчеризацию события.Вы устанавливаете локальный монитор события с
NSEvent
метод классаaddLocalMonitorForEventsMatchingMask:handler:
.
Параметры обоих методов установки монитора почти идентичны. Первый параметр является маской события для указания мероприятий типом. Второй параметр определяет блок, выполняющий обработку следивших за развитием событий; это вызывают для каждого нового события, соответствующего один из указанных типов. Для обоих методов, 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
уведомление вместо того, чтобы установить глобальный монитор события. Глобальный монитор события не был бы в состоянии обнаружить Вкладку команды или системное предупреждение, оба из которых должны заставить окно быть отклоненным. Мониторы события должны использоваться только, когда нет никакого другого способа решить Вашу проблему.