Chromium Code Reviews| Index: ui/events/keycodes/key_map_win.cc |
| diff --git a/ui/events/keycodes/key_map_win.cc b/ui/events/keycodes/key_map_win.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..7a7440cd832f10e60df08a29088b734c2379a5d5 |
| --- /dev/null |
| +++ b/ui/events/keycodes/key_map_win.cc |
| @@ -0,0 +1,202 @@ |
| +// 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/key_map_win.h" |
| + |
| +#include <utility> |
| + |
| +#include "base/logging.h" |
| +#include "base/macros.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 flags_index[] = { |
|
Wez
2016/02/09 00:18:57
nit: This is the list of interesting modifier flag
|
| + 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 kMaxEventFlagsIndex = (1 << arraysize(flags_index)) - 1; |
|
Wez
2016/02/09 00:18:57
This still isn't the maximum index of the flags_in
|
| + |
| +int GetEventFlagsIndex(int flags) { |
|
Wez
2016/02/09 00:18:57
I don't see this used anywhere?
|
| + int index = 0; |
| + for (int i = 0; i < arraysize(flags_index); ++i) { |
| + if (flags & flags_index[i]) |
| + index |= 1 << i; |
| + } |
| + return index; |
| +} |
| + |
| +int EventFlagsFromIndex(int index) { |
|
Wez
2016/02/09 00:18:57
nit: Suggest GetModifierFlags(int combination) if
|
| + int flags = EF_NONE; |
| + for (int i = 0; i < arraysize(flags_index); ++i) { |
| + if (index & (1 << i)) |
| + flags |= flags_index[i]; |
| + } |
| + return flags; |
| +} |
| + |
| +void SetModifierState(BYTE* keyboard_state, int flags) { |
| + 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; |
|
chongz
2016/02/04 21:10:25
I'm not sure why but only the non-located Alt+Cont
Wez
2016/02/09 00:18:57
OK, sorry for the misleading comment earlier! Not
|
| + 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; |
| +} |
| + |
| +} // anonymous namespace |
| + |
| +WindowsKeyMap::WindowsKeyMap() : keyboard_layout_(0) {} |
|
Wez
2016/02/09 00:18:57
nit: You can set this via inline initializer in th
|
| + |
| +WindowsKeyMap::WindowsKeyMap(HKL layout) : WindowsKeyMap() { |
|
Wez
2016/02/09 00:18:57
See above re inline initializer for |keyboard_layo
|
| + LoadLayout(layout); |
| +} |
| + |
| +DomKey WindowsKeyMap::DomCodeToKey(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 = key_map_.find(std::make_pair(code, try_flags)); |
| + if (it != key_map_.end()) |
| + key = it->second.key; |
| + if (key != DomKey::NONE) |
|
Wez
2016/02/09 00:18:57
nit: You're doing this if() even if you didn't cha
|
| + break; |
| + } |
| + return key; |
| +} |
| + |
| +KeyboardCode WindowsKeyMap::DomCodeToKeyboardCode(DomCode code) const { |
| + const auto& it = key_map_.find(std::make_pair(code, EF_NONE)); |
| + if (it != key_map_.end()) |
| + return it->second.legacy_key_code; |
| + return static_cast<KeyboardCode>(0); |
| +} |
| + |
| +DomCode WindowsKeyMap::KeyboardCodeToDomCode(KeyboardCode key_code) const { |
|
dtapuska
2016/02/04 20:31:45
Is this really required? I'm not sure if we need a
chongz
2016/02/04 21:10:25
I guess Wez wants it in case user only gives us Ke
Wez
2016/02/09 00:18:57
Let's add it if/when it's actually used!
I was th
|
| + // TODO(chongz): Could create another map to improve efficiency if necessary. |
| + for (const auto& dom_code_entry : supported_dom_code_list) { |
| + if (DomCodeToKeyboardCode(dom_code_entry.dom_code) == key_code) |
| + return dom_code_entry.dom_code; |
| + } |
| + return DomCode::NONE; |
| +} |
| + |
| +DomKey WindowsKeyMap::DomCodeToSystemLayoutKey(DomCode code, int flags) { |
|
Wez
2016/02/09 00:18:57
static methods should be prefixed with a "// stati
|
| + static base::LazyInstance<WindowsKeyMap>::Leaky s_instance = |
| + LAZY_INSTANCE_INITIALIZER; |
|
Wez
2016/02/09 00:18:57
Note that the LazyInstance header says it "really
|
| + HKL current_layout = ::GetKeyboardLayout(0); |
|
chongz
2016/02/04 21:10:25
Still, should I add a lock or only allow it to be
Wez
2016/02/09 00:18:57
GetKeyboardLayout(0) gets the current layout for t
dtapuska
2016/02/09 16:46:39
Likely this code is probably only going to execute
Wez
2016/02/09 22:40:01
On-demand thread-local instance SGTM - do we have
|
| + if (s_instance.Get().keyboard_layout_ != current_layout) |
| + s_instance.Get().LoadLayout(current_layout); |
| + return s_instance.Get().DomCodeToKey(code, flags); |
| +} |
| + |
| +void WindowsKeyMap::LoadLayout(HKL layout) { |
| + keyboard_layout_ = layout; |
| + key_map_.clear(); |
| + |
| + BYTE keyboard_state_to_restore[256]; |
| + ::GetKeyboardState(keyboard_state_to_restore); |
| + |
| + for (int eindex = 0; eindex <= kMaxEventFlagsIndex; ++eindex) { |
| + BYTE keyboard_state[256]; |
| + memset(keyboard_state, 0, sizeof(keyboard_state)); |
| + int flags = EventFlagsFromIndex(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 < 0) { |
| + // 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_); |
| + // Must be a repeat of dead key character. |
| + DCHECK(rv == 2); |
| + AddKeyMapEntry( |
| + dom_code_entry.dom_code, |
| + DomKey::DeadKeyFromCombiningCharacter(translated_chars[0]), |
| + static_cast<KeyboardCode>(key_code), flags); |
| + } else if (rv == 1) { |
| + if (translated_chars[0] >= 0x20) { |
| + AddKeyMapEntry(dom_code_entry.dom_code, |
| + DomKey::FromCharacter(translated_chars[0]), |
| + static_cast<KeyboardCode>(key_code), flags); |
| + } else { |
| + // Ignores legacy non-printable control characters. |
| + } |
| + } else { |
| + // TODO(chongz): Handle multiple characters case. |
|
dtapuska
2016/02/04 20:31:45
What are we going to do with non-printable charact
chongz
2016/02/04 21:10:25
I will add (copy?) the US non-printable table here
|
| + } |
| + } |
| + } |
| + ::SetKeyboardState(keyboard_state_to_restore); |
| +} |
| + |
| +void WindowsKeyMap::AddKeyMapEntry(DomCode code, |
| + DomKey key, |
| + KeyboardCode legacy_key_code, |
| + int flags) { |
| + key_map_[std::make_pair(code, flags)] = |
| + KeyMapEntry{code, key, legacy_key_code, flags}; |
| +} |
| + |
| +} // namespace ui |