<> <> <> <> <> <> <> <> <> DIRECTORY Commander USING [ CommandProc, Handle, Register ], Interminal USING [ GetMousePosition ], InterminalBackdoor USING [ terminal ], IO USING [ EndOf, GetTokenRope, RIS, SkipWhitespace, STREAM ], PrincOpsUtils USING [ VERSION ], Process USING [ SetPriority, priorityClient3, priorityRealTime ], Rope USING [ Equal, ROPE ], Terminal USING [ Position, GetMousePosition, SetMousePosition, WaitForBWVerticalRetrace, Virtual ], UserProfile USING [ ProfileChangedProc, Number, Token, CallWhenProfileChanges ], Cursory USING [ SetMousePositionProc, CallWhenMousePositionChanges ]; FastMouse: CEDAR MONITOR IMPORTS Commander, Terminal, Interminal, InterminalBackdoor, IO, Process, PrincOpsUtils, UserProfile, Rope, Cursory ~ BEGIN ROPE: TYPE = Rope.ROPE; mouseProcess: PROCESS _ NIL; vt: Terminal.Virtual ~ InterminalBackdoor.terminal; position, prevPosition: Terminal.Position; width: NAT; height: NAT; cursorInColorDisplay: BOOL _ FALSE; speedUpLinear: BOOL _ TRUE; -- Acceleration law (linear or squared) threshold: INTEGER _ 2; -- Speedup control parameters thresholdxTen: INTEGER _ 20; ampxTenX: INTEGER _ 15; ampxTenY: INTEGER _ 15; ratioYtoXxTen: INTEGER _ 10; overShoot: INTEGER _ 0; -- to allow Escape velocity hack bwOverShoot: INTEGER _ 0; clrOverShoot: INTEGER _ 0; enabled: BOOL _ TRUE; shouldRun: BOOL _ TRUE; running: BOOL _ FALSE; ShouldRun: ENTRY PROC RETURNS [run: BOOL] = { IF NOT (run _ shouldRun) THEN RETURN; IF running THEN RETURN [FALSE]; running _ TRUE; }; NoteNotRunning: ENTRY PROC = {running _ FALSE}; DoradoMouseProcess: PROC = { IF NOT ShouldRun[] THEN RETURN; {ENABLE UNWIND => NoteNotRunning[]; Process.SetPriority[Process.priorityRealTime]; -- this priority is above fault handlers prevPosition _ Terminal.GetMousePosition[vt]; width _ vt.bwWidth; height _ vt.bwHeight; WHILE shouldRun DO xDist, yDist, xDelta, yDelta: INTEGER; Terminal.WaitForBWVerticalRetrace[vt]; position _ Terminal.GetMousePosition[vt]; IF prevPosition = position THEN LOOP; TRUSTED { IF cursorInColorDisplay # Interminal.GetMousePosition[].color THEN { prevPosition _ position; cursorInColorDisplay _ Interminal.GetMousePosition[].color; IF cursorInColorDisplay THEN { width _ vt.colorWidth; height _ vt.colorHeight; overShoot _ clrOverShoot; } ELSE { width _ vt.bwWidth; height _ vt.bwHeight; overShoot _ bwOverShoot; }; LOOP; }; }; xDelta _ position.x - prevPosition.x; yDelta _ position.y - prevPosition.y; xDist _ ABS[xDelta]; yDist _ ABS[yDelta]; IF xDist > threshold OR yDist > threshold THEN { IF speedUpLinear THEN position _ [ -- linear law speedup MAX[ -overShoot, MIN[ width+overShoot, position.x + (xDelta*ampxTenX / 10)] ], MAX[ 0, MIN[ height, position.y + (yDelta*ampxTenY / 10)] ] ] ELSE position _ [ -- square law speedup MAX[ -overShoot, MIN[ width+overShoot, position.x + (xDelta*xDist / threshold)] ], MAX[ 0, MIN[ height, position.y + (yDelta*yDist*ratioYtoXxTen / thresholdxTen) ] ] ]; Terminal.SetMousePosition[vt, position]; }; prevPosition _ [ MAX[ 0, MIN[ width, position.x ]], position.y ]; <> ENDLOOP; }; NoteNotRunning[]; }; -- DoradoMouseProcess DandelionMouseProcess: PROC = { -- note, doesn't work on Dandelions IF NOT ShouldRun[] THEN RETURN; {ENABLE UNWIND => NoteNotRunning[]; Process.SetPriority[Process.priorityClient3]; -- this priority is one below fault handlers prevPosition _ Terminal.GetMousePosition[vt]; width _ vt.bwWidth; height _ vt.bwHeight; WHILE shouldRun DO <> Terminal.WaitForBWVerticalRetrace[vt]; position _ Terminal.GetMousePosition[vt]; <> <> <> <> <> < thresholdX OR yDist > thresholdY THEN {>> <> <> <> <> <> <> <> <> <<};>> <> ENDLOOP; }; NoteNotRunning[]; }; -- MouseProcess FastMouseCmd: Commander.CommandProc = { <> in: IO.STREAM _ IO.RIS[cmd.commandLine]; ok, on: BOOL _ FALSE; [] _ in.SkipWhitespace[]; IF NOT in.EndOf[] THEN { arg: ROPE _ in.GetTokenRope[].token; [] _ in.SkipWhitespace[]; IF NOT in.EndOf[] THEN NULL ELSE IF arg.Equal["on", FALSE] THEN {ok _ TRUE; on _ TRUE} ELSE IF arg.Equal["off", FALSE] THEN {ok _ TRUE; on _ FALSE}; }; IF ok THEN {enabled _ on; HandleChange[]} ELSE {result _ $Failure; msg _ "Usage: FastMouse on|off"} }; ProcessProfile: UserProfile.ProfileChangedProc = TRUSTED { enableToken: ROPE _ UserProfile.Token["FastMouse.Enabled", "UNSPECIFIED"]; IF enableToken.Equal["TRUE"] THEN enabled _ TRUE ELSE IF enableToken.Equal["FALSE"] THEN enabled _ FALSE; threshold _ UserProfile.Number["FastMouse.Threshold", 2]; thresholdxTen _ threshold * 10; ampxTenX _ UserProfile.Number["FastMouse.AmpxTen", 15]; ratioYtoXxTen _ UserProfile.Number["FastMouse.RatioYtoXxTen", 10]; ampxTenY _ ampxTenX * ratioYtoXxTen / 10; speedUpLinear _ Rope.Equal[UserProfile.Token["FastMouse.SpeedUp", "linear"], "linear"]; bwOverShoot _ UserProfile.Number["Interminal.VBWEscape", 0] + 1; clrOverShoot _ UserProfile.Number["Interminal.VColorEscape", 0] + 1; IF cursorInColorDisplay THEN overShoot _ clrOverShoot ELSE overShoot _ bwOverShoot; HandleChange[]; }; HandleChange: ENTRY PROC = { shouldRun _ enabled; IF shouldRun AND NOT running THEN SELECT PrincOpsUtils.VERSION[].machineType FROM dorado => mouseProcess _ FORK DoradoMouseProcess[]; dandelion => mouseProcess _ FORK DandelionMouseProcess[]; dolphin => mouseProcess _ FORK DoradoMouseProcess[]; ENDCASE; }; ProcessMouseChange: Cursory.SetMousePositionProc ~ { IF NOT running THEN RETURN; Terminal.WaitForBWVerticalRetrace[vt]; <> prevPosition _ newPosition; Terminal.SetMousePosition[vt, position]; <> }; Init: PROC = { UserProfile.CallWhenProfileChanges[ProcessProfile]; Cursory.CallWhenMousePositionChanges[ProcessMouseChange]; Commander.Register[key: "FastMouse", proc: FastMouseCmd, doc: "Turn mouse speedup on or off"]; }; Init[]; END.