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