1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.h"
6
7#include "base/strings/stringprintf.h"
8#include "base/strings/utf_string_conversion_utils.h"
9
10namespace extensions {
11namespace api {
12namespace braille_display_private {
13
14namespace {
15// Bitmask for all braille dots in a key command argument, which coincides
16// with the representation in the braille_dots member of the KeyEvent
17// class.
18const int kAllDots = BRLAPI_DOT1 | BRLAPI_DOT2 | BRLAPI_DOT3 | BRLAPI_DOT4 |
19                     BRLAPI_DOT5 | BRLAPI_DOT6 | BRLAPI_DOT7 | BRLAPI_DOT8;
20
21// Maximum Latin 1 character keyboard symbol.
22const brlapi_keyCode_t kMaxLatin1KeySym = 0xff;
23
24// Range of function keys that we support.
25// See ui/events/keycodes/dom4/keycode_converter_data.h for the list of all
26// key codes.
27const brlapi_keyCode_t kMinFunctionKey = BRLAPI_KEY_SYM_FUNCTION;
28const brlapi_keyCode_t kMaxFunctionKey = BRLAPI_KEY_SYM_FUNCTION + 23;
29
30// Maps the keyboard modifier flags to their corresponding flags in a
31// |KeyEvent|.
32void MapModifierFlags(brlapi_keyCode_t code, KeyEvent* event) {
33  if (code & BRLAPI_KEY_FLG_CONTROL)
34    event->ctrl_key.reset(new bool(true));
35  if (code & BRLAPI_KEY_FLG_META)
36    event->alt_key.reset(new bool(true));
37  if (code & BRLAPI_KEY_FLG_SHIFT)
38    event->shift_key.reset(new bool(true));
39}
40
41// Maps a brlapi keysym, which is similar to an X keysym into the
42// provided event.
43// See ui/events/keycodes/dom4/keycode_converter_data.cc for the full
44// list of key codes.
45void MapKeySym(brlapi_keyCode_t code, KeyEvent* event) {
46  brlapi_keyCode_t key_sym = code & BRLAPI_KEY_CODE_MASK;
47  if (key_sym < kMaxLatin1KeySym ||
48      (key_sym & BRLAPI_KEY_SYM_UNICODE) != 0) {
49    uint32 code_point = key_sym & ~BRLAPI_KEY_SYM_UNICODE;
50    if (!base::IsValidCharacter(code_point))
51      return;
52    event->standard_key_char.reset(new std::string);
53    base::WriteUnicodeCharacter(code_point, event->standard_key_char.get());
54  } else if (key_sym >= kMinFunctionKey && key_sym <= kMaxFunctionKey) {
55    // Function keys are 0-based here, so we need to add one to get e.g.
56    // 'F1' for the first key.
57    int function_key_number = key_sym - kMinFunctionKey + 1;
58    event->standard_key_code.reset(
59        new std::string(base::StringPrintf("F%d", function_key_number)));
60  } else {
61    // Explicitly map the keys that brlapi provides.
62    const char* code_string;
63    switch (key_sym) {
64      case BRLAPI_KEY_SYM_BACKSPACE:
65        code_string = "Backspace";
66        break;
67      case BRLAPI_KEY_SYM_TAB:
68        code_string = "Tab";
69        break;
70      case BRLAPI_KEY_SYM_LINEFEED:
71        code_string = "Enter";
72        break;
73      case BRLAPI_KEY_SYM_ESCAPE:
74        code_string = "Escape";
75        break;
76      case BRLAPI_KEY_SYM_HOME:
77        code_string = "Home";
78        break;
79      case BRLAPI_KEY_SYM_LEFT:
80        code_string = "ArrowLeft";
81        break;
82      case BRLAPI_KEY_SYM_UP:
83        code_string = "ArrowUp";
84        break;
85      case BRLAPI_KEY_SYM_RIGHT:
86        code_string = "ArrowRight";
87        break;
88      case BRLAPI_KEY_SYM_DOWN:
89        code_string = "ArrowDown";
90        break;
91      case BRLAPI_KEY_SYM_PAGE_UP:
92        code_string = "PageUp";
93        break;
94      case BRLAPI_KEY_SYM_PAGE_DOWN:
95        code_string = "PageDown";
96        break;
97      case BRLAPI_KEY_SYM_END:
98        code_string = "End";
99        break;
100      case BRLAPI_KEY_SYM_INSERT:
101        code_string = "Insert";
102        break;
103      case BRLAPI_KEY_SYM_DELETE:
104        code_string = "Delete";
105        break;
106      default:
107        return;
108    }
109    event->standard_key_code.reset(new std::string(code_string));
110  }
111  MapModifierFlags(code, event);
112  event->command = KEY_COMMAND_STANDARD_KEY;
113}
114
115void MapCommand(brlapi_keyCode_t code, KeyEvent* event) {
116  brlapi_keyCode_t argument = code & BRLAPI_KEY_CMD_ARG_MASK;
117  switch (code & BRLAPI_KEY_CODE_MASK) {
118    case BRLAPI_KEY_CMD_LNUP:
119      event->command = KEY_COMMAND_LINE_UP;
120      break;
121    case BRLAPI_KEY_CMD_LNDN:
122      event->command = KEY_COMMAND_LINE_DOWN;
123      break;
124    case BRLAPI_KEY_CMD_FWINLT:
125      event->command = KEY_COMMAND_PAN_LEFT;
126      break;
127    case BRLAPI_KEY_CMD_FWINRT:
128      event->command = KEY_COMMAND_PAN_RIGHT;
129      break;
130    case BRLAPI_KEY_CMD_TOP:
131      event->command = KEY_COMMAND_TOP;
132      break;
133    case BRLAPI_KEY_CMD_BOT:
134      event->command = KEY_COMMAND_BOTTOM;
135      break;
136    default:
137      switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
138        case BRLAPI_KEY_CMD_ROUTE:
139          event->command = KEY_COMMAND_ROUTING;
140          event->display_position.reset(new int(argument));
141          break;
142        case BRLAPI_KEY_CMD_PASSDOTS:
143          event->command = KEY_COMMAND_DOTS;
144          event->braille_dots.reset(new int(argument & kAllDots));
145          MapModifierFlags(code, event);
146          break;
147      }
148  }
149}
150
151}  // namespace
152
153scoped_ptr<KeyEvent> BrlapiKeyCodeToEvent(brlapi_keyCode_t code) {
154  scoped_ptr<KeyEvent> result(new KeyEvent);
155  result->command = KEY_COMMAND_NONE;
156  switch (code & BRLAPI_KEY_TYPE_MASK) {
157    case BRLAPI_KEY_TYPE_SYM:
158      MapKeySym(code, result.get());
159      break;
160    case BRLAPI_KEY_TYPE_CMD:
161      MapCommand(code, result.get());
162      break;
163  }
164  if (result->command == KEY_COMMAND_NONE)
165    result.reset();
166  return result.Pass();
167}
168
169}  // namespace braille_display_private
170}  // namespace api
171}  // namespace extensions
172