aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/DictationManager.ts70
-rw-r--r--src/client/views/ContextMenuItem.tsx2
-rw-r--r--src/client/views/GlobalKeyHandler.ts8
3 files changed, 52 insertions, 28 deletions
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index fa34ca9ad..5f443f99e 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -38,14 +38,17 @@ export namespace DictationManager {
}
const { webkitSpeechRecognition }: CORE.IWindow = window as CORE.IWindow;
- let isListening = false;
- let isManuallyStopped = false;
- const results: string[] = [];
- const recognizer: SpeechRecognition = new webkitSpeechRecognition();
-
export namespace Controls {
- let newestResult: string;
+ const defaultDelimiter = "...";
+ let isListening = false;
+ let isManuallyStopped = false;
+ let sessionResults: string[] = [];
+
+ const recognizer: SpeechRecognition = new webkitSpeechRecognition() || new SpeechRecognition();
+ recognizer.onstart = () => console.log("initiating speech recognition session...");
+
+ let current: string | undefined = undefined;
export type InterimResultHandler = (results: any) => any;
export type ContinuityArgs = { indefinite: boolean } | false;
export interface ListeningOptions {
@@ -60,8 +63,7 @@ export namespace DictationManager {
try {
results = await listenImpl(options);
} catch (e) {
- results = "Dictation Error: ";
- results += "error" in e ? e.error : "unknown error";
+ results = `Dictation Error: ${"error" in e ? e.error : "unknown error"}`;
}
return results;
};
@@ -74,6 +76,7 @@ export namespace DictationManager {
let handler = options ? options.interimHandler : undefined;
let continuous = options ? options.continuous : undefined;
+ let indefinite = continuous && continuous.indefinite;
let language = options ? options.language : undefined;
let delimiter = options ? options.delimiter : undefined;
@@ -85,41 +88,56 @@ export namespace DictationManager {
return new Promise<string>((resolve, reject) => {
- recognizer.onerror = (e: any) => {
- reject(e);
- stop();
+ recognizer.onerror = (e: SpeechRecognitionError) => {
+ if (!(indefinite && e.error === "no-speech")) {
+ stop(true);
+ reject(e);
+ }
};
recognizer.onresult = (e: SpeechRecognitionEvent) => {
- newestResult = synthesize(e, delimiter);
- continuous && continuous.indefinite && results.push(newestResult);
- handler && handler(newestResult);
+ current = synthesize(e, delimiter);
+ handler && handler(current);
+ isManuallyStopped && complete();
};
recognizer.onend = (e: Event) => {
- let indefinite = continuous && continuous.indefinite;
- if (indefinite && !isManuallyStopped) {
- recognizer.start();
+ if (!indefinite || isManuallyStopped) {
+ return complete();
+ }
+
+ if (current) {
+ sessionResults.push(current);
+ current = undefined;
+ }
+ recognizer.start();
+ };
+
+ let complete = () => {
+ if (indefinite) {
+ current && sessionResults.push(current);
+ resolve(connect(sessionResults, delimiter));
} else {
- resolve(indefinite ? newestResult : results.join(delimiter));
- reset();
+ resolve(current);
}
+ reset();
};
});
};
- export const stop = (saveCumulative = true) => {
- saveCumulative ? recognizer.stop() : recognizer.abort();
- reset();
+ export const stop = (errorTriggered = false) => {
+ !errorTriggered && (isManuallyStopped = true);
+ recognizer.stop();
};
const reset = () => {
isListening = false;
isManuallyStopped = false;
- recognizer.onerror = null;
recognizer.onresult = null;
+ recognizer.onerror = null;
recognizer.onend = null;
+ sessionResults = [];
};
const synthesize = (e: SpeechRecognitionEvent, delimiter?: string) => {
@@ -128,7 +146,11 @@ export namespace DictationManager {
for (let i = 0; i < results.length; i++) {
transcripts.push(results.item(i).item(0).transcript.trim());
}
- return transcripts.join(delimiter || "...");
+ return transcripts.join(delimiter || defaultDelimiter);
+ };
+
+ const connect = (sessions: string[], delimiter?: string) => {
+ return sessions.map(text => `(${text})`).join(delimiter || defaultDelimiter);
};
}
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index a1787e78f..90f7be33f 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -39,13 +39,13 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
handleEvent = async (e: React.MouseEvent<HTMLDivElement>) => {
if ("event" in this.props) {
+ this.props.closeMenu && this.props.closeMenu();
let batch: UndoManager.Batch | undefined;
if (this.props.undoable !== false) {
batch = UndoManager.StartBatch(`Context menu event: ${this.props.description}`);
}
await this.props.event();
batch && batch.end();
- this.props.closeMenu && this.props.closeMenu();
}
}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 98df43a1e..c3e6ae6c8 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -72,9 +72,11 @@ export default class KeyManager {
main.toggleColorPicker(true);
SelectionManager.DeselectAll();
DictationManager.Controls.stop();
- main.dictationOverlayVisible = false;
- main.dictationSuccess = undefined;
- main.cancelDictationFade();
+ if (main.dictationOverlayVisible) {
+ main.dictationOverlayVisible = false;
+ main.dictationSuccess = undefined;
+ main.cancelDictationFade();
+ }
break;
case "delete":
case "backspace":