<<>> <> <> <> <> DIRECTORY KeyNames, KeyTypes, IO, MouseTrap, Process, Real, RealFns, UserInput, UserInputOps, ViewerClasses, ViewersWorld, ViewersWorldRefType, ViewerOps, ViewersWorldInstance; MouseTrapImpl: CEDAR MONITOR IMPORTS KeyNames, Process, Real, RealFns, UserInputOps, ViewersWorld, ViewerOps, ViewersWorldInstance EXPORTS MouseTrap ~ BEGIN <> <> <> round: MouseTrap.RoundTrapData ¬ NEW[MouseTrap.RoundTrapDataRep]; roundWrap: MouseTrap.RoundTrapData ¬ NEW[MouseTrap.RoundTrapDataRep ¬ [yes]]; box: MouseTrap.BoxTrapData ¬ NEW[MouseTrap.BoxTrapDataRep]; boxWrap: MouseTrap.BoxTrapData ¬ NEW[MouseTrap.BoxTrapDataRep ¬ [yes]]; TrapTillMouseUp: PUBLIC PROC [v: Viewer, circle, wrapAround: BOOL] ~ { IF circle THEN { trapData: MouseTrap.RoundTrapData ¬ IF wrapAround THEN roundWrap ELSE round; radius: REAL ¬ (v.cw-1)/2.0-1.5; trapData.radiusSquared ¬ radius*radius; trapData.center ¬ UserToMouseCoords[v, v.cx+(v.cw-2)/2, v.cy+(v.ch-2)/2]; [] ¬ SetTrap[[TRUE, RoundTrap, trapData]]; } ELSE { trapData: MouseTrap.BoxTrapData ¬ IF wrapAround THEN boxWrap ELSE box; trapData.minCorner ¬ UserToMouseCoords[v, v.cx, v.cy]; trapData.maxCorner ¬ UserToMouseCoords[v, v.cx+v.cw, v.cy+v.ch]; [] ¬ SetTrap[[TRUE, BoxTrap, trapData]]; }; }; <> Position: TYPE ~ MouseTrap.Position; MouseTrapSpecs: TYPE ~ MouseTrap.MouseTrapSpecs; Viewer: TYPE ~ ViewerClasses.Viewer; <> watch: BOOL ¬ TRUE; trapSpecs: MouseTrapSpecs ¬ [enabled: FALSE]; <> terminalProcess: PROCESS; terminalHandlerCurrent: INTEGER ¬ 0; terminalHandlerEnabled: BOOL ¬ FALSE; enableTerminalHandler: CONDITION; viewersWorld: ViewersWorldRefType.Ref ¬ ViewersWorldInstance.GetWorld[]; inputHandle: UserInput.Handle ¬ ViewersWorld.GetInputHandle[viewersWorld]; leftMouse: KeyTypes.KeySym ¬ KeyNames.KeySymFromName["LeftMouse"]; middleMouse: KeyTypes.KeySym ¬ KeyNames.KeySymFromName["MiddleMouse"]; rightMouse: KeyTypes.KeySym ¬ KeyNames.KeySymFromName["RightMouse"]; debug: IO.STREAM ¬ NIL; <> UserToMouseCoords: PUBLIC PROC [self: Viewer, vx, vy: INTEGER ¬ 0] RETURNS [p: Position] ~ { <> [p.x, p.y] ¬ ViewerOps.UserToScreenCoords[self, vx, vy]; }; UserFromMouseCoords: PUBLIC PROC [self: Viewer, mx, my: INTEGER ¬ 0] RETURNS [p: Position] <> <> <> ~ { tx, ty: INTEGER; -- translation from viewer to screen [tx, ty] ¬ ViewerOps.UserToScreenCoords[self, 0, 0]; p ¬ [mx-tx, my-ty]; }; SetTrap: PUBLIC PROC [newSpecs: MouseTrapSpecs] RETURNS [oldSpecs: MouseTrapSpecs] ~ { <> oldSpecs ¬ trapSpecs; <> <> <> <> <> <> <> <> <<}>> <> <<};>> trapSpecs ¬ newSpecs; }; GetTrap: PUBLIC PROC RETURNS [MouseTrapSpecs] ~ {RETURN[trapSpecs]}; <> UnsetTrap: PUBLIC PROC RETURNS [MouseTrapSpecs] ~ { <> specs: MouseTrapSpecs ¬ trapSpecs; specs.enabled ¬ FALSE; RETURN[SetTrap[specs]]; }; TrapMouse: PROC [mouse: Position] ~ { IF trapSpecs.enabled AND trapSpecs.proc # NIL THEN { mouseTo: Position; changed: BOOL ¬ FALSE; <> [changed, mouseTo] ¬ trapSpecs.proc[mouse, trapSpecs.data]; IF changed THEN ViewersWorld.SetMousePosition[viewersWorld, mouseTo.x, mouseTo.y]; <> }; }; WaitForTick: PROC ~ { WaitForEnabled: ENTRY PROC ~ INLINE { UNTIL terminalHandlerEnabled DO WAIT enableTerminalHandler; ENDLOOP; }; WaitForEnabled[]; Process.Pause[1]; -- can't get vert. retrace; also, scheduler operates only every 1/10 sec <> }; MouseTrapWatcher: PROC ~ { <> x, y: INTEGER; WHILE watch DO Process.CheckForAbort[! ABORTED => EXIT]; WaitForTick[]; -- run once per tick [x: x, y: y] ¬ ViewersWorld.GetMousePosition[viewersWorld]; TrapMouse[[x, y]]; ENDLOOP; }; StartWatchingMouseTrap: PUBLIC PROC ~ { <> KeyboardPriority: Process.Priority ~ 6; save: Process.Priority ~ Process.GetPriority[]; watch ¬ TRUE; Process.SetPriority[KeyboardPriority]; TRUSTED {Process.Detach[terminalProcess ¬ FORK MouseTrapWatcher[]]}; Process.SetPriority[save]; <> EnableTerminalHandler[]; -- we're on. }; StopWatchingMouseTrap: PUBLIC PROC ~ {watch ¬ FALSE}; <> <> <<[vt: Virtual, action: SwapAction, clientData: REF ANY]>> <