Commit f2dbc59d authored by Gary Kacmarcik's avatar Gary Kacmarcik Committed by Commit Bot

[Keyboard Map] Add shared DomKeyboardLayout class.

This class contains all the platform-independent code for creating
the Keyboard Map.

Bug: 832811
Change-Id: Icb4dbf85419c72e795b090bae816b0b1c6b03f67
Reviewed-on: https://chromium-review.googlesource.com/1062925
Commit-Queue: Gary Kacmarcik <garykac@chromium.org>
Reviewed-by: default avatarJoe Downing <joedow@chromium.org>
Reviewed-by: default avatarThomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#559408}
parent 8bab3477
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <dlfcn.h> #include <dlfcn.h>
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <math.h> #include <math.h>
#include <pango/pango.h> #include <pango/pango.h>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include <utility> #include <utility>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/containers/flat_map.h"
#include "base/debug/leak_annotations.h" #include "base/debug/leak_annotations.h"
#include "base/environment.h" #include "base/environment.h"
#include "base/i18n/rtl.h" #include "base/i18n/rtl.h"
...@@ -47,6 +49,7 @@ ...@@ -47,6 +49,7 @@
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_keyboard_layout_manager.h"
#include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/font_render_params.h" #include "ui/gfx/font_render_params.h"
...@@ -841,16 +844,28 @@ std::unique_ptr<views::NavButtonProvider> GtkUi::CreateNavButtonProvider() { ...@@ -841,16 +844,28 @@ std::unique_ptr<views::NavButtonProvider> GtkUi::CreateNavButtonProvider() {
} }
#endif #endif
// Mapping from GDK dead keys to corresponding printable character.
static struct {
guint gdk_key;
guint16 unicode;
} kDeadKeyMapping[] = {
{GDK_KEY_dead_grave, 0x0060}, {GDK_KEY_dead_acute, 0x0027},
{GDK_KEY_dead_circumflex, 0x005e}, {GDK_KEY_dead_tilde, 0x007e},
{GDK_KEY_dead_diaeresis, 0x00a8},
};
base::flat_map<std::string, std::string> GtkUi::GetKeyboardLayoutMap() { base::flat_map<std::string, std::string> GtkUi::GetKeyboardLayoutMap() {
GdkDisplay* display = gdk_display_get_default(); GdkDisplay* display = gdk_display_get_default();
GdkKeymap* keymap = gdk_keymap_get_for_display(display); GdkKeymap* keymap = gdk_keymap_get_for_display(display);
if (!keymap)
return {};
ui::DomKeyboardLayoutManager* layouts = new ui::DomKeyboardLayoutManager();
auto map = base::flat_map<std::string, std::string>(); auto map = base::flat_map<std::string, std::string>();
if (!keymap)
return map;
for (unsigned int i = 0; i < ui::kWritingSystemKeyDomCodeEntries; ++i) { for (unsigned int i_domcode = 0;
ui::DomCode domcode = ui::writing_system_key_domcodes[i]; i_domcode < ui::kWritingSystemKeyDomCodeEntries; ++i_domcode) {
ui::DomCode domcode = ui::writing_system_key_domcodes[i_domcode];
guint16 keycode = ui::KeycodeConverter::DomCodeToNativeKeycode(domcode); guint16 keycode = ui::KeycodeConverter::DomCodeToNativeKeycode(domcode);
GdkKeymapKey* keys = nullptr; GdkKeymapKey* keys = nullptr;
guint* keyvals = nullptr; guint* keyvals = nullptr;
...@@ -862,16 +877,20 @@ base::flat_map<std::string, std::string> GtkUi::GetKeyboardLayoutMap() { ...@@ -862,16 +877,20 @@ base::flat_map<std::string, std::string> GtkUi::GetKeyboardLayoutMap() {
if (gdk_keymap_get_entries_for_keycode(keymap, keycode, &keys, &keyvals, if (gdk_keymap_get_entries_for_keycode(keymap, keycode, &keys, &keyvals,
&n_entries)) { &n_entries)) {
for (gint i = 0; i < n_entries; ++i) { for (gint i = 0; i < n_entries; ++i) {
// There are 4 entries per layout, one each for shift level 0..3. // There are 4 entries per layout group, one each for shift level 0..3.
// We only care about the unshifted values (level = 0). // We only care about the unshifted values (level = 0).
if (keys[i].level != 0 || keyvals[i] >= 255) if (keys[i].level == 0) {
continue; uint16_t unicode = gdk_keyval_to_unicode(keyvals[i]);
char keystring[2]; if (unicode == 0) {
keystring[0] = keyvals[i]; for (unsigned int i_dead = 0; i_dead < base::size(kDeadKeyMapping);
keystring[1] = '\0'; ++i_dead) {
map.emplace(ui::KeycodeConverter::DomCodeToCodeString(domcode), if (keyvals[i] == kDeadKeyMapping[i_dead].gdk_key)
keystring); unicode = kDeadKeyMapping[i_dead].unicode;
break; }
}
if (unicode != 0)
layouts->GetLayout(keys[i].group)->AddKeyMapping(domcode, unicode);
}
} }
} }
g_free(keys); g_free(keys);
...@@ -879,7 +898,7 @@ base::flat_map<std::string, std::string> GtkUi::GetKeyboardLayoutMap() { ...@@ -879,7 +898,7 @@ base::flat_map<std::string, std::string> GtkUi::GetKeyboardLayoutMap() {
g_free(keyvals); g_free(keyvals);
keyvals = nullptr; keyvals = nullptr;
} }
return map; return layouts->GetFirstAsciiCapableLayout()->GetMap();
} }
bool GtkUi::MatchEvent(const ui::Event& event, bool GtkUi::MatchEvent(const ui::Event& event,
......
...@@ -21,6 +21,10 @@ static_library("dom_keycode_converter") { ...@@ -21,6 +21,10 @@ static_library("dom_keycode_converter") {
"keycodes/dom/dom_code.h", "keycodes/dom/dom_code.h",
"keycodes/dom/dom_key.h", "keycodes/dom/dom_key.h",
"keycodes/dom/dom_key_data.inc", "keycodes/dom/dom_key_data.inc",
"keycodes/dom/dom_keyboard_layout.cc",
"keycodes/dom/dom_keyboard_layout.h",
"keycodes/dom/dom_keyboard_layout_manager.cc",
"keycodes/dom/dom_keyboard_layout_manager.h",
"keycodes/dom/keycode_converter.cc", "keycodes/dom/keycode_converter.cc",
"keycodes/dom/keycode_converter.h", "keycodes/dom/keycode_converter.h",
"keycodes/dom/keycode_converter_data.inc", "keycodes/dom/keycode_converter_data.inc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/events/keycodes/dom/dom_keyboard_layout.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
namespace ui {
const DomCode writing_system_key_domcodes[] = {
// Keyboard Row E
DomCode::BACKQUOTE, DomCode::DIGIT1, DomCode::DIGIT2, DomCode::DIGIT3,
DomCode::DIGIT4, DomCode::DIGIT5, DomCode::DIGIT6, DomCode::DIGIT7,
DomCode::DIGIT8, DomCode::DIGIT9, DomCode::DIGIT0, DomCode::MINUS,
DomCode::EQUAL, DomCode::INTL_YEN,
// Keyboard Row D
DomCode::US_Q, DomCode::US_W, DomCode::US_E, DomCode::US_R, DomCode::US_T,
DomCode::US_Y, DomCode::US_U, DomCode::US_I, DomCode::US_O, DomCode::US_P,
DomCode::BRACKET_LEFT, DomCode::BRACKET_RIGHT, DomCode::BACKSLASH,
// Keyboard Row C
DomCode::US_A, DomCode::US_S, DomCode::US_D, DomCode::US_F, DomCode::US_G,
DomCode::US_H, DomCode::US_J, DomCode::US_K, DomCode::US_L,
DomCode::SEMICOLON, DomCode::QUOTE,
// Keyboard Row B
DomCode::INTL_BACKSLASH, DomCode::US_Z, DomCode::US_X, DomCode::US_C,
DomCode::US_V, DomCode::US_B, DomCode::US_N, DomCode::US_M, DomCode::COMMA,
DomCode::PERIOD, DomCode::SLASH, DomCode::INTL_RO,
};
const size_t kWritingSystemKeyDomCodeEntries =
base::size(writing_system_key_domcodes);
DomKeyboardLayout::DomKeyboardLayout() = default;
DomKeyboardLayout::~DomKeyboardLayout() = default;
void DomKeyboardLayout::AddKeyMapping(DomCode code, uint32_t unicode) {
layout_.emplace(code, unicode);
}
base::flat_map<std::string, std::string> DomKeyboardLayout::GetMap() {
auto dom_map = base::flat_map<std::string, std::string>();
for (size_t i = 0; i < kWritingSystemKeyDomCodeEntries; ++i) {
ui::DomCode dom_code = ui::writing_system_key_domcodes[i];
uint16_t unicode = layout_[dom_code];
if (unicode == 0)
continue;
std::string key_str;
size_t len = base::WriteUnicodeCharacter(unicode, &key_str);
if (len == 0)
continue;
dom_map.emplace(KeycodeConverter::DomCodeToCodeString(dom_code), key_str);
}
return dom_map;
}
bool DomKeyboardLayout::IsAsciiCapable() {
uint16_t uniA = layout_[DomCode::US_A];
uint16_t uniBackquote = layout_[DomCode::BACKQUOTE];
return uniA >= 'a' && uniA <= 'z' && uniBackquote != 0;
}
} // namespace ui
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_H_
#define UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_H_
#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "ui/events/keycodes/dom/dom_code.h"
namespace ui {
enum class DomCode;
// Class for a single keyboard layout (if there is only one group) or single
// layout group within a keyboard layout.
//
// Note that a "group" is not a group of layouts but is rather a "sub-group"
// of a layout. Most layouts have a single group, but layouts can be divided
// into multiple groups. These groups are effectively separate sub-layouts that
// can be enabled within the layout. For example, a Japanese layout can have a
// main group and a separate "kana" group.
class DomKeyboardLayout final {
public:
DomKeyboardLayout();
~DomKeyboardLayout();
// Add a DomCode -> Unicode mapping for this layout (or layout group).
// Only unshifted (shift level = 0) values should be recorded.
void AddKeyMapping(DomCode code, uint32_t unicode);
// Return a dom code string -> dom key string mapping table.
base::flat_map<std::string, std::string> GetMap();
// Return true if this layout can generate all the lowercase ASCII
// characters using only unshifted key presses.
bool IsAsciiCapable();
private:
// Mapping from DomCode -> Unicode character.
base::flat_map<ui::DomCode, uint32_t> layout_;
DISALLOW_COPY_AND_ASSIGN(DomKeyboardLayout);
};
// An array of DomCodes that identifies the Writing System Keys on the
// keyboard.
//
// The Writing System Keys are those that change meaning (i.e., they produce
// a different KeyboardEvent key value) based on the current keyboard layout.
// See https://www.w3.org/TR/uievents-code/#key-alphanumeric-writing-system
//
// This is used by the Keyboard Map API
// (see https://wicg.github.io/keyboard-map/)
extern const DomCode writing_system_key_domcodes[];
extern const size_t kWritingSystemKeyDomCodeEntries;
} // namespace ui
#endif // UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/events/keycodes/dom/dom_keyboard_layout_manager.h"
#include <utility>
#include "base/logging.h"
namespace ui {
DomKeyboardLayoutManager::DomKeyboardLayoutManager() = default;
DomKeyboardLayoutManager::~DomKeyboardLayoutManager() = default;
DomKeyboardLayout* DomKeyboardLayoutManager::GetLayout(int layout_group_id) {
if (layouts_.find(layout_group_id) == layouts_.end()) {
layout_order_.push_back(layout_group_id);
layouts_.emplace(layout_group_id, std::make_unique<DomKeyboardLayout>());
}
return layouts_[layout_group_id].get();
}
DomKeyboardLayout* DomKeyboardLayoutManager::GetFirstAsciiCapableLayout() {
for (const auto i : layout_order_) {
if (GetLayout(i)->IsAsciiCapable())
return GetLayout(i);
}
return GetLayout(0);
}
} // namespace ui
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_MANAGER_H_
#define UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_MANAGER_H_
#include <map>
#include <vector>
#include "ui/events/keycodes/dom/dom_keyboard_layout.h"
namespace ui {
class DomKeyboardLayoutManager final {
public:
DomKeyboardLayoutManager();
~DomKeyboardLayoutManager();
// Get the layout with the given id, or create a new one if it doesn't
// already exist in the list of layouts.
// When adding multiple layouts, they should be added in priority order
// (as determined by the underlying platform).
DomKeyboardLayout* GetLayout(int layout_group_id);
DomKeyboardLayout* GetFirstAsciiCapableLayout();
private:
std::vector<int> layout_order_;
std::map<int, std::unique_ptr<DomKeyboardLayout>> layouts_;
DISALLOW_COPY_AND_ASSIGN(DomKeyboardLayoutManager);
};
} // namespace ui
#endif // UI_EVENTS_KEYCODES_DOM_DOM_KEYBOARD_LAYOUT_MANAGER_H_
...@@ -318,30 +318,4 @@ int KeycodeConverter::CodeStringToNativeKeycode(const std::string& code) { ...@@ -318,30 +318,4 @@ int KeycodeConverter::CodeStringToNativeKeycode(const std::string& code) {
return UsbKeycodeToNativeKeycode(CodeStringToUsbKeycode(code)); return UsbKeycodeToNativeKeycode(CodeStringToUsbKeycode(code));
} }
const DomCode writing_system_key_domcodes[] = {
// Keyboard Row E
DomCode::BACKQUOTE, DomCode::DIGIT1, DomCode::DIGIT2, DomCode::DIGIT3,
DomCode::DIGIT4, DomCode::DIGIT5, DomCode::DIGIT6, DomCode::DIGIT7,
DomCode::DIGIT8, DomCode::DIGIT9, DomCode::DIGIT0, DomCode::MINUS,
DomCode::EQUAL, DomCode::INTL_YEN,
// Keyboard Row D
DomCode::US_Q, DomCode::US_W, DomCode::US_E, DomCode::US_R, DomCode::US_T,
DomCode::US_Y, DomCode::US_U, DomCode::US_I, DomCode::US_O, DomCode::US_P,
DomCode::BRACKET_LEFT, DomCode::BRACKET_RIGHT, DomCode::BACKSLASH,
// Keyboard Row C
DomCode::US_A, DomCode::US_S, DomCode::US_D, DomCode::US_F, DomCode::US_G,
DomCode::US_H, DomCode::US_J, DomCode::US_K, DomCode::US_L,
DomCode::SEMICOLON, DomCode::QUOTE,
// Keyboard Row B
DomCode::INTL_BACKSLASH, DomCode::US_Z, DomCode::US_X, DomCode::US_C,
DomCode::US_V, DomCode::US_B, DomCode::US_N, DomCode::US_M, DomCode::COMMA,
DomCode::PERIOD, DomCode::SLASH, DomCode::INTL_RO,
};
const size_t kWritingSystemKeyDomCodeEntries =
base::size(writing_system_key_domcodes);
} // namespace ui } // namespace ui
...@@ -21,19 +21,6 @@ enum class DomCode; ...@@ -21,19 +21,6 @@ enum class DomCode;
enum class DomKeyLocation { STANDARD, LEFT, RIGHT, NUMPAD }; enum class DomKeyLocation { STANDARD, LEFT, RIGHT, NUMPAD };
// An array of DomCodes that identifies the Writing System Keys on the
// keyboard.
//
// The Writing System Keys are those that change meaning (i.e., they produce
// a different KeyboardEvent key value) based on the current keyboard layout.
// See https://www.w3.org/TR/uievents-code/#key-alphanumeric-writing-system
//
// This is used by the Keyboard Map API
// (see https://wicg.github.io/keyboard-map/)
extern const DomCode writing_system_key_domcodes[];
extern const size_t kWritingSystemKeyDomCodeEntries;
// This structure is used to define the keycode mapping table. // This structure is used to define the keycode mapping table.
// It is defined here because the unittests need access to it. // It is defined here because the unittests need access to it.
typedef struct { typedef struct {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment