如何在Mac OS X下捕获/发布系统范围的键盘/鼠标事件?

5
为了一个脚本工具,我需要记录应用程序在焦点状态下发生的一系列键盘和鼠标事件。第二部分是能够稍后将这些事件发送到活动窗口。
我不需要担心菜单或跟踪哪个窗口接收输入的标识符。
我知道如何在Windows下做到这一点,但对Mac OS X毫无头绪。
3个回答

10

我要告诉您的第一件事是,如果用户没有在辅助功能控制面板中启用对辅助设备的支持,则无法完成此操作。这是内置在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);
}

5

对于后半部分,发布事件,使用ApplicationServices / ApplicationServices.h中提供的CGEvent方法。

以下是将鼠标移动到指定绝对位置的示例函数:

#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;
}

1

关于鼠标事件的操作,请参见链接

我没有在10.5 Leopard下测试过,但在10.4上可以正常工作。


也适用于键盘事件,但是(如果我没记错的话)用户必须在“系统偏好设置”中启用辅助设备访问。 - Peter Hosey
附注:我的先前评论仅适用于键盘事件挂钩。鼠标事件挂钩始终可用(再次提醒,如我所知)。 - Peter Hosey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接