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 <map>
33 #include <set>
34 #include <string>
35 
36 #include "base/logging.h"
37 #include "base/port.h"
38 
39 namespace {
40 
41 const struct SpecialKeyMap {
42   guint from;
43   mozc::commands::KeyEvent::SpecialKey to;
44 } special_key_map[] = {
45   {IBUS_space, mozc::commands::KeyEvent::SPACE},
46   {IBUS_Return, mozc::commands::KeyEvent::ENTER},
47   {IBUS_Left, mozc::commands::KeyEvent::LEFT},
48   {IBUS_Right, mozc::commands::KeyEvent::RIGHT},
49   {IBUS_Up, mozc::commands::KeyEvent::UP},
50   {IBUS_Down, mozc::commands::KeyEvent::DOWN},
51   {IBUS_Escape, mozc::commands::KeyEvent::ESCAPE},
52   {IBUS_Delete, mozc::commands::KeyEvent::DEL},
53   {IBUS_BackSpace, mozc::commands::KeyEvent::BACKSPACE},
54   {IBUS_Insert, mozc::commands::KeyEvent::INSERT},
55   {IBUS_Henkan, mozc::commands::KeyEvent::HENKAN},
56   {IBUS_Muhenkan, mozc::commands::KeyEvent::MUHENKAN},
57   {IBUS_Hiragana, mozc::commands::KeyEvent::KANA},
58   {IBUS_Hiragana_Katakana, mozc::commands::KeyEvent::KANA},
59   {IBUS_Katakana, mozc::commands::KeyEvent::KATAKANA},
60   {IBUS_Zenkaku, mozc::commands::KeyEvent::HANKAKU},
61   {IBUS_Hankaku, mozc::commands::KeyEvent::HANKAKU},
62   {IBUS_Zenkaku_Hankaku, mozc::commands::KeyEvent::HANKAKU},
63   {IBUS_Eisu_toggle, mozc::commands::KeyEvent::EISU},
64   {IBUS_Home, mozc::commands::KeyEvent::HOME},
65   {IBUS_End, mozc::commands::KeyEvent::END},
66   {IBUS_Tab, mozc::commands::KeyEvent::TAB},
67   {IBUS_F1, mozc::commands::KeyEvent::F1},
68   {IBUS_F2, mozc::commands::KeyEvent::F2},
69   {IBUS_F3, mozc::commands::KeyEvent::F3},
70   {IBUS_F4, mozc::commands::KeyEvent::F4},
71   {IBUS_F5, mozc::commands::KeyEvent::F5},
72   {IBUS_F6, mozc::commands::KeyEvent::F6},
73   {IBUS_F7, mozc::commands::KeyEvent::F7},
74   {IBUS_F8, mozc::commands::KeyEvent::F8},
75   {IBUS_F9, mozc::commands::KeyEvent::F9},
76   {IBUS_F10, mozc::commands::KeyEvent::F10},
77   {IBUS_F11, mozc::commands::KeyEvent::F11},
78   {IBUS_F12, mozc::commands::KeyEvent::F12},
79   {IBUS_F13, mozc::commands::KeyEvent::F13},
80   {IBUS_F14, mozc::commands::KeyEvent::F14},
81   {IBUS_F15, mozc::commands::KeyEvent::F15},
82   {IBUS_F16, mozc::commands::KeyEvent::F16},
83   {IBUS_F17, mozc::commands::KeyEvent::F17},
84   {IBUS_F18, mozc::commands::KeyEvent::F18},
85   {IBUS_F19, mozc::commands::KeyEvent::F19},
86   {IBUS_F20, mozc::commands::KeyEvent::F20},
87   {IBUS_F21, mozc::commands::KeyEvent::F21},
88   {IBUS_F22, mozc::commands::KeyEvent::F22},
89   {IBUS_F23, mozc::commands::KeyEvent::F23},
90   {IBUS_F24, mozc::commands::KeyEvent::F24},
91   {IBUS_Page_Up, mozc::commands::KeyEvent::PAGE_UP},
92   {IBUS_Page_Down, mozc::commands::KeyEvent::PAGE_DOWN},
93 
94   // Keypad (10-key).
95   {IBUS_KP_0, mozc::commands::KeyEvent::NUMPAD0},
96   {IBUS_KP_1, mozc::commands::KeyEvent::NUMPAD1},
97   {IBUS_KP_2, mozc::commands::KeyEvent::NUMPAD2},
98   {IBUS_KP_3, mozc::commands::KeyEvent::NUMPAD3},
99   {IBUS_KP_4, mozc::commands::KeyEvent::NUMPAD4},
100   {IBUS_KP_5, mozc::commands::KeyEvent::NUMPAD5},
101   {IBUS_KP_6, mozc::commands::KeyEvent::NUMPAD6},
102   {IBUS_KP_7, mozc::commands::KeyEvent::NUMPAD7},
103   {IBUS_KP_8, mozc::commands::KeyEvent::NUMPAD8},
104   {IBUS_KP_9, mozc::commands::KeyEvent::NUMPAD9},
105   {IBUS_KP_Equal, mozc::commands::KeyEvent::EQUALS},  // [=]
106   {IBUS_KP_Multiply, mozc::commands::KeyEvent::MULTIPLY},  // [*]
107   {IBUS_KP_Add, mozc::commands::KeyEvent::ADD},  // [+]
108   {IBUS_KP_Separator, mozc::commands::KeyEvent::SEPARATOR},  // enter
109   {IBUS_KP_Subtract, mozc::commands::KeyEvent::SUBTRACT},  // [-]
110   {IBUS_KP_Decimal, mozc::commands::KeyEvent::DECIMAL},  // [.]
111   {IBUS_KP_Divide, mozc::commands::KeyEvent::DIVIDE},  // [/]
112   {IBUS_KP_Space, mozc::commands::KeyEvent::SPACE},
113   {IBUS_KP_Tab, mozc::commands::KeyEvent::TAB},
114   {IBUS_KP_Enter, mozc::commands::KeyEvent::ENTER},
115   {IBUS_KP_Home, mozc::commands::KeyEvent::HOME},
116   {IBUS_KP_Left, mozc::commands::KeyEvent::LEFT},
117   {IBUS_KP_Up, mozc::commands::KeyEvent::UP},
118   {IBUS_KP_Right, mozc::commands::KeyEvent::RIGHT},
119   {IBUS_KP_Down, mozc::commands::KeyEvent::DOWN},
120   {IBUS_KP_Page_Up, mozc::commands::KeyEvent::PAGE_UP},
121   {IBUS_KP_Page_Down, mozc::commands::KeyEvent::PAGE_DOWN},
122   {IBUS_KP_End, mozc::commands::KeyEvent::END},
123   {IBUS_KP_Delete, mozc::commands::KeyEvent::DEL},
124   {IBUS_KP_Insert, mozc::commands::KeyEvent::INSERT},
125   {IBUS_Caps_Lock, mozc::commands::KeyEvent::CAPS_LOCK},
126 
127   // Shift+TAB.
128   {IBUS_ISO_Left_Tab, mozc::commands::KeyEvent::TAB},
129 
130   // TODO(mazda): Handle following keys?
131   //   - IBUS_Kana_Lock? IBUS_KEY_Kana_Shift?
132 };
133 
134 const struct ModifierKeyMapData {
135   guint from;
136   mozc::commands::KeyEvent::ModifierKey to;
137 } modifier_key_map_data[] = {
138   {IBUS_Shift_L, mozc::commands::KeyEvent::SHIFT},
139   {IBUS_Shift_R, mozc::commands::KeyEvent::SHIFT},
140   {IBUS_Control_L, mozc::commands::KeyEvent::CTRL},
141   {IBUS_Control_R, mozc::commands::KeyEvent::CTRL},
142   {IBUS_Alt_L, mozc::commands::KeyEvent::ALT},
143   {IBUS_Alt_R, mozc::commands::KeyEvent::ALT},
144   {IBUS_LOCK_MASK, mozc::commands::KeyEvent::CAPS},
145 };
146 
147 const struct ModifierMaskMapData {
148   guint from;
149   mozc::commands::KeyEvent::ModifierKey to;
150 } modifier_mask_map_data[] = {
151   {IBUS_SHIFT_MASK, mozc::commands::KeyEvent::SHIFT},
152   {IBUS_CONTROL_MASK, mozc::commands::KeyEvent::CTRL},
153   {IBUS_MOD1_MASK, mozc::commands::KeyEvent::ALT},
154 };
155 
156 // TODO(team): Add kana_map_dv to support Dvoraklayout.
157 const struct KanaMap {
158   guint code;
159   const char *no_shift;
160   const char *shift;
161 } kana_map_jp[] = {
162   { '1' , "ぬ", "ぬ" },
163   { '!' , "ぬ", "ぬ" },
164   { '2' , "ふ", "ふ" },
165   { '\"', "ふ", "ふ" },
166   { '3' , "あ", "ぁ" },
167   { '#' , "あ", "ぁ" },
168   { '4' , "う", "ぅ" },
169   { '$' , "う", "ぅ" },
170   { '5' , "え", "ぇ" },
171   { '%' , "え", "ぇ" },
172   { '6' , "お", "ぉ" },
173   { '&' , "お", "ぉ" },
174   { '7' , "や", "ゃ" },
175   { '\'', "や", "ゃ" },
176   { '8' , "ゆ", "ゅ" },
177   { '(' , "ゆ", "ゅ" },
178   { '9' , "よ", "ょ" },
179   { ')' , "よ", "ょ" },
180   { '0' , "わ", "を" },
181   { '-' , "ほ", "ほ" },
182   { '=' , "ほ", "ほ" },
183   { '^' , "へ", "を" },
184   { '~' , "へ", "を" },
185   { '|' , "ー", "ー" },
186   { 'q' , "た", "た" },
187   { 'Q' , "た", "た" },
188   { 'w' , "て", "て" },
189   { 'W' , "て", "て" },
190   { 'e' , "い", "ぃ" },
191   { 'E' , "い", "ぃ" },
192   { 'r' , "す", "す" },
193   { 'R' , "す", "す" },
194   { 't' , "か", "か" },
195   { 'T' , "か", "か" },
196   { 'y' , "ん", "ん" },
197   { 'Y' , "ん", "ん" },
198   { 'u' , "な", "な" },
199   { 'U' , "な", "な" },
200   { 'i' , "に", "に" },
201   { 'I' , "に", "に" },
202   { 'o' , "ら", "ら" },
203   { 'O' , "ら", "ら" },
204   { 'p' , "せ", "せ" },
205   { 'P' , "せ", "せ" },
206   { '@' , "゛", "゛" },
207   { '`' , "゛", "゛" },
208   { '[' , "゜", "「" },
209   { '{' , "゜", "「" },
210   { 'a' , "ち", "ち" },
211   { 'A' , "ち", "ち" },
212   { 's' , "と", "と" },
213   { 'S' , "と", "と" },
214   { 'd' , "し", "し" },
215   { 'D' , "し", "し" },
216   { 'f' , "は", "は" },
217   { 'F' , "は", "は" },
218   { 'g' , "き", "き" },
219   { 'G' , "き", "き" },
220   { 'h' , "く", "く" },
221   { 'H' , "く", "く" },
222   { 'j' , "ま", "ま" },
223   { 'J' , "ま", "ま" },
224   { 'k' , "の", "の" },
225   { 'K' , "の", "の" },
226   { 'l' , "り", "り" },
227   { 'L' , "り", "り" },
228   { ';' , "れ", "れ" },
229   { '+' , "れ", "れ" },
230   { ':' , "け", "け" },
231   { '*' , "け", "け" },
232   { ']' , "む", "」" },
233   { '}' , "む", "」" },
234   { 'z' , "つ", "っ" },
235   { 'Z' , "つ", "っ" },
236   { 'x' , "さ", "さ" },
237   { 'X' , "さ", "さ" },
238   { 'c' , "そ", "そ" },
239   { 'C' , "そ", "そ" },
240   { 'v' , "ひ", "ひ" },
241   { 'V' , "ひ", "ひ" },
242   { 'b' , "こ", "こ" },
243   { 'B' , "こ", "こ" },
244   { 'n' , "み", "み" },
245   { 'N' , "み", "み" },
246   { 'm' , "も", "も" },
247   { 'M' , "も", "も" },
248   { ',' , "ね", "、" },
249   { '<' , "ね", "、" },
250   { '.' , "る", "。" },
251   { '>' , "る", "。" },
252   { '/' , "め", "・" },
253   { '?' , "め", "・" },
254   { '_' , "ろ", "ろ" },
255   // A backslash is handled in a special way because it is input by
256   // two different keys (the one next to Backslash and the one next
257   // to Right Shift).
258   { '\\', "", "" },
259 }, kana_map_us[] = {
260   { '`' , "ろ", "ろ" },
261   { '~' , "ろ", "ろ" },
262   { '1' , "ぬ", "ぬ" },
263   { '!' , "ぬ", "ぬ" },
264   { '2' , "ふ", "ふ" },
265   { '@' , "ふ", "ふ" },
266   { '3' , "あ", "ぁ" },
267   { '#' , "あ", "ぁ" },
268   { '4' , "う", "ぅ" },
269   { '$' , "う", "ぅ" },
270   { '5' , "え", "ぇ" },
271   { '%' , "え", "ぇ" },
272   { '6' , "お", "ぉ" },
273   { '^' , "お", "ぉ" },
274   { '7' , "や", "ゃ" },
275   { '&' , "や", "ゃ" },
276   { '8' , "ゆ", "ゅ" },
277   { '*' , "ゆ", "ゅ" },
278   { '9' , "よ", "ょ" },
279   { '(' , "よ", "ょ" },
280   { '0' , "わ", "を" },
281   { ')' , "わ", "を" },
282   { '-' , "ほ", "ー" },
283   { '_' , "ほ", "ー" },
284   { '=' , "へ", "へ" },
285   { '+' , "へ", "へ" },
286   { 'q' , "た", "た" },
287   { 'Q' , "た", "た" },
288   { 'w' , "て", "て" },
289   { 'W' , "て", "て" },
290   { 'e' , "い", "ぃ" },
291   { 'E' , "い", "ぃ" },
292   { 'r' , "す", "す" },
293   { 'R' , "す", "す" },
294   { 't' , "か", "か" },
295   { 'T' , "か", "か" },
296   { 'y' , "ん", "ん" },
297   { 'Y' , "ん", "ん" },
298   { 'u' , "な", "な" },
299   { 'U' , "な", "な" },
300   { 'i' , "に", "に" },
301   { 'I' , "に", "に" },
302   { 'o' , "ら", "ら" },
303   { 'O' , "ら", "ら" },
304   { 'p' , "せ", "せ" },
305   { 'P' , "せ", "せ" },
306   { '[' , "゛", "゛" },
307   { '{' , "゛", "゛" },
308   { ']' , "゜", "「" },
309   { '}' , "゜", "「" },
310   { '\\', "む", "」" },
311   { '|' , "む", "」" },
312   { 'a' , "ち", "ち" },
313   { 'A' , "ち", "ち" },
314   { 's' , "と", "と" },
315   { 'S' , "と", "と" },
316   { 'd' , "し", "し" },
317   { 'D' , "し", "し" },
318   { 'f' , "は", "は" },
319   { 'F' , "は", "は" },
320   { 'g' , "き", "き" },
321   { 'G' , "き", "き" },
322   { 'h' , "く", "く" },
323   { 'H' , "く", "く" },
324   { 'j' , "ま", "ま" },
325   { 'J' , "ま", "ま" },
326   { 'k' , "の", "の" },
327   { 'K' , "の", "の" },
328   { 'l' , "り", "り" },
329   { 'L' , "り", "り" },
330   { ';' , "れ", "れ" },
331   { ':' , "れ", "れ" },
332   { '\'', "け", "け" },
333   { '\"', "け", "け" },
334   { 'z' , "つ", "っ" },
335   { 'Z' , "つ", "っ" },
336   { 'x' , "さ", "さ" },
337   { 'X' , "さ", "さ" },
338   { 'c' , "そ", "そ" },
339   { 'C' , "そ", "そ" },
340   { 'v' , "ひ", "ひ" },
341   { 'V' , "ひ", "ひ" },
342   { 'b' , "こ", "こ" },
343   { 'B' , "こ", "こ" },
344   { 'n' , "み", "み" },
345   { 'N' , "み", "み" },
346   { 'm' , "も", "も" },
347   { 'M' , "も", "も" },
348   { ',' , "ね", "、" },
349   { '<' , "ね", "、" },
350   { '.' , "る", "。" },
351   { '>' , "る", "。" },
352   { '/' , "め", "・" },
353   { '?' , "め", "・" },
354 };
355 
356 }  // namespace
357 
358 namespace mozc {
359 namespace ibus {
360 
KeyTranslator()361 KeyTranslator::KeyTranslator() {
362   Init();
363 }
364 
~KeyTranslator()365 KeyTranslator::~KeyTranslator() {
366 }
367 
368 // TODO(nona): Fix 'Shift-0' behavior b/4338394
Translate(guint keyval,guint keycode,guint modifiers,config::Config::PreeditMethod method,bool layout_is_jp,commands::KeyEvent * out_event) const369 bool KeyTranslator::Translate(guint keyval,
370                               guint keycode,
371                               guint modifiers,
372                               config::Config::PreeditMethod method,
373                               bool layout_is_jp,
374                               commands::KeyEvent *out_event) const {
375   DCHECK(out_event) << "out_event is NULL";
376   out_event->Clear();
377 
378   // Due to historical reasons, many linux ditributions set Hiragana_Katakana
379   // key as Hiragana key (which is Katkana key with shift modifier). So, we
380   // translate Hiragana_Katanaka key as Hiragana key by mapping table, and
381   // Shift + Hiragana_Katakana key as Katakana key by functionally.
382   // TODO(nona): Fix process modifier to handle right shift
383   if (IsHiraganaKatakanaKeyWithShift(keyval, keycode, modifiers)) {
384     modifiers &= ~IBUS_SHIFT_MASK;
385     keyval = IBUS_Katakana;
386   }
387   string kana_key_string;
388   if ((method == config::Config::KANA) && IsKanaAvailable(
389           keyval, keycode, modifiers, layout_is_jp, &kana_key_string)) {
390     out_event->set_key_code(keyval);
391     out_event->set_key_string(kana_key_string);
392   } else if (IsAscii(keyval, keycode, modifiers)) {
393     if (IBUS_LOCK_MASK & modifiers) {
394       out_event->add_modifier_keys(commands::KeyEvent::CAPS);
395     }
396     out_event->set_key_code(keyval);
397   } else if (IsModifierKey(keyval, keycode, modifiers)) {
398     ModifierKeyMap::const_iterator i = modifier_key_map_.find(keyval);
399     DCHECK(i != modifier_key_map_.end());
400     out_event->add_modifier_keys(i->second);
401   } else if (IsSpecialKey(keyval, keycode, modifiers)) {
402     SpecialKeyMap::const_iterator i = special_key_map_.find(keyval);
403     DCHECK(i != special_key_map_.end());
404     out_event->set_special_key(i->second);
405   } else {
406     VLOG(1) << "Unknown keyval: " << keyval;
407     return false;
408   }
409 
410   for (ModifierKeyMap::const_iterator i = modifier_mask_map_.begin();
411        i != modifier_mask_map_.end(); ++i) {
412     // Do not set a SHIFT modifier when |keyval| is a printable key by following
413     // the Mozc's rule.
414     if ((i->second == commands::KeyEvent::SHIFT) &&
415         IsPrintable(keyval, keycode, modifiers)) {
416       continue;
417     }
418 
419     if (i->first & modifiers) {
420       // Add a modifier key if doesn't exist.
421       commands::KeyEvent::ModifierKey modifier = i->second;
422       bool found = false;
423       for (int i = 0; i < out_event->modifier_keys_size(); ++i) {
424         if (modifier == out_event->modifier_keys(i)) {
425           found = true;
426           break;
427         }
428       }
429       if (!found) {
430         out_event->add_modifier_keys(modifier);
431       }
432     }
433   }
434 
435   return true;
436 }
437 
Init()438 void KeyTranslator::Init() {
439   for (int i = 0; i < arraysize(special_key_map); ++i) {
440     CHECK(special_key_map_.insert(
441         std::make_pair(special_key_map[i].from,
442                        special_key_map[i].to)).second);
443   }
444   for (int i = 0; i < arraysize(modifier_key_map_data); ++i) {
445     CHECK(modifier_key_map_.insert(
446         std::make_pair(modifier_key_map_data[i].from,
447                        modifier_key_map_data[i].to)).second);
448   }
449   for (int i = 0; i < arraysize(modifier_mask_map_data); ++i) {
450     CHECK(modifier_mask_map_.insert(
451         std::make_pair(modifier_mask_map_data[i].from,
452                        modifier_mask_map_data[i].to)).second);
453   }
454   for (int i = 0; i < arraysize(kana_map_jp); ++i) {
455     CHECK(kana_map_jp_.insert(
456         std::make_pair(kana_map_jp[i].code,
457                        std::make_pair(kana_map_jp[i].no_shift,
458                                       kana_map_jp[i].shift))).second);
459   }
460   for (int i = 0; i < arraysize(kana_map_us); ++i) {
461     CHECK(kana_map_us_.insert(
462         std::make_pair(kana_map_us[i].code,
463                        std::make_pair(kana_map_us[i].no_shift,
464                                       kana_map_us[i].shift))).second);
465   }
466 }
467 
IsModifierKey(guint keyval,guint keycode,guint modifiers) const468 bool KeyTranslator::IsModifierKey(guint keyval,
469                                   guint keycode,
470                                   guint modifiers) const {
471   return modifier_key_map_.find(keyval) != modifier_key_map_.end();
472 }
473 
IsSpecialKey(guint keyval,guint keycode,guint modifiers) const474 bool KeyTranslator::IsSpecialKey(guint keyval,
475                                  guint keycode,
476                                  guint modifiers) const {
477   return special_key_map_.find(keyval) != special_key_map_.end();
478 }
479 
IsHiraganaKatakanaKeyWithShift(guint keyval,guint keycode,guint modifiers)480 bool KeyTranslator::IsHiraganaKatakanaKeyWithShift(guint keyval,
481                                                    guint keycode,
482                                                    guint modifiers) {
483   return ((modifiers & IBUS_SHIFT_MASK) && (keyval == IBUS_Hiragana_Katakana));
484 }
485 
IsKanaAvailable(guint keyval,guint keycode,guint modifiers,bool layout_is_jp,string * out) const486 bool KeyTranslator::IsKanaAvailable(guint keyval,
487                                     guint keycode,
488                                     guint modifiers,
489                                     bool layout_is_jp,
490                                     string *out) const {
491   if ((modifiers & IBUS_CONTROL_MASK) || (modifiers & IBUS_MOD1_MASK)) {
492     return false;
493   }
494   const KanaMap &kana_map = layout_is_jp ? kana_map_jp_ : kana_map_us_;
495   KanaMap::const_iterator iter = kana_map.find(keyval);
496   if (iter == kana_map.end()) {
497     return false;
498   }
499 
500   if (out) {
501     // When a Japanese keyboard is in use, the yen-sign key and the backslash
502     // key generate the same |keyval|. In this case, we have to check |keycode|
503     // to return an appropriate string. See the following IBus issue for
504     // details: https://github.com/ibus/ibus/issues/73
505     if (keyval == '\\' && layout_is_jp) {
506       if (keycode == IBUS_bar) {
507         *out = "ー";
508       } else {
509         *out = "ろ";
510       }
511     } else {
512       *out = (modifiers & IBUS_SHIFT_MASK) ?
513           iter->second.second : iter->second.first;
514     }
515   }
516   return true;
517 }
518 
519 // TODO(nona): resolve S-'0' problem (b/4338394).
520 // TODO(nona): Current printable detection is weak. To enhance accuracy, use xkb
521 // key map
IsPrintable(guint keyval,guint keycode,guint modifiers)522 bool KeyTranslator::IsPrintable(guint keyval, guint keycode, guint modifiers) {
523   if ((modifiers & IBUS_CONTROL_MASK) || (modifiers & IBUS_MOD1_MASK)) {
524     return false;
525   }
526   return IsAscii(keyval, keycode, modifiers);
527 }
528 
IsAscii(guint keyval,guint keycode,guint modifiers)529 bool KeyTranslator::IsAscii(guint keyval, guint keycode, guint modifiers) {
530   return (keyval > IBUS_space &&
531           // Note: Space key (0x20) is a special key in Mozc.
532           keyval <= IBUS_asciitilde);  // 0x7e.
533 }
534 
535 }  // namespace ibus
536 }  // namespace mozc
537