Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Unified Diff: ui/events/keycodes/platform_key_map_win.cc

Issue 1585193002: Build key map DomCodeToKey() for Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix unittest Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/events/keycodes/platform_key_map_win.h ('k') | ui/events/keycodes/platform_key_map_win_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/events/keycodes/platform_key_map_win.cc
diff --git a/ui/events/keycodes/platform_key_map_win.cc b/ui/events/keycodes/platform_key_map_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7fe5cad8cd2218e65c05c53a82b8c13e25d71478
--- /dev/null
+++ b/ui/events/keycodes/platform_key_map_win.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2016 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/platform_key_map_win.h"
+
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/threading/thread_local_storage.h"
+
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+
+namespace ui {
+
+namespace {
+
+struct DomCodeEntry {
+ DomCode dom_code;
+ int scan_code;
+};
+#define USB_KEYMAP_DECLARATION const DomCodeEntry supported_dom_code_list[] =
+#define USB_KEYMAP(usb, evdev, xkb, win, mac, code, id) {DomCode::id, win}
+#include "ui/events/keycodes/dom/keycode_converter_data.inc"
+#undef USB_KEYMAP
+#undef USB_KEYMAP_DECLARATION
+
+// List of modifiers mentioned in https://w3c.github.io/uievents/#keys-modifiers
+// Some modifiers are commented out because they usually don't change keys.
+const EventFlags modifier_flags[] = {
+ EF_SHIFT_DOWN,
+ EF_CONTROL_DOWN,
+ EF_ALT_DOWN,
+ // EF_COMMAND_DOWN,
+ EF_ALTGR_DOWN,
+ // EF_NUM_LOCK_ON,
+ EF_CAPS_LOCK_ON,
+ // EF_SCROLL_LOCK_ON
+};
+const int kModifierFlagsCombinations = (1 << arraysize(modifier_flags)) - 1;
+
+int GetModifierFlags(int combination) {
+ int flags = EF_NONE;
+ for (int i = 0; i < arraysize(modifier_flags); ++i) {
+ if (combination & (1 << i))
+ flags |= modifier_flags[i];
+ }
+ return flags;
+}
+
+void SetModifierState(BYTE* keyboard_state, int flags) {
+ // According to MSDN GetKeyState():
+ // 1. If the high-order bit is 1, the key is down; otherwise, it is up.
+ // 2. If the low-order bit is 1, the key is toggled. A key, such as the
+ // CAPS LOCK key, is toggled if it is turned on. The key is off and
+ // untoggled if the low-order bit is 0.
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646301.aspx
+ if (flags & EF_SHIFT_DOWN)
+ keyboard_state[VK_SHIFT] |= 0x80;
+
+ if (flags & EF_CONTROL_DOWN)
+ keyboard_state[VK_CONTROL] |= 0x80;
+
+ if (flags & EF_ALT_DOWN)
+ keyboard_state[VK_MENU] |= 0x80;
+
+ if (flags & EF_ALTGR_DOWN) {
+ // AltGr should be RightAlt+LeftControl within Windows, but actually only
+ // the non-located keys will work here.
+ keyboard_state[VK_MENU] |= 0x80;
+ keyboard_state[VK_CONTROL] |= 0x80;
+ }
+
+ if (flags & EF_COMMAND_DOWN)
+ keyboard_state[VK_LWIN] |= 0x80;
+
+ if (flags & EF_NUM_LOCK_ON)
+ keyboard_state[VK_NUMLOCK] |= 0x01;
+
+ if (flags & EF_CAPS_LOCK_ON)
+ keyboard_state[VK_CAPITAL] |= 0x01;
+
+ if (flags & EF_SCROLL_LOCK_ON)
+ keyboard_state[VK_SCROLL] |= 0x01;
+}
+
+void CleanupKeyMapTls(void* data) {
+ PlatformKeyMap* key_map = reinterpret_cast<PlatformKeyMap*>(data);
+ delete key_map;
+}
+
+struct PlatformKeyMapInstanceTlsTraits
+ : public base::DefaultLazyInstanceTraits<base::ThreadLocalStorage::Slot> {
+ static base::ThreadLocalStorage::Slot* New(void* instance) {
+ // Use placement new to initialize our instance in our preallocated space.
+ // TODO(chongz): Use std::default_delete instead of providing own function.
+ return new (instance) base::ThreadLocalStorage::Slot(CleanupKeyMapTls);
+ }
+};
+
+base::LazyInstance<base::ThreadLocalStorage::Slot,
+ PlatformKeyMapInstanceTlsTraits>
+ g_platform_key_map_tls_lazy = LAZY_INSTANCE_INITIALIZER;
+
+} // anonymous namespace
+
+PlatformKeyMap::PlatformKeyMap() {}
+
+PlatformKeyMap::PlatformKeyMap(HKL layout) {
+ UpdateLayout(layout);
+}
+
+DomKey PlatformKeyMap::DomCodeAndFlagsToDomKey(DomCode code, int flags) const {
+ const int flags_to_try[] = {
+ // Trying to match Firefox's behavior and UIEvents DomKey guidelines.
+ // If the combination doesn't produce a printable character, the key value
+ // should be the key with no modifiers except for Shift and AltGr.
+ // See https://w3c.github.io/uievents/#keys-guidelines
+ flags,
+ flags & (EF_SHIFT_DOWN | EF_ALTGR_DOWN | EF_CAPS_LOCK_ON),
+ flags & (EF_SHIFT_DOWN | EF_CAPS_LOCK_ON),
+ EF_NONE,
+ };
+
+ DomKey key = DomKey::NONE;
+ for (auto try_flags : flags_to_try) {
+ const auto& it = code_to_key_.find(std::make_pair(static_cast<int>(code),
+ try_flags));
+ if (it != code_to_key_.end()) {
+ key = it->second;
+ if (key != DomKey::NONE)
+ break;
+ }
+ }
+ return key;
+}
+
+// static
+DomKey PlatformKeyMap::DomCodeAndFlagsToDomKeyStatic(DomCode code, int flags) {
+ // Use TLS because KeyboardLayout is per thread.
+ // However currently PlatformKeyMap will only be used by the host application,
+ // which is just one process and one thread.
+ base::ThreadLocalStorage::Slot* platform_key_map_tls =
+ g_platform_key_map_tls_lazy.Pointer();
+ PlatformKeyMap* platform_key_map =
+ reinterpret_cast<PlatformKeyMap*>(platform_key_map_tls->Get());
+ if (!platform_key_map) {
+ platform_key_map = new PlatformKeyMap();
+ platform_key_map_tls->Set(platform_key_map);
+ }
+
+ HKL current_layout = ::GetKeyboardLayout(0);
+ platform_key_map->UpdateLayout(current_layout);
+ return platform_key_map->DomCodeAndFlagsToDomKey(code, flags);
+}
+
+void PlatformKeyMap::UpdateLayout(HKL layout) {
+ if (layout == keyboard_layout_)
+ return;
+
+ // TODO(chongz): Optimize layout switching (see crbug.com/587147).
+ keyboard_layout_ = layout;
+ code_to_key_.clear();
+ // Map size for some sample keyboard layouts:
+ // US: 428, French: 554, Persian: 434, Vietnamese: 1388
+ code_to_key_.reserve(500);
+
+ BYTE keyboard_state_to_restore[256];
+ ::GetKeyboardState(keyboard_state_to_restore);
brucedawson 2016/02/19 19:17:54 The /analyze builder points out that this function
Wez 2016/02/19 21:26:42 Agreed that that seems a sensible precaution - at
+
+ for (int eindex = 0; eindex <= kModifierFlagsCombinations; ++eindex) {
+ BYTE keyboard_state[256];
+ memset(keyboard_state, 0, sizeof(keyboard_state));
+ int flags = GetModifierFlags(eindex);
+ SetModifierState(keyboard_state, flags);
+ for (const auto& dom_code_entry : supported_dom_code_list) {
+ wchar_t translated_chars[5];
+ int key_code = ::MapVirtualKeyEx(dom_code_entry.scan_code,
+ MAPVK_VSC_TO_VK, keyboard_layout_);
+ int rv = ::ToUnicodeEx(key_code, 0, keyboard_state, translated_chars,
+ arraysize(translated_chars), 0, keyboard_layout_);
+
+ if (rv == -1) {
+ // Dead key, injecting VK_SPACE to get character representation.
+ BYTE empty_state[256];
+ memset(empty_state, 0, sizeof(empty_state));
+ rv = ::ToUnicodeEx(VK_SPACE, 0, empty_state, translated_chars,
+ arraysize(translated_chars), 0, keyboard_layout_);
+ // Expecting a dead key character (not followed by a space).
+ if (rv == 1) {
+ code_to_key_[std::make_pair(static_cast<int>(dom_code_entry.dom_code),
+ flags)] =
+ DomKey::DeadKeyFromCombiningCharacter(translated_chars[0]);
+ } else {
+ // TODO(chongz): Check if this will actually happen.
+ }
+ } else if (rv == 1) {
+ if (translated_chars[0] >= 0x20) {
+ code_to_key_[std::make_pair(static_cast<int>(dom_code_entry.dom_code),
+ flags)] =
+ DomKey::FromCharacter(translated_chars[0]);
+ } else {
+ // Ignores legacy non-printable control characters.
+ }
+ } else {
+ // TODO(chongz): Handle rv <= -2 and rv >= 2.
+ }
+ }
+ }
+ ::SetKeyboardState(keyboard_state_to_restore);
+}
+
+} // namespace ui
« no previous file with comments | « ui/events/keycodes/platform_key_map_win.h ('k') | ui/events/keycodes/platform_key_map_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698