357 lines
8.1 KiB
JavaScript
357 lines
8.1 KiB
JavaScript
const original_title = document.title;
|
|
const text_decoder = new TextDecoder();
|
|
const text_encoder = new TextEncoder();
|
|
let log_buf = "";
|
|
|
|
function convertKeyCode(code) {
|
|
const mapKeyCode = {
|
|
KeyA: 0,
|
|
KeyB: 1,
|
|
KeyC: 2,
|
|
KeyD: 3,
|
|
KeyE: 4,
|
|
KeyF: 5,
|
|
KeyG: 6,
|
|
KeyH: 7,
|
|
KeyI: 8,
|
|
KeyJ: 9,
|
|
KeyK: 10,
|
|
KeyL: 11,
|
|
KeyM: 12,
|
|
KeyN: 13,
|
|
KeyO: 14,
|
|
KeyP: 15,
|
|
KeyQ: 16,
|
|
KeyR: 17,
|
|
KeyS: 18,
|
|
KeyT: 19,
|
|
KeyU: 20,
|
|
KeyV: 21,
|
|
KeyW: 22,
|
|
KeyX: 23,
|
|
KeyY: 24,
|
|
KeyZ: 25,
|
|
Digit0: 26,
|
|
Digit1: 27,
|
|
Digit2: 28,
|
|
Digit3: 29,
|
|
Digit4: 30,
|
|
Digit5: 31,
|
|
Digit6: 32,
|
|
Digit7: 33,
|
|
Digit8: 34,
|
|
Digit9: 35,
|
|
F1: 36,
|
|
F2: 37,
|
|
F3: 38,
|
|
F4: 39,
|
|
F5: 40,
|
|
F6: 41,
|
|
F7: 42,
|
|
F8: 43,
|
|
F9: 44,
|
|
F10: 45,
|
|
F11: 46,
|
|
F12: 47,
|
|
F13: 48,
|
|
F14: 49,
|
|
F15: 50,
|
|
F16: 51,
|
|
F17: 52,
|
|
F18: 53,
|
|
F19: 54,
|
|
F20: 55,
|
|
F21: 56,
|
|
F22: 57,
|
|
F23: 58,
|
|
F24: 59,
|
|
F25: 60,
|
|
NumpadDivide: 61,
|
|
NumpadMultiply: 62,
|
|
NumpadSubtract: 63,
|
|
NumpadAdd: 64,
|
|
Numpad0: 65,
|
|
Numpad1: 66,
|
|
Numpad2: 67,
|
|
Numpad3: 68,
|
|
Numpad4: 69,
|
|
Numpad5: 70,
|
|
Numpad6: 71,
|
|
Numpad7: 72,
|
|
Numpad8: 73,
|
|
Numpad9: 74,
|
|
NumpadDecimal: 75,
|
|
NumpadEqual: 76,
|
|
NumpadEnter: 77,
|
|
Enter: 78,
|
|
Escape: 79,
|
|
Tab: 80,
|
|
ShiftLeft: 81,
|
|
ShiftRight: 82,
|
|
ControlLeft: 83,
|
|
ControlRight: 84,
|
|
AltLeft: 85,
|
|
AltRight: 86,
|
|
OSLeft: 87,
|
|
MetaLeft: 87,
|
|
OSRight: 88,
|
|
MetaRight: 88,
|
|
ContextMenu: 89,
|
|
NumLock: 90,
|
|
CapsLock: 91,
|
|
PrintScreen: 92,
|
|
ScrollLock: 93,
|
|
Pause: 94,
|
|
Delete: 95,
|
|
Home: 96,
|
|
End: 97,
|
|
PageUp: 98,
|
|
PageDown: 99,
|
|
Insert: 100,
|
|
ArrowLeft: 101,
|
|
ArrowRight: 102,
|
|
ArrowUp: 103,
|
|
ArrowDown: 104,
|
|
Backspace: 105,
|
|
Space: 106,
|
|
Minus: 107,
|
|
Equal: 108,
|
|
BracketLeft: 109,
|
|
BracketRight: 110,
|
|
Backslash: 111,
|
|
Semicolon: 112,
|
|
Quote: 113,
|
|
Comma: 114,
|
|
Period: 115,
|
|
Slash: 116,
|
|
Backquote: 117,
|
|
};
|
|
|
|
const k = mapKeyCode[code];
|
|
if (k != undefined)
|
|
return k;
|
|
return 118; // Unknown
|
|
}
|
|
|
|
const mach = {
|
|
canvases: [],
|
|
wasm: undefined,
|
|
observer: undefined,
|
|
events: [],
|
|
changes: [],
|
|
wait_event_timeout: 0,
|
|
|
|
init(wasm) {
|
|
this.wasm = wasm;
|
|
this.observer = new MutationObserver((mutables) => {
|
|
mutables.forEach((mutable) => {
|
|
if (mutable.type === 'attributes') {
|
|
if (mutable.attributeName === "width" || mutable.attributeName === "height") {
|
|
mutable.target.dispatchEvent(new Event("mach-canvas-resize"));
|
|
}
|
|
}
|
|
})
|
|
})
|
|
},
|
|
|
|
getString(str, len) {
|
|
const memory = mach.wasm.exports.memory.buffer;
|
|
return text_decoder.decode(new Uint8Array(memory, str, len));
|
|
},
|
|
|
|
setString(str, buf) {
|
|
const memory = this.wasm.exports.memory.buffer;
|
|
const strbuf = text_encoder.encode(str);
|
|
const outbuf = new Uint8Array(memory, buf, strbuf.length);
|
|
for (let i = 0; i < strbuf.length; i += 1) {
|
|
outbuf[i] = strbuf[i];
|
|
}
|
|
},
|
|
|
|
machLogWrite(str, len) {
|
|
log_buf += mach.getString(str, len);
|
|
},
|
|
|
|
machLogFlush() {
|
|
console.log(log_buf);
|
|
log_buf = "";
|
|
},
|
|
|
|
machPanic(str, len) {
|
|
throw Error(mach.getString(str, len));
|
|
},
|
|
|
|
machCanvasInit(id) {
|
|
let canvas = document.createElement("canvas");
|
|
canvas.id = "#mach-canvas-" + mach.canvases.length;
|
|
canvas.style.border = "1px solid";
|
|
canvas.style.position = "absolute";
|
|
canvas.style.display = "block";
|
|
canvas.tabIndex = 1;
|
|
|
|
mach.observer.observe(canvas, { attributes: true });
|
|
|
|
mach.setString(canvas.id, id);
|
|
|
|
canvas.addEventListener("contextmenu", (ev) => ev.preventDefault());
|
|
|
|
canvas.addEventListener("keydown", (ev) => {
|
|
if (ev.repeat) {
|
|
mach.events.push(...[2, convertKeyCode(ev.code)]);
|
|
} else {
|
|
mach.events.push(...[1, convertKeyCode(ev.code)]);
|
|
}
|
|
});
|
|
|
|
canvas.addEventListener("keyup", (ev) => {
|
|
mach.events.push(...[3, convertKeyCode(ev.code)]);
|
|
});
|
|
|
|
canvas.addEventListener("mousemove", (ev) => {
|
|
mach.events.push(...[4, ev.clientX, ev.clientY]);
|
|
});
|
|
|
|
canvas.addEventListener("mousedown", (ev) => {
|
|
mach.events.push(...[5, ev.button]);
|
|
});
|
|
|
|
canvas.addEventListener("mouseup", (ev) => {
|
|
mach.events.push(...[6, ev.button]);
|
|
});
|
|
|
|
canvas.addEventListener("wheel", (ev) => {
|
|
mach.events.push(...[7, ev.deltaX, ev.deltaY]);
|
|
});
|
|
|
|
canvas.addEventListener("focus", (ev) => {
|
|
mach.events.push(...[8]);
|
|
});
|
|
|
|
canvas.addEventListener("blur", (ev) => {
|
|
mach.events.push(...[9]);
|
|
});
|
|
|
|
canvas.addEventListener("mach-canvas-resize", (ev) => {
|
|
const cv_index = mach.canvases.findIndex((el) => el.canvas === ev.currentTarget);
|
|
const cv = mach.canvases[cv_index];
|
|
mach.changes.push(...[1, cv.canvas.width, cv.canvas.height, window.devicePixelRatio]);
|
|
});
|
|
|
|
document.body.appendChild(canvas);
|
|
return mach.canvases.push({ canvas: canvas, title: undefined }) - 1;
|
|
},
|
|
|
|
machCanvasDeinit(canvas) {
|
|
if (mach.canvases[canvas] != undefined) {
|
|
mach.canvases.splice(canvas, 1);
|
|
}
|
|
},
|
|
|
|
machCanvasSetTitle(canvas, title, len) {
|
|
const str = len > 0 ?
|
|
mach.getString(title, len) :
|
|
original_title;
|
|
|
|
mach.canvases[canvas].title = str;
|
|
},
|
|
|
|
machCanvasSetSize(canvas, width, height) {
|
|
const cv = mach.canvases[canvas];
|
|
if (width > 0 && height > 0) {
|
|
cv.canvas.style.width = width + "px";
|
|
cv.canvas.style.height = height + "px";
|
|
cv.canvas.width = Math.floor(width * window.devicePixelRatio);
|
|
cv.canvas.height = Math.floor(height * window.devicePixelRatio);
|
|
}
|
|
},
|
|
|
|
machCanvasSetFullscreen(canvas, value) {
|
|
const cv = mach.canvases[canvas];
|
|
if (value) {
|
|
cv.canvas.style.border = "0px";
|
|
cv.canvas.style.width = "100%";
|
|
cv.canvas.style.height = "100%";
|
|
cv.canvas.style.top = "0";
|
|
cv.canvas.style.left = "0";
|
|
cv.canvas.style.margin = "0px";
|
|
} else {
|
|
cv.canvas.style.border = "1px solid;"
|
|
cv.canvas.style.top = "2px";
|
|
cv.canvas.style.left = "2px";
|
|
}
|
|
},
|
|
|
|
machCanvasGetWindowWidth(canvas) {
|
|
const cv = mach.canvases[canvas];
|
|
return cv.canvas.width / window.devicePixelRatio;
|
|
},
|
|
|
|
machCanvasGetWindowHeight(canvas) {
|
|
const cv = mach.canvases[canvas];
|
|
return cv.canvas.height / window.devicePixelRatio;
|
|
},
|
|
|
|
machCanvasGetFramebufferWidth(canvas) {
|
|
const cv = mach.canvases[canvas];
|
|
return cv.canvas.width;
|
|
},
|
|
|
|
machCanvasGetFramebufferHeight(canvas) {
|
|
const cv = mach.canvases[canvas];
|
|
return cv.canvas.height;
|
|
},
|
|
|
|
machEmitCloseEvent() {
|
|
window.dispatchEvent(new Event("mach-close"));
|
|
},
|
|
|
|
machSetMouseCursor(cursor_ptr, len) {
|
|
let mach_name = mach.getString(cursor_ptr, len);
|
|
|
|
if (mach_name === 'arrow') document.body.style.cursor = 'default';
|
|
else if (mach_name === 'ibeam') document.body.style.cursor = 'text';
|
|
else if (mach_name === 'crosshair') document.body.style.cursor = 'crosshair';
|
|
else if (mach_name === 'pointing_hand') document.body.style.cursor = 'pointer';
|
|
else if (mach_name === 'resize_ew') document.body.style.cursor = 'ew-resize';
|
|
else if (mach_name === 'resize_ns') document.body.style.cursor = 'ns-resize';
|
|
else if (mach_name === 'resize_nwse') document.body.style.cursor = 'nwse-resize';
|
|
else if (mach_name === 'resize_nesw') document.body.style.cursor = 'nesw-resize';
|
|
else if (mach_name === 'resize_all') document.body.style.cursor = 'move';
|
|
else if (mach_name === 'not_allowed') document.body.style.cursor = 'not-allowed';
|
|
else {
|
|
console.log("machSetMouseCursor failed for " + mach_name);
|
|
}
|
|
},
|
|
|
|
machSetWaitEvent(timeout) {
|
|
mach.wait_event_timeout = timeout;
|
|
},
|
|
|
|
machHasEvent() {
|
|
return (mach.events.length > 0);
|
|
},
|
|
|
|
machEventShift() {
|
|
if (mach.events.length === 0)
|
|
return 0;
|
|
|
|
return mach.events.shift();
|
|
},
|
|
|
|
machEventShiftFloat() {
|
|
return mach.machEventShift();
|
|
},
|
|
|
|
machChangeShift() {
|
|
if (mach.changes.length === 0)
|
|
return 0;
|
|
|
|
return mach.changes.shift();
|
|
},
|
|
|
|
machPerfNow() {
|
|
return performance.now();
|
|
},
|
|
};
|
|
|
|
export { mach };
|