implement mouse wheel handling and clean up mouse handling in general

This commit is contained in:
modeco80 2024-03-11 21:24:40 -04:00
parent f981a661da
commit b59ebe2466
2 changed files with 55 additions and 22 deletions

View File

@ -1,4 +1,4 @@
import {createNanoEvents } from "nanoevents"; import {createNanoEvents, Emitter, DefaultEvents } from "nanoevents";
import * as Guacutils from './Guacutils.js'; import * as Guacutils from './Guacutils.js';
import VM from "./VM.js"; import VM from "./VM.js";
import { User } from "./User.js"; import { User } from "./User.js";
@ -24,9 +24,9 @@ export default class CollabVMClient {
private voteStatus : VoteStatus | null = null; private voteStatus : VoteStatus | null = null;
private node : string | null = null; private node : string | null = null;
// events that are used internally and not exposed // events that are used internally and not exposed
private emitter; private emitter : Emitter<DefaultEvents>;
// public events // public events
private publicEmitter; private publicEmitter : Emitter<DefaultEvents>;
constructor(url : string) { constructor(url : string) {
// Save the URL // Save the URL
@ -45,28 +45,32 @@ export default class CollabVMClient {
if (this.users.find(u => u.username === this.username)?.turn === -1) if (this.users.find(u => u.username === this.username)?.turn === -1)
this.turn(true); this.turn(true);
}); });
// Bind keyboard and mouse // Bind keyboard and mouse
this.canvas.addEventListener('mousedown', (e : MouseEvent) => { this.canvas.addEventListener('mousedown', (e : MouseEvent) => {
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return; if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
this.mouse.processEvent(e, true); this.mouse.initFromMouseEvent(e);
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask()); this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
}, { }, {
capture: true capture: true
}); });
this.canvas.addEventListener('mouseup', (e : MouseEvent) => { this.canvas.addEventListener('mouseup', (e : MouseEvent) => {
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return; if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
this.mouse.processEvent(e, false); this.mouse.initFromMouseEvent(e);
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask()); this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
}, { }, {
capture: true capture: true
}); });
this.canvas.addEventListener('mousemove', (e : MouseEvent) => { this.canvas.addEventListener('mousemove', (e : MouseEvent) => {
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return; if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
this.mouse.processEvent(e, null); this.mouse.initFromMouseEvent(e);
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask()); this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
}, { }, {
capture: true capture: true
}); });
this.canvas.addEventListener('keydown', (e : KeyboardEvent) => { this.canvas.addEventListener('keydown', (e : KeyboardEvent) => {
e.preventDefault(); e.preventDefault();
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return; if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
@ -76,6 +80,7 @@ export default class CollabVMClient {
}, { }, {
capture: true capture: true
}); });
this.canvas.addEventListener('keyup', (e : KeyboardEvent) => { this.canvas.addEventListener('keyup', (e : KeyboardEvent) => {
e.preventDefault(); e.preventDefault();
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return; if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
@ -85,6 +90,23 @@ export default class CollabVMClient {
}, { }, {
capture: true capture: true
}); });
this.canvas.addEventListener('wheel', (ev: WheelEvent) => {
ev.preventDefault();
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
this.mouse.initFromWheelEvent(ev);
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
// this is a very, very ugly hack but it seems to work so /shrug
if(this.mouse.scrollUp)
this.mouse.scrollUp = false;
else if(this.mouse.scrollDown)
this.mouse.scrollDown = false;
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
}, { capture: true });
this.canvas.addEventListener('contextmenu', e => e.preventDefault()); this.canvas.addEventListener('contextmenu', e => e.preventDefault());
// Create the WebSocket // Create the WebSocket
this.socket = new WebSocket(url, "guacamole"); this.socket = new WebSocket(url, "guacamole");

View File

@ -1,9 +1,13 @@
function maskContains(mask: number, bit: number): boolean {
return (mask & bit) == bit;
}
export default class Mouse { export default class Mouse {
left : boolean = false; left : boolean = false;
middle : boolean = false; middle : boolean = false;
right : boolean = false; right : boolean = false;
scrolldown : boolean = false; scrollDown : boolean = false;
scrollup : boolean = false; scrollUp : boolean = false;
x : number = 0; x : number = 0;
y : number = 0; y : number = 0;
constructor() {} constructor() {}
@ -13,24 +17,31 @@ export default class Mouse {
if (this.left) mask |= 1; if (this.left) mask |= 1;
if (this.middle) mask |= 2; if (this.middle) mask |= 2;
if (this.right) mask |= 4; if (this.right) mask |= 4;
if (this.scrollup) mask |= 8; if (this.scrollUp) mask |= 8;
if (this.scrolldown) mask |= 16; if (this.scrollDown) mask |= 16;
return mask; return mask;
} }
processEvent(e : MouseEvent, down : boolean | null = null) { initFromMouseEvent(e: MouseEvent) {
if (down !== null) switch (e.button) { this.left = maskContains(e.buttons, 1);
case 0: this.right = maskContains(e.buttons, 2);
this.left = down; this.middle = maskContains(e.buttons, 4);
break;
case 1:
this.middle = down;
break;
case 2:
this.right = down;
break;
}
this.x = e.offsetX; this.x = e.offsetX;
this.y = e.offsetY; this.y = e.offsetY;
} }
// don't think there's a good way of shoehorning this in processEvent so ..
// (I guess could union e to be MouseEvent|WheelEvent and put this in there, but it'd be a
// completely unnesscary runtime check for a one-event situation, so having it be seperate
// and even call the MouseEvent implementation is more than good enough)
initFromWheelEvent(ev: WheelEvent) {
this.initFromMouseEvent(ev as MouseEvent);
// Now do the actual wheel handling
if (ev.deltaY < 0)
this.scrollUp = true;
else if (ev.deltaY > 0)
this.scrollDown = true;
}
} }