Skip to content

Instantly share code, notes, and snippets.

@Overemployed
Last active January 27, 2023 18:51
Show Gist options
  • Save Overemployed/3595853329092ccff5fa2990c5dbde20 to your computer and use it in GitHub Desktop.
Save Overemployed/3595853329092ccff5fa2990c5dbde20 to your computer and use it in GitHub Desktop.
PIKVM mouse jiggler
// assumes your mouse is in relative mode https://docs.pikvm.org/mouse/?h=relative#relative-mouse-on-v2-platform-otg-hid
// You may want to set your pikvm to support dual mode, so you can switch between absolute and relative
const { PIKVM_HOST, PIKVM_USER, PIKVM_PASSWORD, MOUSE_MODE = 'normal' } = process.env
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
import fetch from 'node-fetch';
import { path } from "ghost-cursor";
import websocket from 'websocket';
const WebSocketClient = websocket.client
let connection;
let previous = {
x: 0,
y: 0
}
let begin = true;
async function tracePath(vectors) {
const isPixelMode = MOUSE_MODE === 'pixel'
if (isPixelMode) {
const randomDirection = randomValue(1, 4)
let x = 0;
let y = 0;
switch (randomDirection) {
case 1:
x = 1
y = 0
break;
case 2:
x = -1
y = 0
break;
case 3:
x = 0
y = 1
break;
case 4:
default:
x = 0
y = -1
break;
}
await sendMouse({ x, y });
await wait(randomValue(600, 5000));
return
}
for (const v of vectors) {
const x = Math.floor(previous.x - v.x)
const y = Math.floor(previous.y - v.y)
try {
await sendMouse({ x, y });
await wait(randomValue(10, 30));
previous = v;
} catch (error) {
console.log(error.message);
}
}
}
async function sendMouse({ x, y }) {
console.log(x, y)
connection.send(`{
"event_type":"mouse_relative",
"event":{
"delta":[
{"x":${x},"y":${y}}
],
"squash":true
}
}`)
}
async function connectTo() {
const client = new WebSocketClient();
client.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
connectTo()
});
client.on('connect', async function(conn) {
connection = conn
console.log(`Connected`);
connection.on('error', function(error) {
console.log(`Connection Error: ` + error.toString());
connectTo()
});
connection.on('close', function() {
console.log(`echo-protocol Connection Closed`);
connectTo()
});
if (connection.connected) {
await updateMouseMode(true)
while (true) {
try {
const from = begin ? getRandomPoint() : previous
begin = false
await wait(randomValue(20, 5000));
const to = getRandomPoint();
const pathV = path(from, to);
await tracePath(pathV, connection);
} catch (e) {
console.log('Warning: stopping random mouse movements', e);
}
}
}
})
await wait(1000)
console.log(`connectiong to ${PIKVM_HOST}, ${PIKVM_USER}, ${PIKVM_PASSWORD}`)
client.connect(`wss://${PIKVM_HOST}/api/ws?stream=0`, '', '', {
'X-KVMD-User': PIKVM_USER,
'X-KVMD-Passwd': PIKVM_PASSWORD
})
}
function randomValue(min, max) {
min = Math.ceil(min);
max = ~~max;
return ~~(Math.random() * (max - min)) + min;
}
async function updateMouseMode(on) {
await fetch(
`https://${PIKVM_HOST}/api/hid/set_params?mouse_output=${on ? 'usb_rel' : 'usb'}`
, {
"headers": {
'X-KVMD-User': PIKVM_USER,
'X-KVMD-Passwd': PIKVM_PASSWORD
},
"method": "POST"
});
}
function getRandomPoint(){
const height = 1920
const width = 1080
let paddingPercentage = 1
const paddingWidth = (width * paddingPercentage) / 100;
const paddingHeight = (height * paddingPercentage) / 100;
const x = 0+ paddingWidth / 2 + Math.random() * (width - paddingWidth)
const y = 0+ paddingHeight / 2 + Math.random() * (height - paddingHeight)
return {
x: Math.floor(x),
y: Math.floor(y)
};
}
function wait(time){
return new Promise((resolve)=>{
setTimeout(resolve, time)
})
}
connectTo()
{
"name": "jiggler",
"version": "1.0.0",
"description": "",
"main": "jiggler.mjs",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"ghost-cursor": "^1.1.15",
"node-fetch": "^3.2.10",
"websocket": "^1.0.34"
}
}
@Overemployed
Copy link
Author

