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