diff options
Diffstat (limited to 'src/client/util/DictationManager.ts')
-rw-r--r-- | src/client/util/DictationManager.ts | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index b58bdb6c7..60b25afc5 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -1,3 +1,10 @@ +import { string } from "prop-types"; +import { observable, action } from "mobx"; +import { SelectionManager } from "./SelectionManager"; +import { DocumentView } from "../views/nodes/DocumentView"; +import { UndoManager } from "./UndoManager"; +import * as converter from "words-to-numbers"; + namespace CORE { export interface IWindow extends Window { webkitSpeechRecognition: any; @@ -5,9 +12,14 @@ namespace CORE { } const { webkitSpeechRecognition }: CORE.IWindow = window as CORE.IWindow; +export type Action = (target: DocumentView) => any | Promise<any>; +export type DynamicAction = (target: DocumentView, matches: RegExpExecArray) => any | Promise<any>; +export type RegexEntry = { key: RegExp, value: DynamicAction }; export default class DictationManager { public static Instance = new DictationManager(); + private registeredCommands = new Map<string, Action>(); + private registeredRegexes: RegexEntry[] = []; private isListening = false; private recognizer: any; @@ -17,8 +29,16 @@ export default class DictationManager { this.recognizer.continuous = true; } + @observable public current = ""; + + @action finish = (handler: any, data: any) => { + this.current = data; handler(data); + this.stop(); + } + + stop = () => { this.isListening = false; this.recognizer.stop(); } @@ -36,4 +56,72 @@ export default class DictationManager { } + private sanitize = (title: string) => { + return title.replace("...", "").toLowerCase().trim(); + } + + public registerStatic = (keys: Array<string>, action: Action, overwrite = false) => { + let success = true; + keys.forEach(key => { + key = this.sanitize(key); + let existing = this.registeredCommands.get(key); + if (!existing || overwrite) { + this.registeredCommands.set(key, action); + } else { + success = false; + } + }); + return success; + } + + public interpretNumber = (number: string) => { + let initial = parseInt(number); + if (!isNaN(initial)) { + return initial; + } + let converted = converter.wordsToNumbers(number, { fuzzy: true }); + if (converted === null) { + return NaN; + } + return typeof converted === "string" ? parseInt(converted) : converted; + } + + public registerDynamic = (dynamicKey: RegExp, action: DynamicAction) => { + this.registeredRegexes.push({ + key: dynamicKey, + value: action + }); + } + + public execute = async (phrase: string) => { + let target = SelectionManager.SelectedDocuments()[0]; + if (!target) { + return; + } + let batch = UndoManager.StartBatch("Dictation Action"); + phrase = this.sanitize(phrase); + + let registeredAction = this.registeredCommands.get(phrase); + if (registeredAction) { + await registeredAction(target); + return true; + } + + let success = false; + for (let entry of this.registeredRegexes) { + let regex = entry.key; + let registeredDynamicAction = entry.value; + let matches = regex.exec(phrase); + regex.lastIndex = 0; + if (matches !== null) { + await registeredDynamicAction(target, matches); + success = true; + break; + } + } + batch.end(); + + return success; + } + }
\ No newline at end of file |