1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/base/ime/chromeos/character_composer.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/events/event.h"
11 #include "ui/events/event_constants.h"
12 #include "ui/events/event_utils.h"
13 #include "ui/events/keycodes/dom/dom_code.h"
14 #include "ui/events/keycodes/dom/dom_key.h"
15 #include "ui/events/keycodes/keyboard_code_conversion.h"
16 #include "ui/events/keycodes/keyboard_codes.h"
18 using base::ASCIIToUTF16
;
24 const base::char16 kCombiningGrave
= 0x0300;
25 const base::char16 kCombiningAcute
= 0x0301;
26 const base::char16 kCombiningCircumflex
= 0x0302;
27 const base::char16 kCombiningHorn
= 0x031B;
31 class CharacterComposerTest
: public testing::Test
{
33 // Returns a |KeyEvent| for a dead key press.
34 KeyEvent
* DeadKeyPress(base::char16 combining_character
) const {
36 new KeyEvent(ET_KEY_PRESSED
, VKEY_UNKNOWN
, DomCode::NONE
, EF_NONE
,
37 DomKey::DeadKeyFromCombiningCharacter(combining_character
),
42 // Expects key is filtered and no character is composed.
43 void ExpectDeadKeyFiltered(base::char16 combining_character
) {
44 scoped_ptr
<KeyEvent
> event(DeadKeyPress(combining_character
));
45 EXPECT_TRUE(character_composer_
.FilterKeyPress(*event
));
46 EXPECT_TRUE(character_composer_
.composed_character().empty());
49 // Expects key is filtered and the given character is composed.
50 void ExpectDeadKeyComposed(base::char16 combining_character
,
51 const base::string16
& expected_character
) {
52 scoped_ptr
<KeyEvent
> event(DeadKeyPress(combining_character
));
53 EXPECT_TRUE(character_composer_
.FilterKeyPress(*event
));
54 EXPECT_EQ(expected_character
, character_composer_
.composed_character());
57 // Returns a |KeyEvent| for a character key press.
58 KeyEvent
* UnicodeKeyPress(KeyboardCode vkey
,
61 base::char16 character
) const {
62 KeyEvent
* event
= new KeyEvent(ET_KEY_PRESSED
, vkey
, code
, flags
,
63 DomKey::FromCharacter(character
),
68 // Expects key is not filtered and no character is composed.
69 void ExpectUnicodeKeyNotFiltered(KeyboardCode vkey
,
72 base::char16 character
) {
73 scoped_ptr
<KeyEvent
> event(UnicodeKeyPress(vkey
, code
, flags
, character
));
74 EXPECT_FALSE(character_composer_
.FilterKeyPress(*event
));
75 EXPECT_TRUE(character_composer_
.composed_character().empty());
78 // Expects key is filtered and no character is composed.
79 void ExpectUnicodeKeyFiltered(KeyboardCode vkey
,
82 base::char16 character
) {
83 scoped_ptr
<KeyEvent
> event(UnicodeKeyPress(vkey
, code
, flags
, character
));
84 EXPECT_TRUE(character_composer_
.FilterKeyPress(*event
));
85 EXPECT_TRUE(character_composer_
.composed_character().empty());
88 // Expects key is filtered and the given character is composed.
89 void ExpectUnicodeKeyComposed(KeyboardCode vkey
,
92 base::char16 character
,
93 const base::string16
& expected_character
) {
94 scoped_ptr
<KeyEvent
> event(UnicodeKeyPress(vkey
, code
, flags
, character
));
95 EXPECT_TRUE(character_composer_
.FilterKeyPress(*event
));
96 EXPECT_EQ(expected_character
, character_composer_
.composed_character());
99 CharacterComposer character_composer_
;
102 TEST_F(CharacterComposerTest
, InitialState
) {
103 EXPECT_TRUE(character_composer_
.composed_character().empty());
106 TEST_F(CharacterComposerTest
, NormalKeyIsNotFiltered
) {
107 ExpectUnicodeKeyNotFiltered(VKEY_B
, DomCode::KEY_B
, EF_NONE
, 'B');
108 ExpectUnicodeKeyNotFiltered(VKEY_Z
, DomCode::KEY_Z
, EF_NONE
, 'Z');
109 ExpectUnicodeKeyNotFiltered(VKEY_C
, DomCode::KEY_C
, EF_NONE
, 'c');
110 ExpectUnicodeKeyNotFiltered(VKEY_M
, DomCode::KEY_M
, EF_NONE
, 'm');
111 ExpectUnicodeKeyNotFiltered(VKEY_0
, DomCode::DIGIT0
, EF_NONE
, '0');
112 ExpectUnicodeKeyNotFiltered(VKEY_1
, DomCode::DIGIT1
, EF_NONE
, '1');
113 ExpectUnicodeKeyNotFiltered(VKEY_8
, DomCode::DIGIT8
, EF_NONE
, '8');
116 TEST_F(CharacterComposerTest
, PartiallyMatchingSequence
) {
117 // Composition with sequence ['dead acute', '1'] will fail.
118 ExpectDeadKeyFiltered(kCombiningAcute
);
119 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
121 // Composition with sequence ['dead acute', 'dead circumflex', '1'] will fail.
122 ExpectDeadKeyFiltered(kCombiningAcute
);
123 ExpectDeadKeyFiltered(kCombiningCircumflex
);
124 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
127 TEST_F(CharacterComposerTest
, FullyMatchingSequences
) {
128 // LATIN SMALL LETTER A WITH ACUTE
129 ExpectDeadKeyFiltered(kCombiningAcute
);
130 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a',
131 base::string16(1, 0x00E1));
132 // LATIN CAPITAL LETTER A WITH ACUTE
133 ExpectDeadKeyFiltered(kCombiningAcute
);
134 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'A',
135 base::string16(1, 0x00C1));
137 ExpectDeadKeyFiltered(kCombiningGrave
);
138 ExpectDeadKeyComposed(kCombiningGrave
, base::string16(1, 0x0060));
139 // LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
140 ExpectDeadKeyFiltered(kCombiningAcute
);
141 ExpectDeadKeyFiltered(kCombiningCircumflex
);
142 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a',
143 base::string16(1, 0x1EA5));
144 // LATIN CAPITAL LETTER U WITH HORN AND GRAVE
145 ExpectDeadKeyFiltered(kCombiningGrave
);
146 ExpectDeadKeyFiltered(kCombiningHorn
);
147 ExpectUnicodeKeyComposed(VKEY_U
, DomCode::KEY_U
, EF_NONE
, 'U',
148 base::string16(1, 0x1EEA));
149 // LATIN CAPITAL LETTER C WITH CEDILLA
150 ExpectDeadKeyFiltered(kCombiningAcute
);
151 ExpectUnicodeKeyComposed(VKEY_C
, DomCode::KEY_C
, EF_NONE
, 'C',
152 base::string16(1, 0x00C7));
153 // LATIN SMALL LETTER C WITH CEDILLA
154 ExpectDeadKeyFiltered(kCombiningAcute
);
155 ExpectUnicodeKeyComposed(VKEY_C
, DomCode::KEY_C
, EF_NONE
, 'c',
156 base::string16(1, 0x00E7));
157 // GREEK SMALL LETTER EPSILON WITH TONOS
158 ExpectDeadKeyFiltered(kCombiningAcute
);
159 ExpectUnicodeKeyComposed(VKEY_E
, DomCode::KEY_E
, EF_NONE
, 0x03B5,
160 base::string16(1, 0x03AD));
163 TEST_F(CharacterComposerTest
, FullyMatchingSequencesAfterMatchingFailure
) {
164 // Composition with sequence ['dead acute', 'dead circumflex', '1'] will fail.
165 ExpectDeadKeyFiltered(kCombiningAcute
);
166 ExpectDeadKeyFiltered(kCombiningCircumflex
);
167 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
168 // LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
169 ExpectDeadKeyFiltered(kCombiningAcute
);
170 ExpectDeadKeyFiltered(kCombiningCircumflex
);
171 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a',
172 base::string16(1, 0x1EA5));
175 TEST_F(CharacterComposerTest
, ComposedCharacterIsClearedAfterReset
) {
176 ExpectDeadKeyFiltered(kCombiningAcute
);
177 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a',
178 base::string16(1, 0x00E1));
179 character_composer_
.Reset();
180 EXPECT_TRUE(character_composer_
.composed_character().empty());
183 TEST_F(CharacterComposerTest
, CompositionStateIsClearedAfterReset
) {
184 // Even though sequence ['dead acute', 'a'] will compose 'a with acute',
185 // no character is composed here because of reset.
186 ExpectDeadKeyFiltered(kCombiningAcute
);
187 character_composer_
.Reset();
188 ExpectUnicodeKeyNotFiltered(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a');
191 TEST_F(CharacterComposerTest
, KeySequenceCompositionPreedit
) {
192 // LATIN SMALL LETTER A WITH ACUTE
193 // preedit_string() is always empty in key sequence composition mode.
194 ExpectDeadKeyFiltered(kCombiningAcute
);
195 EXPECT_TRUE(character_composer_
.preedit_string().empty());
196 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a',
197 base::string16(1, 0x00E1));
198 EXPECT_TRUE(character_composer_
.preedit_string().empty());
201 // Verify the structure of the primary |TreeComposeChecker| table.
202 TEST_F(CharacterComposerTest
, MainTableIsCorrectlyOrdered
) {
203 // This file is included here intentionally, instead of the top of the file,
204 // because including this file at the top of the file will define a
205 // global constant and contaminate the global namespace.
206 #include "ui/base/ime/chromeos/character_composer_data.h"
207 const int kTypes
= 2;
209 // Record the subtree locations and check subtable sizes.
210 std::vector
<uint16_t> subtrees
;
212 while (index
< kCompositions
.tree_entries
) {
213 // Record the start of the subtree.
215 subtrees
.push_back(index
);
216 for (int t
= 0; t
< kTypes
; ++t
) {
217 // Skip the internal table and verify the next index is within the data.
218 index
+= 1 + 2 * kCompositions
.tree
[index
];
219 EXPECT_GT(kCompositions
.tree_entries
, index
);
220 // Skip the leaf table and verify that the next index is not past the
222 index
+= 1 + 2 * kCompositions
.tree
[index
];
223 EXPECT_GE(kCompositions
.tree_entries
, index
);
226 // We should end up at the end of the data.
227 EXPECT_EQ(kCompositions
.tree_entries
, index
);
229 // Check subtable structure.
231 while (index
< kCompositions
.tree_entries
) {
233 for (int t
= 0; t
< kTypes
; ++t
) {
234 // Check the internal subtable.
235 uint16_t previous_key
= 0;
236 uint16_t size
= kCompositions
.tree
[index
++];
237 for (uint16_t i
= 0; i
< size
; ++i
) {
238 // Verify that the subtable is sorted.
239 uint16_t key
= kCompositions
.tree
[index
];
240 uint16_t value
= kCompositions
.tree
[index
+ 1];
242 EXPECT_LT(previous_key
, key
) << index
;
244 // Verify that the internal link is valid.
245 const auto it
= std::find(subtrees
.begin(), subtrees
.end(), value
);
246 EXPECT_FALSE(subtrees
.end() == it
) << index
;
249 // Check the leaf subtable.
251 size
= kCompositions
.tree
[index
++];
252 for (uint16_t i
= 0; i
< size
; ++i
) {
253 // Verify that the subtable is sorted.
254 uint16_t key
= kCompositions
.tree
[index
];
256 EXPECT_LT(previous_key
, key
) << index
;
264 TEST_F(CharacterComposerTest
, HexadecimalComposition
) {
265 // HIRAGANA LETTER A (U+3042)
266 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
267 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 'U');
268 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
269 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, EF_NONE
, '0');
270 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, EF_NONE
, '4');
271 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
272 ExpectUnicodeKeyComposed(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ',
273 base::string16(1, 0x3042));
274 // MUSICAL KEYBOARD (U+1F3B9)
275 const base::char16 kMusicalKeyboard
[] = {0xd83c, 0xdfb9};
276 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
277 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 'U');
278 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, EF_NONE
, '1');
279 ExpectUnicodeKeyFiltered(VKEY_F
, DomCode::KEY_F
, EF_NONE
, 'f');
280 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
281 ExpectUnicodeKeyFiltered(VKEY_B
, DomCode::KEY_B
, EF_NONE
, 'b');
282 ExpectUnicodeKeyFiltered(VKEY_9
, DomCode::DIGIT9
, EF_NONE
, '9');
283 ExpectUnicodeKeyComposed(
284 VKEY_RETURN
, DomCode::ENTER
, EF_NONE
, '\r',
285 base::string16(kMusicalKeyboard
,
286 kMusicalKeyboard
+ arraysize(kMusicalKeyboard
)));
289 TEST_F(CharacterComposerTest
, HexadecimalCompositionPreedit
) {
290 // HIRAGANA LETTER A (U+3042)
291 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
292 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 'U');
293 EXPECT_EQ(ASCIIToUTF16("u"), character_composer_
.preedit_string());
294 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, 0, '3');
295 EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_
.preedit_string());
296 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, 0, '0');
297 EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_
.preedit_string());
298 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, 0, '4');
299 EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_
.preedit_string());
300 ExpectUnicodeKeyFiltered(VKEY_A
, DomCode::KEY_A
, 0, 'a');
301 EXPECT_EQ(ASCIIToUTF16("u304a"), character_composer_
.preedit_string());
302 ExpectUnicodeKeyFiltered(VKEY_BACK
, DomCode::BACKSPACE
, EF_NONE
, '\b');
303 EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_
.preedit_string());
304 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
305 ExpectUnicodeKeyComposed(VKEY_RETURN
, DomCode::ENTER
, EF_NONE
,
307 base::string16(1, 0x3042));
308 EXPECT_EQ(ASCIIToUTF16(""), character_composer_
.preedit_string());
310 // Sequence with an ignored character ('x') and Escape.
311 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
312 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 'U');
313 EXPECT_EQ(ASCIIToUTF16("u"), character_composer_
.preedit_string());
314 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, 0, '3');
315 EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_
.preedit_string());
316 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, 0, '0');
317 EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_
.preedit_string());
318 ExpectUnicodeKeyFiltered(VKEY_X
, DomCode::KEY_X
, 0, 'x');
319 EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_
.preedit_string());
320 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, 0, '4');
321 EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_
.preedit_string());
322 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, 0, '2');
323 EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer_
.preedit_string());
324 ExpectUnicodeKeyFiltered(VKEY_ESCAPE
, DomCode::ESCAPE
, EF_NONE
, 0x1B);
325 EXPECT_EQ(ASCIIToUTF16(""), character_composer_
.preedit_string());
328 TEST_F(CharacterComposerTest
, HexadecimalCompositionWithNonHexKey
) {
329 // Sequence [Ctrl+Shift+U, x, space] does not compose a character.
330 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
331 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
332 ExpectUnicodeKeyFiltered(VKEY_X
, DomCode::KEY_X
, 0, 'x');
333 ExpectUnicodeKeyFiltered(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ');
334 EXPECT_TRUE(character_composer_
.composed_character().empty());
336 // HIRAGANA LETTER A (U+3042) with a sequence [3, 0, x, 4, 2].
337 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
338 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
339 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
340 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, EF_NONE
, '0');
341 ExpectUnicodeKeyFiltered(VKEY_X
, DomCode::KEY_X
, EF_NONE
, 'x');
342 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, EF_NONE
, '4');
343 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
344 ExpectUnicodeKeyComposed(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ',
345 base::string16(1, 0x3042));
348 TEST_F(CharacterComposerTest
, HexadecimalCompositionWithAdditionalModifiers
) {
350 // HIRAGANA LETTER A (U+3042)
351 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
352 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
| EF_ALT_DOWN
, 0x15);
353 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
354 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, EF_NONE
, '0');
355 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, EF_NONE
, '4');
356 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
357 ExpectUnicodeKeyComposed(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ',
358 base::string16(1, 0x3042));
360 // Ctrl+Shift+u (CapsLock enabled)
361 ExpectUnicodeKeyNotFiltered(
362 VKEY_U
, DomCode::KEY_U
,
363 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
| EF_CAPS_LOCK_DOWN
, 'u');
366 TEST_F(CharacterComposerTest
, CancelHexadecimalComposition
) {
367 // Cancel composition with ESC.
368 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
369 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
370 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
371 ExpectUnicodeKeyFiltered(VKEY_ESCAPE
, DomCode::ESCAPE
, EF_NONE
, 0x1B);
373 // Now we can start composition again since the last composition was
375 // HIRAGANA LETTER A (U+3042)
376 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
377 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
378 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
379 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, EF_NONE
, '0');
380 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, EF_NONE
, '4');
381 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
382 ExpectUnicodeKeyComposed(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ',
383 base::string16(1, 0x3042));
386 TEST_F(CharacterComposerTest
, HexadecimalCompositionWithBackspace
) {
387 // HIRAGANA LETTER A (U+3042)
388 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
389 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
390 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, 0, '3');
391 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, 0, '0');
392 ExpectUnicodeKeyFiltered(VKEY_F
, DomCode::KEY_F
, 0, 'f');
393 ExpectUnicodeKeyFiltered(VKEY_BACK
, DomCode::BACKSPACE
, EF_NONE
, '\b');
394 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, EF_NONE
, '4');
395 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
396 ExpectUnicodeKeyComposed(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ',
397 base::string16(1, 0x3042));
400 TEST_F(CharacterComposerTest
, CancelHexadecimalCompositionWithBackspace
) {
401 // Backspace just after Ctrl+Shift+U.
402 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
403 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
404 ExpectUnicodeKeyFiltered(VKEY_BACK
, DomCode::BACKSPACE
, EF_NONE
, '\b');
405 ExpectUnicodeKeyNotFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
407 // Backspace twice after Ctrl+Shift+U and 3.
408 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
409 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
410 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, 0, '3');
411 ExpectUnicodeKeyFiltered(VKEY_BACK
, DomCode::BACKSPACE
, EF_NONE
, '\b');
412 ExpectUnicodeKeyFiltered(VKEY_BACK
, DomCode::BACKSPACE
, EF_NONE
, '\b');
413 ExpectUnicodeKeyNotFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
416 TEST_F(CharacterComposerTest
,
417 HexadecimalCompositionPreeditWithModifierPressed
) {
418 // This test case supposes X Window System uses 101 keyboard layout.
419 const int kControlShift
= EF_CONTROL_DOWN
| EF_SHIFT_DOWN
;
420 // HIRAGANA LETTER A (U+3042)
421 ExpectUnicodeKeyFiltered(ui::VKEY_U
, DomCode::KEY_U
, kControlShift
, 0x15);
422 EXPECT_EQ(ASCIIToUTF16("u"), character_composer_
.preedit_string());
423 ExpectUnicodeKeyFiltered(ui::VKEY_3
, DomCode::DIGIT3
, kControlShift
, '#');
424 EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_
.preedit_string());
425 ExpectUnicodeKeyFiltered(ui::VKEY_0
, DomCode::DIGIT0
, kControlShift
, ')');
426 EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_
.preedit_string());
427 ExpectUnicodeKeyFiltered(ui::VKEY_4
, DomCode::DIGIT4
, kControlShift
, '$');
428 EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_
.preedit_string());
429 ExpectUnicodeKeyFiltered(ui::VKEY_A
, DomCode::KEY_A
, kControlShift
, 0x01);
430 EXPECT_EQ(ASCIIToUTF16("u304a"), character_composer_
.preedit_string());
431 ExpectUnicodeKeyFiltered(ui::VKEY_BACK
, DomCode::BACKSPACE
, kControlShift
,
433 EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_
.preedit_string());
434 ExpectUnicodeKeyFiltered(ui::VKEY_2
, DomCode::DIGIT2
, kControlShift
, 0);
435 EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer_
.preedit_string());
436 ExpectUnicodeKeyComposed(VKEY_RETURN
, DomCode::ENTER
, kControlShift
,
438 base::string16(1, 0x3042));
439 EXPECT_EQ(ASCIIToUTF16(""), character_composer_
.preedit_string());
441 // Sequence with an ignored character (control + shift + 'x') and Escape.
442 ExpectUnicodeKeyFiltered(ui::VKEY_U
, DomCode::KEY_U
, kControlShift
, 'U');
443 EXPECT_EQ(ASCIIToUTF16("u"), character_composer_
.preedit_string());
444 ExpectUnicodeKeyFiltered(ui::VKEY_3
, DomCode::DIGIT3
, kControlShift
, '#');
445 EXPECT_EQ(ASCIIToUTF16("u3"), character_composer_
.preedit_string());
446 ExpectUnicodeKeyFiltered(ui::VKEY_0
, DomCode::DIGIT0
, kControlShift
, ')');
447 EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_
.preedit_string());
448 ExpectUnicodeKeyFiltered(ui::VKEY_X
, DomCode::KEY_X
, kControlShift
, 'X');
449 EXPECT_EQ(ASCIIToUTF16("u30"), character_composer_
.preedit_string());
450 ExpectUnicodeKeyFiltered(ui::VKEY_4
, DomCode::DIGIT4
, kControlShift
, '$');
451 EXPECT_EQ(ASCIIToUTF16("u304"), character_composer_
.preedit_string());
452 ExpectUnicodeKeyFiltered(ui::VKEY_2
, DomCode::DIGIT2
, kControlShift
, 0);
453 EXPECT_EQ(ASCIIToUTF16("u3042"), character_composer_
.preedit_string());
454 ExpectUnicodeKeyFiltered(ui::VKEY_ESCAPE
, DomCode::ESCAPE
, kControlShift
,
456 EXPECT_EQ(ASCIIToUTF16(""), character_composer_
.preedit_string());
459 TEST_F(CharacterComposerTest
, InvalidHexadecimalSequence
) {
461 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
462 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
463 for (int i
= 0; i
< 8; ++i
)
464 ExpectUnicodeKeyFiltered(VKEY_F
, DomCode::KEY_F
, 0, 'f');
465 ExpectUnicodeKeyFiltered(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ');
467 // U+0000 (Actually, this is a valid unicode character, but we don't
468 // compose a string with a character '\0')
469 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
470 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
471 for (int i
= 0; i
< 4; ++i
)
472 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, 0, '0');
473 ExpectUnicodeKeyFiltered(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ');
476 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
477 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
478 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
479 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, 0, '0');
480 for (int i
= 0; i
< 4; ++i
)
481 ExpectUnicodeKeyFiltered(VKEY_F
, DomCode::KEY_F
, 0, 'f');
482 ExpectUnicodeKeyFiltered(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ');
485 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
486 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
487 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
488 ExpectUnicodeKeyFiltered(VKEY_1
, DomCode::DIGIT1
, 0, '1');
489 for (int i
= 0; i
< 4; ++i
)
490 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, 0, '0');
491 ExpectUnicodeKeyFiltered(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ');
494 TEST_F(CharacterComposerTest
, HexadecimalSequenceAndDeadKey
) {
495 // LATIN SMALL LETTER A WITH ACUTE
496 ExpectDeadKeyFiltered(kCombiningAcute
);
497 ExpectUnicodeKeyComposed(VKEY_A
, DomCode::KEY_A
, EF_NONE
, 'a',
498 base::string16(1, 0x00E1));
499 // HIRAGANA LETTER A (U+3042) with dead_acute ignored.
500 ExpectUnicodeKeyFiltered(VKEY_U
, DomCode::KEY_U
,
501 EF_SHIFT_DOWN
| EF_CONTROL_DOWN
, 0x15);
502 ExpectUnicodeKeyFiltered(VKEY_3
, DomCode::DIGIT3
, EF_NONE
, '3');
503 ExpectUnicodeKeyFiltered(VKEY_0
, DomCode::DIGIT0
, EF_NONE
, '0');
504 ExpectDeadKeyFiltered(kCombiningAcute
);
505 ExpectUnicodeKeyFiltered(VKEY_4
, DomCode::DIGIT4
, EF_NONE
, '4');
506 ExpectUnicodeKeyFiltered(VKEY_2
, DomCode::DIGIT2
, EF_NONE
, '2');
507 ExpectUnicodeKeyComposed(VKEY_SPACE
, DomCode::SPACE
, EF_NONE
, ' ',
508 base::string16(1, 0x3042));