Skip to content

Commit

Permalink
Introduce HID, add documentation, clean chuck code
Browse files Browse the repository at this point in the history
  • Loading branch information
terryzfeng committed Dec 5, 2023
1 parent 82cbb45 commit be90a1c
Show file tree
Hide file tree
Showing 13 changed files with 306 additions and 561 deletions.
39 changes: 26 additions & 13 deletions dist/Hid.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import Chuck from "./Chuck";
/**
* Introducing HID (Human Interface Device) support for WebChucK. WebChucK HID
* brings mouse and keyboard support to work with the native {@link https://chuck.stanford.edu/doc/reference/io.html#Hid | Hid}
* class in ChucK. WebChucK HID wraps JavaScript mouse and keyboard event
* listeners. To get started with HID:
* @example
* ```ts
* import { Chuck, HID } from "webchuck";
*
* const theChuck = await Chuck.init([]);
* const hid = await HID.init(theChuck);
* ```
*/
export default class HID {
private theChuck;
private keymap;
private mousePos;
private lastPos;
private _mouseActive;
private _kbdActive;
private boundHandleMouseMove;
Expand All @@ -20,12 +31,12 @@ export default class HID {
* Mouse and keyboard event listeners are added if `enableMouse` and `enableKeyboard` are true (default).
* @example
* ```ts
* theChuck = await Chuck.init(); // Initialize WebChucK
* theChuck = await Chuck.init([]);
* hid = await HID.init(theChuck); // Initialize HID with mouse and keyboard
* ```
* @example
* ```ts
* theChuck = await Chuck.init(); // Initialize WebChucK
* theChuck = await Chuck.init([]);
* hid = await HID.init(theChuck, false, true); // Initialize HID, no mouse, only keyboard
* ```
* @param theChuck WebChucK instance
Expand Down Expand Up @@ -54,7 +65,7 @@ export default class HID {
y: number;
};
/**
* Enable Mouse HID Javascript event listeners to communicate with ChucK
* Enable Mouse HID Javascript event listeners for Chuck HID
* Adds a mousemove, mousedown, mouseup, and wheel listener to the document.
* @example
* ```ts
Expand All @@ -73,7 +84,7 @@ export default class HID {
*/
disableMouse(): void;
/**
* Enable keyboard HID Javascript event listeners to communicate with ChucK.
* Enable keyboard HID Javascript event listeners for Chuck HID
* Adds a keydown and keyup listener to the document.
* @example
* ```ts
Expand All @@ -92,22 +103,24 @@ export default class HID {
*/
disableKeyboard(): void;
/** @internal */
handleMouseMove(e: MouseEvent): void;
private handleMouseMove;
/** @internal */
handleMouseDown(e: MouseEvent): void;
private handleMouseDown;
/** @internal */
handleMouseUp(e: MouseEvent): void;
private handleMouseUp;
/** @internal */
handleMouseWheel(e: WheelEvent): void;
private handleMouseWheel;
/** @internal */
handleKeyDown(e: KeyboardEvent): void;
private static handleContextMenu;
/** @internal */
handleKeyUp(e: KeyboardEvent): void;
private handleKeyDown;
/** @internal */
private handleKeyUp;
/**
* @internal
* Handle keyboard presses to send to chuck
* @param e Keyboard event
* @param isDown Is key down
*/
keyPressManager(e: KeyboardEvent, isDown: boolean): void;
private keyPressManager;
}
76 changes: 44 additions & 32 deletions dist/Hid.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
import { Hid_ck, HidMsg_ck } from "./hidCk";
var HidMsgType;
(function (HidMsgType) {
HidMsgType[HidMsgType["BUTTON_DOWN"] = 1] = "BUTTON_DOWN";
HidMsgType[HidMsgType["BUTTON_UP"] = 2] = "BUTTON_UP";
HidMsgType[HidMsgType["MOUSE_MOTION"] = 5] = "MOUSE_MOTION";
HidMsgType[HidMsgType["WHEEL_MOTION"] = 6] = "WHEEL_MOTION";
})(HidMsgType || (HidMsgType = {}));
/**
* Introducing HID (Human Interface Device) support for WebChucK. WebChucK HID
* brings mouse and keyboard support to work with the native {@link https://chuck.stanford.edu/doc/reference/io.html#Hid | Hid}
* class in ChucK. WebChucK HID wraps JavaScript mouse and keyboard event
* listeners. To get started with HID:
* @example
* ```ts
* import { Chuck, HID } from "webchuck";
*
* const theChuck = await Chuck.init([]);
* const hid = await HID.init(theChuck);
* ```
*/
export default class HID {
/** @internal */
constructor(theChuck) {
Expand All @@ -7,8 +27,6 @@ export default class HID {
// Initialize members
this.theChuck = theChuck;
this.keymap = new Array(256).fill(false);
this.mousePos = { x: 0, y: 0 };
this.lastPos = { x: 0, y: 0 };
// Bind handlers
this.boundHandleMouseMove = this.handleMouseMove.bind(this);
this.boundHandleMouseDown = this.handleMouseDown.bind(this);
Expand All @@ -23,12 +41,12 @@ export default class HID {
* Mouse and keyboard event listeners are added if `enableMouse` and `enableKeyboard` are true (default).
* @example
* ```ts
* theChuck = await Chuck.init(); // Initialize WebChucK
* theChuck = await Chuck.init([]);
* hid = await HID.init(theChuck); // Initialize HID with mouse and keyboard
* ```
* @example
* ```ts
* theChuck = await Chuck.init(); // Initialize WebChucK
* theChuck = await Chuck.init([]);
* hid = await HID.init(theChuck, false, true); // Initialize HID, no mouse, only keyboard
* ```
* @param theChuck WebChucK instance
Expand Down Expand Up @@ -78,7 +96,7 @@ export default class HID {
};
}
/**
* Enable Mouse HID Javascript event listeners to communicate with ChucK
* Enable Mouse HID Javascript event listeners for Chuck HID
* Adds a mousemove, mousedown, mouseup, and wheel listener to the document.
* @example
* ```ts
Expand All @@ -91,6 +109,7 @@ export default class HID {
document.addEventListener("mousedown", this.boundHandleMouseDown);
document.addEventListener("mouseup", this.boundHandleMouseUp);
document.addEventListener("wheel", this.boundHandleMouseWheel);
document.addEventListener("contextmenu", HID.handleContextMenu);
}
/**
* Disable Mouse HID Javascript event listeners
Expand All @@ -105,9 +124,10 @@ export default class HID {
document.removeEventListener("mousedown", this.boundHandleMouseDown);
document.removeEventListener("mouseup", this.boundHandleMouseUp);
document.removeEventListener("wheel", this.boundHandleMouseWheel);
document.removeEventListener("contextmenu", HID.handleContextMenu);
}
/**
* Enable keyboard HID Javascript event listeners to communicate with ChucK.
* Enable keyboard HID Javascript event listeners for Chuck HID
* Adds a keydown and keyup listener to the document.
* @example
* ```ts
Expand Down Expand Up @@ -139,55 +159,47 @@ export default class HID {
handleMouseMove(e) {
this.mouseActive();
if (this._mouseActive) {
this.mousePos = this.getMousePos(e);
this.theChuck.setInt("_mouseMotion", 1);
this.theChuck.broadcastEvent("_hid");
this.theChuck.setInt("_mouseX", this.mousePos.x);
this.theChuck.setInt("_mouseY", this.mousePos.y);
const mousePos = this.getMousePos(e);
this.theChuck.setFloat("_deltaX", e.movementX);
this.theChuck.setFloat("_deltaY", e.movementY);
this.theChuck.setFloat("_scaledCursorX", this.mousePos.x / document.documentElement.clientWidth);
this.theChuck.setFloat("_scaledCursorY", this.mousePos.y / document.documentElement.clientHeight);
this.theChuck.broadcastEvent("_msg");
this.theChuck.setFloat("_scaledCursorX", mousePos.x / document.documentElement.clientWidth);
this.theChuck.setFloat("_scaledCursorY", mousePos.y / document.documentElement.clientHeight);
this.theChuck.setInt("_type", HidMsgType.MOUSE_MOTION);
this.theChuck.broadcastEvent("_hid");
}
this.lastPos = this.mousePos;
}
/** @internal */
handleMouseDown(e) {
this.mouseActive();
if (this._mouseActive) {
this.theChuck.setInt("_mouseMotion", 0);
this.theChuck.setInt("_mouseDown", 1);
this.theChuck.broadcastEvent("_hid");
this.theChuck.setInt("_hidMouse", 1);
this.theChuck.setInt("_which", e.which);
this.theChuck.broadcastEvent("_msg");
this.theChuck.setInt("_type", HidMsgType.BUTTON_DOWN);
this.theChuck.broadcastEvent("_hid");
}
}
/** @internal */
handleMouseUp(e) {
this.mouseActive();
if (this._mouseActive) {
this.theChuck.setInt("_mouseMotion", 0);
this.theChuck.setInt("_mouseUp", 1);
this.theChuck.broadcastEvent("_hid");
this.theChuck.setInt("_hidMouse", 1);
this.theChuck.setInt("_which", e.which);
this.theChuck.broadcastEvent("_msg");
this.theChuck.setInt("_type", HidMsgType.BUTTON_UP);
this.theChuck.broadcastEvent("_hid");
}
}
/** @internal */
handleMouseWheel(e) {
this.mouseActive();
if (this._mouseActive) {
this.theChuck.setInt("_mouseMotion", 0);
this.theChuck.setInt("_isScroll", 1);
this.theChuck.setInt("_deltaX", clamp(e.deltaX, -1, 1));
this.theChuck.setInt("_deltaY", clamp(e.deltaY, -1, 1));
this.theChuck.setFloat("_deltaX", clamp(e.deltaX, -1, 1));
this.theChuck.setFloat("_deltaY", clamp(e.deltaY, -1, 1));
this.theChuck.setInt("_type", HidMsgType.WHEEL_MOTION);
this.theChuck.broadcastEvent("_hid");
this.theChuck.broadcastEvent("_msg");
}
}
/** @internal */
static handleContextMenu(e) {
e.preventDefault();
}
//----------- KEYBOARD --------- //
/** @internal */
handleKeyDown(e) {
Expand Down Expand Up @@ -215,7 +227,7 @@ export default class HID {
this.theChuck.setString("_key", e.key);
this.theChuck.setInt("_which", e.which);
this.theChuck.setInt("_ascii", e.keyCode);
this.theChuck.setInt("_type", isDown ? 1 : 2);
this.theChuck.setInt("_type", isDown ? HidMsgType.BUTTON_DOWN : HidMsgType.BUTTON_UP);
this.theChuck.broadcastEvent("_hid");
}
}
Expand All @@ -227,7 +239,7 @@ export default class HID {
* @param val value to clamp
* @param min min value
* @param max max value
* @returns clamp value
* @returns clamped value
*/
function clamp(val, min, max) {
return Math.min(Math.max(val, min), max);
Expand Down
4 changes: 2 additions & 2 deletions dist/hidCk.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
declare const HidMsg_ck = "\nglobal Event _msg;\n \nglobal Event _hid;\nglobal int _hidMultiple;\n0 => global int _cursorX;\n0 => global int _cursorY;\n\n0 => global float _deltaX;\n0 => global float _deltaY;\n\nglobal string _key;\nglobal int _isDown;\nglobal int _isUp;\nglobal int _isMouseDown;\nglobal int _isMouseUp;\nglobal int _isScroll;\nglobal int _ascii;\nglobal int _which;\nglobal int _mouseActive;\nglobal int _kbdActive;\nglobal int _mouseMotion;\nglobal float _scaledCursorX;\nglobal float _scaledCursorY;\n\npublic class HidMsg {\n int type;\n int deviceType;\n int cursorX;\n int cursorY;\n float deltaX;\n float deltaY;\n float scaledCursorX;\n float scaledCursorY;\n int which;\n int ascii;\n string key;\n\n // type 1 message\n function int isButtonDown() {\n if (type == 1) { return 1; }\n return 0;\n }\n\n // type 2 message\n function int isButtonUp() {\n if (type == 2) { return 1; }\n return 0;\n }\n\n // type 5 message\n function int isMouseMotion(){\n if (type == 5) { return 1; }\n return 0;\n }\n\n // type 6 message\n function int isWheelMotion(){\n if (type == 6) { return 1; }\n return 0;\n }\n\n function void _copy(HidMsg localMsg) {\n localMsg.type => type;\n localMsg.deviceType => deviceType;\n localMsg.cursorX => cursorX;\n localMsg.cursorY => cursorY;\n localMsg.deltaX => deltaX;\n localMsg.deltaY => deltaY;\n localMsg.scaledCursorX => scaledCursorX;\n localMsg.scaledCursorY => scaledCursorY;\n localMsg.which => which;\n localMsg.ascii => ascii;\n localMsg.key => key;\n }\n}\n";
declare const Hid_ck = "\nglobal Event _msg;\n\nglobal Event _hid;\nglobal int _cursorX;\nglobal int _cursorY;\n\nglobal float _deltaX;\nglobal float _deltaY;\n\nglobal int _type;\nglobal string _key;\nglobal int _isDown;\nglobal int _isUp;\nglobal int _isMouseDown;\nglobal int _isMouseUp;\nglobal int _isScroll;\nglobal int _ascii;\nglobal int _which;\nglobal int _mouseActive;\nglobal int _kbdActive;\nglobal int _mouseMotion;\nglobal float _scaledCursorX;\nglobal float _scaledCursorY;\n\npublic class Hid extends Event {\n\n 0 => int isMouseOpen;\n 0 => int isKBDOpen;\n 0 => int active;\n\n string deviceName; \n int deviceType; // mouse = 2, keyboard = 3\n\n // HidMsg Queue\n HidMsg _hidMsgQueue[0];\n\n function string name() {\n return deviceName;\n }\n\n function int openMouse(int num) {\n if (num < 0) {\n false => active;\n } else {\n \"virtualJS mouse/trackpad\" => deviceName;\n 2 => deviceType;\n true => active;\n }\n active => isMouseOpen => _mouseActive;\n return active;\n }\n\n function int openKeyboard(int num) {\n if (num < 0) {\n false => active;\n } else {\n \"virtualJS keyboard\" => deviceName;\n 3 => deviceType;\n true => active;\n }\n active => isKBDOpen => _kbdActive;\n return active;\n }\n\n // Pop the first HidMsg from the queue\n // Write it to msg and return 1\n function int recv(HidMsg msg) {\n // is empty\n if (_hidMsgQueue.size() <= 0) {\n return 0;\n }\n\n // pop the first HidMsg to msg, return true\n _hidMsgQueue[0] @=> HidMsg localMsg;\n msg._copy(localMsg); \n _hidMsgQueue.popFront();\n return 1;\n }\n\n // Hid Listener\n // Get variables from JS and write to the HidMsg \n function void _HidListener() {\n HidMsg @ msg;\n while(true){\n new HidMsg @=> msg;\n deviceType => msg.deviceType;\n _hid => now;\n\n _type => msg.type;\n _cursorX => msg.cursorX;\n _cursorY => msg.cursorY;\n _deltaX => msg.deltaX;\n _deltaY => msg.deltaY;\n _scaledCursorX => msg.scaledCursorX;\n _scaledCursorY => msg.scaledCursorY;\n _which => msg.which;\n _ascii => msg.ascii;\n _key => msg.key;\n\n _hidMsgQueue << msg;\n this.broadcast();\n }\n }\n spork ~ _HidListener();\n}\n";
declare const HidMsg_ck = "\npublic class HidMsg {\n int type;\n int deviceType;\n int cursorX;\n int cursorY;\n float deltaX;\n float deltaY;\n float scaledCursorX;\n float scaledCursorY;\n int which;\n int ascii;\n string key;\n\n // type 1 message\n function int isButtonDown() {\n return type == 1;\n }\n\n // type 2 message\n function int isButtonUp() {\n return type == 2;\n }\n\n // type 5 message\n function int isMouseMotion(){\n return type == 5;\n }\n\n // type 6 message\n function int isWheelMotion(){\n return type == 6;\n }\n\n function void _copy(HidMsg localMsg) {\n localMsg.type => type;\n localMsg.deviceType => deviceType;\n localMsg.cursorX => cursorX;\n localMsg.cursorY => cursorY;\n localMsg.deltaX => deltaX;\n localMsg.deltaY => deltaY;\n localMsg.scaledCursorX => scaledCursorX;\n localMsg.scaledCursorY => scaledCursorY;\n localMsg.which => which;\n localMsg.ascii => ascii;\n localMsg.key => key;\n }\n}\n";
declare const Hid_ck = "\nglobal Event _hid;\nglobal int _type;\nglobal int _mouseActive;\nglobal int _kbdActive;\n\nglobal int _cursorX;\nglobal int _cursorY;\nglobal float _deltaX;\nglobal float _deltaY;\nglobal float _scaledCursorX;\nglobal float _scaledCursorY;\n\nglobal int _ascii;\nglobal int _which;\nglobal string _key;\n\npublic class Hid extends Event {\n\n 0 => int isMouseOpen;\n 0 => int isKBDOpen;\n 0 => int active;\n\n string deviceName; \n int deviceType; // mouse = 2, keyboard = 3\n\n // HidMsg Queue\n HidMsg _hidMsgQueue[0];\n\n function string name() {\n return deviceName;\n }\n\n function int openMouse(int num) {\n if (num < 0) {\n false => active;\n } else {\n \"virtualJS mouse/trackpad\" => deviceName;\n 2 => deviceType;\n true => active;\n }\n active => isMouseOpen => _mouseActive;\n return active;\n }\n\n function int openKeyboard(int num) {\n if (num < 0) {\n false => active;\n } else {\n \"virtualJS keyboard\" => deviceName;\n 3 => deviceType;\n true => active;\n }\n active => isKBDOpen => _kbdActive;\n return active;\n }\n\n // Pop the first HidMsg from the queue\n // Write it to msg and return 1\n function int recv(HidMsg msg) {\n // is empty\n if (_hidMsgQueue.size() <= 0) {\n return 0;\n }\n\n // pop the first HidMsg to msg, return true\n _hidMsgQueue[0] @=> HidMsg localMsg;\n msg._copy(localMsg); \n _hidMsgQueue.popFront();\n return 1;\n }\n\n // Hid Listener\n // Get variables from JS and write to the HidMsg \n function void _HidListener() {\n HidMsg @ msg;\n while(true){\n new HidMsg @=> msg;\n deviceType => msg.deviceType;\n _hid => now;\n\n _type => msg.type;\n _cursorX => msg.cursorX;\n _cursorY => msg.cursorY;\n _deltaX => msg.deltaX;\n _deltaY => msg.deltaY;\n _scaledCursorX => msg.scaledCursorX;\n _scaledCursorY => msg.scaledCursorY;\n _which => msg.which;\n _ascii => msg.ascii;\n _key => msg.key;\n\n _hidMsgQueue << msg;\n this.broadcast();\n\n // Clear message type\n 0 => _type;\n }\n }\n spork ~ _HidListener();\n}\n";
export { HidMsg_ck, Hid_ck };
Loading

0 comments on commit be90a1c

Please sign in to comment.