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.