Add browser gamepad support with pad button pictograms

Co-Authored-By: deepseek-v4.1-flash (opencode-go) via CodeCraft
This commit is contained in:
Richard Zinkanddeepseek-v4.1-flash (opencode-go) via CodeCraft committed 2026-11-11 14:43:39 +01:00
1 parent 073999d592
commit 8d51d6ec6a
26 files changed
+1066 -22

No files matched your search

+70
View File
@@ -11,6 +11,16 @@
var fetched = { state: 0 }; // download of a file from the server: 0 idle, 1 running, 2 done, 3 failed
var ws = {}; // socket id -> { state, queue, sock }
var wsNext = 1;
var gpPad = null; // the gamepad handed out by dc_gamepad_slot (reused for its buttons/axes)
var gpSlot = -1;
// browsers offer the Gamepad API only in a secure context (https or localhost)
function gamepads() {
try {
return navigator.getGamepads ? navigator.getGamepads() : [];
} catch (e) {
return [];
}
}
function bytes(ptr, len) {
return new Uint8Array(wasm_memory.buffer, ptr, len);
@@ -193,6 +203,66 @@
env.dc_coarse_pointer = function () {
try { return window.matchMedia("(pointer: coarse)").matches ? 1 : 0; } catch (e) { return 0; }
};
// ---- gamepads: the game polls these functions once per frame (see src/pad.rs).
// The Gamepad API needs a secure context (https or localhost) and shows a pad only after
// its first button press. slot = the index in navigator.getGamepads(), -1 = no gamepad.
env.dc_gamepad_slot = function () {
gpPad = null;
gpSlot = -1;
var pads = gamepads();
for (var i = 0; i < pads.length; i++) {
if (pads[i] && pads[i].connected && pads[i].mapping === "standard") {
gpPad = pads[i];
gpSlot = i;
return i;
}
}
// a pad without the standard mapping (old DirectInput devices): use it anyway
for (var j = 0; j < pads.length; j++) {
if (pads[j] && pads[j].connected) {
gpPad = pads[j];
gpSlot = j;
return j;
}
}
return -1;
};
function gamepad(slot) {
if (gpPad && slot === gpSlot) return gpPad;
var pads = gamepads();
return pads[slot] && pads[slot].connected ? pads[slot] : null;
}
// bit i set: standard button i is down (triggers count from 40 % on)
env.dc_gamepad_buttons = function (slot) {
var p = gamepad(slot);
if (!p) return 0;
var m = 0;
for (var i = 0; i < p.buttons.length && i < 16; i++) {
var b = p.buttons[i];
if (b && (b.pressed || b.value > 0.4)) m |= 1 << i;
}
return m;
};
// axis 0/1 = left stick x/y, 2/3 = right stick x/y (all -1..1)
env.dc_gamepad_axis = function (slot, axis) {
var p = gamepad(slot);
if (!p || !p.axes || axis < 0 || axis >= p.axes.length) return 0;
return p.axes[axis];
};
// 0 unknown, 1 Xbox, 2 PlayStation, 3 Nintendo (from the pad's id)
// (the Xbox check comes first: its id contains "Wireless Controller" too)
env.dc_gamepad_kind = function (slot) {
var p = gamepad(slot);
if (!p) return 0;
var id = (p.id || "").toLowerCase();
if (id.indexOf("xbox") >= 0 || id.indexOf("xinput") >= 0 || id.indexOf("microsoft") >= 0) return 1;
if (id.indexOf("nintendo") >= 0 || id.indexOf("switch") >= 0 || id.indexOf("joy-con") >= 0 ||
id.indexOf("joycon") >= 0 || id.indexOf("pro controller") >= 0) return 3;
if (id.indexOf("playstation") >= 0 || id.indexOf("dualshock") >= 0 || id.indexOf("dualsense") >= 0 ||
id.indexOf("sony") >= 0 || id.indexOf("wireless controller") >= 0 || id.indexOf("054c") >= 0 ||
/(^|[^0-9])ps[345]([^0-9]|$)/.test(id)) return 2;
return 0;
};
env.dc_storage_set = function (kp, kl, vp, vl) {
try { window.localStorage.setItem(str(kp, kl), str(vp, vl)); } catch (e) { }
};