| // Copyright (c) 2011 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/keyboard_code_conversion.h" |
| |
| #include <algorithm> |
| |
| #include "base/stl_util.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/keycodes/dom/dom_code.h" |
| #include "ui/events/keycodes/dom/dom_key.h" |
| #include "ui/events/keycodes/dom_us_layout_data.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| bool IsRightSideDomCode(DomCode code) { |
| return (code == DomCode::SHIFT_RIGHT) || (code == DomCode::CONTROL_RIGHT) || |
| (code == DomCode::ALT_RIGHT) || (code == DomCode::META_RIGHT); |
| } |
| |
| } // anonymous namespace |
| |
| base::char16 DomCodeToUsLayoutCharacter(DomCode dom_code, int flags) { |
| DomKey dom_key; |
| KeyboardCode key_code; |
| if (DomCodeToUsLayoutDomKey(dom_code, flags, &dom_key, &key_code) && |
| dom_key.IsCharacter()) { |
| return dom_key.ToCharacter(); |
| } |
| return 0; |
| } |
| |
| bool DomCodeToNonPrintableDomKey(DomCode dom_code, |
| DomKey* out_dom_key, |
| KeyboardCode* out_key_code) { |
| for (const auto& it : kNonPrintableCodeMap) { |
| if (it.dom_code == dom_code) { |
| *out_dom_key = it.dom_key; |
| *out_key_code = NonPrintableDomKeyToKeyboardCode(it.dom_key); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool DomCodeToUsLayoutDomKey(DomCode dom_code, |
| int flags, |
| DomKey* out_dom_key, |
| KeyboardCode* out_key_code) { |
| for (const auto& it : kPrintableCodeMap) { |
| if (it.dom_code == dom_code) { |
| int state = ((flags & EF_SHIFT_DOWN) == EF_SHIFT_DOWN); |
| base::char16 ch = it.character[state]; |
| if ((flags & EF_CAPS_LOCK_ON) == EF_CAPS_LOCK_ON) { |
| ch |= 0x20; |
| if ((ch >= 'a') && (ch <= 'z')) |
| ch = it.character[state ^ 1]; |
| } |
| *out_dom_key = DomKey::FromCharacter(ch); |
| *out_key_code = DomCodeToUsLayoutNonLocatedKeyboardCode(dom_code); |
| return true; |
| } |
| } |
| |
| return DomCodeToNonPrintableDomKey(dom_code, out_dom_key, out_key_code); |
| } |
| |
| bool DomCodeToControlCharacter(DomCode dom_code, |
| int flags, |
| DomKey* dom_key, |
| KeyboardCode* key_code) { |
| if ((flags & EF_CONTROL_DOWN) == 0) |
| return false; |
| |
| int code = static_cast<int>(dom_code); |
| const int kKeyA = static_cast<int>(DomCode::US_A); |
| // Control-A - Control-Z map to 0x01 - 0x1A. |
| if (code >= kKeyA && code <= static_cast<int>(DomCode::US_Z)) { |
| *dom_key = DomKey::FromCharacter(code - kKeyA + 1); |
| *key_code = static_cast<KeyboardCode>(code - kKeyA + VKEY_A); |
| switch (dom_code) { |
| case DomCode::US_H: |
| *key_code = VKEY_BACK; |
| break; |
| case DomCode::US_I: |
| *key_code = VKEY_TAB; |
| break; |
| case DomCode::US_M: |
| *key_code = VKEY_RETURN; |
| break; |
| default: |
| break; |
| } |
| return true; |
| } |
| |
| if (flags & EF_SHIFT_DOWN) { |
| switch (dom_code) { |
| case DomCode::DIGIT2: |
| // NUL |
| *dom_key = DomKey::FromCharacter(0); |
| *key_code = VKEY_2; |
| return true; |
| case DomCode::DIGIT6: |
| // RS |
| *dom_key = DomKey::FromCharacter(0x1E); |
| *key_code = VKEY_6; |
| return true; |
| case DomCode::MINUS: |
| // US |
| *dom_key = DomKey::FromCharacter(0x1F); |
| *key_code = VKEY_OEM_MINUS; |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| switch (dom_code) { |
| case DomCode::ENTER: |
| // NL |
| *dom_key = DomKey::FromCharacter(0x0A); |
| *key_code = VKEY_RETURN; |
| return true; |
| case DomCode::BRACKET_LEFT: |
| // ESC |
| *dom_key = DomKey::FromCharacter(0x1B); |
| *key_code = VKEY_OEM_4; |
| return true; |
| case DomCode::BACKSLASH: |
| // FS |
| *dom_key = DomKey::FromCharacter(0x1C); |
| *key_code = VKEY_OEM_5; |
| return true; |
| case DomCode::BRACKET_RIGHT: |
| // GS |
| *dom_key = DomKey::FromCharacter(0x1D); |
| *key_code = VKEY_OEM_6; |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| // Returns a Windows-based VKEY for a non-printable DOM Level 3 |key|. |
| // The returned VKEY is non-positional (e.g. VKEY_SHIFT). |
| KeyboardCode NonPrintableDomKeyToKeyboardCode(DomKey dom_key) { |
| for (const auto& it : kDomKeyToKeyboardCodeMap) { |
| if (it.dom_key == dom_key) |
| return it.key_code; |
| } |
| return VKEY_UNKNOWN; |
| } |
| |
| // Determine the non-located VKEY corresponding to a located VKEY. |
| KeyboardCode LocatedToNonLocatedKeyboardCode(KeyboardCode key_code) { |
| switch (key_code) { |
| case VKEY_RWIN: |
| return VKEY_LWIN; |
| case VKEY_LSHIFT: |
| case VKEY_RSHIFT: |
| return VKEY_SHIFT; |
| case VKEY_LCONTROL: |
| case VKEY_RCONTROL: |
| return VKEY_CONTROL; |
| case VKEY_LMENU: |
| case VKEY_RMENU: |
| return VKEY_MENU; |
| case VKEY_NUMPAD0: |
| return VKEY_0; |
| case VKEY_NUMPAD1: |
| return VKEY_1; |
| case VKEY_NUMPAD2: |
| return VKEY_2; |
| case VKEY_NUMPAD3: |
| return VKEY_3; |
| case VKEY_NUMPAD4: |
| return VKEY_4; |
| case VKEY_NUMPAD5: |
| return VKEY_5; |
| case VKEY_NUMPAD6: |
| return VKEY_6; |
| case VKEY_NUMPAD7: |
| return VKEY_7; |
| case VKEY_NUMPAD8: |
| return VKEY_8; |
| case VKEY_NUMPAD9: |
| return VKEY_9; |
| default: |
| return key_code; |
| } |
| } |
| |
| // Determine the located VKEY corresponding to a non-located VKEY. |
| KeyboardCode NonLocatedToLocatedKeyboardCode(KeyboardCode key_code, |
| DomCode dom_code) { |
| switch (key_code) { |
| case VKEY_SHIFT: |
| return IsRightSideDomCode(dom_code) ? VKEY_RSHIFT : VKEY_LSHIFT; |
| case VKEY_CONTROL: |
| return IsRightSideDomCode(dom_code) ? VKEY_RCONTROL : VKEY_LCONTROL; |
| case VKEY_MENU: |
| return IsRightSideDomCode(dom_code) ? VKEY_RMENU : VKEY_LMENU; |
| case VKEY_LWIN: |
| return IsRightSideDomCode(dom_code) ? VKEY_RWIN : VKEY_LWIN; |
| case VKEY_0: |
| return (dom_code == DomCode::NUMPAD0) ? VKEY_NUMPAD0 : VKEY_0; |
| case VKEY_1: |
| return (dom_code == DomCode::NUMPAD1) ? VKEY_NUMPAD1 : VKEY_1; |
| case VKEY_2: |
| return (dom_code == DomCode::NUMPAD2) ? VKEY_NUMPAD2 : VKEY_2; |
| case VKEY_3: |
| return (dom_code == DomCode::NUMPAD3) ? VKEY_NUMPAD3 : VKEY_3; |
| case VKEY_4: |
| return (dom_code == DomCode::NUMPAD4) ? VKEY_NUMPAD4 : VKEY_4; |
| case VKEY_5: |
| return (dom_code == DomCode::NUMPAD5) ? VKEY_NUMPAD5 : VKEY_5; |
| case VKEY_6: |
| return (dom_code == DomCode::NUMPAD6) ? VKEY_NUMPAD6 : VKEY_6; |
| case VKEY_7: |
| return (dom_code == DomCode::NUMPAD7) ? VKEY_NUMPAD7 : VKEY_7; |
| case VKEY_8: |
| return (dom_code == DomCode::NUMPAD8) ? VKEY_NUMPAD8 : VKEY_8; |
| case VKEY_9: |
| return (dom_code == DomCode::NUMPAD9) ? VKEY_NUMPAD9 : VKEY_9; |
| default: |
| return key_code; |
| } |
| } |
| |
| DomCode UsLayoutKeyboardCodeToDomCode(KeyboardCode key_code) { |
| key_code = NonLocatedToLocatedKeyboardCode(key_code, DomCode::NONE); |
| for (const auto& it : kDomCodeToKeyboardCodeMap) { |
| if (it.key_code == key_code) |
| return it.dom_code; |
| } |
| for (const auto& it : kFallbackKeyboardCodeToDomCodeMap) { |
| if (it.key_code == key_code) |
| return it.dom_code; |
| } |
| return DomCode::NONE; |
| } |
| |
| KeyboardCode DomCodeToUsLayoutKeyboardCode(DomCode dom_code) { |
| const DomCodeToKeyboardCodeEntry* end = |
| kDomCodeToKeyboardCodeMap + base::size(kDomCodeToKeyboardCodeMap); |
| const DomCodeToKeyboardCodeEntry* found = std::lower_bound( |
| kDomCodeToKeyboardCodeMap, end, dom_code, |
| [](const DomCodeToKeyboardCodeEntry& a, DomCode b) { |
| return static_cast<int>(a.dom_code) < static_cast<int>(b); |
| }); |
| if ((found != end) && (found->dom_code == dom_code)) |
| return found->key_code; |
| |
| return VKEY_UNKNOWN; |
| } |
| |
| KeyboardCode DomCodeToUsLayoutNonLocatedKeyboardCode(DomCode dom_code) { |
| return LocatedToNonLocatedKeyboardCode( |
| DomCodeToUsLayoutKeyboardCode(dom_code)); |
| } |
| |
| int ModifierDomKeyToEventFlag(DomKey key) { |
| switch (key) { |
| case DomKey::ALT: |
| return EF_ALT_DOWN; |
| case DomKey::ALT_GRAPH: |
| return EF_ALTGR_DOWN; |
| case DomKey::CAPS_LOCK: |
| return EF_CAPS_LOCK_ON; |
| case DomKey::CONTROL: |
| return EF_CONTROL_DOWN; |
| case DomKey::META: |
| return EF_COMMAND_DOWN; |
| case DomKey::SHIFT: |
| return EF_SHIFT_DOWN; |
| case DomKey::SHIFT_LEVEL5: |
| return EF_MOD3_DOWN; |
| default: |
| return EF_NONE; |
| } |
| // Not represented: |
| // DomKey::ACCEL |
| // DomKey::FN |
| // DomKey::FN_LOCK |
| // DomKey::HYPER |
| // DomKey::NUM_LOCK |
| // DomKey::SCROLL_LOCK |
| // DomKey::SUPER |
| // DomKey::SYMBOL_LOCK |
| } |
| |
| } // namespace ui |