Advertisement
longlostbro

NonStickMouse.lpr increased verticalrange

Aug 29th, 2017
181
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 8.04 KB | None | 0 0
  1. program NonStickMouse;  { http://www.jawfin.net/nsm }                         (*
  2. Developed by Jonathan Barton to counter sticky corners and edges in Windows 10
  3. Original: 25th November, 2015
  4. This app checks the mouse position 1000 times a second and moves it onto the
  5.   next monitor when it is found to be stuck in a corner or on an edge.
  6. 2nd December, 2016: -
  7.      Added stochastic ability. Also some code streamlining.
  8. 25th April, 2017: -
  9.      [hoplimit] Locked firing range of stochastic (thus oxymoron!)
  10.      Fixed bug in handling lookahead, it should have priority of all checks
  11. 7th July, 2017: -
  12.      Removed significant chunks of code when it was noticed the stochastic
  13.       approach is all that's needed.  In fact, the legacy code was causing
  14.       re-hops (flicking back to first monitor) - not wanted or required!
  15. 9th July, 2017: -
  16.      Noted that a nested procedure was now only called once, so moved that
  17.       into the body, makes code and overhead less.
  18.      Removed range check on corner detection, and extended it to just edges.
  19. 9th July, 2017: -
  20.      Twice in one day!
  21.      Big rewrite, removed "heavy" units: Forms & Controls.
  22.      Introduced unit MultiMon, and re-wrote code to use this.
  23.      The execuable dropped from 792 KB to 31 KB!
  24. 10th July, 2017: -
  25.      Newer approach killed diagonal only monitors.
  26.      Merged older code with newer units to compensate.
  27.      Code is again more complex, but it works!
  28. 16th July, 2017: -
  29.      Removed Timer object, just replaced with a loop with CPUs sleeps.
  30.      CPU usage is now about a 10th of what it was, if that!
  31.      Rewrote the checking code, getting a tad more speed out of it.
  32.      Also fixed a minor bug in the corner checking!
  33.  
  34. This mouse... is clean.                                                       *)
  35.  
  36. uses
  37.   Windows, MultiMon;
  38.  
  39. var //save runtime stack & other overheads via global vars instead of passed params
  40.   prev:TPoint; //stores where the mouse was last frame, so we can see what direction it's moving in
  41.  
  42. procedure CheckMouse;
  43. const
  44.   hoplimit=30; //if delta greater than this in 1ms then is either computer controlled or will hop anyway!
  45.   range:integer=8; //casting about from mouse position this number of pixels
  46.   verticalRange:integer=140; //casting about from mouse position this number of pixels
  47. var
  48.   pt:TPoint;  //where the mouse is, and where it's going to be!
  49.   m:HMONITOR; //for quick access to the active monitor's dimensions
  50.  
  51.  function CheckForMove:boolean; //returns true when mouse has to move
  52.  {Pre:: m:HMONITOR; is initialised
  53.  Post:: pt:TPoint; holds new mouse position
  54.  This function is only called once, but not embedded so I can quickly "exit" the checks}
  55.  var
  56.    mi:TMonitorInfo;  //get info for monitor's bounds
  57.    br:TRect; //just an alias really
  58.  
  59.   function CanMove(x,y:integer):boolean; //tests if the new coords are sound,
  60.   var                                    // on a new screen, and sets pt if it is
  61.     dp:TPoint; //storage of potential destination
  62.     dm:HMONITOR; //destination monitor, if exists and not same as current monitor
  63.   begin
  64.     result:=false; //fails until proven true
  65.     dp.X:=x; dp.Y:=y;
  66.     dm:=MonitorFromPoint(dp,MONITOR_DEFAULTTONULL); //what monitor is the projection on?
  67.     if (dm<>0) and (dm<>m) then //valid monitor and different to our current monitor
  68.     begin
  69.       pt:=dp; //we want to be here!
  70.       result:=true;
  71.     end;
  72.   end; //End CanMove
  73.  
  74.  begin //Begin CheckForMove
  75.    //stochastic ability: it's not stuck in any corner, but see if it's approaching one
  76.    result:=(pt.X-prev.X>-hoplimit) and (pt.X-prev.X<hoplimit) and //limit hop check range
  77.            (pt.Y-prev.Y>-hoplimit) and (pt.Y-prev.Y<hoplimit) and // note short-circuit faster than abs()
  78.            CanMove(pt.X*2-prev.X,pt.Y*2-prev.Y); //on it's given trajectory, will it cross a monitor?
  79.    if result then //the check above will now cover almost all hops, but keep rest of code for completeness
  80.      exit;
  81.    //corner checks: check diagonal then horizonal then vertical.
  82.    mi.cbSize:=SizeOf(mi); //prepare destination data for next call
  83.    GetMonitorInfo(m,@mi); //get the bounds rectangle for the monitor
  84.    br:=mi.rcMonitor; //check corners first, then edges.
  85.    if pt.Y=br.Top then //at top, do corners then check above
  86.    begin
  87.      if pt.X=br.Left then //top-left
  88.      begin
  89.        result:=CanMove(br.Left-range,br.Top-range); //check diagonal hop first
  90.        if not result then
  91.          if prev.X>=pt.X then //moving left
  92.            result:=CanMove(br.Left-range,br.Top+range);
  93.        if not result then
  94.          if prev.Y>=pt.Y then //moving up
  95.            result:=CanMove(br.Left+range,br.Top-range);
  96.        exit; //whether found or not, as this condition was true then all below cannot be
  97.      end;
  98.      if pt.X=br.Right-1 then //top-right
  99.      begin //code logic repeated as above
  100.        result:=CanMove(br.Right-1+range,br.Top-range);
  101.        if not result then
  102.          if prev.X<=pt.X then //moving right
  103.            result:=CanMove(br.Right-1+range,br.Top+range);
  104.        if not result then
  105.          if prev.Y>=pt.Y then //moving up
  106.            result:=CanMove(br.Right-1-range,br.Top-range);
  107.        exit; //save CPU cycles, the quicker we escape this code-block the better
  108.      end;
  109.      if prev.y>=pt.y then //top edge and moving up
  110.        result:=CanMove(pt.x,br.Top-verticalRange);
  111.      exit; //no more "tops" to check, quit now
  112.    end;
  113.    if pt.Y=br.Bottom-1 then //at bottom
  114.    begin
  115.      if pt.X=br.Left then //bottom-left
  116.      begin
  117.        result:=CanMove(br.Left-range,br.Bottom-1+range);
  118.        if not result then
  119.          if prev.X>=pt.X then //moving left
  120.            result:=CanMove(br.Left-range,br.Bottom-range);
  121.        if not result then
  122.          if prev.Y<=pt.Y then //moving down
  123.            result:=CanMove(br.Left+range,br.Bottom-1+range);
  124.        exit;
  125.      end;
  126.      if pt.X=br.Right-1 then //bottom-right
  127.      begin
  128.        result:=CanMove(br.Right-1+range,br.Bottom-1+range);
  129.        if not result then
  130.          if prev.X<=pt.X then //moving right
  131.            result:=CanMove(br.Right-1+range,br.Bottom-1-range);
  132.        if not result then
  133.          if prev.Y<=pt.Y then //moving down
  134.            result:=CanMove(br.Right-1-range,br.Bottom-1+range);
  135.        exit;
  136.      end; //end of all corner checks, now to check below
  137.      if prev.y<=pt.y then //bottom edge and moving down
  138.        result:=CanMove(pt.x,br.Bottom-1+verticalRange);
  139.      exit;
  140.    end; //top and bottom covered its corners edges, so now only need to check sides
  141.    if (pt.x=br.Right-1) and (prev.x<=pt.x) then //right edge and moving right
  142.    begin //i am not checking if the mouse is dragging a window, just hop it anyway!
  143.      result:=CanMove(br.Right-1+range,pt.y);
  144.      exit; //note this code could be done with a list of "if then else"
  145.    end;    // instead of exits - but harder to read even if shorter
  146.    if (pt.x=br.Left) and (prev.x>=pt.x) then //left edge and moving left
  147.    begin
  148.      result:=CanMove(br.Left-range,pt.y);
  149.      exit; //Superfluous exit, but here in case more code goes in below
  150.    end;
  151.  end; //End CheckForMove
  152.  
  153. begin //Begin CheckMouse
  154.   try
  155.     GetCursorPos(pt); //get where our mouse is now, var used in CheckForMove above too
  156.     if (pt.X=prev.X) and (pt.Y=prev.Y) then //mouse not moving, don't check any further
  157.       exit;
  158.     m:=MonitorFromPoint(pt,MONITOR_DEFAULTTONULL); //what monitor our mouse is on?
  159.     if m=0 then //Danger, danger, Will Robinson.
  160.       exit;
  161.     if CheckForMove then //draws from pt & m, and sets new pt if moving
  162.       SetCursorPos(pt.X,pt.Y); //something about the whole point of this application!
  163.     prev:=pt; //our current point, whether its original or where we placed it, is stored
  164.   finally //user locked screen / logged out? or just some random unhappiness
  165.   end;
  166. end; //End CheckMouse
  167.  
  168. begin //main code, program starts here, contains main loop
  169.   prev.X:=0; prev.Y:=0; //people who comment like "initialise variables" should be fired!
  170.   repeat
  171.     sleep(50); //50 is near 0 CPU usage, but sensitive enough to hop without lag
  172.     CheckMouse;
  173.   until false;
  174. end. //End program
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement