Использование событий мыши и трекпада OSX с помощью события

Я пытаюсь добавить ловушку событий, чтобы включить / отключить событие с моего волшебного трекпада. Я думал, что это будет прямо вперед, то есть зарегистрировать ловушку события и при необходимости отменить событие, возвращая NULL, Идея состоит в том, чтобы использовать панель для какого-то конкретного, трудоемкого ввода данных, приложения для ввода данных являются сторонними, так что я не могу просто добавить код, который я хочу, там, где я хочу. Так что я решил, что буду отслеживать системные события, а затем отправлять желаемые данные через группу CGEventCreateKeyboardEvents.

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

Мой код ниже. С тем, что ниже, я ожидал бы, что не смогу двигать мышью, если я поменяю (A) на использование kCGEventScrollWheel или же kCGEventLeftMouseDragged затем событие расходуется, т.е. прокрутка или перетаскивание влево не происходит. Значит ли это, что не все события могут быть отброшены? Надеюсь, я просто упускаю что-то очевидное здесь

  #define case_print(a) case a: printf("%s - %d\n",#a,a); break;


  CGEventRef eventOccurred(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
    int subType =  CGEventGetIntegerValueField(event, kCGMouseEventSubtype);
    if (type == NSEventTypeGesture || subType == NX_SUBTYPE_MOUSE_TOUCH) {
        printf("touchpad\n");

        switch(type) {
                case_print(kCGEventNull)
                case_print(kCGEventLeftMouseDown)
                case_print(kCGEventLeftMouseUp)
                case_print(kCGEventRightMouseDown)
                case_print(kCGEventRightMouseUp)
                case_print(kCGEventMouseMoved)
                case_print(kCGEventLeftMouseDragged)
                case_print(kCGEventRightMouseDragged)
                case_print(kCGEventScrollWheel)
                case_print(kCGEventOtherMouseDown)
                case_print(kCGEventOtherMouseUp)
                case_print(kCGEventOtherMouseDragged)
                case_print(kCGEventTapDisabledByTimeout)
                case_print(kCGEventTapDisabledByUserInput)
                case_print(NSEventTypeGesture)
                case_print(NSEventTypeMagnify)
                case_print(NSEventTypeSwipe)
                case_print(NSEventTypeRotate)
                case_print(NSEventTypeBeginGesture)
                case_print(NSEventTypeEndGesture)
            default:
                printf("default: %d\n",type);
                break;    
        }

        event = NULL;
    }  else {
        if (type == kCGEventMouseMoved) {  // (A)
            printf("discarding mouse event");
            event = NULL;
        }
    }

    return event;
}


CFMachPortRef createEventTap() {  
    CGEventMask eventMask = NSAnyEventMask;

    if (!AXAPIEnabled() && !AXIsProcessTrusted()) { 
        printf("axapi not enabled");
    } 

    return CGEventTapCreate(kCGHIDEventTap, 
                            kCGHeadInsertEventTap, 
                            kCGEventTapOptionDefault, 
                            eventMask, 
                            eventOccurred, 
                            NULL); 
}

int main (int argc, const char * argv[]) {
    CFMachPortRef tap = createEventTap();

    if (tap) {
        CFRunLoopSourceRef rl = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0);
        CFRunLoopAddSource(CFRunLoopGetMain(), rl, kCFRunLoopCommonModes);
        CGEventTapEnable(tap, true);
        CFRunLoopRun();

        printf("Tap created.\n");
        sleep(-1);
    } else {
        printf("failed!\n");
    }

    return 0;
}

Обратите внимание: "axapi not enabled" не выводится, хотя я не думаю, что опция доступности влияет на что-либо, кроме событий клавиатуры.

Кстати, я видел несколько похожих постов о том, как получить события с сенсорной панели, просто ничего не применимо к их отбрасыванию (кроме возврата нуля должно работать).

4 ответа

Решение

Если ваше нажатие пассивно, возвращение NULL не повлияет на поток событий. Из справочной документации CGEventTapCallBack:

"Если отвод события является пассивным слушателем, ваша функция обратного вызова может вернуть переданное событие, или NULL. В любом случае поток событий не затронут".

Тем не менее, похоже, что ваш кран активен. Таким образом, ваш возврат NULL должен удалить событие. Рассматривали ли вы изменение события, чтобы аннулировать действие?

Также обратите внимание, что для вызова CGEventTapCreate требуются права пользователя root для перехвата всех событий. Ваш процесс работает как root?

Я могу подтвердить, что на 10.6 ни один из следующих методов не был успешным для этой цели.

1-возвращающий NULL

2 - возвращение нового события мыши с предыдущей позицией курсора

3- возвращение пройденного события с его kCGMouseEventDelta, измененным на 0

Я не могу говорить о 10.7, но давайте просто скажем, что мои надежды не оправдаются.

Однако есть одна вещь, которую вы могли бы сделать вместо того, чтобы отбросить движение, переместить его обратно в предыдущее местоположение с помощью CGWarpMouseCursorPosition, по сути, курсор перестанет двигаться с небольшим изменением первого.

Я думаю, что невозможно просто отбросить эти события. Из заголовочного файла CGEventTypes.h:

"Событие, переданное обратному вызову, сохраняется вызывающим кодом и освобождается после возврата обратного вызова и передачи данных обратно в систему событий. Если функция обратного вызова возвращает другое событие, то это событие будет освобождено код вызова вместе с исходным событием после передачи данных события обратно в систему событий ".

Я немного поиграл с этим, и кажется, что после обратного вызова сервер окон снова активно проверяет, что вы сделали с событием. Он позволяет только удалять ключевые события и события мыши вверх / вниз, но так же, как он игнорирует удаление событий перемещения мыши (я думаю, что рендеринг мыши обрабатывается в другом месте в любом случае), он, кажется, игнорирует удаление (т. Е. Ваш обратный вызов, возвращающий NULL) для жестов мыши.

Рисунки, учитывающие нажатие на жесты, специально не объясняются в документации (на этом уровне не определен тип).

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

Единственное, что я не попробовал, - это непосредственно манипулировал внутренними данными переданного CGEvent, чтобы, по крайней мере, заставить жест ничего не делать (удаляя все движения и тому подобное), но это довольно сложно, потому что нет определенных методов, определенных для этого. Я уверен, что необходимая информация находится где-то в различных полях, доступных через методы CGEventSet*.

Я посмотрел вниз до IOLLEvent.h, чтобы выяснить их структуру данных, но это было слишком уродливо, чтобы я мог вникнуть в них гораздо дальше. Будем надеяться, что Lion предложит немного больше о типе жестов на уровне CF.

CGAssociateMouseAndMouseCursorPosition(FALSE);

Будет препятствовать работе мыши, пока ваше приложение активно.

Все еще исследую, могу ли я распространить это на глобальные приложения...

http://lists.apple.com/archives/quartz-dev/2007/May/msg00112.html

Другие вопросы по тегам