chromium/chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.cc

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

#include "chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.h"

#include <stdint.h>

#include <memory>

#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversion_utils.h"

namespace extensions {
namespace api {
namespace braille_display_private {

namespace {
// Bitmask for all braille dots in a key command argument, which coincides
// with the representation in the braille_dots member of the KeyEvent
// class.
const int kAllDots = BRLAPI_DOT1 | BRLAPI_DOT2 | BRLAPI_DOT3 | BRLAPI_DOT4 |
                     BRLAPI_DOT5 | BRLAPI_DOT6 | BRLAPI_DOT7 | BRLAPI_DOT8;

// Maximum Latin 1 character keyboard symbol.
const brlapi_keyCode_t kMaxLatin1KeySym = 0xff;

// Range of function keys that we support.
// See ui/events/keycodes/dom/dom_code_data.inc for the list of all
// key codes.
const brlapi_keyCode_t kMinFunctionKey = BRLAPI_KEY_SYM_FUNCTION;
const brlapi_keyCode_t kMaxFunctionKey = BRLAPI_KEY_SYM_FUNCTION + 23;

// Maps the keyboard modifier flags to their corresponding flags in a
// |KeyEvent|.
void MapModifierFlags(brlapi_keyCode_t code, KeyEvent* event) {
  if (code & BRLAPI_KEY_FLG_CONTROL)
    event->ctrl_key = true;
  if (code & BRLAPI_KEY_FLG_META)
    event->alt_key = true;
  if (code & BRLAPI_KEY_FLG_SHIFT)
    event->shift_key = true;
}

// Maps a brlapi keysym, which is similar to an X keysym into the
// provided event.
// See ui/events/keycodes/dom/dom_code_data.cc for the full
// list of key codes.
void MapKeySym(brlapi_keyCode_t code, KeyEvent* event) {
  brlapi_keyCode_t key_sym = code & BRLAPI_KEY_CODE_MASK;
  if (key_sym < kMaxLatin1KeySym ||
      (key_sym & BRLAPI_KEY_SYM_UNICODE) != 0) {
    base_icu::UChar32 code_point = key_sym & ~BRLAPI_KEY_SYM_UNICODE;
    if (!base::IsValidCharacter(code_point))
      return;
    event->standard_key_char.emplace();
    base::WriteUnicodeCharacter(code_point, &*event->standard_key_char);
  } else if (key_sym >= kMinFunctionKey && key_sym <= kMaxFunctionKey) {
    // Function keys are 0-based here, so we need to add one to get e.g.
    // 'F1' for the first key.
    int function_key_number = key_sym - kMinFunctionKey + 1;
    event->standard_key_code = base::StringPrintf("F%d", function_key_number);
  } else {
    // Explicitly map the keys that brlapi provides.
    const char* code_string;
    switch (key_sym) {
      case BRLAPI_KEY_SYM_BACKSPACE:
        code_string = "Backspace";
        break;
      case BRLAPI_KEY_SYM_TAB:
        code_string = "Tab";
        break;
      case BRLAPI_KEY_SYM_LINEFEED:
        code_string = "Enter";
        break;
      case BRLAPI_KEY_SYM_ESCAPE:
        code_string = "Escape";
        break;
      case BRLAPI_KEY_SYM_HOME:
        code_string = "Home";
        break;
      case BRLAPI_KEY_SYM_LEFT:
        code_string = "ArrowLeft";
        break;
      case BRLAPI_KEY_SYM_UP:
        code_string = "ArrowUp";
        break;
      case BRLAPI_KEY_SYM_RIGHT:
        code_string = "ArrowRight";
        break;
      case BRLAPI_KEY_SYM_DOWN:
        code_string = "ArrowDown";
        break;
      case BRLAPI_KEY_SYM_PAGE_UP:
        code_string = "PageUp";
        break;
      case BRLAPI_KEY_SYM_PAGE_DOWN:
        code_string = "PageDown";
        break;
      case BRLAPI_KEY_SYM_END:
        code_string = "End";
        break;
      case BRLAPI_KEY_SYM_INSERT:
        code_string = "Insert";
        break;
      case BRLAPI_KEY_SYM_DELETE:
        code_string = "Delete";
        break;
      default:
        return;
    }
    event->standard_key_code = code_string;
  }
  MapModifierFlags(code, event);
  event->command = KeyCommand::kStandardKey;
}

void MapCommand(brlapi_keyCode_t code, KeyEvent* event) {
  brlapi_keyCode_t argument = code & BRLAPI_KEY_CMD_ARG_MASK;
  switch (code & BRLAPI_KEY_CODE_MASK) {
    case BRLAPI_KEY_CMD_LNUP:
      event->command = KeyCommand::kLineUp;
      break;
    case BRLAPI_KEY_CMD_LNDN:
      event->command = KeyCommand::kLineDown;
      break;
    case BRLAPI_KEY_CMD_FWINLT:
      event->command = KeyCommand::kPanLeft;
      break;
    case BRLAPI_KEY_CMD_FWINRT:
      event->command = KeyCommand::kPanRight;
      break;
    case BRLAPI_KEY_CMD_TOP:
      event->command = KeyCommand::kTop;
      break;
    case BRLAPI_KEY_CMD_BOT:
      event->command = KeyCommand::kBottom;
      break;
    default:
      switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
        case BRLAPI_KEY_CMD_ROUTE:
          event->command = KeyCommand::kRouting;
          event->display_position = argument;
          break;
        case BRLAPI_KEY_CMD_PASSDOTS:
          unsigned int dots = argument & kAllDots;
          event->braille_dots = dots;

          // BRLAPI_DOTC represents when the braille space key is pressed.
          if (dots && (argument & BRLAPI_DOTC))
            event->command = KeyCommand::kChord;
          else
            event->command = KeyCommand::kDots;
          MapModifierFlags(code, event);
          break;
      }
  }
}

}  // namespace

std::unique_ptr<KeyEvent> BrlapiKeyCodeToEvent(brlapi_keyCode_t code) {
  std::unique_ptr<KeyEvent> result(new KeyEvent);
  result->command = KeyCommand::kNone;
  switch (code & BRLAPI_KEY_TYPE_MASK) {
    case BRLAPI_KEY_TYPE_SYM:
      MapKeySym(code, result.get());
      break;
    case BRLAPI_KEY_TYPE_CMD:
      MapCommand(code, result.get());
      break;
  }
  if (result->command == KeyCommand::kNone) {
    result.reset();
  }
  return result;
}

}  // namespace braille_display_private
}  // namespace api
}  // namespace extensions