TipDoc.Tioga
Christian LeCocq September 24, 1986 3:16:40 pm PDT
Doug Wyatt, September 24, 1986 3:23:34 pm PDT
Rick Beach, March 13, 1987 11:41:29 am PST
Willie-Sue, November 25, 1987 4:16:51 pm PST
Bill Jackson (bj) February 3, 1988 5:25:51 pm PST
Bier, August 9, 1990 11:48 pm PDT
Spreitze, November 27, 1990 7:43 am PST
Christian Jacobi, March 3, 1992 1:32 pm PST
TIP TABLES
CEDAR 10.0 — FOR INTERNAL XEROX USE ONLY
Tip Tables
User Input Parser
Werner Winiger, updated by Christian Le Cocq, Eric Bier, Christian Jacobi
© Copyright 1986, 1987, 1988, 1992 Xerox Corporation. All rights reserved.
Abstract: TIP (Terminal Interface Package) is a package that parses hardware-level actions from the keyboard, mouse, and keyset, into higher-level user actions. The input to TIP is a Mesa-like program (called here a TIP table) describing the set of events to be recognized and the output to be passed through a client supplied procedure, which is called once per event parsed. TIP runs as a separate process from the client and is reentrant, allowing several instances to run at once. There are public interfaces to create a new TIP client and to change the parse table by which TIP recognises events. A very important TIP client (and perhaps the only one in use in most Cedar worlds) is the TIP client created by the Viewers package.
Created by: Winiger & Paxton
Maintained by: CedarSupport^.pa
Keywords: input, keyboard, mouse, parsing, TIP tables, user interface
XEROX  Xerox Corporation
   Palo Alto Research Center
   3333 Coyote Hill Road
   Palo Alto, California 94304

