代码之家  ›  专栏  ›  技术社区  ›  Andrew Grant

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

  •  5
  • Andrew Grant  · 技术社区  · 16 年前

    对于脚本实用程序,我需要能够记录应用程序有焦点时发生的一系列键盘和鼠标事件。第二部分是稍后将这些事件发送到活动窗口。

    我不需要担心菜单或跟踪哪个窗口接收输入的标识符。

    我知道如何在Windows下执行此操作,但不知道Mac OS X。

    3 回复  |  直到 16 年前
        1
  •  10
  •   Lounges    16 年前

    我要告诉你的第一件事是你 不能 这样做时,不需要用户在可访问性控制面板中启用对辅助设备的支持。这是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);
    }
    
        2
  •  4
  •   Ben    16 年前

    对于后一部分,发布事件,使用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;
    }
    
        3
  •  1
  •   diciu    16 年前

    有关点击鼠标事件,请参见 http://osxbook.com/book/bonus/chapter2/altermouse/

    我没有在10.5豹下检查过这个,但在10.4它起作用了。