# Monitoring Events Through the Event Broker

## Waiting for Event Messages on the Reply Port

After a task is connected as a listener, it can choose either of the following methods for event notification:

- The task can enter the wait state until it receives an event broker message on the reply port (synchronous I/O).

- The task can continue to execute, and pay attention to the event broker only when the task receives notification of a message received on the reply port (asynchronous I/O).

### The Event Broker Trigger Mechanism

While listeners wait for event notification, the event broker checks the pods once per field for events. The event broker checks occurring events against the trigger mask of each connected listener. If an event matches a set bit in a listener's trigger mask and the listener has the input focus (if required), the event broker sends an event notification to the listener.

When the event broker sends an event notification, it uses its own event messages, which it creates as necessary. After the event broker creates an event message, it copies the information into the message's data block. The information contains a report of the status of each event type that matches a set bit in either the listener of the trigger or capture masks. You can think of the event message data block as a snapshot of the status of all listener-specified events during the field. Only events specified in the trigger mask can trigger the snapshot, but the status of all events specified in either mask is reported in the message.

For example, consider a listener that specifies the "Gun Button Pressed" event type in its trigger mask, and the "Control Button Update" and "Keyboard Update" event types in its capture mask. When any gun attached to the control port is pressed during a field, the event broker prepares an event message for the listener. The event message's data field reports a gun button press and the status of the Control Button Update and Keyboard Update events (indicating whether or not either of those events occurred during the field). If the "gun button pressed" event had not occurred, the event broker would not have sent an event message to the listener, even if keyboard or controller pad button updates occurred, because those event types were in the capture mask but not in the trigger mask.

### Retrieving and Replying to Event Messages

After a listener has been notified of an incoming event message from the event broker, it must retrieve the message to read the reported events. To do so, it uses the `GetMsg()` call. The listener can then read the message's data block (described in Reading an Event Message Data Block below), and either act on the data or store it for later use.

After a listener has processed the event data in an event message, the listener must reply to the event broker. Its reply tells the event broker that the event message is once again free for use. If the listener does not reply to an event message, the event broker assumes that the message was not processed. Each unprocessed event message is one element in the listener's event queue. When the number of unprocessed event messages exceeds the maximum event queue depth, the event broker stops reporting events to the listener. Consequently, the listener loses events until it can process and free up messages in its queue. If the listener asks to be notified of an event queue overflow, the event broker reports it as soon as an event message is free. The update event types (`EB_ControlButtonUpdate`, `EB_MouseUpdate`, and so on) are all reported as occurring, because an event queue overflow is considered an update.

To reply to an event message and return it to the event broker, a listener uses the `ReplyMsg()` call. Always pass NULL as the data pointer, and 0 as the data size parameter to `ReplyMsg()`.

## Reading an Event Message Data Block

When a listener receives an event message from the event broker, a pointer to the event data block is in the `msg_DataPtr` field of the message structure, and the size in bytes of the data block in the `msg_DataSize` field. To interpret the event data stored in the event message, the listener task must be able to read the data structures used in the data block.

### Event Data Block Structure

When the event broker reports events in an event data block, it can report one or more events. Therefore, it must have a flexible data arrangement within the data block to report any number of events. An event data block starts with an EventBrokerHeader structure that specifies the message flavor as `EB_EventRecord` and follows with one or more `EventFrame` structures, each containing the report of a single event. (Each event report is called an event frame.) The final structure in the data block is a degenerate EventFrame data structure, which indicates the end of the event frames.

### The EventFrame Data Structure

The EventFrame data structure is defined in event.h as follows:

``

    typedef struct EventFrame
    {
        uint32            ef_ByteCount;                        /* total size of EventFrame */
        uint32            ef_SystemID;                        /* 3DO machine ID, or 0=local */
        uint32            ef_SystemTimeStamp;                        /* event-count timestamp */
        int32            ef_Submitter;                        /* Item of event sender, or 0 */
        uint8            ef_EventNumber;                        /* event code, [0,255] */
        uint8            ef_PodNumber;                        /* CP pod number, or 0 */
        uint8            ef_PodPosition;                        /* CP position on daisychain, or 0 */
        uint8            ef_GenericPosition;                        /* Nth generic device of type, or 0 */
        uint8            ef_Trigger;                        /* 1 for trigger, 0 for capture */
        uint8            rfu1[3];
        uint32            rfu2;
        uint32            ef_EventData[1];                        /* first word of event data */
    } EventFrame;

- `ef_ByteCount` gives the total size of the `EventFrame` in bytes. Because the event data at the end of the frame varies in size depending on the event, this value changes from frame to frame.

- `ef_SystemID` reports the ID number of the 3DO unit where this event occurred. This value is useful if two or more 3DO units are linked together (as they might be for networked games). If the event occurred on the local 3DO unit, this value is set to 0.

- `ef_SystemTimeStamp` is the exact system time the event broker recorded this event. This time value corresponds to the current vblank count value as provided by the timer device's `TIMER_UNIT_VBLANK` unit.

