-- 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.x2 => mouseConstraintBox.x2, ENDCASE => inCoord.x; outCoord.y ¬ SELECT inCoord.y FROM 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.