Как записывать/отправлять общесистемные события клавиатуры/мыши в Mac OS X?

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

Мне не нужно беспокоиться о меню или отслеживании идентификатора того окна, которое получает ввод.

Я знаю, как это сделать под Windows, но понятия не имею о Mac OS X.


person Andrew Grant    schedule 30.12.2008    source источник


Ответы (3)


Первое, что я вам скажу, это то, что вы НЕ МОЖЕТЕ сделать это, если пользователь не включит поддержку вспомогательных устройств в панели управления доступностью. Это своего рода защита, встроенная в OSX.

Вот фрагмент кода, который я использую в одном из своих приложений для этого:

//this method calls a carbon method to attach a global event handler
- (void)attachEventHandlers
{
    //create our event type spec for the keyup
    EventTypeSpec eventType;
    eventType.eventClass = kEventClassKeyboard;
    eventType.eventKind = kEventRawKeyUp;

    //create a callback for our event to fire in
    EventHandlerUPP handlerFunction = NewEventHandlerUPP(globalKeyPress);

    //install the event handler
    OSStatus err = InstallEventHandler(GetEventMonitorTarget(), handlerFunction, 1, &eventType, self, NULL);

    //error checking
    if( err )
    {
        //TODO: need an alert sheet here
        NSLog(@"Error registering keyboard handler...%d", err);
    }

    //create our event type spec for the mouse events
    EventTypeSpec eventTypeM;
    eventTypeM.eventClass = kEventClassMouse;
    eventTypeM.eventKind = kEventMouseUp;

    //create a callback for our event to fire in
    EventHandlerUPP handlerFunctionM = NewEventHandlerUPP(globalMousePress);

    //install the event handler
    OSStatus errM = InstallEventHandler(GetEventMonitorTarget(), handlerFunctionM, 1, &eventTypeM, self, NULL);

    //error checking
    if( errM )
    {
        //TODO: need an alert sheet here
        NSLog(@"Error registering mouse handler...%d", err);
    }
}

Вот пример метода обратного вызова, который я использую:

OSStatus globalKeyPress(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) 
{
    NSEvent *anEvent = [NSEvent eventWithEventRef:theEvent];
    NSEventType type = [anEvent type];
    WarStrokerApplication *application = (WarStrokerApplication*)userData;

    //is it a key up event?
    if( type == NSKeyUp)
    {
        //which key is it?
        switch( [anEvent keyCode] )
        {
            case NUMERIC_KEYPAD_PLUS: 
                //this is the character we are using for our toggle
                //call the handler function
                [application toggleKeyPressed];
                break;

                //Comment this line back in to figure out the keykode for a particular character                
            default:
                NSLog(@"Keypressed: %d, **%@**", [anEvent keyCode], [anEvent characters]);
                break;
        }
    }

    return CallNextEventHandler(nextHandler, theEvent);
}
person Lounges    schedule 30.12.2008

Для последней части, публикации событий, используйте методы CGEvent, представленные в ApplicationServices/ApplicationServices.h.

Вот пример функции для перемещения мыши в указанное абсолютное местоположение:

#include <ApplicationServices/ApplicationServices.h>

int to(int x, int y)
{
    CGPoint newloc;
    CGEventRef eventRef;
    newloc.x = x;
    newloc.y = y;

    eventRef = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, newloc,
                                        kCGMouseButtonCenter);
    //Apparently, a bug in xcode requires this next line
    CGEventSetType(eventRef, kCGEventMouseMoved);
    CGEventPost(kCGSessionEventTap, eventRef);
    CFRelease(eventRef);

    return 0;
}
person Ben    schedule 30.12.2008

О событиях касания мышью см. http://osxbook.com/book/bonus/chapter2/altermouse/

Под Леопардом 10.5 не проверял, но на 10.4 работает.

person diciu    schedule 30.12.2008
comment
Работает и для событий клавиатуры, но (IIRC) пользователь должен включить доступ для вспомогательных устройств в Системных настройках. - person Peter Hosey; 30.12.2008
comment
Приложение: мой предыдущий комментарий относится только к касаниям клавиатуры. Нажатия событий мыши всегда доступны (опять же, IIRC). - person Peter Hosey; 31.12.2008