[comp.windows.news] mousee.ps -- see the mouse in a window

don@BRILLIG.UMD.EDU (Don Hopkins) (03/20/88)

Here's a little NeWS "desk accessory" I wrote to make a graphical
mouse in a window whose movement tracks the real mouse's movement
around the screen. It leaves behind a trail where you move, and spots
where you press buttons. The buttons light up when you press them, and
it leaves a thick trail behind when you drag with a button down. I
find it useful for making screen dumps and demonstrating how to
operate the mouse. It's a neat way to show where heavy mouse traffic
happens over a long period of time. It also works nicely with
journalling!

This is but a first cut -- I plan to add more features (of course!).
I want to make a remote MouSee, so you can see other people's mice
over the network, and even grab them, move them around, and press
their buttons for them! (Aww, c'mon! I can think of a /few/ legitimate
uses for it!)

	-Don

====Cut here: 8X========================================================
%!
%
% MouSee.ps
% By Don Hopkins, University of Maryland Human Computer Interaction Lab.
%
% MouSee run.
% MouSee Spot make, You Button press when. 
% MouSee Trail leave, You Mouse move when.
% MouSee Trail thick leave, You Button press Mouse move and when.
% Fun have!
%
% Copyright (C) 1988 by Don Hopkins. All rights reserved.
% This program is provided for unrestricted use, provided that this 
% copyright message is preserved. There is no warranty, and no author 
% or distributer accepts responsibility for any damage caused by this 
% program. 
%

/MouSeeWindow DefaultWindow
dictbegin
  /MouseWidth 38 def
  /MouseHeight 50 def
  /MouseX 0 def
  /MouseY 0 def
  /OldMouseX 0 def
  /OldMouseY 0 def
  /CornerRadius 4 def
  /HScale null def
  /VScale null def
  /LeftButtonState false def
  /MiddleButtonState false def
  /RightButtonState false def
  /ButtonRadius 3 def
  /ButtonWidth .1 def
  /MouseCanvas null def
dictend
classbegin
  /PaintClient {
    gsave
      1 fillcanvas
      draw-mouse
    grestore
  } def

  /reshape { % x y w h => -
    /reshape super send
    gsave
      framebuffer setcanvas
      clippath pathbbox 4 -2 roll pop pop % fbw fbh
      ClientCanvas setcanvas
      clippath pathbbox 4 -2 roll pop pop % fbw fbh ccw cch
      MouseHeight sub 1 max exch
      MouseWidth sub 1 max exch
      3 -1 roll div /VScale exch def
      exch div /HScale exch def
    grestore
  } def

  /mouse-path {
    CornerRadius 0 0 MouseWidth MouseHeight rrectpath
  } def

  /mouse-trail {
    DX DY rlineto
  } def

  /move-mouse { % x y => -
    gsave
      /OldMouseX MouseX def  /OldMouseY MouseY def
      /MouseY exch def  /MouseX exch def
      /DX MouseX OldMouseX sub HScale mul def
      /DY MouseY OldMouseY sub VScale mul def
      ClientCanvas setcanvas
      ((%, %)   ) [MouseX MouseY] sprintf
      dup stringbbox 8 add rectpath 1 setgray fill
      0 0 moveto
      0 setgray show
      OldMouseX HScale mul
      OldMouseY VScale mul translate
%      mouse-path
%      gsave 1 setgray fill grestore
%      1 setgray fill
      MouseWidth 2 div MouseHeight 2 div moveto mouse-trail
%      MouseWidth 0 moveto mouse-trail
%      MouseWidth MouseHeight moveto mouse-trail
%      0 MouseHeight moveto mouse-trail
      0 setlinecap
      LeftButtonState MiddleButtonState RightButtonState
      or or 4 1 ifelse
      gsave dup 2 add setlinewidth 1 setgray stroke grestore
      setlinewidth 0 setgray stroke
      MouseCanvas setcanvas
      MouseX HScale mul MouseY 3 sub VScale mul 
      movecanvas
    grestore
  } def

  /draw-mouse {
    gsave
      MouseCanvas setcanvas
      mouse-path
      gsave .5 setgray fill grestore
      0 setgray 3 setlinewidth stroke
      draw-buttons
    grestore
  } def

  /draw-buttons {
    LeftButtonState draw-left-button
    MiddleButtonState draw-middle-button
    RightButtonState draw-right-button
  } def

  /draw-left-button {
    MouseWidth .2 mul draw-button
  } def

  /draw-middle-button {
    MouseWidth .5 mul draw-button
  } def

  /draw-right-button {
    MouseWidth .8 mul draw-button
  } def

  /mark-button {
    gsave
      framebuffer setcanvas
      XLocation HScale mul MouseWidth 2 div add
      YLocation VScale mul MouseHeight 2 div add
      ClientCanvas setcanvas
      2 copy 10 0 360 arc 1 setgray fill
      8 0 360 arc 0 setgray fill
    grestore
  } def

  /set-left-button {
    mark-button
    /DownTransition eq
    dup /LeftButtonState exch def
    draw-left-button
  } def

  /set-middle-button {
    mark-button
    /DownTransition eq
    dup /MiddleButtonState exch def
    draw-middle-button
  } def

  /set-right-button {
    mark-button
    /DownTransition eq
    dup /RightButtonState exch def
    draw-right-button
  } def

  /draw-button { % bool x => -
    gsave
    MouseCanvas setcanvas
    ButtonRadius exch
    MouseWidth ButtonWidth mul sub  MouseHeight .5 mul round
    MouseWidth ButtonWidth mul dup add  MouseHeight .4 mul round
    rrectpath
    gsave .25 .75 ifelse setgray fill grestore
    1 setlinewidth 1 setgray stroke
    grestore
  } def

  /update-mouse {
    XLocation YLocation move-mouse
  } def

  /make-mouse {
    gsave
      /MouseCanvas ClientCanvas newcanvas def
      MouseCanvas /Transparent false put
      MouseCanvas /Retained true put
      ClientCanvas setcanvas
      mouse-path MouseCanvas 
      reshapecanvas
      framebuffer setcanvas
      currentcursorlocation
      /MouseY exch def
      /MouseX exch def
      MouseCanvas setcanvas
      MouseX HScale mul MouseY VScale mul movecanvas
      MouseCanvas /Mapped true put
    grestore
  } def


  /tracker {
      createevent dup begin
        /Name [
	  /LeftMouseButton /MiddleMouseButton /RightMouseButton
          /MouseDragged
        ] def
	/Priority 10 def
	/Exclusivity true def
      end expressinterest
      createevent dup begin
        /Name /Damaged def
	/Canvas MouseCanvas def
      end expressinterest
      framebuffer setcanvas
      { awaitevent dup begin
        Name {
	  /LeftMouseButton { Action set-left-button }
	  /MiddleMouseButton { Action set-middle-button }
	  /RightMouseButton { Action set-right-button }
	  /MouseDragged { update-mouse }
	  /Damaged { draw-mouse }
	} case
	redistributeevent
        end
      } loop
  } def

  /track {
    make-mouse
    /TrackProcess {tracker} fork def
  } def
classend def

/win framebuffer /new MouSeeWindow send def
/reshapefromuser win send
/map win send
/track win send