Better implementation of PPT and key listener.

canary
WolverinDEV 2018-11-17 16:25:44 +01:00
parent 69b4730bd8
commit f37b918a5b
9 changed files with 250 additions and 52 deletions

View File

@ -5,22 +5,59 @@ namespace ppt {
KEY_TYPED KEY_TYPED
} }
export interface KeyEvent { export enum SpecialKey {
CTRL,
WINDOWS,
SHIFT,
ALT
}
export interface KeyDescriptor {
key_code: string;
key_ctrl: boolean;
key_windows: boolean;
key_shift: boolean;
key_alt: boolean;
}
export interface KeyEvent extends KeyDescriptor {
readonly type: EventType; readonly type: EventType;
readonly key: string; readonly key: string;
readonly key_code: string; }
readonly key_ctrl: boolean; export interface KeyHook extends KeyDescriptor {
readonly key_windows: boolean; cancel: boolean;
readonly key_shift: boolean;
readonly key_alt: boolean;
callback_press: () => any;
callback_release: () => any;
}
export function key_description(key: KeyDescriptor) {
let result = "";
if(key.key_shift)
result += " + Shift";
if(key.key_alt)
result += " + Alt";
if(key.key_ctrl)
result += " + CTRL";
if(key.key_windows)
result += " + Win";
result += " + " + (key.key_code ? key.key_code : "unset");
return result.substr(3);
} }
export declare function initialize() : Promise<void>; export declare function initialize() : Promise<void>;
export declare function finalize(); /* most the times not really required */ export declare function finalize(); /* most the times not really required */
export declare function register_key_hook(callback: (event: KeyEvent) => any, cancel: boolean); export declare function register_key_listener(listener: (_: KeyEvent) => any);
export declare function unregister_key_hook(callback: (event: KeyEvent) => any); export declare function unregister_key_listener(listener: (_: KeyEvent) => any);
export declare function register_key_hook(hook: KeyHook);
export declare function unregister_key_hook(hook: KeyHook);
export declare function key_pressed(code: string | SpecialKey) : boolean;
} }

View File

