chromium/chrome/browser/resources/chromeos/accessibility/chromevox/background/braille/braille_key_event_rewriter.ts

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

/**
 * @fileoverview Rewrites a braille key event.
 */
import {BrailleKeyCommand, BrailleKeyEvent} from '../../common/braille/braille_key_types.js';
import {QueueMode} from '../../common/tts_types.js';
import {Output} from '../output/output.js';

interface Modifiers {
  altKey?: boolean;
  ctrlKey?: boolean;
  shiftKey?: boolean;

  [key: string]: boolean | undefined;
}

/**
 * A class that transforms a sequence of braille key events into a standard key
 * event.
 */
export class BrailleKeyEventRewriter {
  static instance: BrailleKeyEventRewriter;

  private incrementalKey_: Modifiers | null = null;

  static init(): void {
    if (BrailleKeyEventRewriter.instance) {
      throw new Error('Cannot create two BrailleKeyEventRewriter instances');
    }
    BrailleKeyEventRewriter.instance = new BrailleKeyEventRewriter();
  }

  /**
   * Accumulates and optionally modifies in-coming braille key events.
   * @return False to continue event propagation.
   */
  onBrailleKeyEvent(evt: BrailleKeyEvent): boolean {
    let standardKeyCode;
    const dots = evt.brailleDots;
    if (!dots) {
      this.incrementalKey_ = null;
      return false;
    }

    if (evt.command === BrailleKeyCommand.CHORD) {
      Output.forceModeForNextSpeechUtterance(QueueMode.CATEGORY_FLUSH);
      const modifiers = BrailleKeyEvent.brailleDotsToModifiers[dots];

      // Check for a modifier mapping.
      if (modifiers) {
        this.incrementalKey_ = this.incrementalKey_ || {};
        for (const key in modifiers) {
          this.incrementalKey_[key] = true;
        }

        return true;
      }

      // Check for a chord to standard key mapping.
      standardKeyCode = BrailleKeyEvent.brailleChordsToStandardKeyCode[dots];
    }

    // Check for a 'dots' command, which is typed on the keyboard with a
    // previous incremental key press.
    if (evt.command === BrailleKeyCommand.DOTS && this.incrementalKey_) {
      // Check if this braille pattern has a standard key mapping.
      standardKeyCode = BrailleKeyEvent.brailleDotsToStandardKeyCode[dots];
    }

    if (standardKeyCode) {
      evt.command = BrailleKeyCommand.STANDARD_KEY;
      evt.standardKeyCode = standardKeyCode;
      if (this.incrementalKey_) {
        // Apply all modifiers seen so far to the outgoing event as a standard
        // keyboard command.
        evt.altKey = this.incrementalKey_.altKey;
        evt.ctrlKey = this.incrementalKey_.ctrlKey;
        evt.shiftKey = this.incrementalKey_.shiftKey;
        this.incrementalKey_ = null;
      }
      return false;
    }

    this.incrementalKey_ = null;
    return false;
  }
}