CGEventTapCreate ломает загадочно с “ключом вниз” события

Я использую 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 ...
6
задан svintus 3 June 2010 в 19:27
поделиться

2 ответа

Убивает ли что-то мое касание события, если обратный вызов занимает слишком много времени?

Некоторые люди подозревают, что в Snow Leopard есть ошибка, которая иногда отключает касания события, даже если они не занимают слишком много времени. Чтобы справиться с этим, вы можете следить за типом события kCGEventTapDisabledByTimeout, и реагировать на него повторным включением тапа с помощью CGEventTapEnable.

9
ответ дан 9 December 2019 в 20:40
поделиться

Прежде всего, почему ваше первое «если» разрешает прохождение событий нажатия и подъема ключа? Ваше второе «если» в любом случае пропускает только системные события. Итак, для всех событий нажатия / подъема вы создаете 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 о событии, которое вы только что видели?

3
ответ дан 9 December 2019 в 20:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: