| // Copyright 2010-2015, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "session/key_event_util.h" |
| |
| #include <cctype> |
| |
| #include "base/logging.h" |
| #include "base/port.h" |
| #include "session/commands.pb.h" |
| |
| namespace mozc { |
| using commands::KeyEvent; |
| |
| namespace { |
| const uint32 kAltMask = |
| KeyEvent::ALT | KeyEvent::LEFT_ALT | KeyEvent::RIGHT_ALT; |
| const uint32 kCtrlMask = |
| KeyEvent::CTRL | KeyEvent::LEFT_CTRL | KeyEvent::RIGHT_CTRL; |
| const uint32 kShiftMask = |
| KeyEvent::SHIFT | KeyEvent::LEFT_SHIFT | KeyEvent::RIGHT_SHIFT; |
| const uint32 kCapsMask = KeyEvent::CAPS; |
| |
| uint32 Ignore(uint32 modifiers, uint32 modifiers_to_be_ignored) { |
| return modifiers & ~modifiers_to_be_ignored; |
| } |
| |
| bool Any(uint32 modifiers_to_be_tested, uint32 modifiers_to_be_queried) { |
| return (modifiers_to_be_tested & modifiers_to_be_queried) != 0; |
| } |
| |
| bool None(uint32 modifiers_to_be_tested, uint32 modifiers_to_be_queried) { |
| return !Any(modifiers_to_be_tested, modifiers_to_be_queried); |
| } |
| |
| } // namespace |
| |
| uint32 KeyEventUtil::GetModifiers(const KeyEvent &key_event) { |
| uint32 modifiers = 0; |
| if (key_event.has_modifiers()) { |
| modifiers = key_event.modifiers(); |
| } else { |
| for (size_t i = 0; i < key_event.modifier_keys_size(); ++i) { |
| modifiers |= key_event.modifier_keys(i); |
| } |
| } |
| return modifiers; |
| } |
| |
| bool KeyEventUtil::GetKeyInformation(const KeyEvent &key_event, |
| KeyInformation *key) { |
| DCHECK(key); |
| |
| const uint16 modifier_keys = static_cast<uint16>(GetModifiers(key_event)); |
| const uint16 special_key = key_event.has_special_key() ? |
| key_event.special_key() : KeyEvent::NO_SPECIALKEY; |
| const uint32 key_code = key_event.has_key_code() ? key_event.key_code() : 0; |
| |
| // Make sure the translation from the obsolete spesification. |
| // key_code should no longer contain control characters. |
| if (0 < key_code && key_code <= 32) { |
| return false; |
| } |
| |
| *key = |
| (static_cast<KeyInformation>(modifier_keys) << 48) | |
| (static_cast<KeyInformation>(special_key) << 32) | |
| (static_cast<KeyInformation>(key_code)); |
| |
| return true; |
| } |
| |
| void KeyEventUtil::NormalizeModifiers(const KeyEvent &key_event, |
| KeyEvent *new_key_event) { |
| DCHECK(new_key_event); |
| |
| // CTRL (or ALT, SHIFT) should be set on modifier_keys when |
| // LEFT (or RIGHT) ctrl is set. |
| // LEFT_CTRL (or others) is not handled on Japanese, so we remove these. |
| const uint32 kIgnorableModifierMask = |
| (KeyEvent::CAPS | |
| KeyEvent::LEFT_ALT | KeyEvent::RIGHT_ALT | |
| KeyEvent::LEFT_CTRL | KeyEvent::RIGHT_CTRL | |
| KeyEvent::LEFT_SHIFT | KeyEvent::RIGHT_SHIFT); |
| |
| RemoveModifiers(key_event, kIgnorableModifierMask, new_key_event); |
| |
| // Reverts the flip of alphabetical key events caused by CapsLock. |
| const uint32 original_modifiers = GetModifiers(key_event); |
| if ((original_modifiers & KeyEvent::CAPS) && |
| key_event.has_key_code()) { |
| const uint32 key_code = key_event.key_code(); |
| if ('A' <= key_code && key_code <= 'Z') { |
| new_key_event->set_key_code(key_code + ('a' - 'A')); |
| } else if ('a' <= key_code && key_code <= 'z') { |
| new_key_event->set_key_code(key_code + ('A' - 'a')); |
| } |
| } |
| } |
| |
| void KeyEventUtil::NormalizeNumpadKey(const KeyEvent &key_event, |
| KeyEvent *new_key_event) { |
| DCHECK(new_key_event); |
| new_key_event->CopyFrom(key_event); |
| |
| if (!IsNumpadKey(*new_key_event)) { |
| return; |
| } |
| const KeyEvent::SpecialKey numpad_key = new_key_event->special_key(); |
| |
| // KeyEvent::SEPARATOR is transformed to Enter. |
| if (numpad_key == KeyEvent::SEPARATOR) { |
| new_key_event->set_special_key(KeyEvent::ENTER); |
| return; |
| } |
| |
| new_key_event->clear_special_key(); |
| |
| // Handles number keys |
| if (KeyEvent::NUMPAD0 <= numpad_key && numpad_key <= KeyEvent::NUMPAD9) { |
| new_key_event->set_key_code( |
| static_cast<uint32>('0' + (numpad_key - KeyEvent::NUMPAD0))); |
| return; |
| } |
| |
| char new_key_code; |
| switch (numpad_key) { |
| case KeyEvent::MULTIPLY: |
| new_key_code = '*'; |
| break; |
| case KeyEvent::ADD: |
| new_key_code = '+'; |
| break; |
| case KeyEvent::SUBTRACT: |
| new_key_code = '-'; |
| break; |
| case KeyEvent::DECIMAL: |
| new_key_code = '.'; |
| break; |
| case KeyEvent::DIVIDE: |
| new_key_code = '/'; |
| break; |
| case KeyEvent::EQUALS: |
| new_key_code = '='; |
| break; |
| case KeyEvent::COMMA: |
| new_key_code = ','; |
| break; |
| default: |
| LOG(ERROR) << "Should not reach here."; |
| return; |
| } |
| |
| new_key_event->set_key_code(static_cast<uint32>(new_key_code)); |
| } |
| |
| void KeyEventUtil::RemoveModifiers(const KeyEvent &key_event, |
| uint32 remove_modifiers, |
| KeyEvent *new_key_event) { |
| DCHECK(new_key_event); |
| new_key_event->CopyFrom(key_event); |
| |
| if (HasAlt(remove_modifiers)) { |
| remove_modifiers |= KeyEvent::LEFT_ALT | KeyEvent::RIGHT_ALT; |
| } |
| if (HasCtrl(remove_modifiers)) { |
| remove_modifiers |= KeyEvent::LEFT_CTRL | KeyEvent::RIGHT_CTRL; |
| } |
| if (HasShift(remove_modifiers)) { |
| remove_modifiers |= KeyEvent::LEFT_SHIFT | KeyEvent::RIGHT_SHIFT; |
| } |
| |
| new_key_event->clear_modifier_keys(); |
| for (size_t i = 0; i < key_event.modifier_keys_size(); ++i) { |
| const KeyEvent::ModifierKey mod_key = key_event.modifier_keys(i); |
| if (!(remove_modifiers & mod_key)) { |
| new_key_event->add_modifier_keys(mod_key); |
| } |
| } |
| } |
| |
| bool KeyEventUtil::MaybeGetKeyStub(const KeyEvent &key_event, |
| KeyInformation *key) { |
| DCHECK(key); |
| |
| // If any modifier keys were pressed, this function does nothing. |
| if (KeyEventUtil::GetModifiers(key_event) != 0) { |
| return false; |
| } |
| |
| // No stub rule is supported for special keys yet. |
| if (key_event.has_special_key()) { |
| return false; |
| } |
| |
| // Check if both key_code and key_string are invalid. |
| if ((!key_event.has_key_code() || key_event.key_code() <= 32) && |
| (!key_event.has_key_string() || key_event.key_string().empty())) { |
| return false; |
| } |
| |
| KeyEvent stub_key_event; |
| stub_key_event.set_special_key(KeyEvent::TEXT_INPUT); |
| if (!GetKeyInformation(stub_key_event, key)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool KeyEventUtil::HasAlt(uint32 modifiers) { |
| return Any(modifiers, kAltMask); |
| } |
| |
| bool KeyEventUtil::HasCtrl(uint32 modifiers) { |
| return Any(modifiers, kCtrlMask); |
| } |
| |
| bool KeyEventUtil::HasShift(uint32 modifiers) { |
| return Any(modifiers, kShiftMask); |
| } |
| |
| bool KeyEventUtil::HasCaps(uint32 modifiers) { |
| return Any(modifiers, kCapsMask); |
| } |
| |
| bool KeyEventUtil::IsAlt(uint32 modifiers) { |
| if (!HasAlt(modifiers)) { |
| return false; |
| } |
| return None(Ignore(modifiers, kCapsMask), ~kAltMask); |
| } |
| |
| bool KeyEventUtil::IsCtrl(uint32 modifiers) { |
| if (!HasCtrl(modifiers)) { |
| return false; |
| } |
| return None(Ignore(modifiers, kCapsMask), ~kCtrlMask); |
| } |
| |
| bool KeyEventUtil::IsShift(uint32 modifiers) { |
| if (!HasShift(modifiers)) { |
| return false; |
| } |
| return None(Ignore(modifiers, kCapsMask), ~kShiftMask); |
| } |
| |
| bool KeyEventUtil::IsAltCtrl(uint32 modifiers) { |
| if (!HasAlt(modifiers) || !HasCtrl(modifiers)) { |
| return false; |
| } |
| return None(Ignore(modifiers, kCapsMask), ~(kAltMask | kCtrlMask)); |
| } |
| |
| bool KeyEventUtil::IsAltShift(uint32 modifiers) { |
| if (!HasAlt(modifiers) || !HasShift(modifiers)) { |
| return false; |
| } |
| return None(Ignore(modifiers, kCapsMask), ~(kAltMask | kShiftMask)); |
| } |
| |
| bool KeyEventUtil::IsCtrlShift(uint32 modifiers) { |
| if (!HasCtrl(modifiers) || !HasShift(modifiers)) { |
| return false; |
| } |
| return None(Ignore(modifiers, kCapsMask), ~(kCtrlMask | kShiftMask)); |
| } |
| |
| bool KeyEventUtil::IsAltCtrlShift(uint32 modifiers) { |
| if (!HasAlt(modifiers) || !HasCtrl(modifiers) || !HasShift(modifiers)) { |
| return false; |
| } |
| const auto kAltCtrlShiftMask = kAltMask | kCtrlMask | kShiftMask; |
| return None(Ignore(modifiers, kCapsMask), ~kAltCtrlShiftMask); |
| } |
| |
| bool KeyEventUtil::IsLowerAlphabet(const KeyEvent &key_event) { |
| if (!key_event.has_key_code()) { |
| return false; |
| } |
| |
| const uint32 key_code = key_event.key_code(); |
| const uint32 modifier_keys = GetModifiers(key_event); |
| const bool change_case = (HasShift(modifier_keys) != HasCaps(modifier_keys)); |
| |
| if (change_case) { |
| return isupper(key_code) != 0; |
| } else { |
| return islower(key_code) != 0; |
| } |
| } |
| |
| bool KeyEventUtil::IsUpperAlphabet(const KeyEvent &key_event) { |
| if (!key_event.has_key_code()) { |
| return false; |
| } |
| |
| const uint32 key_code = key_event.key_code(); |
| const uint32 modifier_keys = GetModifiers(key_event); |
| const bool change_case = (HasShift(modifier_keys) != HasCaps(modifier_keys)); |
| |
| if (change_case) { |
| return islower(key_code) != 0; |
| } else { |
| return isupper(key_code) != 0; |
| } |
| } |
| |
| bool KeyEventUtil::IsNumpadKey(const KeyEvent &key_event) { |
| if (!key_event.has_special_key()) { |
| return false; |
| } |
| |
| const KeyEvent::SpecialKey special_key = key_event.special_key(); |
| if (KeyEvent::NUMPAD0 <= special_key && special_key <= KeyEvent::EQUALS) { |
| return true; |
| } |
| if (special_key == KeyEvent::COMMA) { |
| return true; |
| } |
| return false; |
| } |
| |
| } // namespace mozc |