Я использую CGEventTapCreate
"украсть" ключи медиа из iTunes, когда мое приложение работает. Код в обратном вызове, которому я передаю CGEventTapCreate
исследует событие, и если оно находит, что это - один из ключей медиа, отправляет соответствующее уведомление центру уведомления по умолчанию.
Теперь, это хорошо работает, если я отправляю уведомление для "настраивать" события. Если я делаю это для "ключа вниз" события, в конечном счете мое приложение прекращает получать ключевые события медиа, и iTunes вступает во владение. Какие-либо идеи о том, что может вызывать это? Соответствующая часть кода ниже
enum {
...
PlayPauseKeyDown = 0x100A00,
PlayPauseKeyUp = 0x100B00,
...
};
static CGEventRef event_tap_callback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
if (!(type == NX_SYSDEFINED) || (type == NX_KEYUP) || (type == NX_KEYDOWN))
return event;
NSEvent* keyEvent = [NSEvent eventWithCGEvent: event];
if (keyEvent.type != NSSystemDefined) return event;
switch(keyEvent.data1)
{
case PlayPauseKeyUp: // <--- this works reliably
//case PlayPauseKeyDown: // <--- this will break eventually
post_notification(@"PlayPauseMediaKeyPressed", nil, nil);
return NULL;
... and so on ...
Убивает ли что-то мое касание события, если обратный вызов занимает слишком много времени?
Некоторые люди подозревают, что в Snow Leopard есть ошибка, которая иногда отключает касания события, даже если они не занимают слишком много времени. Чтобы справиться с этим, вы можете следить за типом события kCGEventTapDisabledByTimeout
, и реагировать на него повторным включением тапа с помощью CGEventTapEnable
.
Прежде всего, почему ваше первое «если» разрешает прохождение событий нажатия и подъема ключа? Ваше второе «если» в любом случае пропускает только системные события. Итак, для всех событий нажатия / подъема вы создаете NSEvent, просто чтобы отбросить событие на одну строку ниже. В этом мало смысла. Обработка событий всегда должна выполняться как можно быстрее, в противном случае это замедлит всю обработку событий во всей системе. Ваш обратный вызов даже не должен вызываться для событий нажатия / -клавиши, поскольку системные события не являются событиями нажатия / -клавиши, они являются системными событиями. Если бы они были ключевыми событиями, вы бы наверняка никогда не получили доступ к data1, а вместо этого использовали бы методы «type» и «keyCode» для получения от них соответствующей информации.
static CGEventRef event_tap_callback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
NSEvent * sysEvent;
// No event we care for? return ASAP
if (type != NX_SYSDEFINED) return event;
sysEvent = [NSEvent eventWithCGEvent:event];
// No need to test event type, we know it is NSSystemDefined,
// becuase that is the same as NX_SYSDEFINED
Также вы не можете определить, является ли это событие правильным, просто взглянув на данные, вы также должны проверить подтип, который должен быть 8 для этого типа события:
if ([sysEvent subtype] != 8) return event;
Следующим логическим шагом является разделение данные в его компоненты:
int data = [sysEvent data1];
int keyCode = (data & 0xFFFF0000) >> 16;
int keyFlags = (data & 0xFFFF);
int keyState = (keyFlags & 0xFF00) >> 8;
BOOL keyIsRepeat = (keyFlags & 0x1) > 0;
И вы, вероятно, не заботитесь о повторении ключевых событий (то есть когда я держу клавишу нажатой, а она продолжает отправлять одно и то же событие снова и снова).
// You probably won't care for repeating events
if (keyIsRepeat) return event;
Наконец, вы не должны определять какие-либо собственные константы, система готова использовать константы для этих ключей:
// Analyze the key
switch (keyCode) {
case NX_KEYTYPE_PLAY:
// Play/Pause key
if (keyState == 0x0A) {
// Key down
// ...do your stuff here...
return NULL;
} else if (keyState == 0x0B) {
// Key Up
// ...do your stuff here...
return NULL;
}
// If neither down nor up, we don't know
// what it is and better ignore it
break;
case NX_KEYTYPE_FAST:
// (Fast) Forward
break;
case NX_KEYTYPE_REWIND:
// Rewind key
break;
}
// If we get here, we have not handled
// the event and want system to handle it
return event;
}
И если это все еще не работает, моим следующим вопросом будет то, как выглядит ваша функция post_notification, и видите ли вы также описанная проблема, если вы не вызываете там post_notification, а просто делаете вызов NSLog о событии, которое вы только что видели?