- `ef_Submitter` gives the item number of the event sender. This value is important when multiple listener tasks tied into the event broker send events to each other. This item number is the item number of the sending task. If the event comes from a pod and not a task, this field is set to 0.

- `ef_EventNumber` is an event code from 0 to 255 that identifies the generic type of event. These event types are the same as the event types identified within a configuration event mask. The include file event.h defines a constant for each type as shown in Table 2.

- `ef_PodNumber` gives the unique pod number of the pod where an event originated. This number is constant and is assigned when a pod is first plugged into the 3DO unit. It does not change if the pod changes its position in the control port daisy chain. This value is set to 0 if the event did not originate in a pod (for example, an event generated by another task or the CD-ROM drive).

- `ef_PodPosition` gives the position of the event-reporting pod in the control port daisy chain. Numbering starts with 1 for the first pod, and continues consecutively the further the chain extends from the 3DO unit. If the event did not originate in a pod, this value is set to 0.

- `ef_GenericPosition`, gives the daisy-chain position of the event-reporting pod among identical generic device types in the daisy chain. A generic device type is a functional description of the pod or part of the pod, and currently includes the following defined types:

  - `POD_IsControlPad`
  - `POD_IsMouse`
  - `POD_IsGun`
  - `POD_IsGlassesCtlr`
  - `POD_IsAudioCtlr`
  - `POD_IsKeyboard`
  - `POD_IsLightGun`
  - `POD_IsStick`
  - `POD_IsIRController`

- For example, an event occurs in the second controller pad in the daisy chain, in which case this value is 2, or in the fourth photo-optic gun in the daisy chain, in which case this value is 4. This value is set to 0 if the event did not occur in a generic device.
- A single pod attached to the 3DO unit can have more than one generic device type. For example, a single pod can be a combination control pad and audio controller. In that case, when an event occurs on its control pad buttons, the generic position listed in the event frame is that of a control pad among other control pads connected to the 3DO unit.

- `ef_Trigger` identifies an event as one that triggered the event notification or as a captured event that did not trigger the notification. If the value is 1, the event was a triggering event; if the value is 0, the event is a captured event.

- `ef_EventData` is the first word of a data structure that contains data about an event. The rest of the data structure follows this field in memory. The definition of the data structure depends entirely on the generic device where the event occurred. The data structures are described in Reading Event Data.

### The Final (Degenerate) Event Frame

The final event frame within an event data block must be a degenerate event frame, which contains the value 0 for the `ef_ByteCount` field. The rest of the EventFrame data structure cannot be present.

## Reading Event Data

The event data array at the end of each full event frame is a data structure that determines the type of device reporting the event. For example, an event occurring on a controller pad uses a structure designed to report control pad data. An event occurring on a mouse uses a structure designed to report mouse data.

### Control Pad Data Structure

The data structure that reports control pad data is `ControlPadEventData`, defined in event.h as follows:

``

    typedef struct ControlPadEventData
    {
      uint32 cped_ButtonBits;  /* left justified, zero fill */
    } ControlPadEventData;

- `cped_ButtonBits` contains a value whose bits tell the status of each controller pad button during the field. The constants defining these flag bits are as follows:

  - `ControlDown` - the down arm of the joypad cross.
  - `ControlUp` - the up arm of the joypad cross.
  - `ControlRight` - the right arm of the joypad cross.
  - `ControlLeft` -the left arm of the joypad cross.
  - `ControlA` -the A button.
  - `ControlB` - the B button.
  - `ControlC` - the C button.
  - `ControlStart` - the P (play/pause) button.
  - `ControlX` -the X (stop) button.
  - `ControlLeftShift` - the left shift button.
  - `ControlRightShift` - the right shift button.

- The meaning of these bits varies for each type of control pad event:

  - For the `EVENTNUM_ControlButtonPressed` event, 1 means the button was pressed since the last field, 0 means the button was not pressed.

  - For the `EVENTNUM_ControlButtonReleased` event, 1 means the button was released since the last field, 0 means the button was not released.

  - For the `EVENTNUM_ControlButtonUpdat` event, 1 means the button is down; 0 means the button is up.

  - For the `EVENTNUM_ControlButtonArrived` event, 1 means the button is down; 0 means the button is up.

### Mouse and Trackball Data

The data structure used to report mouse and trackball data is `MouseEventData`, defined in event.h as follows:

``

    typedef struct MouseEventData
    {
      uint32    med_ButtonBits;   /* left justified, zero fill */
      int32     med_HorizPosition;
      int32     med_VertPosition;
    } MouseEventData;

- `med_ButtonBits` contains a value whose bits tell which mouse button (or buttons) generated the event. The constants defining these flag bits are as follows:

  - `MouseLeft` - the left mouse button.

  - `MouseMiddle` - the middle mouse button.

  - `MouseRight` - the right mouse button.

  - `MouseShift` - the mouse's shift button.

- 3DO mice currently have three buttons: left, middle, and right. The fourth constant provides for an extra shift button if one ever appears on 3DO mice.

