Writing the Event Handler

Now it’s time to write the event handler. Event handlers take the form.

pascal OSStatus EventHandler(EventHandlerCallRef myHandlerChain, 
        EventRef event, void* userData)

The pascal keyword tells the compiler to use Pascal language parameter passing conventions. Event handling functions require the Pascal language conventions. The myHandlerChain argument contains the hierarchy of event handlers that could handle this particular event. Use the myHandlerChain argument if you want to call another event handler in your event handler function. I won’t be using the myHandlerChain argument in this article. The event argument is the event you’re passing to the handler. The userData argument is the data you supplied when you installed the event handler.

C++ programs that want event handlers to be members of a class must declare the timer to be a static function in the header file.

static pascal OSStatus EventHandler(EventHandlerCallRef myHandlerChain, 
        EventRef event, void* userData);

You can give your event handler function any name you want, but the function name must match the name you supply to the function NewEventHandlerUPP() when installing the event handler.

Determining Which Key the User Pressed

The code you write for an event handler depends on the types of events you want to handle. For a keyboard event handler you must declare a variable of type UInt32 (unsigned 32-bit integer) to store the key the user pressed. Call the function GetEventParameter() to get the key the user pressed. GetEventParameter() takes six arguments.

  • The event.
  • The name of the parameter you want to get. For a keyboard event, you normally want kEventParamKeyCode, which is the virtual keycode for the key the user pressed.
  • The parameter type you want GetEventParameter() to return. For the keyboard the desired parameter type is typeUInt32.
  • The actual parameter type GetEventParameter() returns. You can get away with passing NULL.
  • The desired size of the data GetEventParameter() returns. For the keyboard the size will be four bytes, the size of a UInt32 variable.
  • The actual size of the data GetEventParameter() returns. You can get away with passing NULL.
  • The data GetEventParameter() returns. For the keyboard the data is the key the user pressed.

Virtual keycodes require some more explanation. A virtual keycode identifies a key on the keyboard. Using the virtual keycode allows you to separate the physical key from its character. Separating the physical key from its character makes international support for your application easier. Not every Mac user has the American QWERTY keyboard layout. Suppose you want to use the W key to move the player up in your game. By using virtual keycodes, everybody presses the same key, whether it’s the W key on an American keyboard or the Z key on a French keyboard. I have compiled an unofficial list of Mac virtual keycodes.

Event Handler Example

After calling GetEventParameter(), write a switch statement with the keys you want your program to handle. Let’s look at a simple example of a keyboard event handler.

pascal OSStatus GameApp::KeyboardEventHandler(EventHandlerCallRef myHandlerChain,
        EventRef event, void* userData)
{ 
    UInt32 keyPressed; 
    OSStatus result; 
    
    GameAppPtr currentApp = (GameAppPtr)userData;
    
    GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, 
        sizeof(UInt32), NULL, &keyPressed); 
    
    switch (keyPressed) { 
        case kEscapeKey: 
            currentApp->Pause(); 
            result = noErr; 
            break; 
            
        default: 
            // The standard application event handler 
            // handles any events our event handler
            // doesn't handle. 
            result = eventNotHandledErr; 
            break; 
    } 
    
    return result; 
}

The event handler pauses the game when the player press the Escape key. Notice how the event handler returns eventNotHandledErr if the user presses a key the event handler doesn’t handle. This is very important. If your event handler does not handle an event, you must return eventNotHandledErr. Returning eventNotHandledErr dispatches the event to the standard event handler to handle. Returning noErr instead of eventNotHandledErr can cause your event handler to work improperly.

Next (Cleaning Up)

Previous (Installing Your Event Handler)