99 lines
3.2 KiB
TypeScript
99 lines
3.2 KiB
TypeScript
// file: Web/game-snake-poc/frontend/ts/provenance.ts
|
|
// version: 2
|
|
|
|
import type { SnakeWasmGame } from "@snake-wasm";
|
|
import { webInfo } from "./logging";
|
|
|
|
export type SnakeInputSource = "keyboard-mouse" | "touch";
|
|
|
|
type DeviceClass = "desktop" | "phone" | "tablet" | "unknown";
|
|
type InputProfile = "keyboard-mouse" | "mixed" | "touch" | "unknown";
|
|
|
|
function detectedDeviceClass(): DeviceClass {
|
|
const coarsePointer = window.matchMedia("(pointer: coarse)").matches;
|
|
const finePointer = window.matchMedia("(pointer: fine)").matches;
|
|
if (!coarsePointer || finePointer) {
|
|
return "desktop";
|
|
}
|
|
const shortEdge = Math.min(window.screen.width, window.screen.height);
|
|
if (!Number.isFinite(shortEdge) || shortEdge <= 0) {
|
|
return "unknown";
|
|
}
|
|
return shortEdge < 768 ? "phone" : "tablet";
|
|
}
|
|
|
|
function inputProfile(keyboardMouseObserved: boolean, touchObserved: boolean): InputProfile {
|
|
if (keyboardMouseObserved && touchObserved) {
|
|
return "mixed";
|
|
}
|
|
if (keyboardMouseObserved) {
|
|
return "keyboard-mouse";
|
|
}
|
|
if (touchObserved) {
|
|
return "touch";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
function displayLabel(game: SnakeWasmGame): string {
|
|
return [
|
|
game.provenance_platform_family(),
|
|
game.provenance_runtime_host(),
|
|
game.provenance_execution_model(),
|
|
game.provenance_device_class(),
|
|
game.provenance_input_profile(),
|
|
].join(" / ");
|
|
}
|
|
|
|
export class BrowserRuntimeProvenance {
|
|
private keyboardMouseObserved = false;
|
|
private touchObserved = false;
|
|
private deviceClass: DeviceClass = detectedDeviceClass();
|
|
|
|
public constructor(
|
|
private readonly game: SnakeWasmGame,
|
|
private readonly output: HTMLOutputElement,
|
|
) {
|
|
this.synchronize();
|
|
}
|
|
|
|
public recordInput(source: SnakeInputSource): void {
|
|
if (source === "touch") {
|
|
if (this.touchObserved) {
|
|
return;
|
|
}
|
|
this.touchObserved = true;
|
|
} else {
|
|
if (this.keyboardMouseObserved) {
|
|
return;
|
|
}
|
|
this.keyboardMouseObserved = true;
|
|
}
|
|
this.synchronize();
|
|
}
|
|
|
|
public refreshDeviceClass(): void {
|
|
const nextDeviceClass = detectedDeviceClass();
|
|
if (nextDeviceClass === this.deviceClass) {
|
|
return;
|
|
}
|
|
this.deviceClass = nextDeviceClass;
|
|
this.synchronize();
|
|
}
|
|
|
|
private synchronize(): void {
|
|
const profile = inputProfile(this.keyboardMouseObserved, this.touchObserved);
|
|
if (!this.game.configure_runtime_provenance("web", "browser", this.deviceClass, profile)) {
|
|
throw new Error("La provenance navigateur n'a pas pu être configurée dans le bridge WASM.");
|
|
}
|
|
this.output.value = displayLabel(this.game);
|
|
webInfo("snake-web-provenance", "runtime_provenance", {
|
|
deviceClass: this.game.provenance_device_class(),
|
|
executionModel: this.game.provenance_execution_model(),
|
|
inputProfile: this.game.provenance_input_profile(),
|
|
platformFamily: this.game.provenance_platform_family(),
|
|
runtimeHost: this.game.provenance_runtime_host(),
|
|
});
|
|
}
|
|
}
|