1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // Keymap utils of Mozc interface.
31
32 #include "session/internal/keymap.h"
33 #include "session/internal/keymap-inl.h"
34
35 #include <memory>
36 #include <sstream>
37 #include <vector>
38
39 #include "base/config_file_stream.h"
40 #include "base/system_util.h"
41 #include "composer/key_parser.h"
42 #include "config/config_handler.h"
43 #include "protocol/commands.pb.h"
44 #include "protocol/config.pb.h"
45 #include "session/internal/keymap_factory.h"
46 #include "testing/base/public/googletest.h"
47 #include "testing/base/public/gunit.h"
48
49 namespace mozc {
50 namespace keymap {
51
52 class KeyMapTest : public testing::Test {
53 protected:
SetUp()54 virtual void SetUp() {
55 SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
56 }
57
isInputModeXCommandSupported() const58 bool isInputModeXCommandSupported() const {
59 return KeyMapManager::kInputModeXCommandSupported;
60 }
61 };
62
TEST_F(KeyMapTest,AddRule)63 TEST_F(KeyMapTest, AddRule) {
64 KeyMap<PrecompositionState> keymap;
65 commands::KeyEvent key_event;
66 // 'a'
67 key_event.set_key_code(97);
68 EXPECT_TRUE(keymap.AddRule(key_event, PrecompositionState::INSERT_CHARACTER));
69
70 // 0 is treated as null input
71 key_event.set_key_code(0);
72 EXPECT_TRUE(keymap.AddRule(key_event, PrecompositionState::INSERT_CHARACTER));
73
74 // 1 to 31 should be rejected.
75 key_event.set_key_code(1);
76 EXPECT_FALSE(keymap.AddRule(key_event,
77 PrecompositionState::INSERT_CHARACTER));
78 key_event.set_key_code(31);
79 EXPECT_FALSE(keymap.AddRule(key_event,
80 PrecompositionState::INSERT_CHARACTER));
81
82 // 32 (space) is also invalid input.
83 key_event.set_key_code(32);
84 EXPECT_FALSE(keymap.AddRule(key_event,
85 PrecompositionState::INSERT_CHARACTER));
86
87 // 33 (!) is a valid input.
88 key_event.set_key_code(33);
89 EXPECT_TRUE(keymap.AddRule(key_event, PrecompositionState::INSERT_CHARACTER));
90
91 // 8bit char is a valid input.
92 key_event.set_key_code(127);
93 EXPECT_TRUE(keymap.AddRule(key_event, PrecompositionState::INSERT_CHARACTER));
94 key_event.set_key_code(255);
95 EXPECT_TRUE(keymap.AddRule(key_event, PrecompositionState::INSERT_CHARACTER));
96 }
97
TEST_F(KeyMapTest,GetCommand)98 TEST_F(KeyMapTest, GetCommand) {
99 {
100 KeyMap<PrecompositionState> keymap;
101 commands::KeyEvent init_key_event;
102 init_key_event.set_key_code(97);
103 EXPECT_TRUE(keymap.AddRule(init_key_event,
104 PrecompositionState::INSERT_CHARACTER));
105
106 commands::KeyEvent key_event;
107 PrecompositionState::Commands command;
108 key_event.set_key_code(97);
109 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
110 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, command);
111
112 key_event.Clear();
113 key_event.set_key_code(98);
114 EXPECT_FALSE(keymap.GetCommand(key_event, &command));
115 }
116 {
117 KeyMap<PrecompositionState> keymap;
118 commands::KeyEvent init_key_event;
119 init_key_event.set_special_key(commands::KeyEvent::TEXT_INPUT);
120 EXPECT_TRUE(keymap.AddRule(init_key_event,
121 PrecompositionState::INSERT_CHARACTER));
122
123 commands::KeyEvent key_event;
124 PrecompositionState::Commands command;
125 key_event.set_key_string("hoge");
126 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
127 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, command);
128 }
129 {
130 KeyMap<CompositionState> keymap;
131 commands::KeyEvent init_key_event;
132 init_key_event.set_key_code(97);
133 EXPECT_TRUE(keymap.AddRule(init_key_event,
134 CompositionState::INSERT_CHARACTER));
135
136 commands::KeyEvent key_event;
137 CompositionState::Commands command;
138 key_event.set_key_code(97);
139 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
140 EXPECT_EQ(CompositionState::INSERT_CHARACTER, command);
141
142 key_event.Clear();
143 key_event.set_key_code(98);
144 EXPECT_FALSE(keymap.GetCommand(key_event, &command));
145 }
146 {
147 KeyMap<CompositionState> keymap;
148 commands::KeyEvent init_key_event;
149 init_key_event.set_special_key(commands::KeyEvent::ENTER);
150 EXPECT_TRUE(keymap.AddRule(init_key_event, CompositionState::COMMIT));
151
152 init_key_event.Clear();
153 init_key_event.set_special_key(commands::KeyEvent::DEL);
154 init_key_event.add_modifier_keys(commands::KeyEvent::CTRL);
155 init_key_event.add_modifier_keys(commands::KeyEvent::ALT);
156 EXPECT_TRUE(keymap.AddRule(init_key_event, CompositionState::IME_OFF));
157
158 commands::KeyEvent key_event;
159 CompositionState::Commands command;
160
161 // ENTER
162 key_event.Clear();
163 key_event.set_special_key(commands::KeyEvent::ENTER);
164 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
165 EXPECT_EQ(CompositionState::COMMIT, command);
166
167 // CTRL-ALT-DELETE
168 key_event.Clear();
169 key_event.set_special_key(commands::KeyEvent::DEL);
170 key_event.add_modifier_keys(commands::KeyEvent::CTRL);
171 key_event.add_modifier_keys(commands::KeyEvent::ALT);
172 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
173 EXPECT_EQ(CompositionState::IME_OFF, command);
174 }
175 }
176
TEST_F(KeyMapTest,GetCommandForKeyString)177 TEST_F(KeyMapTest, GetCommandForKeyString) {
178 KeyMap<PrecompositionState> keymap;
179
180 // When a key event is not registered, GetCommand should return false.
181 {
182 commands::KeyEvent key_event;
183 PrecompositionState::Commands command;
184 key_event.set_key_code(97);
185 EXPECT_FALSE(keymap.GetCommand(key_event, &command));
186 }
187
188 // When a key event is not registered, GetCommand should return false even if
189 // the key event has |key_string|. See also b/9684668
190 {
191 commands::KeyEvent key_event;
192 PrecompositionState::Commands command;
193 key_event.set_key_code(97);
194 key_event.set_key_string("a");
195 EXPECT_FALSE(keymap.GetCommand(key_event, &command));
196 }
197
198 // Special case for b/4170089. VK_PACKET on Windows will be encoded as
199 // {
200 // key_code: (empty)
201 // key_string: (the Unicode string to be input)
202 // }
203 // We always treat such key events as INSERT_CHARACTER command.
204 {
205 commands::KeyEvent key_event;
206 PrecompositionState::Commands command;
207 key_event.set_key_string("a");
208 EXPECT_FALSE(keymap.GetCommand(key_event, &command));
209 }
210
211 // After adding the rule of TEXT_INPUT -> INSERT_CHARACTER, the above cases
212 // should return INSERT_CHARACTER.
213 commands::KeyEvent text_input_key_event;
214 text_input_key_event.set_special_key(commands::KeyEvent::TEXT_INPUT);
215 keymap.AddRule(text_input_key_event, PrecompositionState::INSERT_CHARACTER);
216
217 // key_code = 97, key_string = empty
218 {
219 commands::KeyEvent key_event;
220 PrecompositionState::Commands command;
221 key_event.set_key_code(97);
222 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
223 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, command);
224 }
225
226 // key_code = 97, key_string = "a"
227 {
228 commands::KeyEvent key_event;
229 PrecompositionState::Commands command;
230 key_event.set_key_code(97);
231 key_event.set_key_string("a");
232 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
233 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, command);
234 }
235
236 // key_code = empty, key_string = "a"
237 {
238 commands::KeyEvent key_event;
239 PrecompositionState::Commands command;
240 key_event.set_key_string("a");
241 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
242 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, command);
243 }
244 }
245
TEST_F(KeyMapTest,GetCommandKeyStub)246 TEST_F(KeyMapTest, GetCommandKeyStub) {
247 KeyMap<PrecompositionState> keymap;
248 commands::KeyEvent init_key_event;
249 init_key_event.set_special_key(commands::KeyEvent::TEXT_INPUT);
250 EXPECT_TRUE(keymap.AddRule(init_key_event,
251 PrecompositionState::INSERT_CHARACTER));
252
253 PrecompositionState::Commands command;
254 commands::KeyEvent key_event;
255 key_event.set_key_code(97);
256 EXPECT_TRUE(keymap.GetCommand(key_event, &command));
257 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, command);
258 }
259
TEST_F(KeyMapTest,GetKeyMapFileName)260 TEST_F(KeyMapTest, GetKeyMapFileName) {
261 EXPECT_STREQ("system://atok.tsv",
262 KeyMapManager::GetKeyMapFileName(config::Config::ATOK));
263 EXPECT_STREQ("system://mobile.tsv",
264 KeyMapManager::GetKeyMapFileName(config::Config::MOBILE));
265 EXPECT_STREQ("system://ms-ime.tsv",
266 KeyMapManager::GetKeyMapFileName(config::Config::MSIME));
267 EXPECT_STREQ("system://kotoeri.tsv",
268 KeyMapManager::GetKeyMapFileName(config::Config::KOTOERI));
269 EXPECT_STREQ("system://chromeos.tsv",
270 KeyMapManager::GetKeyMapFileName(config::Config::CHROMEOS));
271 EXPECT_STREQ("user://keymap.tsv",
272 KeyMapManager::GetKeyMapFileName(config::Config::CUSTOM));
273 }
274
TEST_F(KeyMapTest,DefaultKeyBindings)275 TEST_F(KeyMapTest, DefaultKeyBindings) {
276 KeyMapManager manager;
277
278 std::istringstream iss("", std::istringstream::in);
279 EXPECT_TRUE(manager.LoadStream(&iss));
280
281 { // Check key bindings of TextInput.
282 commands::KeyEvent key_event;
283 KeyParser::ParseKey("TextInput", &key_event);
284
285 PrecompositionState::Commands fund_command;
286 EXPECT_TRUE(manager.GetCommandPrecomposition(key_event, &fund_command));
287 EXPECT_EQ(PrecompositionState::INSERT_CHARACTER, fund_command);
288
289 CompositionState::Commands composition_command;
290 EXPECT_TRUE(manager.GetCommandComposition(key_event, &composition_command));
291 EXPECT_EQ(CompositionState::INSERT_CHARACTER, composition_command);
292
293 ConversionState::Commands conv_command;
294 EXPECT_TRUE(manager.GetCommandConversion(key_event, &conv_command));
295 EXPECT_EQ(ConversionState::INSERT_CHARACTER, conv_command);
296 }
297
298 { // Check key bindings of Shift.
299 commands::KeyEvent key_event;
300 KeyParser::ParseKey("Shift", &key_event);
301
302 PrecompositionState::Commands fund_command;
303 EXPECT_FALSE(manager.GetCommandPrecomposition(key_event, &fund_command));
304
305 CompositionState::Commands composition_command;
306 EXPECT_TRUE(manager.GetCommandComposition(key_event, &composition_command));
307 EXPECT_EQ(CompositionState::INSERT_CHARACTER, composition_command);
308
309 ConversionState::Commands conv_command;
310 EXPECT_FALSE(manager.GetCommandConversion(key_event, &conv_command));
311 }
312 }
313
TEST_F(KeyMapTest,LoadStreamWithErrors)314 TEST_F(KeyMapTest, LoadStreamWithErrors) {
315 KeyMapManager manager;
316 std::vector<string> errors;
317 std::unique_ptr<std::istream> is(
318 ConfigFileStream::LegacyOpen("system://atok.tsv"));
319 EXPECT_TRUE(manager.LoadStreamWithErrors(is.get(), &errors));
320 EXPECT_TRUE(errors.empty());
321
322 errors.clear();
323 is.reset(ConfigFileStream::LegacyOpen("system://ms-ime.tsv"));
324 EXPECT_TRUE(manager.LoadStreamWithErrors(is.get(), &errors));
325 EXPECT_TRUE(errors.empty());
326
327 errors.clear();
328 is.reset(ConfigFileStream::LegacyOpen("system://kotoeri.tsv"));
329 EXPECT_TRUE(manager.LoadStreamWithErrors(is.get(), &errors));
330 EXPECT_TRUE(errors.empty());
331
332 errors.clear();
333 is.reset(ConfigFileStream::LegacyOpen("system://mobile.tsv"));
334 EXPECT_TRUE(manager.LoadStreamWithErrors(is.get(), &errors));
335 EXPECT_TRUE(errors.empty());
336 }
337
TEST_F(KeyMapTest,GetName)338 TEST_F(KeyMapTest, GetName) {
339 KeyMapManager manager;
340 {
341 // Direct
342 string name;
343 EXPECT_TRUE(manager.GetNameFromCommandDirect(DirectInputState::IME_ON,
344 &name));
345 EXPECT_EQ("IMEOn", name);
346 EXPECT_TRUE(manager.GetNameFromCommandDirect(DirectInputState::RECONVERT,
347 &name));
348 EXPECT_EQ("Reconvert", name);
349 }
350 {
351 // Precomposition
352 string name;
353 EXPECT_TRUE(manager.GetNameFromCommandPrecomposition(
354 PrecompositionState::IME_OFF, &name));
355 EXPECT_EQ("IMEOff", name);
356 EXPECT_TRUE(manager.GetNameFromCommandPrecomposition(
357 PrecompositionState::IME_ON, &name));
358 EXPECT_EQ("IMEOn", name);
359 EXPECT_TRUE(manager.GetNameFromCommandPrecomposition(
360 PrecompositionState::INSERT_CHARACTER, &name));
361 EXPECT_EQ("InsertCharacter", name);
362 EXPECT_TRUE(manager.GetNameFromCommandPrecomposition(
363 PrecompositionState::RECONVERT, &name));
364 EXPECT_EQ("Reconvert", name);
365 }
366 {
367 // Composition
368 string name;
369 EXPECT_TRUE(manager.GetNameFromCommandComposition(
370 CompositionState::IME_OFF, &name));
371 EXPECT_EQ("IMEOff", name);
372 EXPECT_TRUE(manager.GetNameFromCommandComposition(
373 CompositionState::IME_ON, &name));
374 EXPECT_EQ("IMEOn", name);
375 EXPECT_TRUE(manager.GetNameFromCommandComposition(
376 CompositionState::INSERT_CHARACTER, &name));
377 EXPECT_EQ("InsertCharacter", name);
378 }
379 {
380 // Conversion
381 string name;
382 EXPECT_TRUE(manager.GetNameFromCommandConversion(
383 ConversionState::IME_OFF, &name));
384 EXPECT_EQ("IMEOff", name);
385 EXPECT_TRUE(manager.GetNameFromCommandConversion(
386 ConversionState::IME_ON, &name));
387 EXPECT_EQ("IMEOn", name);
388 EXPECT_TRUE(manager.GetNameFromCommandConversion(
389 ConversionState::INSERT_CHARACTER, &name));
390 EXPECT_EQ("InsertCharacter", name);
391 }
392 }
393
TEST_F(KeyMapTest,DirectModeDoesNotSupportInsertSpace)394 TEST_F(KeyMapTest, DirectModeDoesNotSupportInsertSpace) {
395 // InsertSpace, InsertAlternateSpace, InsertHalfSpace, and InsertFullSpace
396 // are not supported in direct mode.
397 KeyMapManager manager;
398 std::set<string> names;
399 manager.GetAvailableCommandNameDirect(&names);
400
401 // We cannot use EXPECT_EQ because of overload resolution here.
402 EXPECT_TRUE(names.end() == names.find("InsertSpace"));
403 EXPECT_TRUE(names.end() == names.find("InsertAlternateSpace"));
404 EXPECT_TRUE(names.end() == names.find("InsertHalfSpace"));
405 EXPECT_TRUE(names.end() == names.find("InsertFullSpace"));
406 }
407
TEST_F(KeyMapTest,ShiftTabToConvertPrev)408 TEST_F(KeyMapTest, ShiftTabToConvertPrev) {
409 // http://b/2973471
410 // Shift+TAB does not work on a suggestion window
411
412 commands::KeyEvent key_event;
413 ConversionState::Commands conv_command;
414
415 { // MSIME
416 KeyMapManager *manager =
417 KeyMapFactory::GetKeyMapManager(config::Config::MSIME);
418 KeyParser::ParseKey("Shift Tab", &key_event);
419 EXPECT_TRUE(manager->GetCommandConversion(key_event, &conv_command));
420 EXPECT_EQ(ConversionState::CONVERT_PREV, conv_command);
421 }
422
423 { // Kotoeri
424 KeyMapManager *manager =
425 KeyMapFactory::GetKeyMapManager(config::Config::KOTOERI);
426 KeyParser::ParseKey("Shift Tab", &key_event);
427 EXPECT_TRUE(manager->GetCommandConversion(key_event, &conv_command));
428 EXPECT_EQ(ConversionState::CONVERT_PREV, conv_command);
429 }
430
431 { // ATOK
432 KeyMapManager *manager =
433 KeyMapFactory::GetKeyMapManager(config::Config::ATOK);
434 KeyParser::ParseKey("Shift Tab", &key_event);
435 EXPECT_TRUE(manager->GetCommandConversion(key_event, &conv_command));
436 EXPECT_EQ(ConversionState::CONVERT_PREV, conv_command);
437 }
438 }
439
TEST_F(KeyMapTest,LaunchToolTest)440 TEST_F(KeyMapTest, LaunchToolTest) {
441 config::Config config;
442 commands::KeyEvent key_event;
443 PrecompositionState::Commands conv_command;
444
445 { // ATOK
446 KeyMapManager *manager =
447 KeyMapFactory::GetKeyMapManager(config::Config::ATOK);
448
449 KeyParser::ParseKey("Ctrl F7", &key_event);
450 EXPECT_TRUE(manager->GetCommandPrecomposition(key_event, &conv_command));
451 EXPECT_EQ(PrecompositionState::LAUNCH_WORD_REGISTER_DIALOG, conv_command);
452
453 KeyParser::ParseKey("Ctrl F12", &key_event);
454 EXPECT_TRUE(manager->GetCommandPrecomposition(key_event, &conv_command));
455 EXPECT_EQ(PrecompositionState::LAUNCH_CONFIG_DIALOG, conv_command);
456 }
457
458 // http://b/3432829
459 // MS-IME does not have the key-binding "Ctrl F7" in precomposition mode.
460 {
461 KeyMapManager *manager =
462 KeyMapFactory::GetKeyMapManager(config::Config::MSIME);
463
464 KeyParser::ParseKey("Ctrl F7", &key_event);
465 EXPECT_FALSE(manager->GetCommandPrecomposition(key_event, &conv_command));
466 }
467 }
468
TEST_F(KeyMapTest,Undo)469 TEST_F(KeyMapTest, Undo) {
470 PrecompositionState::Commands command;
471 commands::KeyEvent key_event;
472
473 { // ATOK
474 KeyMapManager *manager =
475 KeyMapFactory::GetKeyMapManager(config::Config::ATOK);
476 KeyParser::ParseKey("Ctrl Backspace", &key_event);
477 EXPECT_TRUE(manager->GetCommandPrecomposition(key_event, &command));
478 EXPECT_EQ(PrecompositionState::UNDO, command);
479 }
480 { // MSIME
481 KeyMapManager *manager =
482 KeyMapFactory::GetKeyMapManager(config::Config::MSIME);
483
484 KeyParser::ParseKey("Ctrl Backspace", &key_event);
485 EXPECT_TRUE(manager->GetCommandPrecomposition(key_event, &command));
486 EXPECT_EQ(PrecompositionState::UNDO, command);
487 }
488 { // KOTOERI
489 KeyMapManager *manager =
490 KeyMapFactory::GetKeyMapManager(config::Config::KOTOERI);
491
492 KeyParser::ParseKey("Ctrl Backspace", &key_event);
493 EXPECT_TRUE(manager->GetCommandPrecomposition(key_event, &command));
494 EXPECT_EQ(PrecompositionState::UNDO, command);
495 }
496 }
497
TEST_F(KeyMapTest,Reconvert)498 TEST_F(KeyMapTest, Reconvert) {
499 DirectInputState::Commands direct_command;
500 PrecompositionState::Commands precomposition_command;
501 commands::KeyEvent key_event;
502
503 { // ATOK
504 KeyMapManager *manager =
505 KeyMapFactory::GetKeyMapManager(config::Config::ATOK);
506
507 KeyParser::ParseKey("Shift Henkan", &key_event);
508 EXPECT_TRUE(manager->GetCommandDirect(key_event, &direct_command));
509 EXPECT_EQ(DirectInputState::RECONVERT, direct_command);
510 EXPECT_TRUE(manager->GetCommandPrecomposition(
511 key_event, &precomposition_command));
512 EXPECT_EQ(PrecompositionState::RECONVERT, precomposition_command);
513 }
514 { // MSIME
515 KeyMapManager *manager =
516 KeyMapFactory::GetKeyMapManager(config::Config::MSIME);
517
518 KeyParser::ParseKey("Henkan", &key_event);
519 EXPECT_TRUE(manager->GetCommandDirect(key_event, &direct_command));
520 EXPECT_EQ(DirectInputState::RECONVERT, direct_command);
521 EXPECT_TRUE(manager->GetCommandPrecomposition(
522 key_event, &precomposition_command));
523 EXPECT_EQ(PrecompositionState::RECONVERT, precomposition_command);
524 }
525 { // KOTOERI
526 KeyMapManager *manager =
527 KeyMapFactory::GetKeyMapManager(config::Config::KOTOERI);
528
529 KeyParser::ParseKey("Ctrl Shift r", &key_event);
530 EXPECT_TRUE(manager->GetCommandDirect(key_event, &direct_command));
531 EXPECT_EQ(DirectInputState::RECONVERT, direct_command);
532 EXPECT_TRUE(manager->GetCommandPrecomposition(
533 key_event, &precomposition_command));
534 EXPECT_EQ(PrecompositionState::RECONVERT, precomposition_command);
535 }
536 }
537
TEST_F(KeyMapTest,Initialize)538 TEST_F(KeyMapTest, Initialize) {
539 KeyMapManager manager;
540 config::Config::SessionKeymap keymap_setting;
541 commands::KeyEvent key_event;
542 ConversionState::Commands conv_command;
543
544 { // ATOK
545 keymap_setting = config::Config::ATOK;
546 manager.Initialize(keymap_setting);
547 KeyParser::ParseKey("Right", &key_event);
548 EXPECT_TRUE(manager.GetCommandConversion(key_event, &conv_command));
549 EXPECT_EQ(ConversionState::SEGMENT_WIDTH_EXPAND, conv_command);
550 }
551 { // MSIME
552 keymap_setting = config::Config::MSIME;
553 manager.Initialize(keymap_setting);
554 KeyParser::ParseKey("Right", &key_event);
555 EXPECT_TRUE(manager.GetCommandConversion(key_event, &conv_command));
556 EXPECT_EQ(ConversionState::SEGMENT_FOCUS_RIGHT, conv_command);
557 }
558 }
559
TEST_F(KeyMapTest,AddCommand)560 TEST_F(KeyMapTest, AddCommand) {
561 KeyMapManager manager;
562 commands::KeyEvent key_event;
563 const char kKeyEvent[] = "Ctrl Shift Insert";
564
565 KeyParser::ParseKey(kKeyEvent, &key_event);
566
567 { // Add command
568 CompositionState::Commands command;
569 EXPECT_FALSE(manager.GetCommandComposition(key_event, &command));
570
571 EXPECT_TRUE(manager.AddCommand("Composition", kKeyEvent, "Cancel"));
572
573 EXPECT_TRUE(manager.GetCommandComposition(key_event, &command));
574 EXPECT_EQ(CompositionState::CANCEL, command);
575 }
576
577 { // Error detections
578 EXPECT_FALSE(manager.AddCommand("void", kKeyEvent, "Cancel"));
579 EXPECT_FALSE(manager.AddCommand("Composition", kKeyEvent, "Unknown"));
580 EXPECT_FALSE(manager.AddCommand("Composition", "INVALID", "Cancel"));
581 }
582 }
583
TEST_F(KeyMapTest,ZeroQuerySuggestion)584 TEST_F(KeyMapTest, ZeroQuerySuggestion) {
585 KeyMapManager manager;
586 EXPECT_TRUE(manager.AddCommand("ZeroQuerySuggestion",
587 "ESC", "Cancel"));
588 EXPECT_TRUE(manager.AddCommand("ZeroQuerySuggestion",
589 "Tab", "PredictAndConvert"));
590 EXPECT_TRUE(manager.AddCommand("ZeroQuerySuggestion",
591 "Shift Enter", "CommitFirstSuggestion"));
592 // For fallback testing
593 EXPECT_TRUE(manager.AddCommand("Precomposition", "Ctrl Backspace", "Revert"));
594
595 commands::KeyEvent key_event;
596 PrecompositionState::Commands command;
597
598 KeyParser::ParseKey("ESC", &key_event);
599 EXPECT_TRUE(manager.GetCommandZeroQuerySuggestion(key_event, &command));
600 EXPECT_EQ(PrecompositionState::CANCEL, command);
601
602 KeyParser::ParseKey("Tab", &key_event);
603 EXPECT_TRUE(manager.GetCommandZeroQuerySuggestion(key_event, &command));
604 EXPECT_EQ(PrecompositionState::PREDICT_AND_CONVERT, command);
605
606 KeyParser::ParseKey("Shift Enter", &key_event);
607 EXPECT_TRUE(manager.GetCommandZeroQuerySuggestion(key_event, &command));
608 EXPECT_EQ(PrecompositionState::COMMIT_FIRST_SUGGESTION, command);
609
610 KeyParser::ParseKey("Ctrl Backspace", &key_event);
611 EXPECT_TRUE(manager.GetCommandZeroQuerySuggestion(key_event, &command));
612 EXPECT_EQ(PrecompositionState::REVERT, command);
613 }
614
TEST_F(KeyMapTest,CapsLock)615 TEST_F(KeyMapTest, CapsLock) {
616 // MSIME
617 KeyMapManager *manager =
618 KeyMapFactory::GetKeyMapManager(config::Config::MSIME);
619 commands::KeyEvent key_event;
620 KeyParser::ParseKey("CAPS a", &key_event);
621
622 ConversionState::Commands conv_command;
623 EXPECT_TRUE(manager->GetCommandConversion(key_event, &conv_command));
624 EXPECT_EQ(ConversionState::INSERT_CHARACTER, conv_command);
625 }
626
TEST_F(KeyMapTest,ShortcutKeysWithCapsLock_Issue5627459)627 TEST_F(KeyMapTest, ShortcutKeysWithCapsLock_Issue5627459) {
628 // MSIME
629 KeyMapManager *manager =
630 KeyMapFactory::GetKeyMapManager(config::Config::MSIME);
631
632 commands::KeyEvent key_event;
633 CompositionState::Commands composition_command;
634
635 // "Ctrl CAPS H" means that Ctrl and H key are pressed w/o shift key.
636 // See the description in command.proto.
637 KeyParser::ParseKey("Ctrl CAPS H", &key_event);
638 EXPECT_TRUE(manager->GetCommandComposition(key_event, &composition_command));
639 EXPECT_EQ(CompositionState::BACKSPACE, composition_command);
640
641 // "Ctrl CAPS h" means that Ctrl, Shift and H key are pressed.
642 KeyParser::ParseKey("Ctrl CAPS h", &key_event);
643 EXPECT_FALSE(manager->GetCommandComposition(key_event, &composition_command));
644 }
645
646 // InputModeX is not supported on MacOSX.
TEST_F(KeyMapTest,InputModeChangeIsNotEnabledOnChromeOs_Issue13947207)647 TEST_F(KeyMapTest, InputModeChangeIsNotEnabledOnChromeOs_Issue13947207) {
648 if (!isInputModeXCommandSupported()) {
649 return;
650 }
651
652 KeyMapManager manager;
653 config::Config::SessionKeymap keymap_setting;
654 commands::KeyEvent key_event;
655 ConversionState::Commands conv_command;
656
657 { // MSIME
658 keymap_setting = config::Config::MSIME;
659 manager.Initialize(keymap_setting);
660 KeyParser::ParseKey("Hiragana", &key_event);
661 EXPECT_TRUE(manager.GetCommandConversion(key_event, &conv_command));
662 EXPECT_EQ(ConversionState::INPUT_MODE_HIRAGANA, conv_command);
663 }
664 { // CHROMEOS
665 keymap_setting = config::Config::CHROMEOS;
666 manager.Initialize(keymap_setting);
667 KeyParser::ParseKey("Hiragana", &key_event);
668 EXPECT_FALSE(manager.GetCommandConversion(key_event, &conv_command));
669 }
670 }
671
672 } // namespace keymap
673 } // namespace mozc
674