-- 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.