blob: 181e16964dde18767583c66319c3e8bbb0ec68b7 [file] [log] [blame]
// 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