Files
netris-nestri/packages/input/src/mouse.ts
DatCaptainHorse e0751b368a feat: runner and playsite updates, mouse input stutter fix
- Also fixed mangohud config
2025-12-01 00:27:13 +02:00

141 lines
3.9 KiB
TypeScript

import { WebRTCStream } from "./webrtc-stream";
import {
ProtoMouseKeyDownSchema,
ProtoMouseKeyUpSchema,
ProtoMouseMoveSchema,
ProtoMouseWheelSchema,
} from "./proto/types_pb";
import { mouseButtonToLinuxEventCode } from "./codes";
import { create, toBinary } from "@bufbuild/protobuf";
import { createMessage } from "./utils";
import { ProtoMessageSchema } from "./proto/messages_pb";
interface Props {
webrtc: WebRTCStream;
canvas: HTMLCanvasElement;
}
export class Mouse {
protected wrtc: WebRTCStream;
protected canvas: HTMLCanvasElement;
protected connected!: boolean;
private sendInterval = 10; // 100 updates per second
// Store references to event listeners
private readonly mousemoveListener: (e: MouseEvent) => void;
private movementX: number = 0;
private movementY: number = 0;
private readonly mousedownListener: (e: MouseEvent) => void;
private readonly mouseupListener: (e: MouseEvent) => void;
private readonly mousewheelListener: (e: WheelEvent) => void;
constructor({ webrtc, canvas }: Props) {
this.wrtc = webrtc;
this.canvas = canvas;
this.mousemoveListener = (e: MouseEvent) => {
e.preventDefault();
e.stopPropagation();
this.movementX += e.movementX;
this.movementY += e.movementY;
};
this.mousedownListener = this.createMouseListener((e: any) =>
create(ProtoMouseKeyDownSchema, {
key: this.keyToVirtualKeyCode(e.button),
}),
);
this.mouseupListener = this.createMouseListener((e: any) =>
create(ProtoMouseKeyUpSchema, {
key: this.keyToVirtualKeyCode(e.button),
}),
);
this.mousewheelListener = this.createMouseListener((e: any) =>
create(ProtoMouseWheelSchema, {
x: Math.round(e.deltaX),
y: Math.round(e.deltaY),
}),
);
this.run();
this.startProcessing();
}
private run() {
//calls all the other functions
if (!document.pointerLockElement) {
console.log("no pointerlock");
if (this.connected) {
this.stop();
}
return;
}
if (document.pointerLockElement == this.canvas) {
this.connected = true;
this.canvas.addEventListener("mousemove", this.mousemoveListener);
this.canvas.addEventListener("mousedown", this.mousedownListener);
this.canvas.addEventListener("mouseup", this.mouseupListener);
this.canvas.addEventListener("wheel", this.mousewheelListener);
} else {
if (this.connected) {
this.stop();
}
}
}
private stop() {
this.canvas.removeEventListener("mousemove", this.mousemoveListener);
this.canvas.removeEventListener("mousedown", this.mousedownListener);
this.canvas.removeEventListener("mouseup", this.mouseupListener);
this.canvas.removeEventListener("wheel", this.mousewheelListener);
this.connected = false;
}
private startProcessing() {
setInterval(() => {
if (this.connected) {
this.sendAggregatedMouseMove();
this.movementX = 0;
this.movementY = 0;
}
}, this.sendInterval);
}
private sendAggregatedMouseMove() {
const data = create(ProtoMouseMoveSchema, {
x: Math.round(this.movementX),
y: Math.round(this.movementY),
});
const message = createMessage(data, "input");
this.wrtc.sendBinary(toBinary(ProtoMessageSchema, message));
}
// Helper function to create and return mouse listeners
private createMouseListener(
dataCreator: (e: Event) => any,
): (e: Event) => void {
return (e: Event) => {
e.preventDefault();
e.stopPropagation();
const data = dataCreator(e as any);
const message = createMessage(data, "input");
this.wrtc.sendBinary(toBinary(ProtoMessageSchema, message));
};
}
public dispose() {
document.exitPointerLock();
this.stop();
this.connected = false;
}
private keyToVirtualKeyCode(code: number) {
return mouseButtonToLinuxEventCode[code] || undefined;
}
}