98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
// file: crates/apps/game-snake-poc-tauri/frontend/ts/provenance.ts
|
|
// version: 1
|
|
|
|
import type { SnakeWasmGame } from "@snake-wasm";
|
|
import type { RuntimeDescriptor } from "./bridge";
|
|
import { frontendInfo } 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 TauriRuntimeProvenance {
|
|
private keyboardMouseObserved = false;
|
|
private touchObserved = false;
|
|
private deviceClass: DeviceClass = detectedDeviceClass();
|
|
|
|
public constructor(
|
|
private readonly game: SnakeWasmGame,
|
|
private readonly output: HTMLOutputElement,
|
|
private readonly descriptor: RuntimeDescriptor,
|
|
) {
|
|
if (descriptor.executionModel !== "wasm") {
|
|
throw new Error(`Modèle d'exécution Tauri inattendu : ${descriptor.executionModel}`);
|
|
}
|
|
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(this.descriptor.platformFamily, this.descriptor.runtimeHost, this.deviceClass, profile)) {
|
|
throw new Error("La provenance Tauri Android n'a pas pu être configurée dans le bridge WASM.");
|
|
}
|
|
this.output.value = displayLabel(this.game);
|
|
frontendInfo(`Snake Tauri provenance: ${this.output.value}`);
|
|
}
|
|
}
|