From b471138b5a681ad11447853873e113b4e545b69f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sun, 19 Jun 2022 16:57:42 +0100
Subject: [PATCH] feat: support for keys in wasm

---
 examples/web/chip_ahoyto.d.ts         |  10 +++
 examples/web/chip_ahoyto.js           |  12 ++++
 examples/web/chip_ahoyto_bg.wasm      | Bin 36474 -> 36751 bytes
 examples/web/chip_ahoyto_bg.wasm.d.ts |   2 +
 examples/web/index.js                 |  85 +++++++++++++++++++++-----
 src/chip8_neo.rs                      |   8 +++
 6 files changed, 103 insertions(+), 14 deletions(-)

diff --git a/examples/web/chip_ahoyto.d.ts b/examples/web/chip_ahoyto.d.ts
index f7ec932..77a84e7 100644
--- a/examples/web/chip_ahoyto.d.ts
+++ b/examples/web/chip_ahoyto.d.ts
@@ -38,6 +38,14 @@ export class Chip8Neo {
 /**
 */
   clock_st_ws(): void;
+/**
+* @param {number} key
+*/
+  key_press_ws(key: number): void;
+/**
+* @param {number} key
+*/
+  key_lift_ws(key: number): void;
 }
 
 export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
@@ -53,6 +61,8 @@ export interface InitOutput {
   readonly chip8neo_clock_ws: (a: number) => void;
   readonly chip8neo_clock_dt_ws: (a: number) => void;
   readonly chip8neo_clock_st_ws: (a: number) => void;
+  readonly chip8neo_key_press_ws: (a: number, b: number) => void;
+  readonly chip8neo_key_lift_ws: (a: number, b: number) => void;
   readonly __wbg_chip8classic_free: (a: number) => void;
   readonly chip8classic_new: () => number;
   readonly __wbindgen_malloc: (a: number) => number;
diff --git a/examples/web/chip_ahoyto.js b/examples/web/chip_ahoyto.js
index f66794c..c83bdce 100644
--- a/examples/web/chip_ahoyto.js
+++ b/examples/web/chip_ahoyto.js
@@ -180,6 +180,18 @@ export class Chip8Neo {
     clock_st_ws() {
         wasm.chip8neo_clock_st_ws(this.ptr);
     }
+    /**
+    * @param {number} key
+    */
+    key_press_ws(key) {
+        wasm.chip8neo_key_press_ws(this.ptr, key);
+    }
+    /**
+    * @param {number} key
+    */
+    key_lift_ws(key) {
+        wasm.chip8neo_key_lift_ws(this.ptr, key);
+    }
 }
 
 async function load(module, imports) {
diff --git a/examples/web/chip_ahoyto_bg.wasm b/examples/web/chip_ahoyto_bg.wasm
index 863046d35e007e90f80b2f3235a5beb152ce8643..8ebcfa0bd0912d5f934cf9ea18f88daeb2dd8275 100644
GIT binary patch
delta 3207
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
F1OQDd(!T%z

delta 2944
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

diff --git a/examples/web/chip_ahoyto_bg.wasm.d.ts b/examples/web/chip_ahoyto_bg.wasm.d.ts
index 20b6672..d5813e8 100644
--- a/examples/web/chip_ahoyto_bg.wasm.d.ts
+++ b/examples/web/chip_ahoyto_bg.wasm.d.ts
@@ -10,6 +10,8 @@ export function chip8neo_vram_ws(a: number, b: number): void;
 export function chip8neo_clock_ws(a: number): void;
 export function chip8neo_clock_dt_ws(a: number): void;
 export function chip8neo_clock_st_ws(a: number): void;
+export function chip8neo_key_press_ws(a: number, b: number): void;
+export function chip8neo_key_lift_ws(a: number, b: number): void;
 export function __wbg_chip8classic_free(a: number): void;
 export function chip8classic_new(): number;
 export function __wbindgen_malloc(a: number): number;
diff --git a/examples/web/index.js b/examples/web/index.js
index 65ad984..4ba8e46 100644
--- a/examples/web/index.js
+++ b/examples/web/index.js
@@ -6,10 +6,29 @@ import {
 const PIXEL_SET_COLOR = 0x50cb93ff;
 const PIXEL_UNSET_COLOR = 0x1b1a17ff;
 
-const LOGIC_HZ = 480;
+let LOGIC_HZ = 480;
 const TIMER_HZ = 60;
 const VISUAL_HZ = 60;
 
+const KEYS = {
+    "1": 0x01,
+    "2": 0x02,
+    "3": 0x03,
+    "4": 0x0c,
+    "q": 0x04,
+    "w": 0x05,
+    "e": 0x06,
+    "r": 0x0d,
+    "a": 0x07,
+    "s": 0x08,
+    "d": 0x09,
+    "f": 0x0e,
+    "z": 0x0a,
+    "x": 0x00,
+    "c": 0x0b,
+    "v": 0x0f
+}
+
 const ROM = "res/roms/pong.ch8";
 
 const state = {
@@ -27,9 +46,10 @@ const state = {
     // so that the global symbols become available
     await wasm();
 
-    // initializes the canvas sub-sytem
-    initCanvas();
-    registerDrop();
+    // initializes the complete set of sub-systems
+    // and registers the event handlers
+    init();
+    register();
 
     // loads the ROM data and converts it into the
     // target u8 array bufffer
@@ -69,14 +89,19 @@ const state = {
     }
 })();
 
+const register = () => {
+    registerDrop();
+    registerKeys();
+}
+
 const registerDrop = () => {
-    document.addEventListener("drop", async (e) => {
-        e.preventDefault();
-        e.stopPropagation();
+    document.addEventListener("drop", async (event) => {
+        event.preventDefault();
+        event.stopPropagation();
 
-        if (!e.dataTransfer.files) return;
+        if (!event.dataTransfer.files) return;
 
-        const file = e.dataTransfer.files[0];
+        const file = event.dataTransfer.files[0];
 
         const arrayBuffer = await file.arrayBuffer();
         const data = new Uint8Array(arrayBuffer);
@@ -84,12 +109,44 @@ const registerDrop = () => {
         state.chip8.reset_hard_ws();
         state.chip8.load_rom_ws(data);
     });
-    document.addEventListener("dragover", async (e) => {
-        e.preventDefault();
-        e.stopPropagation();
+    document.addEventListener("dragover", async (event) => {
+        event.preventDefault();
+        event.stopPropagation();
 
         console.info("draging over");
     });
+};
+
+const registerKeys = () => {
+    document.addEventListener("keydown", (event) => {
+        const keyCode = KEYS[event.key];
+        if (keyCode) {
+            state.chip8.key_press_ws(keyCode);
+            return;
+        }
+
+        switch(event.key) {
+            case "+":
+                LOGIC_HZ += 60;
+                break;
+
+            case "-":
+                LOGIC_HZ += 60;
+                break;
+        }
+    });
+
+    document.addEventListener("keyup", (event) => {
+        const keyCode = KEYS[event.key];
+        if (keyCode) {
+            state.chip8.key_lift_ws(keyCode);
+            return;
+        }
+    });
+}
+
+const init = () => {
+    initCanvas();
 }
 
 const initCanvas = () => {
@@ -108,7 +165,7 @@ const initCanvas = () => {
 
     state.image = state.canvasCtx.createImageData(state.canvas.width, state.canvas.height);
     state.videoBuff = new DataView(state.image.data.buffer);
-}
+};
 
 const updateCanvas = (pixels) => {
     for (let i = 0; i < pixels.length; i++) {
@@ -116,4 +173,4 @@ const updateCanvas = (pixels) => {
     }
     state.canvasCtx.putImageData(state.image, 0, 0);
     state.canvasScaledCtx.drawImage(state.canvas, 0, 0);
-}
+};
diff --git a/src/chip8_neo.rs b/src/chip8_neo.rs
index 17a7c82..fa81ef5 100644
--- a/src/chip8_neo.rs
+++ b/src/chip8_neo.rs
@@ -393,6 +393,14 @@ impl Chip8Neo {
     pub fn clock_st_ws(&mut self) {
         self.clock_st()
     }
+
+    pub fn key_press_ws(&mut self, key: u8) {
+        self.key_press(key)
+    }
+
+    pub fn key_lift_ws(&mut self, key: u8) {
+        self.key_lift(key)
+    }
 }
 
 impl Default for Chip8Neo {
-- 
GitLab