blob: 092df61840d8ffa45a2cac0f1b1fa2e0b204dfb8 [file] [log] [blame]
// Copyright 2013 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/base/ime/character_composer.h"
#include <stdint.h>
#include <memory>
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_utils.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/types/event_type.h"
using base::ASCIIToUTF16;
namespace ui {
namespace {
const base::char16 kCombiningGrave = 0x0300;
const base::char16 kCombiningAcute = 0x0301;
const base::char16 kCombiningCircumflex = 0x0302;
const base::char16 kCombiningHorn = 0x031B;
} // namespace
class CharacterComposerTest : public testing::Test {
protected:
// Returns a |KeyEvent| for a dead key press.
KeyEvent* DeadKeyPress(base::char16 combining_character) const {
KeyEvent* event =
new KeyEvent(ET_KEY_PRESSED, VKEY_UNKNOWN, DomCode::NONE, EF_NONE,
DomKey::DeadKeyFromCombiningCharacter(combining_character),
EventTimeForNow());
return event;
}
// Expects key is filtered and no character is composed.
void ExpectDeadKeyFiltered(base::char16 combining_character) {
std::unique_ptr<KeyEvent> event(DeadKeyPress(combining_character));
EXPECT_TRUE(character_composer_.FilterKeyPress(*event));
EXPECT_TRUE(character_composer_.composed_character().empty());
}
// Expects key is filtered and the given character is composed.
void ExpectDeadKeyComposed(base::char16 combining_character,
const base::string16& expected_character) {
std::unique_ptr<KeyEvent> event(DeadKeyPress(combining_character));
EXPECT_TRUE(character_composer_.FilterKeyPress(*event));
EXPECT_EQ(expected_character, character_composer_.composed_character());
}
// Returns a |KeyEvent| for a character key press.
KeyEvent* UnicodeKeyPress(KeyboardCode vkey,
DomCode code,
int flags,
base::char16 character) const {
KeyEvent* event =
new KeyEvent(ET_KEY_PRESSED, vkey, code, flags,
DomKey::FromCharacter(character), EventTimeForNow());
return event;
}
// Expects key is not filtered and no character is composed.
void ExpectUnicodeKeyNotFiltered(KeyboardCode vkey,
DomCode code,
int flags,
base::char16 character) {
std::unique_ptr<KeyEvent> event(
UnicodeKeyPress(vkey, code, flags, character));
EXPECT_FALSE(character_composer_.FilterKeyPress(*event));
EXPECT_TRUE(character_composer_.composed_character().empty());
}
// Expects key is filtered and no character is composed.
void ExpectUnicodeKeyFiltered(KeyboardCode vkey,
DomCode code,
int flags,
base::char16 character) {
std::unique_ptr<KeyEvent> event(
UnicodeKeyPress(vkey, code, flags, character));
EXPECT_TRUE(character_composer_.FilterKeyPress(*event));
EXPECT_TRUE(character_composer_.composed_character().empty());
}
// Expects key is filtered and the given character is composed.
void ExpectUnicodeKeyComposed(KeyboardCode vkey,
DomCode code,
int flags,
base::char16 character,
const base::string16& expected_character) {
std::unique_ptr<KeyEvent> event(
UnicodeKeyPress(vkey, code, flags, character));
EXPECT_TRUE(character_composer_.FilterKeyPress(*event));
EXPECT_EQ(expected_character, character_composer_.composed_character());
}
CharacterComposer character_composer_;
};
TEST_F(CharacterComposerTest, InitialState) {
EXPECT_TRUE(character_composer_.composed_character().empty());
}
TEST_F(CharacterComposerTest, NormalKeyIsNotFiltered) {
ExpectUnicodeKeyNotFiltered(VKEY_B, DomCode::US_B, EF_NONE, 'B');
ExpectUnicodeKeyNotFiltered(VKEY_Z, DomCode::US_Z, EF_NONE, 'Z');
ExpectUnicodeKeyNotFiltered(VKEY_C, DomCode::US_C, EF_NONE, 'c');
ExpectUnicodeKeyNotFiltered(VKEY_M, DomCode::US_M, EF_NONE, 'm');
ExpectUnicodeKeyNotFiltered(VKEY_0, DomCode::DIGIT0, EF_NONE, '0');
ExpectUnicodeKeyNotFiltered(VKEY_1, DomCode::DIGIT1, EF_NONE, '1');
ExpectUnicodeKeyNotFiltered(VKEY_8, DomCode::DIGIT8, EF_NONE, '8');
}
TEST_F(CharacterComposerTest, PartiallyMatchingSequence) {
// Composition with sequence ['dead acute', '1'] will fail.
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
// Composition with sequence ['dead acute', 'dead circumflex', '1'] will fail.
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectDeadKeyFiltered(kCombiningCircumflex);
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
}
TEST_F(CharacterComposerTest, FullyMatchingSequences) {
// LATIN SMALL LETTER A WITH ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x00E1));
// LATIN CAPITAL LETTER A WITH ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'A',
base::string16(1, 0x00C1));
// GRAVE ACCENT
ExpectDeadKeyFiltered(kCombiningGrave);
ExpectDeadKeyComposed(kCombiningGrave, base::string16(1, 0x0060));
// LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectDeadKeyFiltered(kCombiningCircumflex);
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x1EA5));
// LATIN CAPITAL LETTER U WITH HORN AND GRAVE
ExpectDeadKeyFiltered(kCombiningGrave);
ExpectDeadKeyFiltered(kCombiningHorn);
ExpectUnicodeKeyComposed(VKEY_U, DomCode::US_U, EF_NONE, 'U',
base::string16(1, 0x1EEA));
// LATIN CAPITAL LETTER C WITH ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_C, DomCode::US_C, EF_NONE, 'C',
base::string16(1, 0x0106));
// LATIN SMALL LETTER C WITH ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_C, DomCode::US_C, EF_NONE, 'c',
base::string16(1, 0x0107));
// GREEK SMALL LETTER EPSILON WITH TONOS
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_E, DomCode::US_E, EF_NONE, 0x03B5,
base::string16(1, 0x03AD));
// Windows-style sequences.
// LATIN SMALL LETTER A WITH ACUTE
ExpectDeadKeyFiltered('\'');
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x00E1));
// LATIN SMALL LETTER C WITH CEDILLA
ExpectDeadKeyFiltered('\'');
ExpectUnicodeKeyComposed(VKEY_C, DomCode::US_C, EF_NONE, 'c',
base::string16(1, 0x00E7));
// APOSTROPHE
ExpectDeadKeyFiltered('\'');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, '\''));
// Unmatched composition with printable character.
static constexpr base::char16 kApostropheS[] = {'\'', 's'};
ExpectDeadKeyFiltered('\'');
ExpectUnicodeKeyComposed(VKEY_S, DomCode::US_S, EF_NONE, 's',
base::string16(kApostropheS, 2));
// Unmatched composition with dead key.
static constexpr base::char16 kApostropheApostrophe[] = {'\'', '\''};
ExpectDeadKeyFiltered('\'');
ExpectDeadKeyComposed('\'', base::string16(kApostropheApostrophe, 2));
}
TEST_F(CharacterComposerTest, FullyMatchingSequencesAfterMatchingFailure) {
// Composition with sequence ['dead acute', 'dead circumflex', '1'] will fail.
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectDeadKeyFiltered(kCombiningCircumflex);
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
// LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectDeadKeyFiltered(kCombiningCircumflex);
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x1EA5));
}
TEST_F(CharacterComposerTest, ComposedCharacterIsClearedAfterReset) {
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x00E1));
character_composer_.Reset();
EXPECT_TRUE(character_composer_.composed_character().empty());
}
TEST_F(CharacterComposerTest, CompositionStateIsClearedAfterReset) {
// Even though sequence ['dead acute', 'a'] will compose 'a with acute',
// no character is composed here because of reset.
ExpectDeadKeyFiltered(kCombiningAcute);
character_composer_.Reset();
ExpectUnicodeKeyNotFiltered(VKEY_A, DomCode::US_A, EF_NONE, 'a');
}
TEST_F(CharacterComposerTest, KeySequenceCompositionPreedit) {
// LATIN SMALL LETTER A WITH ACUTE
// preedit_string() is always empty in key sequence composition mode.
ExpectDeadKeyFiltered(kCombiningAcute);
EXPECT_TRUE(character_composer_.preedit_string().empty());
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x00E1));
EXPECT_TRUE(character_composer_.preedit_string().empty());
}
// Verify the structure of the primary |TreeComposeChecker| table.
TEST_F(CharacterComposerTest, MainTableIsCorrectlyOrdered) {
// This file is included here intentionally, instead of the top of the file,
// because including this file at the top of the file will define a
// global constant and contaminate the global namespace.
#include "ui/base/ime/character_composer_data.h"
const int kTypes = 2;
// Record the subtree locations and check subtable sizes.
std::vector<uint16_t> subtrees;
uint16_t index = 0;
while (index < kCompositions.tree_entries) {
// Record the start of the subtree.
SCOPED_TRACE(index);
subtrees.push_back(index);
for (int t = 0; t < kTypes; ++t) {
// Skip the internal table and verify the next index is within the data.
index += 1 + 2 * kCompositions.tree[index];
EXPECT_GT(kCompositions.tree_entries, index);
// Skip the leaf table and verify that the next index is not past the
// end of the data.
index += 1 + 2 * kCompositions.tree[index];
EXPECT_GE(kCompositions.tree_entries, index);
}
}
// We should end up at the end of the data.
EXPECT_EQ(kCompositions.tree_entries, index);
// Check subtable structure.
index = 0;
while (index < kCompositions.tree_entries) {
SCOPED_TRACE(index);
for (int t = 0; t < kTypes; ++t) {
// Check the internal subtable.
uint16_t previous_key = 0;
uint16_t size = kCompositions.tree[index++];
for (uint16_t i = 0; i < size; ++i) {
// Verify that the subtable is sorted.
uint16_t key = kCompositions.tree[index];
uint16_t value = kCompositions.tree[index + 1];
if (i)
EXPECT_LT(previous_key, key) << index;
previous_key = key;
// Verify that the internal link is valid.
EXPECT_TRUE(base::Contains(subtrees, value)) << index;
index += 2;
}
// Check the leaf subtable.
previous_key = 0;
size = kCompositions.tree[index++];
for (uint16_t i = 0; i < size; ++i) {
// Verify that the subtable is sorted.
uint16_t key = kCompositions.tree[index];
if (i)
EXPECT_LT(previous_key, key) << index;
previous_key = key;
index += 2;
}
}
}
}
TEST_F(CharacterComposerTest, HexadecimalComposition) {
// HIRAGANA LETTER A (U+3042)
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 'U');
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, EF_NONE, '0');
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, EF_NONE, '4');
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, 0x3042));
// MUSICAL KEYBOARD (U+1F3B9)
const base::char16 kMusicalKeyboard[] = {0xd83c, 0xdfb9};
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 'U');
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, EF_NONE, '1');
ExpectUnicodeKeyFiltered(VKEY_F, DomCode::US_F, EF_NONE, 'f');
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
ExpectUnicodeKeyFiltered(VKEY_B, DomCode::US_B, EF_NONE, 'b');
ExpectUnicodeKeyFiltered(VKEY_9, DomCode::DIGIT9, EF_NONE, '9');
ExpectUnicodeKeyComposed(
VKEY_RETURN, DomCode::ENTER, EF_NONE, '\r',
base::string16(kMusicalKeyboard,
kMusicalKeyboard + base::size(kMusicalKeyboard)));
}
TEST_F(CharacterComposerTest, HexadecimalCompositionPreedit) {
// HIRAGANA LETTER A (U+3042)
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 'U');
EXPECT_EQ(ASCIIToUTF16("u"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, 0, '3');
EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, 0, '0');
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, 0, '4');
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_A, DomCode::US_A, 0, 'a');
EXPECT_EQ(ASCIIToUTF16("u304a"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_BACK, DomCode::BACKSPACE, EF_NONE, '\b');
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_RETURN, DomCode::ENTER, EF_NONE, '\r',
base::string16(1, 0x3042));
EXPECT_EQ(ASCIIToUTF16(""), character_composer_.preedit_string());
// Sequence with an ignored character ('x') and Escape.
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 'U');
EXPECT_EQ(ASCIIToUTF16("u"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, 0, '3');
EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, 0, '0');
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_X, DomCode::US_X, 0, 'x');
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, 0, '4');
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, 0, '2');
EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(VKEY_ESCAPE, DomCode::ESCAPE, EF_NONE, 0x1B);
EXPECT_EQ(ASCIIToUTF16(""), character_composer_.preedit_string());
}
TEST_F(CharacterComposerTest, HexadecimalCompositionWithNonHexKey) {
// Sequence [Ctrl+Shift+U, x, space] does not compose a character.
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_X, DomCode::US_X, 0, 'x');
ExpectUnicodeKeyFiltered(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ');
EXPECT_TRUE(character_composer_.composed_character().empty());
// HIRAGANA LETTER A (U+3042) with a sequence [3, 0, x, 4, 2].
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, EF_NONE, '0');
ExpectUnicodeKeyFiltered(VKEY_X, DomCode::US_X, EF_NONE, 'x');
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, EF_NONE, '4');
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, 0x3042));
}
TEST_F(CharacterComposerTest, HexadecimalCompositionWithAdditionalModifiers) {
// Ctrl+Shift+Alt+U
// HIRAGANA LETTER A (U+3042)
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN | EF_ALT_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, EF_NONE, '0');
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, EF_NONE, '4');
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, 0x3042));
// Ctrl+Shift+u (CapsLock enabled)
ExpectUnicodeKeyNotFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN | EF_CAPS_LOCK_ON,
'u');
}
TEST_F(CharacterComposerTest, CancelHexadecimalComposition) {
// Cancel composition with ESC.
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
ExpectUnicodeKeyFiltered(VKEY_ESCAPE, DomCode::ESCAPE, EF_NONE, 0x1B);
// Now we can start composition again since the last composition was
// cancelled.
// HIRAGANA LETTER A (U+3042)
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, EF_NONE, '0');
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, EF_NONE, '4');
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, 0x3042));
}
TEST_F(CharacterComposerTest, HexadecimalCompositionWithBackspace) {
// HIRAGANA LETTER A (U+3042)
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, 0, '3');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, 0, '0');
ExpectUnicodeKeyFiltered(VKEY_F, DomCode::US_F, 0, 'f');
ExpectUnicodeKeyFiltered(VKEY_BACK, DomCode::BACKSPACE, EF_NONE, '\b');
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, EF_NONE, '4');
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, 0x3042));
}
TEST_F(CharacterComposerTest, CancelHexadecimalCompositionWithBackspace) {
// Backspace just after Ctrl+Shift+U.
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_BACK, DomCode::BACKSPACE, EF_NONE, '\b');
ExpectUnicodeKeyNotFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
// Backspace twice after Ctrl+Shift+U and 3.
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, 0, '3');
ExpectUnicodeKeyFiltered(VKEY_BACK, DomCode::BACKSPACE, EF_NONE, '\b');
ExpectUnicodeKeyFiltered(VKEY_BACK, DomCode::BACKSPACE, EF_NONE, '\b');
ExpectUnicodeKeyNotFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
}
TEST_F(CharacterComposerTest,
HexadecimalCompositionPreeditWithModifierPressed) {
// This test case supposes X Window System uses 101 keyboard layout.
const int kControlShift = EF_CONTROL_DOWN | EF_SHIFT_DOWN;
// HIRAGANA LETTER A (U+3042)
ExpectUnicodeKeyFiltered(ui::VKEY_U, DomCode::US_U, kControlShift, 0x15);
EXPECT_EQ(ASCIIToUTF16("u"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_3, DomCode::DIGIT3, kControlShift, '#');
EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_0, DomCode::DIGIT0, kControlShift, ')');
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_4, DomCode::DIGIT4, kControlShift, '$');
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_A, DomCode::US_A, kControlShift, 0x01);
EXPECT_EQ(ASCIIToUTF16("u304a"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_BACK, DomCode::BACKSPACE, kControlShift,
'\b');
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_2, DomCode::DIGIT2, kControlShift, 0);
EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer_.preedit_string());
ExpectUnicodeKeyComposed(VKEY_RETURN, DomCode::ENTER, kControlShift, '\r',
base::string16(1, 0x3042));
EXPECT_EQ(ASCIIToUTF16(""), character_composer_.preedit_string());
// Sequence with an ignored character (control + shift + 'x') and Escape.
ExpectUnicodeKeyFiltered(ui::VKEY_U, DomCode::US_U, kControlShift, 'U');
EXPECT_EQ(ASCIIToUTF16("u"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_3, DomCode::DIGIT3, kControlShift, '#');
EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_0, DomCode::DIGIT0, kControlShift, ')');
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_X, DomCode::US_X, kControlShift, 'X');
EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_4, DomCode::DIGIT4, kControlShift, '$');
EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_2, DomCode::DIGIT2, kControlShift, 0);
EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer_.preedit_string());
ExpectUnicodeKeyFiltered(ui::VKEY_ESCAPE, DomCode::ESCAPE, kControlShift,
0x1B);
EXPECT_EQ(ASCIIToUTF16(""), character_composer_.preedit_string());
}
TEST_F(CharacterComposerTest, InvalidHexadecimalSequence) {
// U+FFFFFFFF
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
for (int i = 0; i < 8; ++i)
ExpectUnicodeKeyFiltered(VKEY_F, DomCode::US_F, 0, 'f');
ExpectUnicodeKeyFiltered(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ');
// U+0000 (Actually, this is a valid unicode character, but we don't
// compose a string with a character '\0')
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
for (int i = 0; i < 4; ++i)
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, 0, '0');
ExpectUnicodeKeyFiltered(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ');
// U+10FFFF
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, 0, '0');
for (int i = 0; i < 4; ++i)
ExpectUnicodeKeyFiltered(VKEY_F, DomCode::US_F, 0, 'f');
ExpectUnicodeKeyFiltered(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ');
// U+110000
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
ExpectUnicodeKeyFiltered(VKEY_1, DomCode::DIGIT1, 0, '1');
for (int i = 0; i < 4; ++i)
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, 0, '0');
ExpectUnicodeKeyFiltered(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ');
}
TEST_F(CharacterComposerTest, HexadecimalSequenceAndDeadKey) {
// LATIN SMALL LETTER A WITH ACUTE
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyComposed(VKEY_A, DomCode::US_A, EF_NONE, 'a',
base::string16(1, 0x00E1));
// HIRAGANA LETTER A (U+3042) with dead_acute ignored.
ExpectUnicodeKeyFiltered(VKEY_U, DomCode::US_U,
EF_SHIFT_DOWN | EF_CONTROL_DOWN, 0x15);
ExpectUnicodeKeyFiltered(VKEY_3, DomCode::DIGIT3, EF_NONE, '3');
ExpectUnicodeKeyFiltered(VKEY_0, DomCode::DIGIT0, EF_NONE, '0');
ExpectDeadKeyFiltered(kCombiningAcute);
ExpectUnicodeKeyFiltered(VKEY_4, DomCode::DIGIT4, EF_NONE, '4');
ExpectUnicodeKeyFiltered(VKEY_2, DomCode::DIGIT2, EF_NONE, '2');
ExpectUnicodeKeyComposed(VKEY_SPACE, DomCode::SPACE, EF_NONE, ' ',
base::string16(1, 0x3042));
}
} // namespace ui