diff options
author | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 07:58:14 +0000 |
---|---|---|
committer | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 07:58:14 +0000 |
commit | d737d61b8c63eecdca2097c5fcfccce159863070 (patch) | |
tree | 24183ab83a2cfb18c661def6f60c6da318a3f69f /ui/base/ime/character_composer.cc | |
parent | 1ea33a3eb282e4ae9eb1e8bb7dece0336460b6c2 (diff) | |
download | chromium_src-d737d61b8c63eecdca2097c5fcfccce159863070.zip chromium_src-d737d61b8c63eecdca2097c5fcfccce159863070.tar.gz chromium_src-d737d61b8c63eecdca2097c5fcfccce159863070.tar.bz2 |
Implement hexadecimal unicode sequence character composition
Still not supported:
- Preedit
- Compositing with Shift+Control pressed
BUG=chromium-os:15925
TEST=ui_unittests --gtest_filter="CharacterComposerTest.*"
Review URL: http://codereview.chromium.org/9741004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127924 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base/ime/character_composer.cc')
-rw-r--r-- | ui/base/ime/character_composer.cc | 112 |
1 files changed, 99 insertions, 13 deletions
diff --git a/ui/base/ime/character_composer.cc b/ui/base/ime/character_composer.cc index 3194967..7dcfa35 100644 --- a/ui/base/ime/character_composer.cc +++ b/ui/base/ime/character_composer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -7,9 +7,11 @@ #include <algorithm> #include <iterator> +#include "base/third_party/icu/icu_utf.h" // Note for Gtk removal: gdkkeysyms.h only contains a set of // '#define GDK_KeyName 0xNNNN' macros and does not #include any Gtk headers. #include "third_party/gtk+/gdk/gdkkeysyms.h" +#include "ui/base/events.h" #include "ui/base/glib/glib_integers.h" namespace { @@ -62,7 +64,7 @@ inline bool operator!=(const SequenceIterator& l, const SequenceIterator& r) { return !(l == r); } -// A function to compare keycode value. +// A function to compare key value. inline int CompareSequenceValue(unsigned int l, unsigned int r) { return (l > r) ? 1 : ((l < r) ? -1 : 0); } @@ -293,8 +295,8 @@ const uint16 cedilla_compose_seqs[] = { GDK_KEY_Multi_key, GDK_KEY_c, GDK_KEY_apostrophe, 0, 0, 0x00E7, }; -bool KeypressShouldBeIgnored(unsigned int keycode) { - switch(keycode) { +bool KeypressShouldBeIgnored(unsigned int keyval) { + switch(keyval) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: case GDK_KEY_Control_L: @@ -334,36 +336,106 @@ bool CheckCharacterComposeTable(const ComposeBufferType& sequence, return false; } +// Converts |character| to UTF16 string. +// Returns false when |character| is not a valid character. +bool UTF32CharacterToUTF16(uint32 character, string16* output) { + output->clear(); + // Reject invalid character. (e.g. codepoint greater than 0x10ffff) + if (!CBU_IS_UNICODE_CHAR(character)) + return false; + if (character) { + output->resize(CBU16_LENGTH(character)); + size_t i = 0; + CBU16_APPEND_UNSAFE(&(*output)[0], i, character); + } + return true; +} + +// Returns an hexadecimal digit integer (0 to 15) corresponding to |keyval|. +// -1 is returned when |keyval| cannot be a hexadecimal digit. +int KeyvalToHexDigit(unsigned int keyval) { + if (GDK_KEY_0 <= keyval && keyval <= GDK_KEY_9) + return keyval - GDK_KEY_0; + if (GDK_KEY_a <= keyval && keyval <= GDK_KEY_f) + return keyval - GDK_KEY_a + 10; + if (GDK_KEY_A <= keyval && keyval <= GDK_KEY_F) + return keyval - GDK_KEY_A + 10; + return -1; // |keyval| cannot be a hexadecimal digit. +} + } // namespace namespace ui { -CharacterComposer::CharacterComposer() {} +CharacterComposer::CharacterComposer() : composition_mode_(KEY_SEQUENCE_MODE) {} CharacterComposer::~CharacterComposer() {} void CharacterComposer::Reset() { compose_buffer_.clear(); composed_character_.clear(); + composition_mode_ = KEY_SEQUENCE_MODE; } -bool CharacterComposer::FilterKeyPress(unsigned int keycode) { - if(KeypressShouldBeIgnored(keycode)) +bool CharacterComposer::FilterKeyPress(unsigned int keyval, + unsigned int flags) { + composed_character_.clear(); + + // We don't care about modifier key presses. + if(KeypressShouldBeIgnored(keyval)) return false; - compose_buffer_.push_back(keycode); + // When the user presses Ctrl+Shift+U, maybe switch to HEX_MODE. + // We don't care about other modifiers like Alt. When CapsLock is down, we + // do nothing because what we receive is Ctrl+Shift+u (not U). + if (keyval == GDK_KEY_U && (flags & EF_SHIFT_DOWN) && + (flags & EF_CONTROL_DOWN)) { + if (composition_mode_ == KEY_SEQUENCE_MODE && compose_buffer_.empty()) { + // There is no ongoing composition. Let's switch to HEX_MODE. + composition_mode_ = HEX_MODE; + return true; + } + } + + if (composition_mode_ == HEX_MODE) { + const size_t kMaxHexSequenceLength = 8; + const int hex_digit = KeyvalToHexDigit(keyval); + + if (keyval == GDK_KEY_Escape) { + // Cancel composition when ESC is pressed. + Reset(); + } else if (keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter || + keyval == GDK_KEY_ISO_Enter || + keyval == GDK_KEY_space || keyval == GDK_KEY_KP_Space) { + // Commit the composed character when Enter or space is pressed. + CommitHex(); + } else if (keyval == GDK_KEY_BackSpace) { + // Pop back the buffer when Backspace is pressed. + if (!compose_buffer_.empty()) { + compose_buffer_.pop_back(); + } else { + // If there is no character in |compose_buffer_|, cancel composition. + Reset(); + } + } else if (hex_digit >= 0 && + compose_buffer_.size() < kMaxHexSequenceLength) { + // Add the key to the buffer if it is a hex digit. + compose_buffer_.push_back(hex_digit); + } + return true; + } + + DCHECK(composition_mode_ == KEY_SEQUENCE_MODE); + compose_buffer_.push_back(keyval); // Check compose table. - composed_character_.clear(); uint32 composed_character_utf32 = 0; if (CheckCharacterComposeTable(compose_buffer_, &composed_character_utf32)) { // Key press is recognized as a part of composition. - if (composed_character_utf32 !=0) { + if (composed_character_utf32 != 0) { // We get a composed character. compose_buffer_.clear(); - // We assume that composed character is in BMP. - if (composed_character_utf32 <= 0xffff) - composed_character_ += static_cast<char16>(composed_character_utf32); + UTF32CharacterToUTF16(composed_character_utf32, &composed_character_); } return true; } @@ -376,4 +448,18 @@ bool CharacterComposer::FilterKeyPress(unsigned int keycode) { return false; } +void CharacterComposer::CommitHex() { + DCHECK(composition_mode_ == HEX_MODE); + uint32 composed_character_utf32 = 0; + for (size_t i = 0; i != compose_buffer_.size(); ++i) { + const uint32 digit = compose_buffer_[i]; + DCHECK(0 <= digit && digit < 16); + composed_character_utf32 <<= 4; + composed_character_utf32 |= digit; + } + UTF32CharacterToUTF16(composed_character_utf32, &composed_character_); + compose_buffer_.clear(); + composition_mode_ = KEY_SEQUENCE_MODE; +} + } // namespace ui |