-- XMKDriverImpl.mesa
-- Created By Jeff Weinstein on 29-Mar-87 17:16:06
DIRECTORY
BitBlt,
Keys,
Inline,
Process,
Runtime,
System,
UserTerminal,
XDefs,
XEventQ,
XMKDriver;
XMKDriverImpl:PROGRAM IMPORTS Inline, Process, Runtime, System, UserTerminal, XEventQ EXPORTS XMKDriver =
BEGIN
--Types
buttonState:TYPE = {down, up, waitingRelease, waitingChord};
buttons: TYPE = MACHINE DEPENDENT {left(1), middle(2), right(3)};
-- Keyboard vars
lastKeys, newKeys:Keys.KeyBits ← ALL[up];
keyboard: LONG POINTER TO Keys.KeyBits = LOOPHOLE[UserTerminal.keyboard];
keyboardEventsEnabled:BOOLEAN ← FALSE;
-- Mouse vars
lastMouse, newMouse:UserTerminal.Coordinate;
mouseConstraintBox:XMKDriver.Box ← [0, 0, UserTerminal.screenWidth-1, UserTerminal.screenHeight-1];
mouseNoInterestBox:XMKDriver.Box ← [UserTerminal.screenWidth, UserTerminal.screenHeight,UserTerminal.screenWidth, UserTerminal.screenHeight];
mouseEventsEnabled:BOOLEAN ← FALSE;
-- Button vars
buttonStates:ARRAY buttons OF buttonState ← ALL[up];
chordFlag:BOOLEAN ← FALSE;
buttonDownTime:System.Pulses;
buttonDownCoord:UserTerminal.Coordinate;
chordCounter:INTEGER ← -1;
-- Misc Vars
bitMask:ARRAY [0..7] OF INTEGER ← [128, 64, 32, 16, 8, 4, 2, 1];
time:System.Pulses;
lastEventTime:System.Pulses ← [0];
XMKDriverProc:PUBLIC PROCEDURE =
BEGIN
Process.Detach[Process.GetCurrent[]];
Process.SetPriority[Process.priorityForeground];
DO
--Give everyone else a chance to run...
UserTerminal.WaitForScanLine[0];
--Read the new keyboard and mouse values, constraining the mouse position
newKeys ← keyboard↑;
newMouse ← ConstrainMouse[UserTerminal.mouse↑];
--Get the time in clock pulses
time ← System.GetClockPulses[];
--Set the mouse and cursor to the constrained position
UserTerminal.SetMousePosition[newMouse];
UserTerminal.SetCursorPosition[newMouse];
--Find the events and queue them up
IF keyboardEventsEnabled THEN
processKeys[];
IF mouseEventsEnabled THEN
BEGIN
processMouse[];
processButtons[];
END;
--Save the new state
lastKeys ← newKeys;
lastMouse ← newMouse;
ENDLOOP;
END;
ConstrainMouse:PROCEDURE[inCoord:UserTerminal.Coordinate] RETURNS[outCoord:UserTerminal.Coordinate] =
BEGIN
outCoord.x ← SELECT inCoord.x FROM
<mouseConstraintBox.x1 => mouseConstraintBox.x1,
>mouseConstraintBox.x2 => mouseConstraintBox.x2,
ENDCASE => inCoord.x;
outCoord.y ← SELECT inCoord.y FROM
<mouseConstraintBox.y1 => mouseConstraintBox.y1,
>mouseConstraintBox.y2 => mouseConstraintBox.y2,
ENDCASE => inCoord.y;
END;
processMouse:PROCEDURE =
BEGIN
event:XEventQ.EventPtr;
IF newMouse # lastMouse THEN
BEGIN
IF NOT ((newMouse.x IN [mouseNoInterestBox.x1..mouseNoInterestBox.x2]) AND
(newMouse.y IN [mouseNoInterestBox.y1..mouseNoInterestBox.y2]))THEN
BEGIN
lastEventTime ← time;
event ← XEventQ.NewEvent[];
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:MotionNotify, key:0];
XEventQ.EnQEvent[event];
END;
END;
END;
processKeys:PROCEDURE =
BEGIN
size:INTEGER = SIZE[Keys.KeyBits];
newPtr:LONG POINTER TO ARRAY[0..size) OF WORD;
lastPtr:LONG POINTER TO ARRAY[0..size) OF WORD;
nP:LONG POINTER TO Keys.KeyBits ← @newKeys;
lp:LONG POINTER TO Keys.KeyBits ← @lastKeys;
tmpKeys:ARRAY[0..size) OF WORD;
tP:LONG POINTER TO ARRAY[0..size) OF WORD ← @tmpKeys;
tmpPtr:LONG POINTER TO Keys.KeyBits ← LOOPHOLE[tP];
loByte, hiByte:INTEGER;
newPtr ← LOOPHOLE[ nP ];
lastPtr ← LOOPHOLE [ lp ];
FOR i:INTEGER IN [0..size)
DO
tmpKeys[i] ← Inline.BITXOR[newPtr[i], lastPtr[i]];
ENDLOOP;
tmpPtr[Point] ← down;
tmpPtr[Adjust] ← down;
FOR i:INTEGER IN [0..size)
DO
IF tmpKeys[i] # 0 THEN
BEGIN
hiByte ← Inline.HighByte[tmpKeys[i]];
loByte ← Inline.LowByte[tmpKeys[i]];
IF hiByte # 0 THEN
FOR j:INTEGER IN [0..7]
DO
IF Inline.BITAND[hiByte, bitMask[j]] # 0 THEN
sendKeyEvent[i*16+j];
ENDLOOP;
IF loByte # 0 THEN
FOR j:INTEGER IN [0..7]
DO
IF Inline.BITAND[loByte, bitMask[j]] # 0 THEN
BEGIN
sendKeyEvent[i*16+8+j];
IF ( i*16+8+j = 77 ) AND ( newKeys[LOOPHOLE[77]] = down ) THEN
Runtime.Interrupt;
END
ENDLOOP;
END;
ENDLOOP;
END;
sendKeyEvent:PROCEDURE[key:INTEGER] =
BEGIN
event:XEventQ.EventPtr;
type:XDefs.XEventType ← SELECT newKeys[LOOPHOLE[key]] FROM
up => KeyRelease,
down => KeyPress,
ENDCASE => ERROR;
event ← XEventQ.NewEvent[];
IF key < 16 THEN key ← key + 128;
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:type, key:key];
XEventQ.EnQEvent[event];
lastEventTime ← time;
END;
processButtonDown:PROCEDURE[button:buttons] =
BEGIN
event:XEventQ.EventPtr;
otherButton:buttons = SELECT button FROM
left => right,
right => left,
ENDCASE => ERROR;
SELECT buttonStates[otherButton] FROM
waitingChord =>
BEGIN
event ← XEventQ.NewEvent[];
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:ButtonPress, key:LOOPHOLE[buttons.middle]];
XEventQ.EnQEvent[event];
lastEventTime ← time;
chordFlag ← TRUE;
chordCounter ← -1;
buttonStates[button] ← down;
buttonStates[otherButton] ← down;
END;
down, waitingRelease =>
BEGIN
event ← XEventQ.NewEvent[];
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:ButtonPress, key:LOOPHOLE[button]];
XEventQ.EnQEvent[event];
lastEventTime ← time;
buttonStates[button] ← down;
END;
up =>
BEGIN
buttonStates[button] ← waitingChord;
buttonDownTime ← time;
buttonDownCoord ← newMouse;
chordCounter ← 5;
END;
ENDCASE => ERROR;
END;
processButtons:PROCEDURE =
BEGIN
IF newKeys[Point] # lastKeys[Point] THEN
BEGIN
SELECT newKeys[Point] FROM
up => processButtonUp[left];
down => processButtonDown[left];
ENDCASE => ERROR;
END;
IF newKeys[Adjust] # lastKeys[Adjust] THEN
SELECT newKeys[Adjust] FROM
up => processButtonUp[right];
down => processButtonDown[right];
ENDCASE => ERROR;
SELECT chordCounter FROM
>0 => chordCounter ← chordCounter - 1;
=0 => BEGIN
button:buttons;
event:XEventQ.EventPtr;
IF buttonStates[left] = waitingChord THEN
button ← left
ELSE
button ← right;
event ← XEventQ.NewEvent[];
event↑ ← [x:buttonDownCoord.x, y:buttonDownCoord.y, time:buttonDownTime, type:ButtonPress, key:LOOPHOLE[button]];
XEventQ.EnQEvent[event];
lastEventTime ← time;
chordCounter ← -1;
buttonStates[button] ← down;
END;
ENDCASE;
END;
processButtonUp:PROCEDURE[button:buttons] =
BEGIN
event:XEventQ.EventPtr;
otherButton:buttons = SELECT button FROM
left => right,
right => left,
ENDCASE => ERROR;
IF chordFlag THEN
BEGIN
event ← XEventQ.NewEvent[];
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:ButtonRelease, key:LOOPHOLE[buttons.middle]];
XEventQ.EnQEvent[event];
lastEventTime ← time;
buttonStates[button] ← up;
chordFlag ← FALSE;
buttonStates[otherButton] ← waitingRelease;
END
ELSE
SELECT buttonStates[button] FROM
waitingRelease =>
BEGIN
buttonStates[button] ← up;
END;
waitingChord =>
BEGIN
event ← XEventQ.NewEvent[];
event↑ ← [x:buttonDownCoord.x, y:buttonDownCoord.y, time:buttonDownTime, type:ButtonPress, key:LOOPHOLE[button]];
XEventQ.EnQEvent[event];
event ← XEventQ.NewEvent[];
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:ButtonRelease, key:LOOPHOLE[button]];
XEventQ.EnQEvent[event];
lastEventTime ← time;
buttonStates[button] ← up;
chordCounter ← -1;
END;
down =>
BEGIN
event ← XEventQ.NewEvent[];
event↑ ← [x:newMouse.x, y:newMouse.y, time:time, type:ButtonRelease, key:LOOPHOLE[button]];
XEventQ.EnQEvent[event];
lastEventTime ← time;
buttonStates[button] ← up;
END;
ENDCASE => ERROR;
END;
setMouseInterest:PUBLIC PROCEDURE[box:XMKDriver.Box] =
BEGIN
mouseNoInterestBox ← box;
END;
setMouseConstraint:PUBLIC PROCEDURE[box:XMKDriver.Box] =
BEGIN
mouseConstraintBox ← box;
END;
setCursor:PUBLIC PROCEDURE[cursor:LONG POINTER TO UserTerminal.CursorArray] =
BEGIN
UserTerminal.SetCursorPattern[cursor↑];
END;
setCursorPosition:PUBLIC PROCEDURE[x,y:CARDINAL] =
BEGIN
UserTerminal.SetCursorPosition[[x,y]];
UserTerminal.SetMousePosition[[x,y]];
END;
getLastEventTime:PUBLIC PROCEDURE RETURNS[time:LONG CARDINAL] =
BEGIN
time ← System.PulsesToMicroseconds[lastEventTime];
END;
setLastEventTime:PUBLIC PROCEDURE [time:LONG CARDINAL] =
BEGIN
lastEventTime ← System.MicrosecondsToPulses[time];
END;
getTimeInMillis:PUBLIC PROCEDURE RETURNS[time:LONG CARDINAL] =
BEGIN
time ← System.PulsesToMicroseconds[System.GetClockPulses[]];
END;
enableMouseEvents:PUBLIC PROCEDURE [enable:BOOLEAN] =
BEGIN
mouseEventsEnabled ← enable;
END;
enableKeyboardEvents:PUBLIC PROCEDURE[enable:BOOLEAN] =
BEGIN
keyboardEventsEnabled ← enable;
END;
displayInit:PUBLIC PROCEDURE [x,y:LONG POINTER TO CARDINAL] RETURNS[addr:LONG POINTER] =
BEGIN
bbt:BitBlt.BBTable;
[] ← UserTerminal.SetState[disconnected];
[] ← UserTerminal.SetState[on];
[] ← UserTerminal.SetBackground[black];
-- [] ← UserTerminal.SetState[off];
bbt ← UserTerminal.GetBitBltTable[];
addr ← bbt.dst.word;
x↑ ← bbt.width;
y↑ ← bbt.height;
END;
displayOn:PUBLIC PROCEDURE =
BEGIN
[] ← UserTerminal.SetState[on];
END;
displayOff:PUBLIC PROCEDURE =
BEGIN
[] ← UserTerminal.SetState[off];
END;
blinkDisplay:PUBLIC PROCEDURE =
BEGIN
UserTerminal.BlinkDisplay[];
END;
displayClose:PUBLIC PROCEDURE =
BEGIN
[] ← UserTerminal.SetState[disconnected];
END;
--Mainline Code
END.