aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/DictationManager.ts29
-rw-r--r--src/client/views/GlobalKeyHandler.ts14
-rw-r--r--src/client/views/MainView.tsx16
3 files changed, 50 insertions, 9 deletions
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 2ed74a729..b799238ba 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -1,6 +1,6 @@
import { SelectionManager } from "./SelectionManager";
import { DocumentView } from "../views/nodes/DocumentView";
-import { undoBatch } from "./UndoManager";
+import { UndoManager } from "./UndoManager";
import * as converter from "words-to-numbers";
import { Doc, Opt } from "../../new_fields/Doc";
import { List } from "../../new_fields/List";
@@ -11,8 +11,26 @@ import { listSpec } from "../../new_fields/Schema";
import { AudioField, ImageField } from "../../new_fields/URLField";
import { HistogramField } from "../northstar/dash-fields/HistogramField";
+/**
+ * This namespace provides a singleton instance of a manager that
+ * handles the listening and text-conversion of user speech.
+ *
+ * The basic manager functionality can be attained by the DictationManager.Controls namespace, which provide
+ * a simple recording operation that returns the interpreted text as a string.
+ *
+ * Additionally, however, the DictationManager also exposes the ability to execute voice commands within Dash.
+ * It stores a default library of registered commands that can be triggered by listen()'ing for a phrase and then
+ * passing the results into the execute() function.
+ *
+ * In addition to compile-time default commands, you can invoke DictationManager.Commands.Register(Independent|Dependent)
+ * to add new commands as classes or components are constructed.
+ */
export namespace DictationManager {
+ /**
+ * Some type maneuvering to access Webkit's built-in
+ * speech recognizer.
+ */
namespace CORE {
export interface IWindow extends Window {
webkitSpeechRecognition: any;
@@ -24,6 +42,7 @@ export namespace DictationManager {
const recognizer = (() => {
let initialized = new webkitSpeechRecognition();
initialized.continuous = true;
+ initialized.language = "en-US";
return initialized;
})();
@@ -77,6 +96,8 @@ export namespace DictationManager {
export namespace Commands {
+ export const dictationFadeDuration = 2000;
+
export type IndependentAction = (target: DocumentView) => any | Promise<any>;
export type IndependentEntry = { action: IndependentAction, restrictTo?: DocumentType[] };
@@ -91,14 +112,16 @@ export namespace DictationManager {
if (!targets || !targets.length) {
return;
}
-
+ phrase = phrase.toLowerCase();
let entry = Independent.get(phrase);
if (entry) {
let success = false;
let restrictTo = entry.restrictTo;
for (let target of targets) {
if (!restrictTo || validate(target, restrictTo)) {
+ let batch = UndoManager.StartBatch("Independent Command");
await entry.action(target);
+ batch.end();
success = true;
}
}
@@ -114,7 +137,9 @@ export namespace DictationManager {
let restrictTo = entry.restrictTo;
for (let target of targets) {
if (!restrictTo || validate(target, restrictTo)) {
+ let batch = UndoManager.StartBatch("Dependent Command");
await entry.action(target, matches);
+ batch.end();
success = true;
}
}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index b1ea92bb8..82289c249 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -74,7 +74,7 @@ export default class KeyManager {
DictationManager.Controls.stop();
main.dictationOverlayVisible = false;
main.dictationSuccess = undefined;
- main.overlayTimeout && clearTimeout(main.overlayTimeout);
+ main.cancelDictationFade();
break;
case "delete":
case "backspace":
@@ -110,19 +110,19 @@ export default class KeyManager {
case " ":
let main = MainView.Instance;
main.dictationOverlayVisible = true;
+
main.isListening = true;
let command = await DictationManager.Controls.listen((results: any) => console.log(results));
main.isListening = false;
+
if (!command) {
break;
}
- command = command.toLowerCase();
- main.dictatedPhrase = command;
+
+ main.dictatedPhrase = command = command.toLowerCase();
main.dictationSuccess = await DictationManager.Commands.execute(command);
- main.overlayTimeout = setTimeout(() => {
- main.dictationOverlayVisible = false;
- main.dictationSuccess = undefined;
- }, 2000);
+ main.initiateDictationFade();
+
stopPropagation = true;
preventDefault = true;
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4a5e4a3d1..748e1e634 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -39,6 +39,7 @@ import { FilterBox } from './search/FilterBox';
import { CollectionTreeView } from './collections/CollectionTreeView';
import { ClientUtils } from '../util/ClientUtils';
import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField';
+import { DictationManager } from '../util/DictationManager';
@observer
export class MainView extends React.Component {
@@ -55,6 +56,21 @@ export class MainView extends React.Component {
public overlayTimeout: NodeJS.Timeout | undefined;
+ public initiateDictationFade = () => {
+ let duration = DictationManager.Commands.dictationFadeDuration;
+ this.overlayTimeout = setTimeout(() => {
+ this.dictationOverlayVisible = false;
+ this.dictationSuccess = undefined;
+ }, duration);
+ }
+
+ public cancelDictationFade = () => {
+ if (this.overlayTimeout) {
+ clearTimeout(this.overlayTimeout);
+ this.overlayTimeout = undefined;
+ }
+ }
+
@computed private get mainContainer(): Opt<Doc> {
return FieldValue(Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc));
}