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