add turns and control
This commit is contained in:
parent
288edf6b3a
commit
b4559a3841
3
src/js/keyboard.d.ts
vendored
Normal file
3
src/js/keyboard.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
declare function GetKeysym(keyCode : number, key : string, location : number) : number | undefined;
|
||||
|
||||
export default GetKeysym;
|
||||
|
|
@ -3,13 +3,10 @@
|
|||
// shitty but it works so /shrug
|
||||
// THIS SUCKS SO BAD AND I HATE IT PLEASE REWRITE ALL OF THIS
|
||||
|
||||
export default function GetKeysym(keyCode, keyIdentifier, key, location) {
|
||||
export default function GetKeysym(keyCode, key, location) {
|
||||
var keysym = keysym_from_key_identifier(key, location)
|
||||
|| keysym_from_keycode(keyCode, location);
|
||||
|
||||
if (!keysym && key_identifier_sane(keyCode, keyIdentifier))
|
||||
keysym = keysym_from_key_identifier(keyIdentifier, location);
|
||||
|
||||
return keysym;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const elements = {
|
|||
changeUsernameBtn: document.getElementById("changeUsernameBtn") as HTMLButtonElement,
|
||||
turnBtnText: document.getElementById("turnBtnText") as HTMLSpanElement,
|
||||
turnstatus: document.getElementById("turnstatus") as HTMLParagraphElement,
|
||||
takeTurnBtn: document.getElementById("takeTurnBtn") as HTMLButtonElement,
|
||||
}
|
||||
var expectedClose = false;
|
||||
var turn = -1;
|
||||
|
|
@ -32,6 +33,8 @@ const users : {
|
|||
user : User,
|
||||
element : HTMLTableRowElement
|
||||
}[] = [];
|
||||
var turnInterval : number | undefined = undefined;;
|
||||
var turnTimer = 0;
|
||||
|
||||
// Active VM
|
||||
var VM : CollabVMClient | null = null;
|
||||
|
|
@ -166,8 +169,8 @@ function sortVMList() {
|
|||
|
||||
function sortUserList() {
|
||||
users.sort((a, b) => {
|
||||
if (a.user.username === w.username && (a.user.turn >= b.user.turn)) return -1;
|
||||
if (b.user.username === w.username && (b.user.turn >= a.user.turn)) return 1;
|
||||
if (a.user.username === w.username && (a.user.turn >= b.user.turn) && b.user.turn !== 0) return -1;
|
||||
if (b.user.username === w.username && (b.user.turn >= a.user.turn) && a.user.turn !== 0) return 1;
|
||||
if (a.user.turn === b.user.turn) return 0;
|
||||
if (a.user.turn === -1) return 1;
|
||||
if (b.user.turn === -1) return -1;
|
||||
|
|
@ -269,6 +272,9 @@ function userRenamed(oldname : string, newname : string, selfrename : boolean) {
|
|||
function turnUpdate(status : TurnStatus) {
|
||||
// Clear all turn data
|
||||
turn = -1;
|
||||
VM!.canvas.classList.remove("focused", "waiting");
|
||||
clearInterval(turnInterval);
|
||||
turnTimer = 0;
|
||||
for (const user of users) {
|
||||
user.element.classList.remove("user-turn", "user-waiting");
|
||||
user.element.setAttribute("data-cvm-turn", "-1");
|
||||
|
|
@ -286,15 +292,36 @@ function turnUpdate(status : TurnStatus) {
|
|||
}
|
||||
if (status.user?.username === w.username) {
|
||||
turn = 0;
|
||||
turnTimer = status.turnTime! / 1000;
|
||||
elements.turnBtnText.innerHTML = "End Turn";
|
||||
VM!.canvas.classList.add("focused");
|
||||
}
|
||||
if (status.queue.some(u => u.username === w.username)) {
|
||||
turn = status.queue.findIndex(u => u.username === w.username) + 1;
|
||||
turnTimer = status.queueTime! / 1000;
|
||||
elements.turnBtnText.innerHTML = "End Turn";
|
||||
VM!.canvas.classList.add("waiting");
|
||||
}
|
||||
if (turn === -1) elements.turnstatus.innerText = "";
|
||||
else {
|
||||
turnInterval = setInterval(() => turnIntervalCb(), 1000);
|
||||
setTurnStatus();
|
||||
}
|
||||
sortUserList();
|
||||
}
|
||||
|
||||
function turnIntervalCb() {
|
||||
turnTimer--;
|
||||
setTurnStatus();
|
||||
}
|
||||
|
||||
function setTurnStatus() {
|
||||
if (turn === 0)
|
||||
elements.turnstatus.innerText = `Turn expires in ${turnTimer} seconds`;
|
||||
else
|
||||
elements.turnstatus.innerText = `Waiting for turn in ${turnTimer} seconds`;
|
||||
}
|
||||
|
||||
function sendChat() {
|
||||
if (VM === null) return;
|
||||
VM.chat(elements.chatinput.value);
|
||||
|
|
@ -313,7 +340,10 @@ elements.changeUsernameBtn.addEventListener('click', () => {
|
|||
var newname = prompt("Enter new username, or leave blank to be assigned a guest username", w.username);
|
||||
if (newname === w.username) return;
|
||||
VM?.rename(newname);
|
||||
})
|
||||
});
|
||||
elements.takeTurnBtn.addEventListener('click', () => {
|
||||
VM?.turn(turn === -1);
|
||||
});
|
||||
|
||||
// Public API
|
||||
w.collabvm = {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import VM from "./VM.js";
|
|||
import { User } from "./User.js";
|
||||
import { Rank } from "./Permissions.js";
|
||||
import TurnStatus from "./TurnStatus.js";
|
||||
import Mouse from "./mouse.js";
|
||||
import GetKeysym from '../../js/keyboard';
|
||||
|
||||
export default class CollabVMClient {
|
||||
// Fields
|
||||
|
|
@ -14,6 +16,8 @@ export default class CollabVMClient {
|
|||
private connectedToVM : boolean = false;
|
||||
private users : User[] = [];
|
||||
private username : string | null = null;
|
||||
private mouse : Mouse = new Mouse();
|
||||
private rank : Rank = Rank.Unregistered;
|
||||
// events that are used internally and not exposed
|
||||
private emitter;
|
||||
// public events
|
||||
|
|
@ -31,6 +35,50 @@ export default class CollabVMClient {
|
|||
this.canvas.tabIndex = -1;
|
||||
// Get the 2D context
|
||||
this.ctx = this.canvas.getContext('2d')!;
|
||||
// Bind canvas click
|
||||
this.canvas.addEventListener('click', e => {
|
||||
if (this.users.find(u => u.username === this.username)?.turn === -1)
|
||||
this.turn(true);
|
||||
});
|
||||
// Bind keyboard and mouse
|
||||
this.canvas.addEventListener('mousedown', (e : MouseEvent) => {
|
||||
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
|
||||
this.mouse.processEvent(e, true);
|
||||
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
|
||||
}, {
|
||||
capture: true
|
||||
});
|
||||
this.canvas.addEventListener('mouseup', (e : MouseEvent) => {
|
||||
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
|
||||
this.mouse.processEvent(e, false);
|
||||
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
|
||||
}, {
|
||||
capture: true
|
||||
});
|
||||
this.canvas.addEventListener('mousemove', (e : MouseEvent) => {
|
||||
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
|
||||
this.mouse.processEvent(e, null);
|
||||
this.sendmouse(this.mouse.x, this.mouse.y, this.mouse.makeMask());
|
||||
}, {
|
||||
capture: true
|
||||
});
|
||||
this.canvas.addEventListener('keydown', (e : KeyboardEvent) => {
|
||||
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
|
||||
var keysym = GetKeysym(e.keyCode, e.key, e.location);
|
||||
if (keysym === undefined) return;
|
||||
this.key(keysym, true);
|
||||
}, {
|
||||
capture: true
|
||||
});
|
||||
this.canvas.addEventListener('keyup', (e : KeyboardEvent) => {
|
||||
if (this.users.find(u => u.username === this.username)?.turn === -1 && this.rank !== Rank.Admin) return;
|
||||
var keysym = GetKeysym(e.keyCode, e.key, e.location);
|
||||
if (keysym === undefined) return;
|
||||
this.key(keysym, false);
|
||||
}, {
|
||||
capture: true
|
||||
});
|
||||
this.canvas.addEventListener('contextmenu', e => e.preventDefault());
|
||||
// Create the WebSocket
|
||||
this.socket = new WebSocket(url, "guacamole");
|
||||
// Add the event listeners
|
||||
|
|
@ -61,7 +109,6 @@ export default class CollabVMClient {
|
|||
}
|
||||
case "list": {
|
||||
// pass msgarr to the emitter for processing by list()
|
||||
console.log("got list")
|
||||
this.emitter.emit('list', msgArr.slice(1));
|
||||
break;
|
||||
}
|
||||
|
|
@ -194,7 +241,6 @@ export default class CollabVMClient {
|
|||
displayName: list[i + 1],
|
||||
thumbnail: th,
|
||||
});
|
||||
console.log("pushed", list[i]);
|
||||
}
|
||||
res(vms);
|
||||
});
|
||||
|
|
@ -238,5 +284,20 @@ export default class CollabVMClient {
|
|||
else this.send("rename");
|
||||
}
|
||||
|
||||
// Take or drop turn
|
||||
turn(taketurn : boolean) {
|
||||
this.send("turn", taketurn ? "1" : "0");
|
||||
}
|
||||
|
||||
// Send mouse instruction
|
||||
sendmouse(x : number, y : number, mask : number) {
|
||||
this.send("mouse", x.toString(), y.toString(), mask.toString());
|
||||
}
|
||||
|
||||
// Send key
|
||||
key(keysym : number, down : boolean) {
|
||||
this.send("key", keysym.toString(), down ? "1" : "0");
|
||||
}
|
||||
|
||||
on = (event : string | number, cb: (...args: any) => void) => this.publicEmitter.on(event, cb);
|
||||
}
|
||||
36
src/ts/protocol/mouse.ts
Normal file
36
src/ts/protocol/mouse.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
export default class Mouse {
|
||||
left : boolean = false;
|
||||
middle : boolean = false;
|
||||
right : boolean = false;
|
||||
scrolldown : boolean = false;
|
||||
scrollup : boolean = false;
|
||||
x : number = 0;
|
||||
y : number = 0;
|
||||
constructor() {}
|
||||
|
||||
makeMask() {
|
||||
var mask = 0;
|
||||
if (this.left) mask |= 1;
|
||||
if (this.middle) mask |= 2;
|
||||
if (this.right) mask |= 4;
|
||||
if (this.scrollup) mask |= 8;
|
||||
if (this.scrolldown) mask |= 16;
|
||||
return mask;
|
||||
}
|
||||
|
||||
processEvent(e : MouseEvent, down : boolean | null = null) {
|
||||
if (down !== null) switch (e.button) {
|
||||
case 0:
|
||||
this.left = down;
|
||||
break;
|
||||
case 1:
|
||||
this.middle = down;
|
||||
break;
|
||||
case 2:
|
||||
this.right = down;
|
||||
break;
|
||||
}
|
||||
this.x = e.offsetX;
|
||||
this.y = e.offsetY;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user