TeaWeb/web/app/ppt.ts

151 lines
4.6 KiB
TypeScript
Raw Normal View History

2020-03-30 11:44:18 +00:00
import {EventType, KeyEvent, KeyHook, SpecialKey} from "tc-shared/PPTListener";
import {LogCategory} from "tc-shared/log";
import * as log from "tc-shared/log";
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> {
document.addEventListener('keypress', proxy_key_typed);
document.addEventListener('keydown', proxy_key_press);
document.addEventListener('keyup', proxy_key_release);
window.addEventListener('blur', listener_blur);
register_key_listener(listener_hook);
return Promise.resolve();
}
export function finalize() {
document.removeEventListener("keypress", proxy_key_typed);
document.removeEventListener("keydown", proxy_key_press);
document.removeEventListener("keyup", proxy_key_release);
window.removeEventListener('blur', listener_blur);
unregister_key_listener(listener_hook);
}
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 {
keys: {[code: string]:KeyEvent};
special: { [key:number]:boolean };
}
let current_state: CurrentState = {
special: []
} as any;
let key_hooks_active: KeyHook[] = [];
function listener_blur() {
current_state.special[SpecialKey.ALT] = false;
current_state.special[SpecialKey.CTRL] = false;
current_state.special[SpecialKey.SHIFT] = false;
current_state.special[SpecialKey.WINDOWS] = false;
for(const code of Object.keys(current_state))
if(code !== "special")
delete current_state[code];
for(const hook of key_hooks_active)
hook.callback_release();
key_hooks_active = [];
}
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[event.key_code] = undefined;
if(event.type == EventType.KEY_PRESS) {
current_state[event.key_code] = event;
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();
log.trace(LogCategory.GENERAL, tr("Trigger key press for %o!"), hook);
}
}
}
//We have a new situation
for(const hook of old_hooks) {
//Do not test for meta key states because they could differ in a key release event
if(hook.key_code === event.key_code) {
if(hook.callback_release) {
hook.callback_release();
log.trace(LogCategory.GENERAL, tr("Trigger key release for %o!"), hook);
}
} else {
new_hooks.push(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 typeof current_state[code] !== "undefined";
return current_state.special[code];
}