Files
better-xcloud/src/modules/mkb/pointer-client.ts
2024-06-10 08:57:07 +07:00

131 lines
3.7 KiB
TypeScript

import { BxLogger } from "@/utils/bx-logger";
import { Toast } from "@/utils/toast";
import type { MkbHandler } from "./base-mkb-handler";
const LOG_TAG = 'PointerClient';
enum PointerAction {
MOVE = 1,
BUTTON_PRESS = 2,
BUTTON_RELEASE = 3,
SCROLL = 4,
POINTER_CAPTURE_CHANGED = 5,
}
export class PointerClient {
private static instance: PointerClient;
public static getInstance(): PointerClient {
if (!PointerClient.instance) {
PointerClient.instance = new PointerClient();
}
return PointerClient.instance;
}
#socket: WebSocket | undefined | null;
#mkbHandler: MkbHandler | undefined;
start(port: number, mkbHandler: MkbHandler) {
if (!port) {
throw new Error('PointerServer port is 0');
}
this.#mkbHandler = mkbHandler;
// Create WebSocket connection.
this.#socket = new WebSocket(`ws://localhost:${port}`);
this.#socket.binaryType = 'arraybuffer';
// Connection opened
this.#socket.addEventListener('open', (event) => {
BxLogger.info(LOG_TAG, 'connected')
});
// Error
this.#socket.addEventListener('error', (event) => {
BxLogger.error(LOG_TAG, event);
Toast.show('Cannot setup mouse: ' + event);
});
this.#socket.addEventListener('close', (event) => {
this.#socket = null;
});
// Listen for messages
this.#socket.addEventListener('message', (event) => {
const dataView = new DataView(event.data);
let messageType = dataView.getInt8(0);
let offset = Int8Array.BYTES_PER_ELEMENT;
switch (messageType) {
case PointerAction.MOVE:
this.onMove(dataView, offset);
break;
case PointerAction.BUTTON_PRESS:
case PointerAction.BUTTON_RELEASE:
this.onPress(messageType, dataView, offset);
break;
case PointerAction.SCROLL:
this.onScroll(dataView, offset);
break;
case PointerAction.POINTER_CAPTURE_CHANGED:
this.onPointerCaptureChanged(dataView, offset);
}
});
}
onMove(dataView: DataView, offset: number) {
// [X, Y]
const x = dataView.getInt16(offset);
offset += Int16Array.BYTES_PER_ELEMENT;
const y = dataView.getInt16(offset);
this.#mkbHandler?.handleMouseMove({
movementX: x,
movementY: y,
});
// BxLogger.info(LOG_TAG, 'move', x, y);
}
onPress(messageType: PointerAction, dataView: DataView, offset: number) {
const button = dataView.getUint8(offset);
this.#mkbHandler?.handleMouseClick({
pointerButton: button,
pressed: messageType === PointerAction.BUTTON_PRESS,
});
// BxLogger.info(LOG_TAG, 'press', buttonIndex);
}
onScroll(dataView: DataView, offset: number) {
// [V_SCROLL, H_SCROLL]
const vScroll = dataView.getInt16(offset);
offset += Int16Array.BYTES_PER_ELEMENT;
const hScroll = dataView.getInt16(offset);
this.#mkbHandler?.handleMouseWheel({
vertical: vScroll,
horizontal: hScroll,
});
// BxLogger.info(LOG_TAG, 'scroll', vScroll, hScroll);
}
onPointerCaptureChanged(dataView: DataView, offset: number) {
const hasCapture = dataView.getInt8(offset) === 1;
!hasCapture && this.#mkbHandler?.stop();
}
stop() {
try {
this.#socket?.close();
} catch (e) {}
this.#socket = null;
}
}