XlAsciiInputImpl.mesa
Copyright Ó 1988, 1989, 1991, 1992 by Xerox Corporation. All rights reserved.
Christian Jacobi, July 4, 1988 1:01:32 pm PDT
Christian Jacobi, February 26, 1992 1:04 pm PST
DIRECTORY
KeySymsSun,
KeySymsOSF,
KeySymsHP,
Process,
Rope,
Xl,
XlAscii,
XlAsciiInput,
XlCutBuffers;
XlAsciiInputImpl:
CEDAR
MONITOR
IMPORTS Process, Rope, XlAscii, Xl, XlCutBuffers
EXPORTS XlAsciiInput =
BEGIN
OPEN
Xl, XlAsciiInput;
events: EventFilter = CreateEventFilter[destroyNotify, keyPress];
check: CONDITION;
BroadCast:
ENTRY
PROC[] = {
ENABLE UNWIND => NULL;
BROADCAST check;
};
WindowDestroyed: PUBLIC ERROR = CODE;
bufferSize: INT ~ 120;
Buffer:
TYPE =
RECORD [
in, out: INT ¬ 0,
data: PACKED ARRAY [0..bufferSize) OF CHAR,
next: REF Buffer ¬ NIL
];
HandleRec:
TYPE =
MONITORED
RECORD [
connection: Xl.Connection ¬ NIL,
window: Window ¬ nullWindow,
buffer: REF Buffer ¬ NIL,
lastBuffer: REF Buffer ¬ NIL,
alive: BOOL ¬ TRUE
];
cnt: INT ¬ 0;
unused: REF Buffer ¬ NIL;
GetBuffer:
INTERNAL
PROC []
RETURNS [buff:
REF Buffer] = {
IF unused=NIL THEN buff ¬ NEW[Buffer]
ELSE {
buff ¬ unused; unused ¬ buff.next;
buff.in ¬ buff.out ¬ 0; buff.next ¬ NIL; cnt ¬ cnt-1;
};
};
DisposeBuffer:
INTERNAL
PROC [buff:
REF Buffer] = {
IF buff#
NIL
AND cnt<4
THEN {cnt ¬ cnt+1;
buff.next ¬ unused; unused ¬ buff;
};
};
EnableAsciiInput:
PUBLIC
PROC [c:
Xl.Connection, w:
Xl.Window]
RETURNS [Handle] = {
h: REF HandleRec ¬ NEW[HandleRec ¬ [connection: c, window: w]];
match: Match ¬ NEW[MatchRep ¬ [proc: EventProc, handles: events, tq: CreateTQ[], data: h]];
Xl.AddDispatch[c, w, match, [keyPress: TRUE, keyRelease: TRUE, structureNotify: TRUE]];
RETURN [h];
};
listWithPaste: LIST OF Xl.KeySym = LIST[KeySymsSun.Paste, KeySymsOSF.Paste, KeySymsHP.Paste];
EventProc: EventProcType = {
ENABLE Xl.XError => GOTO oops;
h: REF HandleRec ~ NARROW[clientData];
WITH event
SELECT
FROM
keyPress: KeyPressEvent => {
char: CHAR; keysym: Xl.KeySym; matched: Xl.KeySym; isModifier: BOOL;
[char: char, keysym: keysym, matched: matched, isModifier: isModifier] ¬ XlAscii.Convert[event.connection, keyPress.keyCode, keyPress.state, listWithPaste];
IF isModifier THEN RETURN;
IF matched = KeySymsSun.Paste
OR matched = KeySymsOSF.Paste
OR matched = KeySymsHP.Paste
THEN {
r: ROPE ¬ XlCutBuffers.Get[event.connection];
TypeIn[h, r];
RETURN
};
IF char#0c THEN QueueChar[h, char];
};
destroyNotify: DestroyNotifyEvent => {
IF destroyNotify.window=h.window
THEN {
h.alive ¬ FALSE; BroadCast[];
}
};
ENDCASE => {};
EXITS oops => {};
};
TypeIn:
PUBLIC
ENTRY
PROC [handle: Handle, chars:
REF] = {
ENABLE UNWIND => NULL;
WITH handle
SELECT
FROM
h:
REF HandleRec => {
WITH chars
SELECT
FROM
ch: REF CHAR => InternalQueueChar[h, ch];
r: Rope.
ROPE => {
EachChar: INTERNAL Rope.ActionType = {InternalQueueChar[h, c]};
[] ¬ Rope.Map[base: r, action: EachChar];
};
ENDCASE => {};
};
ENDCASE => {};
};
QueueChar:
ENTRY
PROC [h:
REF HandleRec, ch:
CHAR] = {
ENABLE UNWIND => NULL;
InternalQueueChar[h, ch]
};
InternalQueueChar:
INTERNAL
PROC [h:
REF HandleRec, ch:
CHAR] = {
IF ORD[ch]=0 THEN {BROADCAST check; RETURN};
IF h.buffer=
NIL
THEN {
buff: REF Buffer ¬ GetBuffer[];
h.lastBuffer ¬ h.buffer ¬ buff;
};
IF h.lastBuffer.in>=bufferSize
THEN {
h.lastBuffer.next ¬ GetBuffer[];
h.lastBuffer ¬ h.lastBuffer.next;
};
h.lastBuffer.data[h.lastBuffer.in] ¬ ch;
h.lastBuffer.in ¬ h.lastBuffer.in+1;
BROADCAST check;
};
CharAvailable:
PUBLIC
PROC [handle: Handle, wait:
BOOL ¬
FALSE]
RETURNS [n:
INT ¬ 0] = {
EntryCharAvailable:
ENTRY
PROC [] = {
ENABLE {
UNWIND => NULL;
ABORTED => GOTO oops;
};
IF wait
THEN {
WHILE h.buffer=
NIL
OR h.buffer.out>=h.buffer.in
DO
WAIT check;
IF ~h.alive OR ~Xl.Alive[h.connection] THEN RETURN WITH ERROR WindowDestroyed;
Process.CheckForAbort[];
ENDLOOP;
n ¬ ABS[h.buffer.in-h.buffer.out];
}
ELSE {
IF h.buffer=
NIL
OR h.buffer.out>=h.buffer.in
THEN n ¬ 0
ELSE n ¬ ABS[h.buffer.in-h.buffer.out];
};
EXITS oops => RETURN WITH ERROR ABORTED;
};
h: REF HandleRec ¬ NARROW[handle];
IF ~h.alive OR ~Xl.Alive[h.connection] THEN ERROR WindowDestroyed;
IF h.buffer=NIL AND ~wait THEN RETURN [0];
EntryCharAvailable[]
};
GetChar:
PUBLIC PROC [handle: Handle, wait:
BOOL ¬
TRUE]
RETURNS [ch:
CHAR¬0c] = {
EntryGetChar:
ENTRY
PROC [] = {
ENABLE {
UNWIND => NULL;
ABORTED => GOTO oops;
};
IF wait
THEN {
WHILE h.buffer=
NIL
OR h.buffer.out>=h.buffer.in
DO
WAIT check;
IF ~h.alive OR ~Xl.Alive[h.connection] THEN RETURN WITH ERROR WindowDestroyed;
Process.CheckForAbort[];
ENDLOOP
}
ELSE {
IF h.buffer=NIL OR h.buffer.out>=h.buffer.in THEN RETURN;
};
ch ¬ h.buffer.data[h.buffer.out];
h.buffer.out ¬ h.buffer.out+1;
IF h.buffer.out>=bufferSize
THEN {
buf: REF Buffer ¬ h.buffer;
h.buffer ¬ h.buffer.next;
IF h.buffer=NIL THEN h.lastBuffer ¬ NIL;
DisposeBuffer[buf];
};
EXITS oops => RETURN WITH ERROR ABORTED;
};
h: REF HandleRec ¬ NARROW[handle];
IF ~h.alive OR ~Xl.Alive[h.connection] THEN ERROR WindowDestroyed;
EntryGetChar[];
};
ResetBuffer:
PUBLIC ENTRY
PROC [handle: Handle] = {
ENABLE UNWIND => NULL;
WITH handle
SELECT
FROM
h:
REF HandleRec => {
DisposeBuffer[h.buffer];
h.buffer ¬ h.lastBuffer ¬ NIL;
};
ENDCASE => {};
};
InitCond:
ENTRY
PROC [] =
TRUSTED {
ENABLE UNWIND => NULL;
Process.InitializeCondition[@check, Process.MsecToTicks[10000]];
};
InitCond[];
END.