- The meaning of the above bits varies for each type of mouse event:

  - For the `EVENTNUM_MouseButtonPressed` event, 1 means the button was pressed since the last field; 0 means the button was not pressed.

  - For the `EVENTNUM_MouseButtonReleased` event; 1 means the button was released since the last field, 0 means the button was not released.

  - For the `EVENTNUM_MouseUpdate` evenly; 1 means the button is down, a 0 means the button is up.

  - For the `EVENTNUM_MouseDataArrived` event; 1 means the button is down, a 0 means the button is up.

  - For the `EVENTNUM_MouseMoved` event; 1 means the button is down, 0 means the button is up.

- `med_HorizPosition` and `med_VertPosition` report the mouse's current position in absolute space. That position is reckoned from an origin (0,0) that is set when the mouse is first plugged in, and uses units that will typically (depending on the mouse) measure 100, 200, or 400 increments per inch. It is up to the task to interpret the absolute position of the mouse to a pointer position on the display.

### Light Gun Data Structure

The data structure that reports light gun data is LightGunData, defined in event.h as follows:

``

    typedef struct LightGunEventData
    {
      uint32  lged_ButtonBits;      /* left justified, zero fill */
      uint32  lged_Counter;         /*cunter at top-center of hit */
      uint32  lged_LinePulseCount;   /* # of scan lines which were hit */
    } LightGunEventData;

- `lged_ButtonBits` contains a value whose bits tell the state of the various triggers, buttons, and other pushable or flippable controls on a light gun. Most light guns have one trigger and one auxiliary button. The only flag bit currently defined for this field is:

  - `LightGunTrigger` - the main light gun trigger.

- `lged_Counter` contains a value which specifies the number of times that the light gun's internal clock (nominally 20 MHz) counted up, between the time it was reset (during vertical blanking) and the time that the light gun's optical sensor "saw" a flash of light from the display as the display's electron beam passed through its field of view. The beam travels left to right along each line, and downwards from line to line.

- `lged_LinePulseCount` contains the value 0 if the light gun sensor did not detect a sufficiently strong pulse of light while scanning the video field. In this case, the `lged_Counter` value may or may not be valid. If the light gun sensor detected a sufficiently strong pulse of light, `lged_LinePulseCount` contains a nonzero value. Some light guns can actually count the number of successive horizontal scan lines during a pulse and return that value in this field. For light guns of this sort, the `lged_LinePulseCount` is considered a "quality of signal" indicator. Other light guns simply return a constant value (typically 15) to indicate that their sensor detected at least one pulse that was strong enough to trip the sensor.

### Joystick Data

The data structure used to report joystick data is `StickEventData`, defined in event.h as follows:

``

    typedef struct StickEventData
    {
      uint32            stk_ButtonBits;                  /* left justified, zero fill */
      int32            stk_HorizPosition;
      int32            stk_VertPosition;
      int32            stk_DepthPosition;
    } StickEventData;

- `stk_ButtonBits` contains a value that identifies which joystick button (or buttons) generated the event. The constants defining these flag bits are as follows:

  - `StickCapability` - the AND of `Stick4Way` and `StickTurbulence.`
  - `Stick4Way` - determines how many buttons the stick has.
  - `StickTurbulence` - indicates whether or not the stick understands output commands.
  - `StickButtons` - the stick buttons.
  - `StickFire` - the joystick was fired.
  - `StickA` - the A button.
  - `StickB` - the B button.
  - `StickC` - the C button.
  - `StickUp` - the up button of the stick.
  - `StickDown` - the down button of the stick.
  - `StickRight` - the right button of the stick.
  - `StickLeft` - the left button of the stick.
  - `StickPlay` - the play button of the stick.
  - `StickStop` - the stop button of the stick.
  - `StickLeftShift` - the left-shift button of the stick.
  - `StickRightShift` - the right-shift button of the stick.

- `stk_HorizPosition`, `stk_VertPosition`, and `stk_DepthPosition` contain binary numbers and return a value between 0 through 1023. A value of 0 means the joystick is pushed left or all of the way down. A value of 1023 means the joystick is pushed right or all the way up. Keep in mind that some joysticks cannot go all the way to 0 or 1023.

### Device State Data Structure

When media is inserted or removed from a device, `EVENTNUM_DeviceOnline` or `EVENTNUM_DeviceOffline` respectively, the DeviceStateEventData structure contains the Item number of the device, and the unit number within the device that has gone on-line or off-line. The `DeviceStateEventData` structure is defined as follows:

``

    typedef struct DeviceStateEventData
    {
      Item    dsed_DeviceItem;
      uint32  dsed_DeviceUnit;
    } DeviceStateEventData;

### Filesystem State Data Structure

When a filesystem is mounted, dismounted, or placed off-line, `EVENTNUM_FilesystemMounted`, `EVENTNUM_FilesystemDismounted`, or `EVENTNUM_FilesystemOffline`, the FileSystemEventData structure contains the Item number of the Filesystem node, and the name of the filesystem which is changing state. The FileSystemEventData structure is defined as follows:

``

    typedef struct FilesystemEventData
    {
      Item  fsed_FilesystemItem;
      char  fsed_Name[FILESYSTEM_MAX_NAME_LEN];
    } FilesystemEventData;