@ -122,6 +122,7 @@ function loadDebug() {
console.log("Adding browser audio player"); console.log("Adding browser audio player");
custom_scripts.push(["js/audio/AudioPlayer.js"]); custom_scripts.push(["js/audio/AudioPlayer.js"]);
custom_scripts.push(["js/audio/WebCodec.js"]); custom_scripts.push(["js/audio/WebCodec.js"]);
custom_scripts.push(["js/WebPPTListener.js"]);
} }
load_wait_scripts([ load_wait_scripts([
@ -186,6 +187,7 @@ function loadDebug() {
"js/chat.js", "js/chat.js",
"js/Identity.js", "js/Identity.js",
"js/PPTListener.js",
...custom_scripts ...custom_scripts
]).then(() => load_wait_scripts([ ]).then(() => load_wait_scripts([
"js/codec/CodecWrapperWorker.js" "js/codec/CodecWrapperWorker.js"

View File

@ -135,6 +135,11 @@ function main() {
} }
} }
ppt.initialize().catch(error => {
console.error("Failed to initialize ppt!");
//TODO error notification?
});
/* /*
let tag = $("#tmpl_music_frame").renderTag({ let tag = $("#tmpl_music_frame").renderTag({
//thumbnail: "img/loading_image.svg" //thumbnail: "img/loading_image.svg"

View File

@ -29,7 +29,7 @@ class StaticSettings {
if (typeof input === "string") return input as string; if (typeof input === "string") return input as string;
else if (typeof input === "number") return input.toString(); else if (typeof input === "number") return input.toString();
else if (typeof input === "boolean") return input ? "1" : "0"; else if (typeof input === "boolean") return input ? "1" : "0";
else if (typeof input == "undefined") return undefined; else if (typeof input === "undefined") return undefined;
return JSON.stringify(input); return JSON.stringify(input);
} }

View File

@ -4,8 +4,6 @@
/// <reference path="../../voice/AudioController.ts" /> /// <reference path="../../voice/AudioController.ts" />
namespace Modals { namespace Modals {
import set = Reflect.set;
export function spawnSettingsModal() { export function spawnSettingsModal() {
let modal; let modal;
modal = createModal({ modal = createModal({
@ -59,8 +57,10 @@ namespace Modals {
switch (select.value) { switch (select.value) {
case "ppt": case "ppt":
let keyCode: number = parseInt(settings.global("vad_ppt_key", String.fromCharCode(JQuery.Key.T))); let ppt_settings: PPTKeySettings = settings.global('vad_ppt_settings', undefined);
vad_tag.find(".vat_ppt_key").text(String.fromCharCode(keyCode)); ppt_settings = ppt_settings ? JSON.parse(ppt_settings as any as string) : {};
vad_tag.find(".vat_ppt_key").text(ppt.key_description(ppt_settings));
break; break;
case "vad": case "vad":
let slider = vad_tag.find(".vad_vad_slider"); let slider = vad_tag.find(".vad_vad_slider");
@ -88,13 +88,25 @@ namespace Modals {
}, },
footer: "" footer: ""
}); });
$(document).one("keypress", function (e) {
console.log("Got key " + e.keyCode); let listener = (event: ppt.KeyEvent) => {
modal.close(); if(event.type == ppt.EventType.KEY_TYPED) {
settings.changeGlobal("vad_ppt_key", e.keyCode.toString()); settings.changeGlobal('vad_ppt_key', undefined); //TODO remove that because its legacy shit
globalClient.voiceConnection.voiceRecorder.reinitialiseVAD(); console.log("Got key %o", event);
vad_tag.find(".vat_ppt_key").text(String.fromCharCode(e.keyCode));
}); let ppt_settings: PPTKeySettings = settings.global('vad_ppt_settings', undefined);
ppt_settings = ppt_settings ? JSON.parse(ppt_settings as any as string) : {};
Object.assign(ppt_settings, event);
settings.changeGlobal('vad_ppt_settings', ppt_settings);
globalClient.voiceConnection.voiceRecorder.reinitialiseVAD();
ppt.unregister_key_listener(listener);
modal.close();
vad_tag.find(".vat_ppt_key").text(ppt.key_description(event));
}
};
ppt.register_key_listener(listener);
modal.open(); modal.open();
}); });
} }

View File

@ -6,11 +6,6 @@
/// <reference path="client.ts" /> /// <reference path="client.ts" />
/// <reference path="modal/ModalCreateChannel.ts" /> /// <reference path="modal/ModalCreateChannel.ts" />
let shift_pressed = false;
$(document).on('keyup keydown', function(e){
shift_pressed = e.shiftKey;
console.log(shift_pressed);
});
class ChannelTree { class ChannelTree {
client: TSClient; client: TSClient;
htmlTree: JQuery; htmlTree: JQuery;
@ -271,8 +266,7 @@ class ChannelTree {
} }
onSelect(entry?: ChannelEntry | ClientEntry | ServerEntry, enforce_single?: boolean) { onSelect(entry?: ChannelEntry | ClientEntry | ServerEntry, enforce_single?: boolean) {
console.log(shift_pressed); if(this.currently_selected && ppt.key_pressed(ppt.SpecialKey.SHIFT) && entry instanceof ClientEntry) { //Currently we're only supporting client multiselects :D
if(this.currently_selected && shift_pressed && entry instanceof ClientEntry) { //Currently we're only supporting client multiselects :D
if(!entry) return; //Nowhere if(!entry) return; //Nowhere
if($.isArray(this.currently_selected)) { if($.isArray(this.currently_selected)) {

View File

@ -120,10 +120,34 @@ class VoiceRecorder {
reinitialiseVAD() { reinitialiseVAD() {
let type = settings.global("vad_type", "vad"); let type = settings.global("vad_type", "vad");
if(type == "ppt") { if(type == "ppt") {
let keyCode: number = parseInt(settings.global("vad_ppt_key", String.fromCharCode(JQuery.Key.T))); if(settings.global('vad_ppt_key', undefined)) {
//TODO remove that because its legacy shit
createErrorModal("VAD changed!", "VAD key detection changed.<br>Please reset your PPT key!").open();
}
let ppt_settings: PPTKeySettings = settings.global('vad_ppt_settings', undefined);
ppt_settings = ppt_settings ? JSON.parse(ppt_settings as any as string) : {};
if(ppt_settings.version === undefined)
ppt_settings.version = 1;
if(ppt_settings.key_code === undefined)
ppt_settings.key_code = "KeyT";
if(ppt_settings.key_ctrl === undefined)
ppt_settings.key_ctrl = false;
if(ppt_settings.key_shift === undefined)
ppt_settings.key_shift = false;
if(ppt_settings.key_alt === undefined)
ppt_settings.key_alt = false;
if(ppt_settings.key_windows === undefined)
ppt_settings.key_windows = false;
if(!(this.getVADHandler() instanceof PushToTalkVAD)) if(!(this.getVADHandler() instanceof PushToTalkVAD))
this.setVADHandler(new PushToTalkVAD(keyCode)); this.setVADHandler(new PushToTalkVAD(ppt_settings));
else (this.getVADHandler() as PushToTalkVAD).key = keyCode; else (this.getVADHandler() as PushToTalkVAD).key = ppt_settings;
} else if(type == "pt") { } else if(type == "pt") {
if(!(this.getVADHandler() instanceof PassThroughVAD)) if(!(this.getVADHandler() instanceof PassThroughVAD))
this.setVADHandler(new PassThroughVAD()); this.setVADHandler(new PassThroughVAD());
@ -298,35 +322,36 @@ class VoiceActivityDetectorVAD extends VoiceActivityDetector {
} }
} }
interface PPTKeySettings extends ppt.KeyDescriptor{
version?: number;
}
class PushToTalkVAD extends VoiceActivityDetector { class PushToTalkVAD extends VoiceActivityDetector {
private _key: number; private _key: ppt.KeyDescriptor;
private _key_hook: ppt.KeyHook;
private _pushed: boolean = false; private _pushed: boolean = false;
private _evListenerDown = (e: KeyboardEvent) => {
//console.log("Down -> " + e.key + " -> " + e.keyCode);
if(e.key == String.fromCharCode(this._key))
this.pushed = true;
};
private _evListenerUp = e => { constructor(key: ppt.KeyDescriptor) {
if(e.key == String.fromCharCode(this._key))
this.pushed = false;
};
constructor(key: any) {
super(); super();
this._key = key; this._key = key;
this._key_hook = {
callback_release: () => this._pushed = false,
callback_press: () => this._pushed = true,
cancel: false
} as ppt.KeyHook;
Object.assign(this._key_hook, this._key);
} }
initialise() { initialise() {
document.addEventListener("keydown", this._evListenerDown); ppt.register_key_hook(this._key_hook);
document.addEventListener("keyup", this._evListenerUp);
return super.initialise(); return super.initialise();
} }
finalize() { finalize() {
document.removeEventListener("keydown", this._evListenerDown); ppt.unregister_key_hook(this._key_hook);
document.removeEventListener("keyup", this._evListenerUp);
return super.finalize(); return super.finalize();
} }
@ -334,8 +359,8 @@ class PushToTalkVAD extends VoiceActivityDetector {
this._pushed = flag; this._pushed = flag;
} }
set key(key: number) { set key(key: ppt.KeyDescriptor) {
this._key = key; Object.assign(this._key_hook, this._key);
this._pushed = false; this._pushed = false;
} }

View File

@ -7,9 +7,12 @@
}, },
"exclude": [ "exclude": [
"node_modules", "node_modules",
"js/workers", "shared/js/workers",
"shared/declarations/**/*.d.ts", "shared/declarations/**/*.d.ts",
"shared/generated",
"web/declarations/**/*.d.ts", "web/declarations/**/*.d.ts",
"web/generated/",
"web/environment/",
"vendor/**/*.ts" "vendor/**/*.ts"
] ]
} }

