<> <> <> <> <> <> <> <<>> <<<<>>> DIRECTORY ClassInscript USING [ AdvancePage, COmProc, CopyPageDescriptor, GetPageLimits, Inscript, InscriptPageDescriptor, InscriptPageDescBody, InscriptPageNumber, KEyProc, NewStdInscript, InscriptError, ReadEntry, ResetPageDescriptor, SetPage, WaitForEntry, WaitMode], ClassIncreek, Intime USING [ AddDeltaTimeToEventTime, EventTime, EventTimeDifference, IsLaterTime, MsTicks, ReadEventTime], Interminal USING [ DefaultMouseGrain, StartActionRecorder, KeyName, --<<--MousePosition-->>--, SetMouseGrain], InterminalBackdoor USING [InsertAction], List USING [DRemove, Map]; IncreekImpl: MONITOR IMPORTS ClassInscript, Interminal, InterminalBackdoor, Intime, List EXPORTS ClassIncreek SHARES ClassIncreek = BEGIN OPEN ClassIncreek, S: ClassInscript, K: Interminal, T: Intime; river: LIST OF REF ANY _ NIL; -- protected by MONITOR Flow: ENTRY PROC[x: REF] = { river _ CONS[x, river] }; Drain: ENTRY PROC[x: REF] = { river _ List.DRemove[x, river] }; <> InsertAction: PUBLIC PROC[self: Increek, action: ActionBody] = { InterminalBackdoor.InsertAction[action]; }; NewStdIncreek: PUBLIC PROC [template: Increek _ NIL] RETURNS [Increek] = { self: InscriptPosition _ NEW[InscriptPositionBody_ [inscript: stdInscript, inscriptPage: NIL, ip1: CreatePageDescriptor[stdInscript], iP: NIL, ip2: CreatePageDescriptor[stdInscript], mousePosition: [0,FALSE,0]]]; self.inscriptPage_LOOPHOLE[self.ip1]; self.iP_LOOPHOLE[self.ip2]; Flow[self]; IF template = NIL THEN { SetAtLatest[self]; -- sets up rest of state, too SetMouseGrain[self]; } ELSE CopyIncreek[self: self, template: template]; RETURN[self]; }; CreatePageDescriptor: PROC[inscript: S.Inscript] RETURNS [d: REF S.InscriptPageDescBody] = { d_NEW[S.InscriptPageDescBody]; S.ResetPageDescriptor[inscript, LOOPHOLE[d]]; }; Release: PUBLIC PROC [self: InscriptPosition] RETURNS [nilIncreek: Increek] = { SetMouseGrain[self]; -- revert to default Drain[self]; RETURN[NIL[Increek]]; }; CopyIncreek: PUBLIC PROC [self: InscriptPosition, template: InscriptPosition] = { pd1: REF S.InscriptPageDescBody _ self.ip1; pd2: REF S.InscriptPageDescBody _ self.ip2; self^ _ template^; self.ip1_pd1; self.inscriptPage_LOOPHOLE[pd1]; self.ip2_pd2; self.iP_LOOPHOLE[pd2]; S.CopyPageDescriptor[self.inscript, self.inscriptPage, template.inscriptPage]; }; GetAction: PUBLIC PROC [ self: InscriptPosition, waitMode: WaitMode _ forever, waitInterval: T.MsTicks _ 100, acceptance: Acceptance _ clicks] RETURNS [a: ActionBody] = { <> <> <> <> ENABLE S.InscriptError => IF code=entryOutOfBounds THEN ERROR IncreekError[outOfBounds]; inscript: S.Inscript = self.inscript; descriptor: S.InscriptPageDescriptor = self.inscriptPage; dCopy: S.InscriptPageDescriptor = self.iP; actionBody: ActionBody; S.CopyPageDescriptor[self: inscript, dest: dCopy, source: descriptor]; DO -- until Action accepted kN: K.KeyName; -- if no actions left, return NIL unless wait WHILE ~S.ReadEntry[self: inscript, descriptor: descriptor, destination: @actionBody, LengthProc: ActionLength] DO IF (~S.AdvancePage[inscript, descriptor]) AND (~S.WaitForEntry[inscript, waitMode, waitInterval, descriptor, @self.eventTime]) THEN RETURN[timedOutActionBody]; ENDLOOP; self.eT _ T.AddDeltaTimeToEventTime[self.eT, actionBody.deltaDeltaTime]; WITH thisA: actionBody SELECT FROM deltaEventTime => self.eT _ T.AddDeltaTimeToEventTime[self.eT, thisA.value]; eventTime => self.eT _ thisA.eventTime; ENDCASE; IF waitMode=timed AND T.EventTimeDifference[@self.eT, @self.eventTime] > waitInterval THEN { S.CopyPageDescriptor[self: inscript, dest: descriptor, source: dCopy]; RETURN[timedOutActionBody]}; { WITH thisA: actionBody SELECT FROM mousePosition => self.mousePosition _ thisA.mousePosition; deltaMouse => { self.mousePosition.mouseX _ self.mousePosition.mouseX + thisA.value.deltaX; self.mousePosition.mouseY _ self.mousePosition.mouseY + thisA.value.deltaY; }; keyStillDown => { kN _ thisA.value; GO TO RecordDown }; keyDown => { kN _ thisA.value; GO TO RecordDown }; keyUp => { kN _ thisA.value; GO TO RecordUp }; allUp => { self.keyState.bits _ self.chordState.bits _ ALL[up]; self.downCount _ 0 }; deltaEventTime, eventTime => NULL; ENDCASE => ERROR Internal[4]; EXITS -- manual cross-jumping. RecordDown => { IF self.downCount = 0 THEN self.chordState.bits _ ALL[up]; self.downCount _ SUCC[self.downCount]; self.keyState.bits[kN] _ self.chordState.bits[kN] _ down; }; RecordUp => { self.keyState.bits[kN] _ up; self.downCount _ PRED[self.downCount]; }; }; IF acceptance = all THEN EXIT; <> WITH thisE: actionBody SELECT FROM mousePosition, penPosition, deltaMouse => IF acceptance = clicksAndMotion THEN EXIT; keyUp, keyDown => IF acceptance <= clicksAndMotion THEN EXIT; ENDCASE; ENDLOOP; -- until Action accepted self.eventTime_self.eT; RETURN[actionBody]; }; SetAtEarliest: PUBLIC PROC [self: InscriptPosition] = { ENABLE IncreekError=>IF code=outOfBounds THEN RETRY; -- with new "earliest" [] _ FullStateFrom[increek: self, pN: S.GetPageLimits[self.inscript].earliestPageNo]; }; SetAtLatest: PUBLIC PROC [self: InscriptPosition] = { ENABLE IncreekError=>IF code=outOfBounds THEN RETRY; -- ?? [] _ FullStateFrom[increek: self, pN: S.GetPageLimits[self.inscript].latestPageNo]; WHILE GetAction[self: self, waitMode: dontWait, acceptance: all].kind # timedOut DO ENDLOOP; }; SetAtTime: PUBLIC PROC [self: InscriptPosition, eventTime: T.EventTime] RETURNS [pR: PosResult] = { ENABLE IncreekError=>IF code=outOfBounds THEN RETRY; -- with new limits a: ActionBody; res: PosResult _ SetPageAtTime[increek: self, t: eventTime]; <> <> nextCreek: InscriptPosition; IF res # onTime THEN RETURN[res]; nextCreek _ NewStdIncreek[template: self]; DO ENABLE IncreekError=>IF code=outOfBounds THEN nextCreek_Release[nextCreek]; <> CopyIncreek[self: self, template: nextCreek]; a _ GetAction[self: nextCreek, waitMode: dontWait, acceptance: all]; IF a.kind=timedOut THEN GOTO TooLate; -- e.g., no actions waiting -- IF T.IsLaterTime[nextCreek.eventTime, eventTime] THEN GOTO OnTime; REPEAT TooLate => res _ tooLate; OnTime => res _ onTime; ENDLOOP; nextCreek _ Release[self: nextCreek]; RETURN[res]; }; SetMouseGrain: PUBLIC ENTRY PROC [self: InscriptPosition, ticks: T.MsTicks _ 0, dots: INTEGER _ 0] = { t: T.MsTicks; d: INTEGER; GetFinestGrain: SAFE PROC[x: REF ANY, tail: LIST OF REF ANY] = TRUSTED { c: InscriptPosition=NARROW[x]; IF c.mouseGrainTime> RETURN --[res]--}; ActionLength: PROC[a: LONG POINTER TO ActionBody] RETURNS[CARDINAL] = TRUSTED { SELECT a.kind FROM deltaEventTime => RETURN[SIZE[deltaEventTime ActionBody]]; keyDown => RETURN[SIZE[keyDown ActionBody]]; keyStillDown => RETURN[SIZE[keyStillDown ActionBody]]; keyUp => RETURN[SIZE[keyUp ActionBody]]; eventTime => RETURN[SIZE[eventTime ActionBody]]; deltaMouse => RETURN[SIZE[deltaMouse ActionBody]]; mousePosition => RETURN[SIZE[mousePosition ActionBody]]; penPosition => RETURN[SIZE[penPosition ActionBody]]; timedOut => RETURN[SIZE[timedOut ActionBody]]; allUp => RETURN[SIZE[allUp ActionBody]]; ENDCASE => ERROR Internal[1]; }; timedOutActionBody: ActionBody_[contents: timedOut[]]; FullStateFrom: PROC [increek: InscriptPosition, pN: S.InscriptPageNumber] RETURNS [t: T.EventTime] = { a: ActionBody; increek.downCount _ 0; increek.chordState _ increek.keyState _ [bits[ALL[up]]]; IF ~S.SetPage[self: increek.inscript, descriptor: increek.inscriptPage, pageNumber: pN] THEN ERROR IncreekError[outOfBounds]; DO a _ GetAction[self: increek, waitMode: dontWait, acceptance: all]; SELECT a.kind FROM mousePosition, penPosition => EXIT; ENDCASE; <> < NULL;>> < EXIT;>> < ERROR Internal[3] -- timed out or unrecognized --;>> ENDLOOP; RETURN[increek.eventTime]; }; <> KeyProc: S.KEyProc = { a: ActionBody; IF S.ReadEntry[self: inscript, descriptor: descriptor, destination: @a, LengthProc: ActionLength] THEN WITH thisA: a SELECT FROM eventTime => RETURN[LOOPHOLE[thisA.eventTime]]; ENDCASE; ERROR S.InscriptError[invalidPageKey]; }; ComProc: S.COmProc = {RETURN[T.IsLaterTime[LOOPHOLE[a], LOOPHOLE[b]]]; }; Internal: ERROR[code: INTEGER] = CODE; <<<>>> <<<< currentCursorPosition: POINTER TO MousePosition = LOOPHOLE[426B]; >>>> <<<< xMax: CARDINAL = 608; >>>> <<<< yMax: CARDINAL = 808; >>>> <<<>>> <> stdInscript: S.Inscript; InitializeIncreek: PROC = { NSI: PROC[init: BOOL] RETURNS [S.Inscript] = {RETURN[ S.NewStdInscript[ KeyProc: KeyProc, ComProc: ComProc, initializeFile: init]];}; <> stdInscript _ NSI[FALSE ! S.InscriptError=> IF code=invalidInscriptFile THEN { stdInscript _ NSI[TRUE]; CONTINUE}]; K.StartActionRecorder[stdInscript]; }; InitializeIncreek[]; END. <<<< (Goes in GetAction just after all Action info is reflected in state >>>> <<<>>> <<<< currentCursorPosition.mouseX_MAX[MIN[xMax, d.mousePosition.mouseX], 0];>>>> <<<< currentCursorPosition.mouseY_MAX[MIN[yMax, d.mousePosition.mouseY], 0]; >>>> <<<>>>