For Internal Xerox Use Only
-2. News
Times reported by the TIP mechanism are device specific. E.g. When a window moves from one X server to another X server the time base changes. The times are relative to the particular server to avoid network delays playing into timeouts for double clicks. Times should only be used for internal timeouts but not be used like host times. Ch.J.
-1. News
I (Mike Spreitzer) just discovered the truly unique interpretation that the UserInput interfaces place on TimeStamp values. Each handle has a couple of state variables: epochGMT (a BasicTime.GMT) and epochTimeStamp (a UserInput.TimeStamp). For a given handle, a TimeStamp t corresponds to the BasicTime.GMT given by
BasicTime.Update[epochGMT, LOOPHOLE[t-epochTimeStamp, INT32]/1000]
Thus, a TimeStamp represents an integer biased by an arbitrary, and formerly secret, value. I added the UserInputExtras3 interface to export a new UsefulGetAbsoluteTime procedure, which exposes that secret value. N.B.: it really was secret --- even the client that called SetAbsoluteTime doesn't know what it is at a later time, because UserInputImpl updates epochGMT and epochTimeStamp to keep epochGMT near the current time.
0. Executive Summary
Dear PCedar user, much of this document is out of date and I (Eric Bier) don't have time to rewrite it right now. However, if you are porting packages to PCedar or writing new applications with TIP tables, here is some information that you may wish to have.
Most of your old TIP tables should continue to at least load properly. Notice, I didn't say they would work. TIP depends on other routines (such as RawViewersImpl.KeySymFromScanCode, X11TIPSourceImpl.RemapKeys, and X11TIPSourceImpl.EnsureKeyTable) to deliver keystrokes to it. So, getting a keystroke to actually do what you want it to may require some coordination. Also, some TIP key names have been revoked, have changed capitalization, or have just been forgotten (let me know if you find a name that really ought to be defined but isn't).
We are trying to head towards an age where all names appearing as triggers or enablers in TIP tables are either the names of standard symbols that actually tend to appear on keyboards (e.g., A, $, Cut, Paste, F1) or are pseudo-symbols that you might imagine pasting onto a keycap if you only used your keyboard for Cedar (such as LOOK or NEXT). This will require removing from TIP tables words like Spare3 or FL4 that are neither symbols nor Cedar concepts. Hopefully, we can phase these out gradually.
In this section, I list those Symbols which currently will be accepted in a PCedar TIP table. I list them in the following format (the complete up-to-date truth about this list can be found in TIPKeyboardsImpl.BuildKeyTables). Not all names found in this table are actually bound to a key on a given keybaord.
<name(s) you should use> (alternate names, for compatibility) => <the ASCII character associated with this symbol, if any>
A () => A
...
Z () => Z
a () => a
...
z () => z
Button1 (LeftMouse, Red, Point)
Button2 (MiddleMouse, Yellow, Menu)
Button3 (RightMouse, Blue, Adjust)
Space () => Ascii.SP
ExclamationPoint () => !
Quote, QuotationMark () => "
NumberSign () => #
DollarSign () => $
PercentSign () => %
Ampersand () => &
Apostrophe () => '
LeftParen, LeftParenthesis () => (
RightParen, RightParenthesis () => )
Asterisk () => *
PlusSign () => +
Comma () => ,
Hyphen () => -
Period (FullStop) => .
Slash, Solidus () => /
Zero () => 0
One () => 1
Two () => 2
Three () => 3
Four () => 4
Five () => 5
Six () => 6
Seven () => 7
Eight () => 8
Nine () => 9
Colon () => :
SemiColon () => ;
LeftAngleBracket (LessThanSign) => <
Equal, EqualSign () => =
RightAngleBracket (GreaterThanSign) => >
QuestionMark () => ?
AtSign () => @
LeftBracket () => [
BackSlash, ReverseSolidus () => \
RightBracket () => ]
CircumflexAccent () => ^ (temporary, this character also available from UpArrow)
LowLine () => ← (temporary, this character also available from LeftArrow)
GraveAccent () => `
LeftCurly, LeftCurlyBracket
VerticalLine, VerticalBar
RightCurly, RightCurlyBracket
Tilde () => ~
Dash () => -
BackSpace (BS) => Ascii.BS
Tab (TAB) => Ascii.TAB
LineFeed (LF) => Ascii.LF
Return (CR, Enter) => \n
Pause (Hold, ScrollLock)
Esc (ESC, COMPLETE, Center)
Home
UpArrow (Up, MoveUp) => ^
RightArrow (Right, MoveRight)
DownArrow (Down, MoveDown) => ¯
Next (NEXT, STUFF, Keyboard, Spare2)
Print
Execute (Run, Do, DOIT)
Help (HELP)
Break (BREAK)
LeftShift
RightShift
LeftControl (Ctrl, CONTROL, Open, Control)
CapsLock (LOCK, Lock)
Delete (DEL, DELETE)
KeypadMultiplicationSign, KeypadAsterisk () => *
KeypadPlusSign () => +
KeypadComma, KeypadSeparator () => ,
KeypadMinusSign, KeypadHyphen () => -
KeypadDecimalPoint, KeypadFullStop () => .
KeypadDivisionSign, KeypadSolidus () => /
KeypadZero ()
KeypadOne ()
KeypadTwo ()
KeypadThree ()
KeypadFour ()
KeypadFive ()
KeypadSix ()
KeypadSeven ()
KeypadEight ()
KeypadNine ()
KeypadEqualSign () => =
LeftMeta () (bound to the left diamond key on the SPARCStation 1)
RightMeta () (bound to the right diamond key on the SPARCStation 1)
LeftAlt () (bound to the Alt key on the SPARCStation 1)
RightAlt () (unbound on the SPARCStation 1)
LeftSuper ()
RightSuper ()
LeftHyper ()
RightHyper ()
F1 ()
...
F12 ()
L1 ()
L2 ()
L3 (F13)
...
L10 (F20)
R1
...
R8
R9 (Look, LOOK, Spare1, BW, COMMAND)
R10 (LeftArrow, Arrow, Left, MoveLeft) => ←
R11 ()
...
R14 ()
R15 (FormerlySWAT, Spare3, USERABORT)
RightControl ()
Swat (SWAT)
Stop (Cancel, Abort, Exit)
Again (AGAIN)
Props ()
Undo (UNDO)
Front ()
Copy (COPY)
Open ()
Paste (PASTE)
Find (FIND)
Cut ()
Unused0
...
Unused6
Keyset1
...
Keyset5
<more to be written, Bier, December 15, 1989>
1. Wider TIP events (new for 1990)
A new public interface, TIPIdentity, creates two new flavors of "transparent" TIP tables (defined in a revised TIPTables.mesa). A transparent TIP table passes events to client programs without translating them. Such tables are useful for debugging and for applications that wish to choose which (real) TIP table to translate an action through based on context. These new flavors pass through a larger set of events and, for each event, provide more information about the device that produced the event. For the time being, the Commander command "wideTIP on" must be given to activate these TIP tables.
A new private interface, TIPPrivateExtras2, provides routines analagous to TIPPrivate.ParseOneEvent and TIPPrivate.MatchEvent, for the new broader event definition.
-- Eric Bier, August 9, 199
2. A quick disclaimer:
There is still some confusion about the "names" of keys
Before you jump to the conclusion that you think you understand the concept of "a key on the keyboard", let me suggest that it's a little more complicated than you would think, and that you should be wary of what you think you know.
To start, there are basically four different "things" that you have to worry about. First of all, there are the physical objects that you can stare at on your keyboard, let me call them "keycaps". Then there is the hardware associated with those keycaps, which is a bit vector indicating whether the switch underneath a keycap is depressed or not (down/up), we'll call each of these things a "bit position". Then there are the programmer names for the bit positions in the KeyName item of the TerminalDefs interface, which we'll call these "KeyName values", and finally there are the symbols which belong to the TIP vocabulary, which we'll call "TIP names".
Now lets throw in a few distractions; TerminalDefs includes some extra "constants" which can be used in place of Keyname values by programmers. This seems to be a dubious practice and should be discouraged, but is required for backward compatibility. It you happen do discover old code that uses constants, consider changing them to Keyname values instead.
The next distraction is that there are some "synonyms" added to the TIP vocabulary, also primarily for backward compatibility, but some seem to have been added for convienence. Currently, most of these convienence synonyms are not mapped to the keycaps you would think that they should be mapped to.
To confuse things even further, there are the "keyName ropes" which are available thru TIPPrivate.keyNames[KeyName] which contain names (in a derogatory sense) for the keys. Currently, these keyName ropes are not the same as the symbolic KeyName values, but are a mix of representations for values and constants. If you're interested, look in TIPTableBuilder.Mesa for the definition point of keyNames.
Now, to get to the nitty gritty, TIPTableBuilder.Mesa contains a procedure GetWord, which uses ATOMS (yes, ATOMS!) to identify whether tokens in tip tables refer to reserved words, or to names of keys (in the TIP name vocabulary sense). Currently there are problems with this mapping in that some synonyms which historically refered to constants now use the actual KeyName values instead (this isn't a new bug!), and you can discover obvious conflicts between interpretatons. For example, you might want to look at "Move", and "MOVE"
Luckily, all the problems seem to be constrained to keys which are unavailable on the Dorado keyboard (DLion keys?); so, unless you've done something special to your tip tables for DLions (or Daybreaks) none of this matters to you. Hopefully everything can get straightened out, but it is unlikely that the constants in TerminalDefs can be corrected (since it requires a major Cedar bounce/release), hence the suggestion that you avoid these. It should also be the case that the standard tip tables should use only TIP names corresponding to actual KeyName values. This could cause novice tip table hackers to get confused since the mapping between KeyName values and keycaps is not obvious, but judicious use of comments should help out here. Also documenting that mapping should help...
3. Basic Overview
How to use it
In order to get started, you need to create a TIP client. A user is expected to provide a procedure (a TIPNotifyProc) that TIP can call for recognised events. In your start code, you should call CreateClient, passing in your TIPNotifyProc. TIP will fork a process and begin looking for input events. You next need to give TIP a table from which to parse events. Most applications find the default table to be sufficient, but you can read the section on TIP Tables below in order to "roll your own". You can create your own TIPTable from its disk representation using InstantiateNewTIPTable, or simply pass NIL into InstantiateNewTIPTable. The "Compiled" versions of the TIP Table are stored in []<>TipC>*.tipC.
A Macro preprocessor has been added to the TIP language to improve its generality.
How it works
When TIP recognises an event, the TIPNotifyProc is called with the parameter 'results', which is a list of values collected from the TIP Table while parsing an event. The default table provides a REF CHAR for normal keys. In order to receive events from the keyboard you have to acquire first the "Input Focus" (see the InputFocus interface). If not you will only be notified for mouse events when the cursor is in your Viewer (Unless you use InputFocus.CaptureButtons).
4. TIP Tables
Some applications
For a detailed example, see [Cedar]<Cedar®>Tioga>Tioga.tip, and remember that you can always default the table by passing NIL to InstantiateTIPTable. In general, most people will want to use the default mechanisms.
A much simpler table can be found in [Cedar]<Cedar®>Viewers>MessageWindow.tip for instance.
Syntax
Here is the BNF description for a valid TIP table: (terminals are the quoted symbols and the special characters besides the metasymbols ::= and | )
TIPTable ::= Options Macros TriggerStmt .
Options ::= empty | "OPTIONS" OptionList ;
OptionList ::= SmallOrFast | SmallOrFast , PrintOrDefaultKeys | PrintOrDefaultKeys
SmallOrFast ::= "Small" | "Fast"
PrintOrDefaultKeys ::= "PrintKeys" | "DefaultKeys"
Macros ::= empty | MacroList
MacroList ::= Macro ; MacroList
Macro ::= "[DEF,", MacroName, "(", MacroBody, ")]"
A precise definition could probably be found in Strachey: General Purpose Macrogenerator described in Computer Journal, Oct. 1965. pp. 225-241. See below.
TriggerStmt ::= "SELECT" "TRIGGER" "FROM" TriggerChoiceSeries
EnableStmt ::= "SELECT" "ENABLE" "FROM" EnableChoiceSeries
TriggerChoiceSeries ::= TriggerChoice ;
TriggerChoiceSeries | TriggerChoice "ENDCASE" FinalChoice
EnableChoiceSeries ::= EnableChoice ;
EnableChoiceSeries | EnableChoice "ENDCASE" FinalChoice
TriggerChoice ::= TriggerTerm Expression
EnableChoice ::= EnableTerm Expression
TriggerTerm ::= Key TimeOut | "Mouse" TimeOut
EnableTerm ::= Key | PredicateIdent
Key ::= KeyIdent "Up" | KeyIdent "Down"
TimeOut ::= "BEFORE" Number | "AFTER" Number
Expression ::= "AND" TriggerChoice | "WHILE" EnableChoice | => Statement
Results ::= ResultItem | ResultItem , Results | ResultItem Expression
ResultItem ::= "Coords" | "Char" | String | Number | ResultIdent
FinalChoice ::= empty | => Statement
Statement ::= TriggerStmt | EnableStmt | Results
Blanks, tabs and CRs are allowed between symbols, comments are handled as in Mesa.
The meaning of the options is as follows:

DefaultKeys Adds all normal keyboard events
PrintKeys As above, but only printing keys (e.g. not 'Return' or mouse stuff)
Fast  Indicates to table builder that you favor lookup speed over storage
Small  Indicates you favor storage over lookup speed (default)
The whole match process is viewed as a SELECT statement, which is continuously executed reading key transitions, mouse movements, or key states from the input stream. A trigger statement has the effect of looking at the next action recorded in the input stream and branching to the appropriate choice. An enable statement implies selection between the different choices according to the 'current' state of the keyboard or the mouse keys. Trigger terms may appear in sequence, separated by AND. They might be mixed with enable terms which in turn are characterized by the keyword WHILE. A timeout following a trigger indicates a timing condition which has to hold between this trigger and its predecessor. The number associated with the timeout expresses a time intervall in msecs. An enable term consisting of a predicate identifier is interpreted by calling the 'TIPPredicate' with the same name, a boolean procedure registered in TIP by the user. Events starting with the same sequence of trigger and/or enable terms are expressed as nested statements. As result items you may specify names, numbers, strings, or the keywords Char or Coords. The results of a successfully parsed event are passed to the user as a LIST OF REF ANY. Where names appear as atoms, numbers as REF INT, and strings as REF TEXT. Char comes as a REF CHAR pointing to the ASCII interpretation of the key involved with the event, Coords results in a 'TIPScreenCoords' which is a REF to the RECORD [x, y: REAL]; x and y containing the mouse coordinates of the event.
For example, the DefaultKeys entry for the letter "A" might be represented as:

SELECT
TRIGGER FROM
A Down WHILE Ctrl Up => Char;
...

This event will be triggered when the A key goes down, only if the Ctrl key is up and will pass a REF to the character A as a result.
A more elaborate example may look like this:

SELECT
TRIGGER FROM
Red Down =>
SELECT TRIGGER FROM
Red Up BEFORE 200 AND Red Down BEFORE 200 =>
SELECT ENABLE FROM
  LeftShift Down => Coords, ShiftedDoubleClick
ENDCASE => Coords, NormalDoubleClick;
Blue Down BEFORE 300 => RedAndBlue
ENDCASE => Coords, SimpleClick;
...
This table produces the result NormalDoubleClick along with the mouse coordinates if the red mouse button goes down, remains there not longer than 200 ms, and goes down again before another 200 ms elapse.
The result will be ShiftedDoubleClick if the same actions occur but also the left shift key is down.
If less than 300 ms after the initial 'Red Down' the blue mouse button also goes down then we get the result RedAndBlue.
And finaly the table specifies the result SimpleClick (with coordinates) for the case of red going down but none of the above described succeeding actions occuring.
Macro syntax
The macro package used in TIP is based on the "General Purpose Macrogenerator" described by Strachey in the October 1965 Computer Journal. The following summary is based on that article; see the real thing for more details.
A macro-call consists of a macro-name and a list of actual parameters, each separated by a comma. The name is preceded by a left square bracket ([) and the last parameter is followed by a right square bracket. A macro is defined by the special macro DEF which takes two arguments: the name of the macro to be defined and the defining string. The defining string may contain the special symbols ~1, ~2, etc., which stand for the first, second, etc., formal parameters. Enclosing any string in parentheses has the effect of preventing evaluation of any macro-calls inside; in place of evaluation, one "layer" of string quotes is removed. It is usual to enclose the defining string of a macro definition in string quotes in order to prevent any macro-calls or uses of formal parameters from being effective during the process of definition. The symbol  acts as a single character string quote (to enter this, type "d", then hit MakeControlCharacter). Use it in front of special macrogenerator characters in string literals. For example, if you want to insert "(", you need to write "(" to keep the macro scanner from treating the paren as a start of string quote.
Examples :
[DEF,WhileCTRLUp,(WHILE Ctrl Up WHILE Spare3 Up)]
[DEF,BothUp,(~1 Up WHILE ~2 Up)]
[DEF,IfShift,(SELECT ENABLE FROM
[SHIFT] => ~1;
ENDCASE => ~2)]
Which are later used as:
[BothUp,Red,Yellow] => SELECT TRIGGER FROM ...
ESC Down [WhileCTRLUp] => [IfShift,Undo,Repeat];
From Tioga.tip.
Compiled tables syntax
The syntax of "compiled" tip table files follows:
capital letters, numbers and parens are character literals
lower case id's are names of syntax equations
id* means 0 or more instances
<id> is a primitive of some sort such as text
file = TIPTABLE version opaque link ignore variant
version = <char>
opaque = flag
link = N --none-- | P --printKeys-- | D --defaultKeys--
ignore = up down move
up = flag
down = flag
move = flag
variant = S small | F fast
small = choiceseries
fast = choice U choicearray D choicearray time
time = choice
choicearray = ( choiceitem* )
choiceitem = ( key choice )
choiceseries = ( choice* )
choice = ( term* )
term = 1 keytrigger | 2 --mousetrigger-- | 3 timetrigger | 4 keyenable |
5 predenable | 6 --CHAR-- | 7 --COORDS-- | 8 choiceseries | 9 results |
A key2Enable | B keyEnableList | C --TIME--
keytrigger = key keystate
key = <byte>
keystate = U --up-- | D --down--
timetrigger = timeoutflavor msecs
timeoutflavor = G --gt-- | L --lt--
msecs = high low
high = <byte>
low = <byte>
keyenable = key keystate
key2Enable = keyenable keyenable
keyEnableList = ( keyenable* )
predenable = atom
results = ( result* )
result = 1 atom | 2 --TIPUser.stdChar-- | 3 <int> | 4 len <text> |
5 --TIPScreenCoords-- | 6 --TIPUser.stdTime--
flag = T | F -- true or false
atom = len pname
pname = <text>
len = <byte>
<text> stored as series of characters. length limited to 255 chars
<int> stored as 4 bytes
<char> and <byte> stored as themselves
5. Appendix
The Old Dorado Cedar Alto Keyboard KeyIdent definitions (Historical Interest Only)
ESC: [Ascii.ESC, Ascii.ESC], -- Alto ESC (upper left), DLion CENTER (top row, left end)
One: ['1, '!], -- 1 and !
Two: ['2, '@], -- 2 and @
Three: ['3, '#], -- 3 and #
Four: ['4, '$], -- 4 and $
Five: ['5, '%], -- 5 and %
Six: ['6, '~], -- 6 and ~
Seven: ['7, '&], -- 7 and &
Eight: ['8, '*], -- 8 and *
Nine: ['9, '(], -- 9 and (
Zero: ['0, ')], -- 0 and )
Dash: ['-, '—], -- Alto - and —, DLion -
Equal: ['=, '+], -- = and +
BackSlash: ['\\, '|], -- Alto \ and |, DLion DEFAULTS (top row, right end)
LF: [Ascii.LF, Ascii.LF], -- Alto LF (upper right), DLion COPY (left group)
DEL: [Ascii.DEL, Ascii.DEL], -- Alto DEL, DLion DELETE (left group)
TAB: [Ascii.TAB, Ascii.TAB], -- Alto TAB, DLion <paratab> (large key left of Q)
Q: ['q, 'Q],
W: ['w, 'W],
E: ['e, 'E],
R: ['r, 'R],
T: ['t, 'T],
Y: ['y, 'Y],
U: ['u, 'U],
I: ['i, 'I],
O: ['o, 'O],
P: ['p, 'P],
LeftBracket: ['[, '{], -- [ and {
RightBracket: ['], '}], -- ] and }
Arrow: ['←, '^], -- Alto ← and ^, DLion open quotes
BS: [Ascii.BS, Ascii.BS], -- Alto BS (upper right), DLion ← (large key, upper right)
A: ['a, 'A],
S: ['s, 'S],
D: ['d, 'D],
F: ['f, 'F],
G: ['g, 'G],
H: ['h, 'H],
J: ['j, 'J],
K: ['k, 'K],
L: ['l, 'L],
SemiColon: [';, ':], --; and :
Quote: ['\', '\"], -- ' and " (close quotes on DLion)
Return: [Ascii.CR, Ascii.CR], -- Alto RETURN, DLion <newpara> (double-height key, right side)
Z: ['z, 'Z],
X: ['x, 'X],
C: ['c, 'C],
V: ['v, 'V],
B: ['b, 'B],
N: ['n, 'N],
M: ['m, 'M],
Comma: [',, '<], -- , and <
Period: ['., '>], -- . and >
Slash: ['/, '?], -- / and ?
Space: [Ascii.SP, Ascii.SP], -- the space bar
Spare1: ['\201, '\204],
Spare2: ['\202, '\205],
Spare3: ['\203, '\206]
Note that there are no names for shifted characters like left or right paren. Instead you must specify SHIFT plus the unshifted key name e.g.
Nine Down WHILE [SHIFT] instead of LeftParen Down