Overemployed commented Jul 5, 2022

Installation

Tested using NodeJS 16 and on my personal Macbook Pro. Some have reported they could not get this working on the PiKVM so I recommend you to install this script on your personal computer.

NodeJS version 16 or greater is required

After downloading both jiggler.mjs and package.json to a folder, run npm install to install the dependencies.

Notes

Currently this script will attempt to set the mouse mode to relative before running, however the mouse will not move unless you configure your pikvm to use relative mode. This script expects your PIKVM to be in dual mode which allows you to switch between relative and absolute mose modes. Read more here

When the script runs it will try to switch to relative mode for you but only after you have changed your PIKVM config to dual mode.

How to run

In the terminal you'll run the following

PIKVM_HOST=pikvm.local PIKVM_USER=admin PIKVM_PASSWORD=admin node jiggler.mjs

Explanation of the environment variables

PIKVM_HOST is the domain you use to access the pikvm. This can also be an ip address.

PIKVM_USER is the user for the pikvm.

PIVKM_PASSWORD is the password for the pikvm.

MOUSE_MODE can be MOUSE_MODE=normal or MOUSE_MODE=pixel. Use pixel mode if you want the mouse to move 1 pixel every few seconds.

@arch1mede
Copy link

arch1mede commented Sep 3, 2022

This does NOT work on PiKVM, do not install it and expect it to work. Unknown why this does not work.
Windows does not work, at least not in the same way.
Spinning up an Ubuntu VM might be the best to use in this case. But it does work.

@overemployedswe
Copy link

overemployedswe commented Jan 23, 2023

This is working for me with 2 PiKVM's

I am using a Mac Studio (M1 Max, 32GB)

Steps to take before running the script

  • You need to set your PiKVM to be dual mode (reference the PiKVM docs which are linked above)
  • You need to have Node & npm installed on your system (the one thats connecting to the pikvms)
  • create a folder and put the two provided files inside
  • run npm i to get the dependencies
  • run node jiggler.mjs to run the script

I would recommend when running jiggler.mjs you follow the above example where you provide the host, user & password.

Note: I've only tested/used MOUSE_MODE=normal.

I've also written a quick little script that puts my mouse mode back to absolute which can be done with pretty much the existing code in the jiggler.mjs script.

@arch1mede
Copy link

@overemployedswe Can you provide this script and how its used?

@overemployedswe
Copy link

overemployedswe commented Jan 27, 2023

@arch1mede to set the mouse mode back to absolute I'm using this script here which was pretty much taken from the main jiggle script but I stripped everything jiggle related out:

const { PIKVM_HOST, PIKVM_USER, PIKVM_PASSWORD } = process.env;
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
import fetch from "node-fetch";

async function updateMouseMode() {
  try {
    await fetch(`https://${PIKVM_HOST}/api/hid/set_params?mouse_output=usb`, {
      headers: {
        "X-KVMD-User": PIKVM_USER,
        "X-KVMD-Passwd": PIKVM_PASSWORD,
      },
      method: "POST",
    });
  } catch (e) {
    console.log("ERROR: ", e);
  }
}

updateMouseMode();

You call this script the exact same way you call the jiggler script by passing in the env variables nessecary, then when you run the script it makes an api call to the pikvm to set the mouse mode to absolute so its back to normal.

I don't have it yet but I plan to build an orchestration api to start & stop mouse jigglers via an api call so that I can utilize macropads to handle these scripts rather than needing to actually run a script in my terminal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment