chromium/chrome/browser/resources/chromeos/accessibility/chromevox/common/braille/braille_command_data.ts

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

/**
 * @fileoverview ChromeVox braille command data.
 */
import {TestImportManager} from '/common/testing/test_import_manager.js';

import {Command} from '../command.js';
import {Msgs} from '../msgs.js';

export namespace BrailleCommandData {
  /** Maps a dot pattern to a command. */
  export const DOT_PATTERN_TO_COMMAND: Record<number, Command> = {};

  /**
   * Makes a dot pattern given a list of dots numbered from 1 to 8 arranged in a
   * braille cell (a 2 x 4 dot grid).
   * @param dots The dots to be set in the returned pattern.
   */
  export function makeDotPattern(dots: number[]): number {
    return dots.reduce(
        (pattern: number, cell: number) => pattern | (1 << cell - 1), 0);
  }

  /** Gets a braille command based on a dot pattern from a chord. */
  export function getCommand(dots: number): Command|undefined {
    return DOT_PATTERN_TO_COMMAND[dots];
  }

  /**
   * Gets a dot shortcut for a command.
   * @param chord True if the pattern comes from a chord.
   * @return The shortcut.
   */
  export function getDotShortcut(command: Command, chord?: boolean): string {
    const commandDots = getDots(command);
    return makeShortcutText(commandDots, chord);
  }

  export function makeShortcutText(pattern: number, chord?: boolean): string {
    const dots: number[] = [];
    for (let shifter = 0; shifter <= 7; shifter++) {
      if ((1 << shifter) & pattern) {
        dots.push(shifter + 1);
      }
    }
    let msgid;
    if (dots.length > 1) {
      msgid = 'braille_dots';
    } else if (dots.length === 1) {
      msgid = 'braille_dot';
    }

    if (msgid) {
      let dotText = Msgs.getMsg(msgid, [dots.join('-')]);
      if (chord) {
        dotText = Msgs.getMsg('braille_chord', [dotText]);
      }
      return dotText;
    }
    return '';
  }

  /**
   * @return The dot pattern for |command|.
   */
  export function getDots(command: Command): number {
    for (const keyStr in DOT_PATTERN_TO_COMMAND) {
      const key = parseInt(keyStr, 10);
      if (command === DOT_PATTERN_TO_COMMAND[key]) {
        return key;
      }
    }
    return 0;
  }

  export function init(): void {
    const map = function(dots: number[], command: Command): void {
      const pattern = makeDotPattern(dots);
      const existingCommand = DOT_PATTERN_TO_COMMAND[pattern];
      if (existingCommand) {
        throw 'Braille command pattern already exists: ' + dots + ' ' +
            existingCommand + '. Trying to map ' + command;
      }

      DOT_PATTERN_TO_COMMAND[pattern] = command;
    };

    map([2, 3], Command.PREVIOUS_GROUP);
    map([5, 6], Command.NEXT_GROUP);
    map([1], Command.PREVIOUS_OBJECT);
    map([4], Command.NEXT_OBJECT);
    map([2], Command.PREVIOUS_WORD);
    map([5], Command.NEXT_WORD);
    map([3], Command.PREVIOUS_CHARACTER);
    map([6], Command.NEXT_CHARACTER);
    map([1, 2, 3], Command.JUMP_TO_TOP);
    map([4, 5, 6], Command.JUMP_TO_BOTTOM);

    map([1, 4], Command.FULLY_DESCRIBE);
    map([1, 3, 4], Command.CONTEXT_MENU);
    map([1, 2, 3, 5], Command.READ_FROM_HERE);
    map([2, 3, 4], Command.TOGGLE_SELECTION);

    // Forward jump.
    map([1, 2], Command.NEXT_BUTTON);
    map([1, 5], Command.NEXT_EDIT_TEXT);
    map([1, 2, 4], Command.NEXT_FORM_FIELD);
    map([1, 2, 5], Command.NEXT_HEADING);
    map([4, 5], Command.NEXT_LINK);
    map([2, 3, 4, 5], Command.NEXT_TABLE);

    // Backward jump.
    map([1, 2, 7], Command.PREVIOUS_BUTTON);
    map([1, 5, 7], Command.PREVIOUS_EDIT_TEXT);
    map([1, 2, 4, 7], Command.PREVIOUS_FORM_FIELD);
    map([1, 2, 5, 7], Command.PREVIOUS_HEADING);
    map([4, 5, 7], Command.PREVIOUS_LINK);
    map([2, 3, 4, 5, 7], Command.PREVIOUS_TABLE);

    map([8], Command.FORCE_CLICK_ON_CURRENT_ITEM);
    map([3, 4], Command.TOGGLE_SEARCH_WIDGET);

    // Question.
    map([1, 4, 5, 6], Command.TOGGLE_KEYBOARD_HELP);

    // All cells.
    map([1, 2, 3, 4, 5, 6], Command.TOGGLE_SCREEN);

    // s.
    map([1, 2, 3, 4, 5], Command.TOGGLE_SPEECH_ON_OR_OFF);

    // g.
    map([1, 2, 4, 5], Command.TOGGLE_BRAILLE_TABLE);

    // Stop speech.
    map([5, 6, 7], Command.STOP_SPEECH);
  }

  init();
}

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