Receiving Events
You receive events by calling an Event Manager routine, usuallyWaitNextEvent. When you ask for an event, the Event Manager returns the next available event according to its event priority. The Event Manager returns events in this order of priority:
To retrieve an event, you pass the
- activate events
- mouse-down, mouse-up, key-down, key-up, and disk-inserted events in FIFO (first-in, first-out) order
- auto-key events
- update events (in front-to-back order of windows)
- operating-system events (suspend, resume, mouse-moved)
- high-level events
- null events
WaitNextEventfunction an event record, defined by theEventRecorddata type:
TYPE EventRecord = RECORD what: Integer; {event code} message: LongInt; {event message} when: LongInt; {ticks since startup} where: Point; {mouse location} modifiers: Integer; {modifier flags} END;On return fromWaitNextEvent, thewhatfield of the event record contains an integer that specifies the type of event received. The Event Manager uses this set of predefined constants to indicate the event type:
CONST nullEvent = 0; {no other pending events} mouseDown = 1; {mouse button pressed} mouseUp = 2; {mouse button released} keyDown = 3; {key pressed} keyUp = 4; {key released} autoKey = 5; {key held down} updateEvt = 6; {a window needs updating} diskEvt = 7; {disk inserted} activateEvt = 8; {activate/deactivate window} osEvt = 15; {operating-system event} kHighLevelEvent = 23; {high-level event}Themessagefield of the event record contains additional information about the event. The interpretation of this field depends on the type of event you've received. For some events (such as null events, mouse-up, and mouse-down events), the value in themessagefield is undefined. For keyboard events, themessagefield indicates which key was pressed. For activate and update events, themessagefield contains a window pointer to the affected window. For disk-inserted events, themessagefield contains the drive number in the low-order word and the result code of the File Manager's attempt to mount that disk in that drive. Listing 4-3 illustrates how an application reads parts of themessagefield while handling disk-inserted events.Listing 4-3 Handling disk-inserted events
PROCEDURE DoDiskEvent (myEvent: EventRecord); VAR myResult: Integer; myPoint: Point; BEGIN IF HiWord(myEvent.message) <> noErr THEN BEGIN SetPt(myPoint, 100, 100); myResult := DIBadMount(myPoint, myEvent.message); END; END;If the disk was not successfully mounted (that is, if the high-order word of themessagefield does not containnoErr), thenDoDiskEventcalls the system software routineDIBadMountto inform the user and allow the disk to be ejected or reformatted. (See the chapter "Disk Initialization Manager" in Inside Macintosh: Files for more information about handling disk-inserted events.)The
wherefield of the event record contains, for low-level events, the location of the cursor at the time the event was posted. You can use this information to determine where on the screen a mouse-down event occurred, for instance.The
modifiersfield contains information about the state of the modifier keys and the mouse button at the time the event was posted. For activate events, this field also indicates whether the window should be activated or deactivated. (In System 7, it also indicates whether a mouse-down event caused your application to switch to the foreground.)To handle an event, you simply take whatever action is appropriate for the kind of event it is. Listing 4-4 shows one way to structure an event-handling routine.
PROCEDURE DoMainEventLoop; VAR myEvent: EventRecord; gotEvent: Boolean; {is returned event for me?} BEGIN REPEAT gotEvent := WaitNextEvent(everyEvent, myEvent, 15, NIL); IF NOT DoHandleDialogEvent(myEvent) THEN IF gotEvent THEN BEGIN CASE myEvent.what OF mouseDown: DoMouseDown(myEvent); {see page 120} keyDown, autoKey: DoKeyDown(myEvent); {see page 160} updateEvt: DoUpdate(WindowPtr(myEvent.message)); {see page 124} diskEvt: DoDiskEvent(myEvent); {see page 77} activateEvt: DoActivate(WindowPtr(myEvent.message), myEvent.modifiers); {see page 126} osEvt: DoOSEvent(myEvent); {see page 171} keyUp, mouseUp: ; nullEvent: DoIdle(myEvent); {see page 173} OTHERWISE ; END; {CASE} END ELSE DoIdle(myEvent); UNTIL gDone; {loop until user quits} END;The event loop defined in Listing 4-4 repeatedly calls theWaitNextEventfunction to retrieve the next available event. This function returns a value ofFALSEif there are no events of the desired type (other than null events) pending for your application. Otherwise,WaitNextEventreturnsTRUE.After the next available event is retrieved, the
DoMainEventLoopprocedure calls the application-defined functionDoHandleDialogEvent(defined in Listing 7-5 on page 141) to determine whether the event applies to a dialog box. TheDoHandleDialogEventfunction returnsTRUEif it handled the event andFALSEotherwise.
If the event retrieved does not apply to a dialog box, and if it isn't a null event, then
- Note
- Dialog boxes receive special treatment because the system software automatically handles many user actions in dialog boxes. For example, the Dialog Manager handles update events for dialog boxes, and it calls the Control Manager to handle user actions affecting any controls in the dialog box.
![]()
DoMainEventLoopbranches into a PascalCASEstatement in which the labels are simply the predefined constants for each event type. As you can see, the event loop calls an application-defined routine to handle each particular kind of event. These routines are defined throughout this book.