mpp-frontend-ts/src/Pianoctor/KeyboardHandler.ts

198 lines
6.6 KiB
TypeScript

import { MPP } from "..";
import { Note } from "./Note";
import * as $ from "jquery";
import { MultiplayerPianoClient } from "../MultiplayerPianoClient";
export class KeyboardHandler {
key_binding: Record<number, {note: Note, held: boolean}>;
capsLockKey: boolean;
capKeyboard: boolean;
transpose_octave: number;
gInterface: MultiplayerPianoClient;
recapListenerFunc: (evt: JQuery.MouseDownEvent | JQuery.TouchStartEvent) => void;
recapListenerFunc2: (evt: JQuery.MouseDownEvent | JQuery.TouchStartEvent) => void;
handleKeyDownFunc: (evt: JQuery.KeyDownEvent) => void;
handleKeyUpFunc: (evt: JQuery.KeyUpEvent) => void;
constructor(gInterface: MultiplayerPianoClient) {
this.gInterface = gInterface;
this.key_binding = this.getKeyBinding();
this.capsLockKey = false;
this.capKeyboard = true;
this.transpose_octave = 0;
this.recapListenerFunc = this.recapListener.bind(this);
this.recapListenerFunc2 = this.recapListener.bind(this);
this.handleKeyDownFunc = this.handleKeyDown.bind(this);
this.handleKeyUpFunc = this.handleKeyUp.bind(this);
$(document).on("keydown", this.handleKeyDownFunc);
$(document).on("keyup", this.handleKeyUpFunc);
$(window).on("keypress", this.handleKeyPress);
$("#piano").on("mousedown", this.recapListenerFunc);
$("#piano").on("touchstart", this.recapListenerFunc2);
}
n(a: string, b?: number): {note: Note, held: boolean} {
return {
note: new Note(a, b),
held: false
};
}
getKeyBinding(): Record<number, {note: Note, held: boolean}> {
return {
65: this.n("gs"),
90: this.n("a"),
83: this.n("as"),
88: this.n("b"),
67: this.n("c", 1),
70: this.n("cs", 1),
86: this.n("d", 1),
71: this.n("ds", 1),
66: this.n("e", 1),
78: this.n("f", 1),
74: this.n("fs", 1),
77: this.n("g", 1),
75: this.n("gs", 1),
188: this.n("a", 1),
76: this.n("as", 1),
190: this.n("b", 1),
191: this.n("c", 2),
222: this.n("cs", 2),
49: this.n("gs", 1),
81: this.n("a", 1),
50: this.n("as", 1),
87: this.n("b", 1),
69: this.n("c", 2),
52: this.n("cs", 2),
82: this.n("d", 2),
53: this.n("ds", 2),
84: this.n("e", 2),
89: this.n("f", 2),
55: this.n("fs", 2),
85: this.n("g", 2),
56: this.n("gs", 2),
73: this.n("a", 2),
57: this.n("as", 2),
79: this.n("b", 2),
80: this.n("c", 3),
189: this.n("cs", 3),
173: this.n("cs", 3), // firefox why
219: this.n("d", 3),
187: this.n("ds", 3),
61: this.n("ds", 3), // firefox why
221: this.n("e", 3)
};
}
handleKeyDown(evt: JQuery.KeyDownEvent) {
if (!this.capKeyboard) return;
//console.log(evt);
let code = parseInt(evt.keyCode as any); //! Deprecated - Hri7566
if (this.key_binding[code] !== undefined) {
let binding = this.key_binding[code];
if (!binding.held) {
binding.held = true;
let note = binding.note;
let octave = 1 + note.octave + this.transpose_octave;
if (evt.shiftKey) ++octave;
else if (this.capsLockKey || evt.ctrlKey) --octave;
let noteStr = note.note + octave;
let vol = this.velocityFromMouseY();
this.gInterface.keyboard.press(noteStr, vol);
}
if (++this.gInterface.settings.gKeyboardSeq === 3) {
this.gInterface.settings.gKnowsYouCanUseKeyboard = true;
if (this.gInterface.settings.gKnowsYouCanUseKeyboardTimeout) clearTimeout(this.gInterface.settings.gKnowsYouCanUseKeyboardTimeout);
if (localStorage) localStorage.knowsYouCanUseKeyboard = true;
if (this.gInterface.settings.gKnowsYouCanUseKeyboardNotification) this.gInterface.settings.gKnowsYouCanUseKeyboardNotification.close();
}
evt.preventDefault();
evt.stopPropagation();
return false;
} else if (code === 20) { // Caps Lock
this.capsLockKey = true;
evt.preventDefault();
} else if (code === 0x20) { // Space Bar
this.gInterface.keyboard.pressSustain();
evt.preventDefault();
} else if ((code === 38 || code === 39) && this.transpose_octave < 3) {
++this.transpose_octave;
} else if ((code === 40 || code === 37) && this.transpose_octave > -2) {
--this.transpose_octave;
} else if (code === 9) { // Tab (don't tab away from the piano)
evt.preventDefault();
} else if (code === 8) { // Backspace (don't navigate Back)
this.gInterface.keyboard.gAutoSustain = !this.gInterface.keyboard.gAutoSustain;
evt.preventDefault();
}
}
handleKeyUp(evt: JQuery.KeyUpEvent) {
if (!this.capKeyboard) return;
let code = parseInt(evt.keyCode as any); //! Also deprecated - Hri7566
if (this.key_binding[code] !== undefined) {
let binding = this.key_binding[code];
if (binding.held) {
binding.held = false;
let note = binding.note;
let octave = 1 + note.octave + this.transpose_octave;
if (evt.shiftKey) ++octave;
else if (this.capsLockKey || evt.ctrlKey) --octave;
let noteStr = note.note + octave;
this.gInterface.keyboard.release(noteStr);
}
evt.preventDefault();
evt.stopPropagation();
return false;
} else if (code === 20) { // Caps Lock
this.capsLockKey = false;
evt.preventDefault();
} else if (code === 0x20) { // Space Bar
this.gInterface.keyboard.releaseSustain();
evt.preventDefault();
}
}
handleKeyPress(evt: JQuery.KeyPressEvent) {
if (!this.capKeyboard) return;
evt.preventDefault();
evt.stopPropagation();
if (evt.keyCode === 27 || evt.keyCode === 13) {
//$("#chat input").focus();
}
return false;
}
recapListener(evt: JQuery.MouseDownEvent | JQuery.TouchStartEvent) {
this.captureKeyboard();
}
captureKeyboard() {
this.capKeyboard = true;
/*$("#piano").off("mousedown", this.recapListenerFunc); //old, inefficient way of handling things
$("#piano").off("touchstart", this.recapListenerFunc2);
$(document).on("keydown", this.handleKeyDownFunc);
$(document).on("keyup", this.handleKeyUpFunc);
$(window).on("keypress", this.handleKeyPress);*/
};
releaseKeyboard() {
this.capKeyboard = false;
/*$(document).off("keydown", this.handleKeyDownFunc);
$(document).off("keyup", this.handleKeyUpFunc);
$(window).off("keypress", this.handleKeyPress);
$("#piano").on("mousedown", this.recapListenerFunc);
$("#piano").on("touchstart", this.recapListenerFunc2);*/
};
velocityFromMouseY(): number {
return 0.1 + (this.gInterface.cursor.my / 100) * 0.6;
}
}