JunoUserEvents.mesa (ex JunoKeyboard + pieces of JunoTop and JunoGraphics)
Coded by Greg Nelson & Donna Auguste, June 1982
Last Edited by Stolfi June 7, 1984 3:39:25 pm PDT

All mouse, keyboard, and button events that go to JunoTop are chanelled into a single user event queue maintained by this module. As it emerges from the other end of the queue, this stream of events is reformatted and cleaned up, with spurious events deleted and missing ones inserted, so as to simplify its parsing by JunoTop.

DIRECTORY

JunoStorage USING [IntCoords],
Rope USING [ROPE];

JunoUserEvents: DEFINITIONS =

BEGIN

OPEN Stor: JunoStorage;

- - - - USER EVENTS

Event: TYPE = RECORD
[type: EventType ← Null,
value: REF ANYNIL,
coords: EventCoords ← [0,0]];
A cleaned-up keyboard/mouse/button event.

EventType: TYPE =

{Char, -- A printable character: value is REF CHAR.
BackSpace, -- value is NIL.
MouseDown, Roll, MouseUp, -- value is $Red, $Yellow, $Blue; coords are defined.
Cursor, -- cursor pickup; value is atomic cursor name.
Button, -- ViewRec button event; value is atomic button name.
End, -- End of command; value is $Escape, $Delete, $Tab, $Return, or $None.
Atom, Rope, Real, -- Button argument; value is ATOM, ROPE, or REF REAL.
Quit, -- Last event.
Null -- No event.
};

EventCoords: TYPE = Stor.IntCoords;
Coordinates of a mouse event, in the Juno reference frame, rounded to the nearest integer for speedy "roll" processing (is this worth the trouble?)

- - - - THE USER EVENT STREAM

Next: PROC RETURNS [ev: Event];
Removes and returns the next event from the User Event Queue.

Sources of user events:

As of now (June 4, 1984 2:41:08 pm PDT) there are four sources of events that ultimately turn up in the User Event Queue:

I. Mouse and keyboard events on the main (image) viewer, generated by TIP, passed to the image viewer's NotifyProc, and inserted by the latter in the queue using AppentTIPEvent below;

II. Cursor pickup events, generated by the JunoCursorMenu interface, and passed (like TIP events) to the image viewer's NotifyProc.

III. Button events, generated by the JunoButtons module (with the help of Spreitzer's ViewRec), and inserted directly into the queue using AppendEvents below.

IV. The image viewer's DestroyProc. This does not generate an event in the proper sense, but rather closes the queue in such a way that JunoTop will get interrupted (by the signal Evs.UserAborted) the next time it tries to get something out of the queue.

Structure of the user event stream:

The raw events from all the four sources mentioned above are merged, reformatted and cleaned up in their passage through the queue, and emerge as a stream of Event s. This stream has the form

<stream> ==> {<command>}* Quit

<command> ==> {Cursor | Button} {<argument>}* End

Cursor or Button events denote respectively the selection of a new cursor or the clicking (trough the ViewRec interface) of a JunoButtons procedure. The value field is the atomic name of the cursor or button.

An End event may have value = $Escape, $Delete, $Return, $Tab, or $None. Value will be $None if it was interpolated by the event filter.

<argument> ==> <mouse click> | <character> | <other argument>

<mouse click> ==> MouseDown {Roll}* MouseUp

All events in a <mouse click> sequence have the same atomic value, the name ($Red, $Yellow, or $Blue) of the mouse button used in the click. The coords field gives the coordinates of the event, already mapped to the Juno coordinate system (this field is undefined for all other events).

<character> ==> Char | BackSpace

If the type is Char, then the value is a REF to a printable characer.

<other argument> ==> Atom | Rope | Real.

Such events are used to pass the arguments of a button procedure (if any) to JunoTop. The value is the atom or rope itself, or a REF to the real.

Null events are used only for internal hacks, and never appear at the output end of the queue.

How the raw user events are cleaned up:

TIP items are converted to the Event format when first inserted in the queue. At this time, mouse coordinates are converted to the Juno coordinate system.

When events are removed from the other end of the queue, they are passed through a filter that ensures the event stream has the nice format described above. This filtering is necessary due to the rather weird things the user can do with the mouse, and requires discarding spurious events and/or interpolating missing ones.

A new $Cursor event is automatically interpolated (if missing) after each $Escape, $Delete, $Return, or $Tab typed by the user, and after the End event that closes a Button command. The value will be the name of the cursor most recently picked up.

An End event (with value = $None) is automatically inserted before Button, Cursor, or Quit if it is missing.

Each of the present JunoButtons procedures always produces a sequence of events of the form Button {Atom | Rope | Real}* End. However, this module can cope also with JunoButtons procedures that add extra arguments to the current cursor command. Such procedures should append to the queue one or more "argument" events (i.e., of type Atom, Rope, Real, Char, or complete <mouse click>s) without the Button or the End.

The filter regularizes mouse clicks by keeping track of the first mouse button to go down (say, the Red one), and discarding any Yellow or Blue up/down events until finds a Red MouseUp event. Any Roll events encountered until then will pass through the filter, with value set to Red. If the next event in the queue is not MouseUp, MouseDown, or Roll, the filter will interpolate a Red MouseUp event, and consider the Red button released. After returning a MouseUp event (real or faked), and before encountering the next MouseDown, the filter will ignore any Roll and MouseUp events.

- - - - EVENT INSERTION

AppendEvents: PUBLIC PROC [ev1, ev2, ev3, ev4, ev5: Event ← [type: Null]];
Appends the given events (if non-Null) to the rear end of the user input queue.

The events are guaranteed to to be in consecutive positions in the queue (no other processes will sneak in between them).

Appending a Quit event will gracefully close the user event queue: any events after that will be ignored. It will not destroy the viewers, however.

- - - - ERROR MESSAGES

Blink: PUBLIC PROC [item1, item2, item3, item4, item5: Rope.ROPENIL];

- - - - DEBUGGING STREAMS

bugin, bugout: READONLY IO.STREAM; -- must call StartUp [debug: TRUE] to create them

- - - - SETUP

StartUp: PUBLIC PROC [debug: BOOLFALSE];
Creates the image and button viewers, directing their TIP, cursor, and button events to the user event queue.

If debug = TRUE, also opens a typescript stream for bugin and bugout

Terminate: PUBLIC PROC;
Destroys the image and button viewers (if still alive), and appends a Quit event to the queue (if not there already).

END.