chromium/chrome/browser/resources/chromeos/accessibility/chromevox/background/editing/typing_echo.js

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {LocalStorage} from '/common/local_storage.js';
import {TestImportManager} from '/common/testing/test_import_manager.js';

import {Msgs} from '../../common/msgs.js';
import {Personality, QueueMode} from '../../common/tts_types.js';
import {ChromeVox} from '../chromevox.js';


/**
 * A list of typing echo options.
 * This defines the way typed characters get spoken.
 * CHARACTER: echoes typed characters.
 * WORD: echoes a word once a breaking character is typed (i.e. spacebar).
 * CHARACTER_AND_WORD: combines CHARACTER and WORD behavior.
 * NONE: speaks nothing when typing.
 * @enum
 */
export const TypingEchoState = {
  CHARACTER: 0,
  WORD: 1,
  CHARACTER_AND_WORD: 2,
  NONE: 3,
};
// STATE_COUNT is the number of possible echo levels.
const STATE_COUNT = Object.entries(TypingEchoState).length;

export class TypingEcho {
  static init() {
    if (TypingEcho.current !== undefined) {
      throw new Error('TypingEcho should only be initialized once.');
    }
    TypingEcho.current = /** @type {TypingEchoState} */ (
        LocalStorage.get('typingEcho', TypingEchoState.CHARACTER));
    LocalStorage.addListenerForKey(
        'typingEcho', newValue => TypingEcho.current = newValue);
  }
  /**
   * @param {number=} cur Current typing echo.
   * @return {number} Next typing echo.
   */
  static cycle(cur) {
    return ((cur ?? TypingEcho.current) + 1) % STATE_COUNT;
  }

  static cycleWithAnnouncement() {
    LocalStorage.set(
        'typingEcho', TypingEcho.cycle(LocalStorage.getNumber('typingEcho')));
    let announce = '';
    switch (LocalStorage.get('typingEcho')) {
      case TypingEchoState.CHARACTER:
        announce = Msgs.getMsg('character_echo');
        break;
      case TypingEchoState.WORD:
        announce = Msgs.getMsg('word_echo');
        break;
      case TypingEchoState.CHARACTER_AND_WORD:
        announce = Msgs.getMsg('character_and_word_echo');
        break;
      case TypingEchoState.NONE:
        announce = Msgs.getMsg('none_echo');
        break;
    }
    ChromeVox.tts.speak(announce, QueueMode.FLUSH, Personality.ANNOTATION);
  }

  /**
   * Return if characters should be spoken given the typing echo option.
   * @param {number} typingEcho Typing echo option.
   * @return {boolean} Whether the character should be spoken.
   */
  static shouldSpeakChar(typingEcho) {
    return typingEcho === TypingEchoState.CHARACTER_AND_WORD ||
        typingEcho === TypingEchoState.CHARACTER;
  }
}

/**
 * Stores the current choice of how ChromeVox should echo when entering text
 * into an editable text field.
 * @type {TypingEchoState}
 */
TypingEcho.current;

TestImportManager.exportForTesting(['TypingEchoState', TypingEchoState]);