-- Keyboard.Mesa Edited by Sandman on May 22, 1980 3:24 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDisplay USING [Coordinate], InlineDefs USING [BITAND, BITSHIFT, BITXOR], KeyDefs USING [KeyArray, KeyBits, KeyItem, updown], KeyPrivate USING [Xmax, Ymax], StreamDefs USING [KeyboardHandle, KeyBufChars, StreamHandle]; Keyboard: MONITOR LOCKS monitor IMPORTS InlineDefs EXPORTS KeyDefs, KeyPrivate, StreamDefs SHARES StreamDefs = BEGIN OPEN KeyDefs, StreamDefs; monitor: PUBLIC MONITORLOCK; wakeup: PUBLIC CONDITION; charactersAvailable: PUBLIC CONDITION; -- variables set by KeyStreams ks: PUBLIC KeyboardHandle; userAbort, halt, trackCursor: PUBLIC BOOLEAN; KeyTable: PUBLIC POINTER TO ARRAY [0..80) OF KeyItem; -- The Keyboard part: -- fixed addresses for keyboard and mouse keys: PUBLIC POINTER TO KeyArray; mouse: PUBLIC POINTER TO AltoDisplay.Coordinate; cursor: PUBLIC POINTER TO AltoDisplay.Coordinate; oldState, newState: PUBLIC POINTER TO KeyArray; ProcessKeyboard: PUBLIC ENTRY PROCEDURE = BEGIN OPEN InlineDefs; bitcount, start: [0..15]; char: [0..377B]; entry: KeyItem; i: [0..SIZE[KeyArray]); newin: CARDINAL; StateWord: WORD; stroke: POINTER TO KeyBits = LOOPHOLE[newState]; DO WAIT wakeup[ ! ABORTED => CONTINUE]; IF halt THEN EXIT; -- first update the cursor IF trackCursor THEN BEGIN mouse.x ← cursor.x ← MAX[MIN[KeyPrivate.Xmax, mouse.x], 0]; mouse.y ← cursor.y ← MAX[MIN[KeyPrivate.Ymax, mouse.y], 0]; END; newState↑ ← keys↑; -- The following code checks for down transitions in the keyboard state -- and enters characters in the current keystream buffer FOR i IN [0..SIZE[KeyArray]) DO IF (StateWord ← BITXOR[oldState[i], newState[i]]) # 0 THEN BEGIN -- found one or more transitions start ← 0; DO FOR bitcount IN [start..15] DO IF LOOPHOLE[StateWord, INTEGER] < 0 THEN EXIT; StateWord ← BITSHIFT[StateWord, 1]; ENDLOOP; entry ← KeyTable[i*16 + bitcount]; IF (char ← entry.NormalCode) # 0 AND BITAND[ oldState[i], BITSHIFT[100000B, -bitcount]] # 0 THEN BEGIN SELECT updown[down] FROM stroke.Ctrl => IF char = 177B THEN BEGIN userAbort ← TRUE; GOTO skip END ELSE char ← BITAND[char, 37B]; stroke.LeftShift, stroke.RightShift => char ← entry.ShiftCode; stroke.Lock => IF entry.Letter THEN char ← entry.ShiftCode; ENDCASE; IF (newin ← ks.in + 1) = KeyBufChars THEN newin ← 0; IF newin # ks.out THEN BEGIN ks.buffer[ks.in] ← LOOPHOLE[char]; ks.in ← newin; BROADCAST charactersAvailable; END; EXITS skip => NULL; END; IF (StateWord ← BITSHIFT[StateWord, 1]) = 0 THEN EXIT; start ← bitcount + 1; ENDLOOP; END; ENDLOOP; oldState↑ ← newState↑; ENDLOOP; END; ReadChar: PUBLIC ENTRY PROCEDURE [stream: StreamHandle] RETURNS [char: UNSPECIFIED] = BEGIN char ← 0; WITH s: stream SELECT FROM Keyboard => DO -- until character typed IF s.out # s.in THEN BEGIN char ← s.buffer[s.out]; s.out ← IF s.out = KeyBufChars - 1 THEN 0 ELSE s.out + 1; RETURN END; WAIT charactersAvailable[ ! UNWIND => NULL]; ENDLOOP; ENDCASE; RETURN; END; InputBufferEmpty: PUBLIC ENTRY PROCEDURE [stream: StreamHandle] RETURNS [empty: BOOLEAN] = BEGIN empty ← TRUE; WITH s: stream SELECT FROM Keyboard => IF s.in # s.out THEN empty ← FALSE; ENDCASE; RETURN END; END.