-- MMKeyboard.Mesa Edited by Sandman on June 20, 1979 9:28 AM -- Edited by Forrest on July 15, 1980 2:49 PM DIRECTORY InlineDefs USING [BITAND, BITOR, BITSHIFT, BITXOR], KeyDefs USING [KeyArray, KeyBits, KeyItem, Keys, updown], MMInit, ProcessDefs USING [ CV, Detach, DIW, GetPriority, InterruptLevel, Priority, SetPriority], StreamDefs USING [ KeyboardHandle, KeyBufChars, StreamHandle, StreamObject, StreamErrorCode]; MMKeyboard: MONITOR LOCKS monitor IMPORTS InlineDefs, ProcessDefs EXPORTS StreamDefs, MMInit SHARES StreamDefs = BEGIN OPEN InlineDefs, KeyDefs, StreamDefs; StreamError: PUBLIC SIGNAL [stream: StreamHandle, error: StreamErrorCode] = CODE; monitor: MONITORLOCK; wait: CONDITION; charactersAvailable: CONDITION; -- variables set by KeyStreams ks: KeyboardHandle; cursorTracking: BOOLEAN; continue: BOOLEAN ← TRUE; -- The Keyboard part: -- fixed addresses for keyboard and mouse Keys: POINTER TO KeyArray; Coordinate: TYPE = RECORD [x,y: INTEGER]; Mouse: POINTER TO Coordinate; Cursor: POINTER TO Coordinate; Xmax: CARDINAL = 606-16; Ymax: CARDINAL = 808-16; ns, os: KeyArray; OldState: POINTER TO KeyArray = @os; NewState: POINTER TO KeyArray = @ns; ProcessKeyboard: PUBLIC ENTRY PROCEDURE = BEGIN bitcount, start: [0..15]; char: [0..377B]; entry: KeyItem; i: [0..SIZE[KeyArray]); interruptState: updown ← up; newin: CARDINAL; StateWord: WORD; stroke: POINTER TO KeyBits = LOOPHOLE[NewState]; WHILE continue DO WAIT wait; -- first update the cursor IF cursorTracking THEN BEGIN Mouse.x ← Cursor.x ← MAX[MIN[Xmax,Mouse.x], 0]; Mouse.y ← Cursor.y ← MAX[MIN[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 => 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; 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; 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; KS: Keyboard StreamObject ← StreamObject [ reset: ClearInputBuffer, get: ReadChar, putback: PutBackChar, put: WriteChar, endof: InputBufferEmpty, destroy: DestroyKey, link: NIL, body: Keyboard[0,0,]]; GetDefaultKey, GetCurrentKey: PUBLIC PROCEDURE RETURNS [KeyboardHandle] = BEGIN RETURN[@KS]; END; OpenKeyStream: PUBLIC ENTRY PROCEDURE [stream:StreamHandle] = BEGIN WITH s:stream SELECT FROM Keyboard => ks ← @s; ENDCASE => SIGNAL StreamError[stream,StreamType ! UNWIND => NULL]; RETURN; END; ClearInputBuffer: ENTRY PROCEDURE [stream:StreamHandle] = BEGIN WITH s:stream SELECT FROM Keyboard => s.in ← s.out ← 0; ENDCASE => SIGNAL StreamError[stream,StreamType ! UNWIND => NULL]; RETURN; END; PutBackChar: ENTRY PROCEDURE [stream:StreamHandle, char:UNSPECIFIED] = BEGIN newout: CARDINAL; WITH s:stream SELECT FROM Keyboard => BEGIN newout ← s.out; newout ← IF newout = 0 THEN KeyBufChars-1 ELSE newout-1; IF newout # s.in THEN BEGIN s.out ← newout; s.buffer[s.out] ← char; BROADCAST charactersAvailable; END; END; ENDCASE => SIGNAL StreamError[stream,StreamType ! UNWIND => NULL]; RETURN; END; WriteChar: PROCEDURE [stream:StreamHandle, char:UNSPECIFIED] = BEGIN SIGNAL StreamError[stream,StreamAccess]; RETURN END; CloseKeyStream: PUBLIC ENTRY PROCEDURE [stream:StreamHandle] = BEGIN END; DestroyKey: --ENTRY-- PROCEDURE [stream:StreamHandle] = BEGIN continue ← FALSE; ProcessDefs.CV[KeyboardLevel] ← LOOPHOLE[0] END; CursorTrack: PUBLIC PROCEDURE [b: BOOLEAN] = BEGIN cursorTracking ← b; RETURN END; KeyItem: TYPE = KeyDefs.KeyItem; KeyTable: ARRAY [0..80) OF KeyItem = [ -- MEMORY[177033B] Index [0..15] KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- UNUSED KeyItem[FALSE, 0, 0], -- KeyItemset1 KeyItem[FALSE, 0, 0], -- KeyItemset2 KeyItem[FALSE, 0, 0], -- KeyItemset3 KeyItem[FALSE, 0, 0], -- KeyItemset4 KeyItem[FALSE, 0, 0], -- KeyItemset5 KeyItem[FALSE, 0, 0], -- Red KeyItem[FALSE, 0, 0], -- Blue KeyItem[FALSE, 0, 0], -- Yellow -- MEMORY[177034B] Index [16..31] KeyItem[FALSE, 45B, 65B], -- %,5 KeyItem[FALSE, 44B, 64B], -- $,4 KeyItem[FALSE, 176B, 66B], -- ~,6 KeyItem[TRUE, 105B, 145B], -- E KeyItem[FALSE, 46B, 67B], -- &,7 KeyItem[TRUE, 104B, 144B], -- D KeyItem[TRUE, 125B, 165B], -- U KeyItem[TRUE, 126B, 166B], -- V KeyItem[FALSE, 51B, 60B], -- ),0 KeyItem[TRUE, 113B, 153B], -- K KeyItem[FALSE, 30B, 55B], -- `,- KeyItem[TRUE, 120B, 160B], -- P KeyItem[FALSE, 77B, 57B], -- ?,/ KeyItem[FALSE, 174B, 134B], -- |,\ KeyItem[FALSE, 12B, 12B], -- LF KeyItem[FALSE, 10B, 10B], -- BS -- MEMORY[177035B] Index [32..47] KeyItem[FALSE, 43B, 63B], -- #,3 KeyItem[FALSE, 100B, 62B], -- @,2 KeyItem[TRUE, 127B, 167B], -- W KeyItem[TRUE, 121B, 161B], -- Q KeyItem[TRUE, 123B, 163B], -- S KeyItem[TRUE, 101B, 141B], -- A KeyItem[FALSE, 50B, 71B], -- (,9 KeyItem[TRUE, 111B, 151B], -- I KeyItem[TRUE, 130B, 170B], -- X KeyItem[TRUE, 117B, 157B], -- O KeyItem[TRUE, 114B, 154B], -- L KeyItem[FALSE, 74B, 54B], -- <,, KeyItem[FALSE, 42B, 47B], -- ",' KeyItem[FALSE, 175B, 135B], -- },] KeyItem[FALSE, 0B, 0B], -- SPARE2 KeyItem[FALSE, 0B, 0B], -- SPARE1 -- MEMORY[177036B] Index [48..63] KeyItem[FALSE, 41B, 61B], -- !,1 KeyItem[FALSE, 33B, 33B], -- ESCAPE KeyItem[FALSE, 11B, 11B], -- TAB KeyItem[TRUE, 106B, 146B], -- F KeyItem[FALSE, 0B, 0B], -- CONTROL KeyItem[TRUE, 103B, 143B], -- C KeyItem[TRUE, 112B, 152B], -- J KeyItem[TRUE, 102B, 142B], -- B KeyItem[TRUE, 132B, 172B], -- Z KeyItem[FALSE, 0B, 0B], -- SHIFT KeyItem[FALSE, 76B, 56B], -- >,. KeyItem[FALSE, 72B, 73B], -- :,; KeyItem[FALSE, 15B, 15B], -- CR KeyItem[FALSE, 136B, 137B], -- ↑,← KeyItem[FALSE, 177B, 177B], -- DEL KeyItem[FALSE, 0B, 0B], -- NOT USED (FL3) -- MEMORY[177037B] Index [64..79] KeyItem[TRUE, 122B, 162B], -- R KeyItem[TRUE, 124B, 164B], -- T KeyItem[TRUE, 107B, 147B], -- G KeyItem[TRUE, 131B, 171B], -- Y KeyItem[TRUE, 110B, 150B], -- H KeyItem[FALSE, 52B, 70B], -- *,8 KeyItem[TRUE, 116B, 156B], -- N KeyItem[TRUE, 115B, 155B], -- M KeyItem[FALSE, 0B, 0B], -- LOCK KeyItem[FALSE, 40B, 40B], -- SPACE KeyItem[FALSE, 173B, 133B], -- {,[ KeyItem[FALSE, 53B, 75B], -- +,= KeyItem[FALSE, 0B, 0B], -- SHIFT KeyItem[FALSE, 0B, 0B], -- SPARE3 KeyItem[FALSE, 0B, 0B], -- NOT USED (FL4) KeyItem[FALSE, 0B, 0B]]; -- NOT USED (FR5) -- The Process (and initialization) part KeyboardLevel: ProcessDefs.InterruptLevel = 7; Init: PROCEDURE = BEGIN OPEN ProcessDefs; KeyboardBit: WORD = InlineDefs.BITSHIFT[1,KeyboardLevel]; save: Priority = GetPriority[]; KeyboardPriority: Priority = 6; OldState↑ ← Keys↑; CursorTrack[TRUE]; Keys ← LOOPHOLE[KeyDefs.Keys]; ks ← @KS; Mouse ← LOOPHOLE[424B]; Cursor ← LOOPHOLE[426B]; SetPriority[KeyboardPriority]; Detach[FORK ProcessKeyboard]; SetPriority[save]; CV[KeyboardLevel] ← @wait; DIW↑ ← InlineDefs.BITOR[DIW↑,KeyboardBit]; END; Init[]; END.