View File

@ -1,13 +1,133 @@
/// <reference path="../declarations/imports_shared.d.ts"/> /// <reference path="../declarations/imports_shared.d.ts"/>
namespace ppt { namespace ppt {
interface WebKeyEvent extends KeyEvent {
canceled: boolean;
}
let key_listener: ((_: KeyEvent) => any)[] = [];
function listener_key(type: EventType, event: KeyboardEvent) {
const key_event = {
type: type,
key: event.key,
key_code: event.code,
key_ctrl: event.ctrlKey,
key_shift: event.shiftKey,
key_alt: event.altKey,
key_windows: event.metaKey,
canceled: event.defaultPrevented
} as WebKeyEvent;
//console.debug("Trigger key event %o", key_event);
for(const listener of key_listener)
listener(key_event);
if(key_event.canceled)
event.preventDefault();
}
const proxy_key_press = event => listener_key(EventType.KEY_PRESS, event);
const proxy_key_release = event => listener_key(EventType.KEY_RELEASE, event);
const proxy_key_typed = event => listener_key(EventType.KEY_TYPED, event);
export function initialize() : Promise<void> { export function initialize() : Promise<void> {
document.addEventListener('keypress', proxy_key_typed);
document.addEventListener('keydown', proxy_key_press);
document.addEventListener('keyup', proxy_key_release);
register_key_listener(listener_hook);
return Promise.resolve(); return Promise.resolve();
} }
export function finalize() {} export function finalize() {
document.removeEventListener("keypress", proxy_key_typed);
document.removeEventListener("keydown", proxy_key_press);
document.removeEventListener("keyup", proxy_key_release);
export function register_key_hook(callback: (event: KeyEvent) => any, cancel: boolean) {} unregister_key_listener(listener_hook);
export function unregister_key_hook(callback: (event: KeyEvent) => any) {} }
export function register_key_listener(listener: (_: KeyEvent) => any) {
key_listener.push(listener);
}
export function unregister_key_listener(listener: (_: KeyEvent) => any) {
key_listener.remove(listener);
}
let key_hooks: KeyHook[] = [];
interface CurrentState {
event: KeyEvent;
code: string;
special: { [key:number]:boolean };
}
let current_state: CurrentState = {
special: []
} as any;
let key_hooks_active: KeyHook[] = [];
function listener_hook(event: KeyEvent) {
if(event.type == EventType.KEY_TYPED)
return;
let old_hooks = [...key_hooks_active];
let new_hooks = [];
current_state.special[SpecialKey.ALT] = event.key_alt;
current_state.special[SpecialKey.CTRL] = event.key_ctrl;
current_state.special[SpecialKey.SHIFT] = event.key_shift;
current_state.special[SpecialKey.WINDOWS] = event.key_windows;
current_state.code = undefined;
current_state.event = undefined;
if(event.type == EventType.KEY_PRESS) {
current_state.event = event;
current_state.code = event.key_code;
for(const hook of key_hooks) {
if(hook.key_code != event.key_code) continue;
if(hook.key_alt != event.key_alt) continue;
if(hook.key_ctrl != event.key_ctrl) continue;
if(hook.key_shift != event.key_shift) continue;
if(hook.key_windows != event.key_windows) continue;
new_hooks.push(hook);
if(!old_hooks.remove(hook) && hook.callback_press) {
hook.callback_press();
console.debug("Trigger key press for %o!", hook);
}
}
}
//We have a new situation
for(const hook of old_hooks)
if(hook.callback_release) {
hook.callback_release();
console.debug("Trigger key release for %o!", hook);
}
key_hooks_active = new_hooks;
}
export function register_key_hook(hook: KeyHook) {
key_hooks.push(hook);
}
export function unregister_key_hook(hook: KeyHook) {
key_hooks.remove(hook);
}
export function key_pressed(code: string | SpecialKey) : boolean {
if(typeof(code) === 'string')
return current_state.code == code;
return current_state.special[code];
}
} }