Results 1 to 13 of 13

Thread: MouseRecorder

  1. #1
    Join Date
    Dec 2013
    Location
    Pitcairn Island
    Posts
    288
    Mentioned
    20 Post(s)
    Quoted
    166 Post(s)

    Default MouseRecorder

    I made this since a few people were talking about it. This little script can record all of your mouse clicks and save it to a file. This is meant for recording yourself play and will work with any window (such as SMART, the official client, or whatever). You can also load the data from the saved file and generate some averages too.

    It is easiest to use it as an included file like so:

    Simba Code:
    program new;
    {$DEFINE SMART}
    {$i srl-6/srl.simba}
    {$i mouserecorder.simba} // Throw it in your includes folder

    begin
      setupSRL();

      if recorder.setTargetWindow() then // Sets the target to SMART by default
      begin
        recorder.setDebug(True); // To print each click as you make it

        while not isKeyDown(VK_RETURN) do // Will log data until you press enter
          recorder.recordMouse();

        recorder.clicks.write(); // Debug all click parameters
        recorder.clicks.averages(); // Print out average stats
        recorder.clicks.saveToFile(); // Saves to a text file (ScriptPath + 'MouseData.txt' by default)
      end;

    end.

    The output of this would look like the following:

    Code:
    {CLICKTYPE = 1, STARTX = 684, ENDX = 686, STARTY = 327, ENDY = 301, ISDRAG = True, STARTTIME = 166556375, DURATION = 78}
    {CLICKTYPE = 1, STARTX = 609, ENDX = 512, STARTY = 296, ENDY = 333, ISDRAG = True, STARTTIME = 166556531, DURATION = 78}
    {CLICKTYPE = 1, STARTX = 529, ENDX = 515, STARTY = 372, ENDY = 376, ISDRAG = True, STARTTIME = 166556687, DURATION = 63}
    {CLICKTYPE = 1, STARTX = 431, ENDX = 431, STARTY = 423, ENDY = 423, ISDRAG = False, STARTTIME = 166556968, DURATION = 63}
    {CLICKTYPE = 0, STARTX = 426, ENDX = 427, STARTY = 477, ENDY = 477, ISDRAG = True, STARTTIME = 166557218, DURATION = 63}
    {CLICKTYPE = 0, STARTX = 407, ENDX = 407, STARTY = 356, ENDY = 356, ISDRAG = False, STARTTIME = 166558218, DURATION = 78}
    {CLICKTYPE = 0, STARTX = 387, ENDX = 358, STARTY = 367, ENDY = 422, ISDRAG = True, STARTTIME = 166558390, DURATION = 78}
    {CLICKTYPE = 0, STARTX = 349, ENDX = 352, STARTY = 522, ENDY = 526, ISDRAG = True, STARTTIME = 166558562, DURATION = 63}
    ---------------------------------------
    - Mean left click duration:     75.45 -
    - Mean right click duration:    80.11 -
    - Mean total click duration:    76.81 -
    - Drag clicks (% of total):     80.65 -
    ---------------------------------------
    Here is an example of loading the clicks from a file, and displaying some averages:

    Simba Code:
    program new;
    {$i mouserecorder.simba}

    begin
      recorder.clicks.loadFromFile(); // Loads from 'ScriptPath + MouseData.txt' by default)
      recorder.clicks.write();
      recorder.clicks.averages();
    end.

    I also threw in some painting stuff for generating a heatmap of the recorded clicks. Here is an example of using the official runescape client, and then drawing a heatmap on a new canvas after you're finished recording:

    Simba Code:
    program new;
    {$i mouserecorder.simba}

    begin

      if recorder.setTargetWindow('RuneScape') then // Title of the official client
      begin

        while not isKeyDown(VK_RETURN) do // Will log data until you press enter
          recorder.recordMouse();

        recorder.canvas.init(); // Initialize the canvas grid
        recorder.canvas.draw(recorder.clicks); // Create a heatmap of the clicks
      end;

    end.

    An example of me mashing the mouse on the login screen would look something like this:



    You can also change some of the drawing parameters, like so:

    Simba Code:
    recorder.canvas.init(2); // 2 means 2x2px grid (default is 4)
    recorder.canvas.draw(recorder.clicks, MOUSE_RIGHT); // Only draw right clicks on the map

    I am not maintaining this or improving it, so free free to do what you like with it. Here is the actual mouserecorder.simba file

    Simba Code:
    {$include_once srl-6/lib/utilities/math.simba}

    type
      TMapCell = record
        count, cpm: SmallInt;
        color: Integer;
        box: TBox;
      end;

      TMapCanvas = array of TMapCell;

      TMouseParam = record
        clickType: TClickType;
        startX, endX, startY, endY: Integer;
        isDrag: Boolean;
        startTime: Integer;
        duration: SmallInt;
      end;

      TMouseParams = array of TMouseParam;

      TMouseRecorder = record
        clicks: TMouseParams;
        canvas: TMapCanvas;
        debug: Boolean;
      end;

    const
      MOUSE_ALL = -2;

    var
      recorder: TMouseRecorder;

    procedure TMouseRecorder.setDebug(Enabled: Boolean);
    begin
      Self.debug := Enabled;
    end;

    function TMouseRecorder.setTargetWindow(TargetWindow: String = 'SMARTv8'): Boolean;
    var
      processes: TSysProcArr;
      i: Integer;
    begin
      processes := Client.GetIOManager().GetProcesses();

      for i := 0 to High(processes) do
        if pos(TargetWindow, processes[i].Title) then
        begin
          SetTarget(processes[i]);
          WriteLn('TMouseParams: Target window ' + TargetWindow + ' is set.');
          Exit(True);
        end;

      WriteLn('TMouseParams: Failed to find the target window: ' + TargetWindow);
      Result := False;
    end;

    procedure TMouseRecorder.recordMouse();
    begin
      if System.IsMouseButtonDown(0) or System.IsMouseButtonDown(1) then
      begin
        SetLength(Self.clicks, Length(Self.clicks) + 1);
        System.GetMousePos(Self.clicks[High(Self.clicks)].startX, Self.clicks[High(Self.clicks)].startY);
        Self.clicks[High(Self.clicks)].startTime := GetSystemTime();

        if System.IsMouseButtonDown(1) then
          Self.clicks[High(Self.clicks)].clickType := MOUSE_LEFT
        else
          Self.clicks[High(Self.clicks)].clickType := MOUSE_RIGHT;

        while System.IsMouseButtonDown(0) or System.IsMouseButtonDown(1) do
          Sleep(1);

        Self.clicks[High(Self.clicks)].duration := GetSystemTime() - Self.clicks[High(Self.clicks)].startTime;
        System.GetMousePos(Self.clicks[High(Self.clicks)].endX, Self.clicks[High(Self.clicks)].endY);

        if (Self.clicks[High(Self.clicks)].startX <> Self.clicks[High(Self.clicks)].endX) or
           (Self.clicks[High(Self.clicks)].startY <> Self.clicks[High(Self.clicks)].endY) then
           Self.clicks[High(Self.clicks)].isDrag := True;

        if Self.clicks[High(Self.clicks)].duration = 0 then
          SetLength(Self.clicks, High(Self.clicks))
        else if Self.debug then
            WriteLn(Self.clicks[High(Self.clicks)]);
      end else
        Sleep(3);
    end;

    procedure TMouseParams.saveToFile(Path: String = ScriptPath + 'mouseData.txt');
    var
      newfile, i: Integer;
    begin
      newfile := RewriteFile(Path, false);

      for i := 0 to High(Self) do
        WriteFileString(newfile, '[' + toStr(i) + ']' + toStr(recorder.clicks[i])+#13#10);

      WriteFileString(newfile, '[');
      WriteLn('TMouseParams: Saved ' + toStr(Length(Self)) + ' clicks to file: ' + path);
      CloseFile(newfile);
    end;

    procedure TMouseParams.loadFromFile(Path: String = ScriptPath + 'mouseData.txt');
    var
      mouseData, i: Integer;
      str: String;
      TSA: TStringArray;
    begin
      mouseData := OpenFile(Path, false);
      ReadFileString(mouseData, str, FileSize(mouseData));
      TSA := MultiBetween(str, ']', '[');
      SetLength(Self, Length(TSA));

      for i := 0 to High(TSA) do
      begin
        Self[i].clickType := StrToInt(Between('CLICKTYPE = ', ',', TSA[i]));
        Self[i].startX := StrToInt(Between('STARTX = ', ',', TSA[i]));
        Self[i].endX := StrToInt(Between('ENDX = ', ',', TSA[i]));
        Self[i].startY := StrToInt(Between('STARTY = ', ',', TSA[i]));
        Self[i].endY := StrToInt(Between('ENDY = ', ',', TSA[i]));
        Self[i].isDrag := StrToBool(Between('ISDRAG = ', ',', TSA[i]));
        Self[i].startTime := StrToInt(Between('STARTTIME = ', ',', TSA[i]));
        Self[i].duration := StrToInt(Between('DURATION = ', '}', TSA[i]));
      end;

      WriteLn('TMouseParams: Loaded ' + toStr(Length(TSA)) + ' clicks from file: ' + path);
      CloseFile(mouseData);
    end;

    procedure TMouseParams.write();
    var
      i: Integer;
    begin
      for i := 0 to High(Self) do WriteLn(Self[i]);
    end;

    procedure TMouseParams.averages();
    var
      i: Integer;
      avg, avgL, avgR, dragP: Extended;
      cntL: Integer = 1;
      cntR: Integer = 1;
    begin
      if Length(Self) < 1 then
      begin
        WriteLn('TMouseParams: Cannot generate avarages; No mouse data');
        Exit;
      end;

      for i := 0 to High(Self) do
      begin
        if Self[i].isDrag then dragP += 1;

        if Self[i].clickType = MOUSE_LEFT then
        begin
          cntL += 1;
          avgL += Self[i].duration;
        end;

        if Self[i].clickType = MOUSE_RIGHT then
        begin
          cntR += 1;
          avgR += Self[i].duration;
        end;
      end;

      avg := avgL + avgR;
      avg /= Length(Self);
      avgL /= cntL;
      avgR /= cntR;
      dragP := (dragP / Length(Self)) * 100;

      WriteLn('---------------------------------------');
      WriteLn(PadR('- Mean left click duration: ', 32) + toStr(Round(avgL, 2)) + ' -');
      WriteLn(PadR('- Mean right click duration: ', 32) + toStr(Round(avgR, 2)) + ' -');
      WriteLn(PadR('- Mean total click duration: ', 32) + toStr(Round(avg, 2)) + ' -');
      WriteLn(PadR('- Drag clicks (% of total): ', 32) + toStr(Round(dragP, 2)) + ' -');
      WriteLn('---------------------------------------');
    end;


    function TMouseParams.getClickPoints(ClickType: Integer = MOUSE_ALL; DragOnly: Boolean = False): TPointArray;
    var
      i, j, width, height: Integer;
      p: TPoint;
    begin
      GetClientDimensions(width, height);

      for i := 0 to High(Self) do
        if (Self[i].clickType = ClickType) or (ClickType = MOUSE_ALL)  then
        begin
          p := Point(Self[i].startX, Self[i].startY);
          if InRange(p.x, 0, width - 1) and InRange(p.y, 0, height - 1) then
            Insert(p, Result, Length(Result));
        end;
    end;

    procedure TMapCanvas.calcCellDensity(MouseData: TMouseParams; ClickType: Integer = MOUSE_ALL);
    var
      i, j, duration: Integer;
      TPA: TpointArray;
    begin
      TPA := MouseData.getClickPoints(ClickType);
      duration := MouseData[High(MouseData)].startTime - MouseData[Low(MouseData)].startTime;

      for i := 0 to High(TPA) do
        for j := 0 to High(Self) do
          if PointInBox(TPA[i], Self[j].box) then
            Self[j].count += 1;

      for i := 0 to High(Self) do
        Self[i].cpm := round(Self[i].count / (duration / 60000));
    end;

    procedure TMapCanvas.getCellColors();
    var
      i: Integer;
    begin
      if Length(Self) then
        for i := 0 to High(Self) do
          case Self[i].cpm of
            1..3: Self[i].color := 14145535;
            4..6: Self[i].color := 11579647;
            7..9: Self[i].color := 9540095;
            10..12: Self[i].color := 7303167;
            13..15: Self[i].color := 5987327;
            16..18: Self[i].color := 5197823;
            19..21: Self[i].color := 4210943;
            22..24: Self[i].color := 2960895;
            25..27: Self[i].color := 1245437;
            28..maxInt: Self[i].color := 255;
          else
            Self[i].color := 0;
        end;
    end;

    procedure TMapCanvas.init(CellSize: Integer = 4);
    var
      i, width, height: Integer;
      TBA: TBoxArray;
    begin
      WriteLn('TMapCanvas: Initializing the canvas with CellSize = ' + toStr(CellSize));
      GetClientDimensions(width, height);
      TBA := grid(round((width div CellSize)-1), round((height div CellSize)-1), CellSize, CellSize, CellSize, CellSize, Point(CellSize, CellSize));
      SetLength(Self, Length(TBA));

      for i := 0 to High(TBA) do Self[i].box := TBA[i];
    end;

    procedure TMapCanvas.draw(MouseData: TMouseParams; ClickType: Integer = MOUSE_ALL);
    var
      i, width, height: Integer;
      bmp: Integer;
    begin
      WriteLn('TMapCanvas: Generating heat map');

      if Length(MouseData) > 1 then
      begin
        GetClientDimensions(width, height);
        bmp := CreateBitmap(width, height);
        GetMufasaBitmap(bmp).CopyClientToBitmap(Client.GetIOManager(), False, 0, 0, width, height);

        Self.calcCellDensity(MouseData, ClickType);
        Self.getCellColors();

        for i := 0 to High(Self) do
          if Self[i].color <> 0 then
            GetMufasaBitmap(bmp).Rectangle(Self[i].box, Self[i].color);

        ClearDebugImg();
        DisplayDebugImgWindow(width, height);
        DrawBitmapDebugImg(GetMufasaBitmap(bmp).GetIndex());
        FreeBitmap(bmp);
      end else
        WriteLn('TMapCanvas: Cannot generate map; less than 2 data points.');
    end;

  2. #2
    Join Date
    Jun 2012
    Posts
    586
    Mentioned
    112 Post(s)
    Quoted
    296 Post(s)

    Default

    You can now purchase VIP for Simba Genesis for the low price of $200USD from villavu.com/#purchase.

    Naw, but seriously cool stuff. GJ. Which acc should I rep?




    Skype: obscuritySRL@outlook.com

  3. #3
    Join Date
    Dec 2007
    Posts
    289
    Mentioned
    4 Post(s)
    Quoted
    86 Post(s)

    Default

    Awesome stuff dude! Cheers for sharing

    Edit: It's probably worth noting that theoretically you could run this alongside an actual script to generate similar data for the script (provided your script doesn't hit the ENTER key... or you change the key it checks for ! ) Another note is that it also records clicks outside of the client area. Intentional?

    Quote Originally Posted by Obscurity View Post
    You can now purchase VIP for Simba Genesis for the low price of $200USD from villavu.com/#purchase.
    Haha, put a big grin of my face when I read that!

  4. #4
    Join Date
    Dec 2013
    Location
    Pitcairn Island
    Posts
    288
    Mentioned
    20 Post(s)
    Quoted
    166 Post(s)

    Default

    You can now purchase VIP for Simba Genesis for the low price of $200USD from villavu.com/#purchase.

    Naw, but seriously cool stuff. GJ. Which acc should I rep?
    Haha, this is nothing like Genesis really, it is simply some raw mouse data. Genesis would use this type of data to derive other variables, and then base mouse movements/clicks off those variables. The heatmap won’t be that useful in reality for reasons I have already mentioned, but it kinda looks cool.


    Quote Originally Posted by honeyhoney View Post
    It's probably worth noting that theoretically you could run this alongside an actual script to generate similar data for the script (provided your script doesn't hit the ENTER key... or you change the key it checks for ! )
    Good idea, you could literally do that without any changes. Just don't define smart and make the script use your own mouse.

  5. #5
    Join Date
    Dec 2007
    Posts
    289
    Mentioned
    4 Post(s)
    Quoted
    86 Post(s)

    Default

    Quote Originally Posted by The Simba Noob View Post
    Good idea, you could literally do that without any changes. Just don't define smart and make the script use your own mouse.
    Already tried and tested!

    Just changed it to log data until I pressed a key less common than ENTER

  6. #6
    Join Date
    Dec 2013
    Location
    Pitcairn Island
    Posts
    288
    Mentioned
    20 Post(s)
    Quoted
    166 Post(s)

    Default

    Quote Originally Posted by honeyhoney View Post
    Another note is that it also records clicks outside of the client area. Intentional?
    Yes, some people might find that useful as I'm sure legit players do things off client. Those points are filtered before drawing though.

  7. #7
    Join Date
    Dec 2008
    Posts
    10
    Mentioned
    0 Post(s)
    Quoted
    1 Post(s)

    Default

    Nice, I'm looking forward to using this

  8. #8
    Join Date
    Feb 2016
    Posts
    2
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Default

    do you think this would be safe to use on osrs or rs3?

  9. #9
    Join Date
    Mar 2016
    Location
    Isle de Muerta
    Posts
    40
    Mentioned
    0 Post(s)
    Quoted
    23 Post(s)

    Default

    i have a question how to make it load recorded clicks from file and replay them in smart client for x time?

    What i wanna do is to record some mouse movements and then play them again and again, but in smart client like bot. Because i can do this easy with mouse recorder program but then PC is useless...
    Maybe someone has such script and wanna share or sell?

  10. #10
    Join Date
    Jan 2012
    Location
    East Coast
    Posts
    733
    Mentioned
    81 Post(s)
    Quoted
    364 Post(s)

    Default

    Quote Originally Posted by kyyskis View Post
    i have a question how to make it load recorded clicks from file and replay them in smart client for x time?

    What i wanna do is to record some mouse movements and then play them again and again, but in smart client like bot. Because i can do this easy with mouse recorder program but then PC is useless...
    Maybe someone has such script and wanna share or sell?
    Just create a loop of mouse clicks and write in the static coordinates with some offsets.

  11. #11
    Join Date
    Sep 2008
    Location
    Not here.
    Posts
    5,422
    Mentioned
    13 Post(s)
    Quoted
    242 Post(s)

  12. #12
    Join Date
    Mar 2016
    Location
    Isle de Muerta
    Posts
    40
    Mentioned
    0 Post(s)
    Quoted
    23 Post(s)

    Default

    Quote Originally Posted by Ross View Post
    Just create a loop of mouse clicks and write in the static coordinates with some offsets.
    Something like this?

    program new;
    {$DEFINE SMART}
    {$I SRL-OSR/SRL.Simba}

    const
    XCord = x;
    YCord = y;
    MinWait = 1000;
    MaxWait = 2000;

    begin

    SetupSRL;

    repeat
    Mouse(XCord,YCord,0,0,mouse_left);
    Sleep(RandomRange(MinWait,MaxWait));
    until (false);

    end.

  13. #13
    Join Date
    Dec 2013
    Location
    Pitcairn Island
    Posts
    288
    Mentioned
    20 Post(s)
    Quoted
    166 Post(s)

    Default

    Quote Originally Posted by Ross View Post
    Just create a loop of mouse clicks and write in the static coordinates with some offsets.
    Trivial but no example?

    Quote Originally Posted by kyyskis View Post
    Something like this?

    program new;
    {$DEFINE SMART}
    {$I SRL-OSR/SRL.Simba}

    const
    XCord = x;
    YCord = y;
    MinWait = 1000;
    MaxWait = 2000;

    begin

    SetupSRL;

    repeat
    Mouse(XCord,YCord,0,0,mouse_left);
    Sleep(RandomRange(MinWait,MaxWait));
    until (false);

    end.
    For it to play back as intended, you need to account for time, both in terms of click duration and time between clicks.

    Something like this should work:

    Simba Code:
    procedure TMouseParams.play();
    var
      i: Integer;
    begin
      for i := 0 to High(Self) do
      begin
        MoveMouse(Self[i].startX, Self[i].startY);
        HoldMouse(Self[i].startX, Self[i].startY, Self[i].clickType);
        Sleep(Floor(Self[i].duration/2));
        MoveMouse(Self[i].endX, Self[i].endY);
        Sleep(Ceil(Self[i].duration/2));
        ReleaseMouse(Self[i].endX, Self[i].endY, Self[i].clickType);
        Sleep(Max(Self[i + 1].startTime - (Self[i].startTime + Self[i].duration), 0));
      end;
    end;

    If you paste that into the simba file, then you can write something like:

    Simba Code:
    program new;
    {$DEFINE SMART}
    {$i srl-6/srl.simba}
    {$i mouserecorder.simba}

    begin
      SetupSRL();

      recorder.clicks.loadFromFile();
      recorder.clicks.play();
    end.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •