window["require_setup"](module); import {KeyEvent as NKeyEvent} from "teaclient_ppt"; namespace _ppt { let key_listener: ((_: ppt.KeyEvent) => any)[] = []; let native_ppt; function listener_key(type: ppt.EventType, nevent: NKeyEvent) { if(nevent.key_code === 'VoidSymbol' || nevent.key_code === 'error') nevent.key_code = undefined; /* trigger event for state update */ let event: ppt.KeyEvent = { type: type, key: nevent.key_code, key_code: nevent.key_code, key_ctrl: nevent.key_ctrl, key_shift: nevent.key_shift, key_alt: nevent.key_alt, key_windows: nevent.key_windows } as any; //console.debug("Trigger key event %o", key_event); for (const listener of key_listener) listener(event); } function native_keyhook(event: NKeyEvent) { //console.log("Native event!: %o", event); if(event.type == 0) listener_key(ppt.EventType.KEY_PRESS, event); else if(event.type == 1) listener_key(ppt.EventType.KEY_RELEASE, event); else if(event.type == 2) listener_key(ppt.EventType.KEY_TYPED, event); } export async function initialize() : Promise { native_ppt = require("teaclient_ppt"); register_key_listener(listener_hook); native_ppt.RegisterCallback(native_keyhook); } export function finalize() { unregister_key_listener(listener_hook); native_ppt.UnregisterCallback(native_keyhook); } export function register_key_listener(listener: (_: ppt.KeyEvent) => any) { key_listener.push(listener); } export function unregister_key_listener(listener: (_: ppt.KeyEvent) => any) { key_listener.remove(listener); } let key_hooks: ppt.KeyHook[] = []; interface CurrentState { keys: {[code: string]:ppt.KeyEvent}; special: { [key:number]:boolean }; } let current_state: CurrentState = { special: [] } as any; let key_hooks_active: ppt.KeyHook[] = []; function listener_blur() { current_state.special[ppt.SpecialKey.ALT] = false; current_state.special[ppt.SpecialKey.CTRL] = false; current_state.special[ppt.SpecialKey.SHIFT] = false; current_state.special[ppt.SpecialKey.WINDOWS] = false; for(const code of Object.keys(current_state.keys)) delete current_state[code]; for(const hook of key_hooks_active) hook.callback_release(); key_hooks_active = []; } function listener_hook(event: ppt.KeyEvent) { if(event.type == ppt.EventType.KEY_TYPED) return; let old_hooks = [...key_hooks_active]; let new_hooks = []; current_state.special[ppt.SpecialKey.ALT] = event.key_alt; current_state.special[ppt.SpecialKey.CTRL] = event.key_ctrl; current_state.special[ppt.SpecialKey.SHIFT] = event.key_shift; current_state.special[ppt.SpecialKey.WINDOWS] = event.key_windows; current_state[event.key_code] = undefined; if(event.type == ppt.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: ppt.KeyHook) { key_hooks.push(hook); } export function unregister_key_hook(hook: ppt.KeyHook) { key_hooks.remove(hook); key_hooks_active.remove(hook); } export function key_pressed(code: string | ppt.SpecialKey) : boolean { if(typeof(code) === 'string') return current_state.code == code; return current_state.special[code]; } } Object.assign(window["ppt"] || (window["ppt"] = {} as any), _ppt); console.dir(_ppt);