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 #include "unix/ibus/key_translator.h"
31 
32 #include <memory>
33 #include <set>
34 
35 #include "protocol/commands.pb.h"
36 #include "testing/base/public/gunit.h"
37 
38 namespace mozc {
39 namespace ibus {
40 
41 struct {
42   guint ibus_key;
43   commands::KeyEvent::SpecialKey mozc_key;
44 } kSpecialKeys[] = {
45   {IBUS_space, commands::KeyEvent::SPACE},
46   {IBUS_Return, commands::KeyEvent::ENTER},
47   {IBUS_Left, commands::KeyEvent::LEFT},
48   {IBUS_Right, commands::KeyEvent::RIGHT},
49   {IBUS_Up, commands::KeyEvent::UP},
50   {IBUS_Down, commands::KeyEvent::DOWN},
51   {IBUS_Escape, commands::KeyEvent::ESCAPE},
52   {IBUS_Delete, commands::KeyEvent::DEL},
53   {IBUS_BackSpace, commands::KeyEvent::BACKSPACE},
54   {IBUS_Insert, commands::KeyEvent::INSERT},
55   {IBUS_Henkan, commands::KeyEvent::HENKAN},
56   {IBUS_Muhenkan, commands::KeyEvent::MUHENKAN},
57   {IBUS_Hiragana, commands::KeyEvent::KANA},
58   {IBUS_Katakana, commands::KeyEvent::KATAKANA},
59   {IBUS_Hiragana_Katakana, commands::KeyEvent::KANA},
60   {IBUS_Eisu_toggle, commands::KeyEvent::EISU},
61   {IBUS_Home, commands::KeyEvent::HOME},
62   {IBUS_End, commands::KeyEvent::END},
63   {IBUS_Tab, commands::KeyEvent::TAB},
64   {IBUS_F1, commands::KeyEvent::F1},
65   {IBUS_F2, commands::KeyEvent::F2},
66   {IBUS_F3, commands::KeyEvent::F3},
67   {IBUS_F4, commands::KeyEvent::F4},
68   {IBUS_F5, commands::KeyEvent::F5},
69   {IBUS_F6, commands::KeyEvent::F6},
70   {IBUS_F7, commands::KeyEvent::F7},
71   {IBUS_F8, commands::KeyEvent::F8},
72   {IBUS_F9, commands::KeyEvent::F9},
73   {IBUS_F10, commands::KeyEvent::F10},
74   {IBUS_F11, commands::KeyEvent::F11},
75   {IBUS_F12, commands::KeyEvent::F12},
76   {IBUS_F13, commands::KeyEvent::F13},
77   {IBUS_F14, commands::KeyEvent::F14},
78   {IBUS_F15, commands::KeyEvent::F15},
79   {IBUS_F16, commands::KeyEvent::F16},
80   {IBUS_F17, commands::KeyEvent::F17},
81   {IBUS_F18, commands::KeyEvent::F18},
82   {IBUS_F19, commands::KeyEvent::F19},
83   {IBUS_F20, commands::KeyEvent::F20},
84   {IBUS_F21, commands::KeyEvent::F21},
85   {IBUS_F22, commands::KeyEvent::F22},
86   {IBUS_F23, commands::KeyEvent::F23},
87   {IBUS_F24, commands::KeyEvent::F24},
88   {IBUS_Page_Up, commands::KeyEvent::PAGE_UP},
89   {IBUS_Page_Down, commands::KeyEvent::PAGE_DOWN},
90   {IBUS_KP_0, commands::KeyEvent::NUMPAD0},
91   {IBUS_KP_1, commands::KeyEvent::NUMPAD1},
92   {IBUS_KP_2, commands::KeyEvent::NUMPAD2},
93   {IBUS_KP_3, commands::KeyEvent::NUMPAD3},
94   {IBUS_KP_4, commands::KeyEvent::NUMPAD4},
95   {IBUS_KP_5, commands::KeyEvent::NUMPAD5},
96   {IBUS_KP_6, commands::KeyEvent::NUMPAD6},
97   {IBUS_KP_7, commands::KeyEvent::NUMPAD7},
98   {IBUS_KP_8, commands::KeyEvent::NUMPAD8},
99   {IBUS_KP_9, commands::KeyEvent::NUMPAD9},
100   {IBUS_KP_Equal, commands::KeyEvent::EQUALS},
101   {IBUS_KP_Multiply, commands::KeyEvent::MULTIPLY},
102   {IBUS_KP_Add, commands::KeyEvent::ADD},
103   {IBUS_KP_Separator, commands::KeyEvent::SEPARATOR},
104   {IBUS_KP_Subtract, commands::KeyEvent::SUBTRACT},
105   {IBUS_KP_Decimal, commands::KeyEvent::DECIMAL},
106   {IBUS_KP_Divide, commands::KeyEvent::DIVIDE},
107   {IBUS_KP_Space, commands::KeyEvent::SPACE},
108   {IBUS_KP_Tab, commands::KeyEvent::TAB},
109   {IBUS_KP_Enter, commands::KeyEvent::ENTER},
110   {IBUS_KP_Home, commands::KeyEvent::HOME},
111   {IBUS_KP_Left, commands::KeyEvent::LEFT},
112   {IBUS_KP_Up, commands::KeyEvent::UP},
113   {IBUS_KP_Right, commands::KeyEvent::RIGHT},
114   {IBUS_KP_Down, commands::KeyEvent::DOWN},
115   {IBUS_KP_Page_Up, commands::KeyEvent::PAGE_UP},
116   {IBUS_KP_Page_Down, commands::KeyEvent::PAGE_DOWN},
117   {IBUS_KP_End, commands::KeyEvent::END},
118   {IBUS_KP_Delete, commands::KeyEvent::DEL},
119   {IBUS_KP_Insert, commands::KeyEvent::INSERT},
120   {IBUS_Caps_Lock, commands::KeyEvent::CAPS_LOCK},
121   {IBUS_ISO_Left_Tab, commands::KeyEvent::TAB},
122 };
123 
124 // Checks "container" contains "key" value or not
IsContained(commands::KeyEvent_ModifierKey key,const::google::protobuf::RepeatedField<int> & container)125 bool IsContained(commands::KeyEvent_ModifierKey key,
126                  const ::google::protobuf::RepeatedField<int>& container) {
127   for (int i = 0; i< container.size(); ++i) {
128     if (container.Get(i) == key) {
129       return true;
130     }
131   }
132   return false;
133 }
134 
135 class KeyTranslatorTest : public testing::Test {
136  protected:
KeyTranslatorTest()137   KeyTranslatorTest() {}
~KeyTranslatorTest()138   ~KeyTranslatorTest() {}
139 
SetUp()140   virtual void SetUp() {
141     translator_.reset(new KeyTranslator);
142   }
143 
144   std::unique_ptr<KeyTranslator> translator_;
145 };
146 
TEST_F(KeyTranslatorTest,TranslateAscii)147 TEST_F(KeyTranslatorTest, TranslateAscii) {
148   commands::KeyEvent out;
149   // ' ' (0x20) is treated as a special key by Mozc.
150   EXPECT_TRUE(translator_->Translate(0x20, 0, 0, config::Config::ROMAN, true,
151                                      &out));
152   EXPECT_FALSE(out.has_key_code());
153   EXPECT_TRUE(out.has_special_key());
154   EXPECT_EQ(0, out.modifier_keys_size());
155 
156   for (char c = 0x21; c < 0x7f; ++c) {
157     EXPECT_TRUE(translator_->Translate(c, 0, 0, config::Config::ROMAN, true,
158                                        &out));
159     EXPECT_TRUE(out.has_key_code());
160     EXPECT_FALSE(out.has_special_key());
161     EXPECT_EQ(c, out.key_code());
162     EXPECT_EQ(0, out.modifier_keys_size());
163   }
164 }
165 
TEST_F(KeyTranslatorTest,TranslateSpecial)166 TEST_F(KeyTranslatorTest, TranslateSpecial) {
167   commands::KeyEvent out;
168   for (int i = 0; i < arraysize(kSpecialKeys); ++i) {
169     EXPECT_TRUE(translator_->Translate(kSpecialKeys[i].ibus_key, 0, 0,
170                                        config::Config::ROMAN, true, &out));
171     EXPECT_FALSE(out.has_key_code());
172     EXPECT_TRUE(out.has_special_key());
173     EXPECT_EQ(kSpecialKeys[i].mozc_key, out.special_key());
174     EXPECT_EQ(0, out.modifier_keys_size());
175   }
176 
177   // Check Hiragana_Katakana local hack. The detail is described in
178   // key_translator.cc file.
179   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, 0,
180                                      config::Config::ROMAN, true, &out));
181   EXPECT_FALSE(out.has_key_code());
182   ASSERT_TRUE(out.has_special_key());
183   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
184   EXPECT_EQ(0, out.modifier_keys_size());
185 }
186 
TEST_F(KeyTranslatorTest,TranslateSingleModifierMasks)187 TEST_F(KeyTranslatorTest, TranslateSingleModifierMasks) {
188   commands::KeyEvent out;
189 
190   // CTRL modifier
191   // C-F1
192   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, IBUS_CONTROL_MASK,
193                                      config::Config::ROMAN, true, &out));
194   ASSERT_EQ(1, out.modifier_keys_size());
195 
196   // C-a
197   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', IBUS_CONTROL_MASK,
198                                      config::Config::ROMAN, true, &out));
199   ASSERT_EQ(1, out.modifier_keys_size());
200   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
201 
202   // SHIFT modifier
203   // S-F1
204   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, IBUS_SHIFT_MASK,
205                                      config::Config::ROMAN, true, &out));
206   ASSERT_EQ(1, out.modifier_keys_size());
207   EXPECT_EQ(commands::KeyEvent::SHIFT, out.modifier_keys(0));
208 
209   // S-a
210   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', IBUS_SHIFT_MASK,
211                                      config::Config::ROMAN, true, &out));
212   EXPECT_EQ(0, out.modifier_keys_size());
213 
214   // S-0
215   // TODO(nona): Resolve Shift-0 problem (b/4338394)
216   // We have to check the behavior of Shift-0, because most of japanese
217   // keyboard are not assigned Shift-0 character. So that, we expect the client
218   // send keycode='0'(\x30) with shift modifier, but currently only send
219   // keycode='0'. There are few difficulties because the mapping of Shift-0 are
220   // controled xkb in X11, but the way to get the mapping is unclear.
221 
222   // ALT modifier
223   // M-F1
224   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, IBUS_MOD1_MASK,
225                                      config::Config::ROMAN, true, &out));
226   ASSERT_EQ(1, out.modifier_keys_size());
227   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
228 
229   // M-a
230   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', IBUS_MOD1_MASK,
231                                      config::Config::ROMAN, true, &out));
232   ASSERT_EQ(1, out.modifier_keys_size());
233   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
234 }
235 
TEST_F(KeyTranslatorTest,TranslateMultipleModifierMasks)236 TEST_F(KeyTranslatorTest, TranslateMultipleModifierMasks) {
237   commands::KeyEvent out;
238   guint modifier;
239 
240   // CTRL + SHIFT modifier
241   // C-S-F1 (CTRL + SHIFT + SpecialKey)
242   modifier = IBUS_CONTROL_MASK | IBUS_SHIFT_MASK;
243   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, modifier,
244                                      config::Config::ROMAN, true, &out));
245   EXPECT_EQ(2, out.modifier_keys_size());
246   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
247   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
248 
249   // C-S-a (CTRL + SHIFT + OtherKey)
250   modifier = IBUS_CONTROL_MASK | IBUS_SHIFT_MASK;
251   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', modifier,
252                                      config::Config::ROMAN, true, &out));
253   EXPECT_EQ(2, out.modifier_keys_size());
254   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
255   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
256 
257   // CTRL + ALT modifier
258   // C-M-F1 (CTRL + ALT + SpecialKey)
259   modifier = IBUS_CONTROL_MASK | IBUS_MOD1_MASK;
260   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, modifier,
261                                      config::Config::ROMAN, true, &out));
262   EXPECT_EQ(2, out.modifier_keys_size());
263   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
264   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
265 
266   // C-M-a (CTRL + ALT + OtherKey)
267   modifier = IBUS_CONTROL_MASK | IBUS_MOD1_MASK;
268   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', modifier,
269                                      config::Config::ROMAN, true, &out));
270   EXPECT_EQ(2, out.modifier_keys_size());
271   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
272   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
273 
274   // SHIFT + ALT modifier
275   // S-M-F1 (CTRL + ALT + SpecialKey)
276   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK;
277   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, modifier,
278                                      config::Config::ROMAN, true, &out));
279   EXPECT_EQ(2, out.modifier_keys_size());
280   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
281   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
282 
283   // S-M-a (CTRL + ALT + OtherKey)
284   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK;
285   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', modifier,
286                                      config::Config::ROMAN, true, &out));
287   EXPECT_EQ(2, out.modifier_keys_size());
288   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
289   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
290 
291   // CTRL + SHIFT + ALT modifier
292   // C-S-M-F1 (CTRL + SHIFT + ALT + SpecialKey)
293   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
294   EXPECT_TRUE(translator_->Translate(IBUS_F1, 0, modifier,
295                                      config::Config::ROMAN, true, &out));
296   EXPECT_EQ(3, out.modifier_keys_size());
297   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
298   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
299   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
300 
301   // C-S-M-a (CTRL + SHFIT + ALT + OtherKey)
302   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
303   EXPECT_TRUE(translator_->Translate(IBUS_A, 'a', modifier,
304                                      config::Config::ROMAN, true, &out));
305   EXPECT_EQ(3, out.modifier_keys_size());
306   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
307   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
308   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
309 }
310 
TEST_F(KeyTranslatorTest,HiraganaKatakanaHandlingWithSingleModifierTest)311 TEST_F(KeyTranslatorTest, HiraganaKatakanaHandlingWithSingleModifierTest) {
312   // Check Hiragana_Katakana local hack. The detail is described in
313   // key_translator.cc file.
314   commands::KeyEvent out;
315 
316   // S-Hiragana_Katakana
317   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, IBUS_SHIFT_MASK,
318                                      config::Config::ROMAN, true, &out));
319   EXPECT_FALSE(out.has_key_code());
320   ASSERT_TRUE(out.has_special_key());
321   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
322   EXPECT_EQ(0, out.modifier_keys_size());
323 
324   // C-Hiragana_Katakana
325   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0,
326                                      IBUS_CONTROL_MASK, config::Config::ROMAN,
327                                      true, &out));
328   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
329   ASSERT_EQ(1, out.modifier_keys_size());
330   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
331 
332   // M-Hiragana_Katakana
333   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, IBUS_MOD1_MASK,
334                                      config::Config::ROMAN, true, &out));
335   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
336   ASSERT_EQ(1, out.modifier_keys_size());
337   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
338 
339   // Hiragana_Katakana handling should have no effect into Hiragana key or
340   // Katakana key.
341   // S-Hiragana
342   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, IBUS_SHIFT_MASK,
343                                      config::Config::ROMAN, true, &out));
344   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
345   EXPECT_EQ(1, out.modifier_keys_size());
346   EXPECT_EQ(commands::KeyEvent::SHIFT, out.modifier_keys(0));
347 
348   // C-Hiragana
349   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, IBUS_CONTROL_MASK,
350                                      config::Config::ROMAN, true, &out));
351   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
352   ASSERT_EQ(1, out.modifier_keys_size());
353   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
354 
355   // M-Hiragana
356   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, IBUS_MOD1_MASK,
357                                      config::Config::ROMAN, true, &out));
358   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
359   ASSERT_EQ(1, out.modifier_keys_size());
360   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
361 
362   // S-Katakana
363   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, IBUS_SHIFT_MASK,
364                                      config::Config::ROMAN, true, &out));
365   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
366   EXPECT_EQ(1, out.modifier_keys_size());
367   EXPECT_EQ(commands::KeyEvent::SHIFT, out.modifier_keys(0));
368 
369   // C-Katakana
370   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, IBUS_CONTROL_MASK,
371                                      config::Config::ROMAN, true, &out));
372   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
373   ASSERT_EQ(1, out.modifier_keys_size());
374   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
375 
376   // M-Katakana
377   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, IBUS_MOD1_MASK,
378                                      config::Config::ROMAN, true, &out));
379   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
380   ASSERT_EQ(1, out.modifier_keys_size());
381   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
382 }
383 
TEST_F(KeyTranslatorTest,HiraganaKatakanaHandlingWithMultipleModifiersTest)384 TEST_F(KeyTranslatorTest, HiraganaKatakanaHandlingWithMultipleModifiersTest) {
385   // Check Hiragana_Katakana local hack. The detail is described in
386   // key_translator.cc file.
387   commands::KeyEvent out;
388   guint modifier;
389 
390   // C-S-Hiragana_Katakana
391   modifier = IBUS_SHIFT_MASK | IBUS_CONTROL_MASK;
392   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, modifier,
393                                      config::Config::ROMAN, true, &out));
394   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
395   ASSERT_EQ(1, out.modifier_keys_size());
396   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
397 
398   // M-S-Hiragana_Katakana
399   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK;
400   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, modifier,
401                                      config::Config::ROMAN, true, &out));
402   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
403   ASSERT_EQ(1, out.modifier_keys_size());
404   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
405 
406   // C-M-Hiragana_Katakana
407   modifier = IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
408   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, modifier,
409                                      config::Config::ROMAN, true, &out));
410   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
411   ASSERT_EQ(2, out.modifier_keys_size());
412   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
413   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
414 
415   // C-S-M-Hiragana_Katakana
416   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
417   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana_Katakana, 0, modifier,
418                                      config::Config::ROMAN, true, &out));
419   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
420   EXPECT_EQ(2, out.modifier_keys_size());
421   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
422   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
423 
424   // Hiragana_Katakana handling should have no effect into Hiragana key or
425   // Katakana key.
426   // C-S-Hiragana
427   modifier = IBUS_SHIFT_MASK | IBUS_CONTROL_MASK;
428   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, modifier,
429                                      config::Config::ROMAN, true, &out));
430   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
431   ASSERT_EQ(2, out.modifier_keys_size());
432   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
433   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
434 
435   // M-S-Hiragana
436   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK;
437   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, modifier,
438                                      config::Config::ROMAN, true, &out));
439   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
440   ASSERT_EQ(2, out.modifier_keys_size());
441   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
442   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
443 
444   // C-M-Hiragana
445   modifier = IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
446   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, modifier,
447                                      config::Config::ROMAN, true, &out));
448   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
449   ASSERT_EQ(2, out.modifier_keys_size());
450   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
451   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
452 
453   // C-S-M-Hiragana
454   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
455   EXPECT_TRUE(translator_->Translate(IBUS_Hiragana, 0, modifier,
456                                      config::Config::ROMAN, true, &out));
457   EXPECT_EQ(commands::KeyEvent::KANA, out.special_key());
458   EXPECT_EQ(3, out.modifier_keys_size());
459   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
460   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
461   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
462 
463   // C-S-Katakana
464   modifier = IBUS_SHIFT_MASK | IBUS_CONTROL_MASK;
465   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, modifier,
466                                      config::Config::ROMAN, true, &out));
467   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
468   ASSERT_EQ(2, out.modifier_keys_size());
469   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
470   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
471 
472   // M-S-Katakana
473   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK;
474   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, modifier,
475                                      config::Config::ROMAN, true, &out));
476   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
477   ASSERT_EQ(2, out.modifier_keys_size());
478   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
479   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
480 
481   // C-M-Katakana
482   modifier = IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
483   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, modifier,
484                                      config::Config::ROMAN, true, &out));
485   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
486   ASSERT_EQ(2, out.modifier_keys_size());
487   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
488   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
489 
490   // C-S-M-Katakana
491   modifier = IBUS_SHIFT_MASK | IBUS_MOD1_MASK | IBUS_CONTROL_MASK;
492   EXPECT_TRUE(translator_->Translate(IBUS_Katakana, 0, modifier,
493                                      config::Config::ROMAN, true, &out));
494   EXPECT_EQ(commands::KeyEvent::KATAKANA, out.special_key());
495   EXPECT_EQ(3, out.modifier_keys_size());
496   IsContained(commands::KeyEvent::CTRL, out.modifier_keys());
497   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
498   IsContained(commands::KeyEvent::ALT, out.modifier_keys());
499 }
500 
TEST_F(KeyTranslatorTest,MultipleShiftKeysTest)501 TEST_F(KeyTranslatorTest, MultipleShiftKeysTest) {
502   commands::KeyEvent out;
503 
504   // Hit Shift_L with shift modifier (typically Shift_R).
505   EXPECT_TRUE(translator_->Translate(IBUS_Shift_L, 0, IBUS_SHIFT_MASK,
506                                      config::Config::ROMAN, true, &out));
507   EXPECT_EQ(1, out.modifier_keys_size());
508   IsContained(commands::KeyEvent::SHIFT, out.modifier_keys());
509 }
510 
TEST_F(KeyTranslatorTest,TranslateUnknow)511 TEST_F(KeyTranslatorTest, TranslateUnknow) {
512   commands::KeyEvent out;
513   EXPECT_FALSE(translator_->Translate(IBUS_VoidSymbol, 0, 0,
514                                       config::Config::ROMAN, true, &out));
515 
516   // Mozc does not support F25 - F35.
517   EXPECT_FALSE(translator_->Translate(IBUS_F25, 0, 0, config::Config::ROMAN,
518                                       true, &out));
519   EXPECT_FALSE(translator_->Translate(IBUS_F26, 0, 0, config::Config::ROMAN,
520                                       true, &out));
521   EXPECT_FALSE(translator_->Translate(IBUS_F27, 0, 0, config::Config::ROMAN,
522                                       true, &out));
523   EXPECT_FALSE(translator_->Translate(IBUS_F28, 0, 0, config::Config::ROMAN,
524                                       true, &out));
525   EXPECT_FALSE(translator_->Translate(IBUS_F29, 0, 0, config::Config::ROMAN,
526                                       true, &out));
527   EXPECT_FALSE(translator_->Translate(IBUS_F30, 0, 0, config::Config::ROMAN,
528                                       true, &out));
529   EXPECT_FALSE(translator_->Translate(IBUS_F31, 0, 0, config::Config::ROMAN,
530                                       true, &out));
531   EXPECT_FALSE(translator_->Translate(IBUS_F32, 0, 0, config::Config::ROMAN,
532                                       true, &out));
533   EXPECT_FALSE(translator_->Translate(IBUS_F33, 0, 0, config::Config::ROMAN,
534                                       true, &out));
535   EXPECT_FALSE(translator_->Translate(IBUS_F34, 0, 0, config::Config::ROMAN,
536                                       true, &out));
537   EXPECT_FALSE(translator_->Translate(IBUS_F35, 0, 0, config::Config::ROMAN,
538                                       true, &out));
539 }
540 
TEST_F(KeyTranslatorTest,TranslateModiferOnly)541 TEST_F(KeyTranslatorTest, TranslateModiferOnly) {
542   commands::KeyEvent out;
543 
544   // Just tap left_shift key
545   EXPECT_TRUE(translator_->Translate(
546       IBUS_Shift_L, 0, 0, config::Config::ROMAN, true, &out));
547   EXPECT_EQ(1, out.modifier_keys_size());
548   EXPECT_EQ(commands::KeyEvent::SHIFT, out.modifier_keys(0));
549 
550   // Just tap right_shift key
551   out.Clear();
552   EXPECT_TRUE(translator_->Translate(
553       IBUS_Shift_R, 0, 0, config::Config::ROMAN, true, &out));
554   EXPECT_EQ(1, out.modifier_keys_size());
555   EXPECT_EQ(commands::KeyEvent::SHIFT, out.modifier_keys(0));
556 
557   // Just tap left_ctrl key
558   out.Clear();
559   EXPECT_TRUE(translator_->Translate(
560       IBUS_Control_L, 0, 0, config::Config::ROMAN, true, &out));
561   EXPECT_EQ(1, out.modifier_keys_size());
562   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
563 
564   // Just tap right_ctrl key
565   out.Clear();
566   EXPECT_TRUE(translator_->Translate(
567       IBUS_Control_R, 0, 0, config::Config::ROMAN, true, &out));
568   EXPECT_EQ(1, out.modifier_keys_size());
569   EXPECT_EQ(commands::KeyEvent::CTRL, out.modifier_keys(0));
570 
571   // Just tap left_alt key
572   out.Clear();
573   EXPECT_TRUE(translator_->Translate(
574       IBUS_Alt_L, 0, 0, config::Config::ROMAN, true, &out));
575   EXPECT_EQ(1, out.modifier_keys_size());
576   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
577 
578   // Just tap right_alt key
579   out.Clear();
580   EXPECT_TRUE(translator_->Translate(
581       IBUS_Alt_R, 0, 0, config::Config::ROMAN, true, &out));
582   EXPECT_EQ(1, out.modifier_keys_size());
583   EXPECT_EQ(commands::KeyEvent::ALT, out.modifier_keys(0));
584 }
585 
586 }  // namespace ibus
587 }  // namespace mozc
588