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 "composer/key_event_util.h"
31 
32 #include <cctype>
33 
34 #include "base/logging.h"
35 #include "base/port.h"
36 #include "protocol/commands.pb.h"
37 
38 namespace mozc {
39 using commands::KeyEvent;
40 
41 namespace {
42 const uint32 kAltMask =
43     KeyEvent::ALT | KeyEvent::LEFT_ALT | KeyEvent::RIGHT_ALT;
44 const uint32 kCtrlMask =
45     KeyEvent::CTRL | KeyEvent::LEFT_CTRL | KeyEvent::RIGHT_CTRL;
46 const uint32 kShiftMask =
47     KeyEvent::SHIFT | KeyEvent::LEFT_SHIFT | KeyEvent::RIGHT_SHIFT;
48 const uint32 kCapsMask = KeyEvent::CAPS;
49 
Ignore(uint32 modifiers,uint32 modifiers_to_be_ignored)50 uint32 Ignore(uint32 modifiers, uint32 modifiers_to_be_ignored) {
51   return modifiers & ~modifiers_to_be_ignored;
52 }
53 
Any(uint32 modifiers_to_be_tested,uint32 modifiers_to_be_queried)54 bool Any(uint32 modifiers_to_be_tested, uint32 modifiers_to_be_queried) {
55   return (modifiers_to_be_tested & modifiers_to_be_queried) != 0;
56 }
57 
None(uint32 modifiers_to_be_tested,uint32 modifiers_to_be_queried)58 bool None(uint32 modifiers_to_be_tested, uint32 modifiers_to_be_queried) {
59   return !Any(modifiers_to_be_tested, modifiers_to_be_queried);
60 }
61 
62 }  // namespace
63 
GetModifiers(const KeyEvent & key_event)64 uint32 KeyEventUtil::GetModifiers(const KeyEvent &key_event) {
65   uint32 modifiers = 0;
66   if (key_event.has_modifiers()) {
67     modifiers = key_event.modifiers();
68   } else {
69     for (size_t i = 0; i < key_event.modifier_keys_size(); ++i) {
70       modifiers |= key_event.modifier_keys(i);
71     }
72   }
73   return modifiers;
74 }
75 
GetKeyInformation(const KeyEvent & key_event,KeyInformation * key)76 bool KeyEventUtil::GetKeyInformation(const KeyEvent &key_event,
77                                      KeyInformation *key) {
78   DCHECK(key);
79 
80   const uint16 modifier_keys = static_cast<uint16>(GetModifiers(key_event));
81   const uint16 special_key = key_event.has_special_key() ?
82       key_event.special_key() : KeyEvent::NO_SPECIALKEY;
83   const uint32 key_code = key_event.has_key_code() ? key_event.key_code() : 0;
84 
85   // Make sure the translation from the obsolete spesification.
86   // key_code should no longer contain control characters.
87   if (0 < key_code && key_code <= 32) {
88     return false;
89   }
90 
91   *key =
92       (static_cast<KeyInformation>(modifier_keys) << 48) |
93       (static_cast<KeyInformation>(special_key) << 32) |
94       (static_cast<KeyInformation>(key_code));
95 
96   return true;
97 }
98 
NormalizeModifiers(const KeyEvent & key_event,KeyEvent * new_key_event)99 void KeyEventUtil::NormalizeModifiers(const KeyEvent &key_event,
100                                       KeyEvent *new_key_event) {
101   DCHECK(new_key_event);
102 
103   // CTRL (or ALT, SHIFT) should be set on modifier_keys when
104   // LEFT (or RIGHT) ctrl is set.
105   // LEFT_CTRL (or others) is not handled on Japanese, so we remove these.
106   const uint32 kIgnorableModifierMask =
107       (KeyEvent::CAPS |
108        KeyEvent::LEFT_ALT | KeyEvent::RIGHT_ALT |
109        KeyEvent::LEFT_CTRL | KeyEvent::RIGHT_CTRL |
110        KeyEvent::LEFT_SHIFT | KeyEvent::RIGHT_SHIFT);
111 
112   RemoveModifiers(key_event, kIgnorableModifierMask, new_key_event);
113 
114   // Reverts the flip of alphabetical key events caused by CapsLock.
115   const uint32 original_modifiers = GetModifiers(key_event);
116   if ((original_modifiers & KeyEvent::CAPS) &&
117       key_event.has_key_code()) {
118     const uint32 key_code = key_event.key_code();
119     if ('A' <= key_code && key_code <= 'Z') {
120       new_key_event->set_key_code(key_code + ('a' - 'A'));
121     } else if ('a' <= key_code && key_code <= 'z') {
122       new_key_event->set_key_code(key_code + ('A' - 'a'));
123     }
124   }
125 }
126 
NormalizeNumpadKey(const KeyEvent & key_event,KeyEvent * new_key_event)127 void KeyEventUtil::NormalizeNumpadKey(const KeyEvent &key_event,
128                                       KeyEvent *new_key_event) {
129   DCHECK(new_key_event);
130   new_key_event->CopyFrom(key_event);
131 
132   if (!IsNumpadKey(*new_key_event)) {
133     return;
134   }
135   const KeyEvent::SpecialKey numpad_key = new_key_event->special_key();
136 
137   // KeyEvent::SEPARATOR is transformed to Enter.
138   if (numpad_key == KeyEvent::SEPARATOR) {
139     new_key_event->set_special_key(KeyEvent::ENTER);
140     return;
141   }
142 
143   new_key_event->clear_special_key();
144 
145   // Handles number keys
146   if (KeyEvent::NUMPAD0 <= numpad_key && numpad_key <= KeyEvent::NUMPAD9) {
147     new_key_event->set_key_code(
148         static_cast<uint32>('0' + (numpad_key - KeyEvent::NUMPAD0)));
149     return;
150   }
151 
152   char new_key_code;
153   switch (numpad_key) {
154     case KeyEvent::MULTIPLY:
155       new_key_code = '*';
156       break;
157     case KeyEvent::ADD:
158       new_key_code = '+';
159       break;
160     case KeyEvent::SUBTRACT:
161       new_key_code = '-';
162       break;
163     case KeyEvent::DECIMAL:
164       new_key_code = '.';
165       break;
166     case KeyEvent::DIVIDE:
167       new_key_code = '/';
168       break;
169     case KeyEvent::EQUALS:
170       new_key_code = '=';
171       break;
172     case KeyEvent::COMMA:
173       new_key_code = ',';
174       break;
175     default:
176       LOG(ERROR) << "Should not reach here.";
177       return;
178   }
179 
180   new_key_event->set_key_code(static_cast<uint32>(new_key_code));
181 }
182 
RemoveModifiers(const KeyEvent & key_event,uint32 remove_modifiers,KeyEvent * new_key_event)183 void KeyEventUtil::RemoveModifiers(const KeyEvent &key_event,
184                                    uint32 remove_modifiers,
185                                    KeyEvent *new_key_event) {
186   DCHECK(new_key_event);
187   new_key_event->CopyFrom(key_event);
188 
189   if (HasAlt(remove_modifiers)) {
190     remove_modifiers |= KeyEvent::LEFT_ALT | KeyEvent::RIGHT_ALT;
191   }
192   if (HasCtrl(remove_modifiers)) {
193     remove_modifiers |= KeyEvent::LEFT_CTRL | KeyEvent::RIGHT_CTRL;
194   }
195   if (HasShift(remove_modifiers)) {
196     remove_modifiers |= KeyEvent::LEFT_SHIFT | KeyEvent::RIGHT_SHIFT;
197   }
198 
199   new_key_event->clear_modifier_keys();
200   for (size_t i = 0; i < key_event.modifier_keys_size(); ++i) {
201     const KeyEvent::ModifierKey mod_key = key_event.modifier_keys(i);
202     if (!(remove_modifiers & mod_key)) {
203       new_key_event->add_modifier_keys(mod_key);
204     }
205   }
206 }
207 
MaybeGetKeyStub(const KeyEvent & key_event,KeyInformation * key)208 bool KeyEventUtil::MaybeGetKeyStub(const KeyEvent &key_event,
209                                    KeyInformation *key) {
210   DCHECK(key);
211 
212   // If any modifier keys were pressed, this function does nothing.
213   if (KeyEventUtil::GetModifiers(key_event) != 0) {
214     return false;
215   }
216 
217   // No stub rule is supported for special keys yet.
218   if (key_event.has_special_key()) {
219     return false;
220   }
221 
222   // Check if both key_code and key_string are invalid.
223   if ((!key_event.has_key_code() || key_event.key_code() <= 32) &&
224       (!key_event.has_key_string() || key_event.key_string().empty())) {
225     return false;
226   }
227 
228   KeyEvent stub_key_event;
229   stub_key_event.set_special_key(KeyEvent::TEXT_INPUT);
230   if (!GetKeyInformation(stub_key_event, key)) {
231     return false;
232   }
233 
234   return true;
235 }
236 
HasAlt(uint32 modifiers)237 bool KeyEventUtil::HasAlt(uint32 modifiers) {
238   return Any(modifiers, kAltMask);
239 }
240 
HasCtrl(uint32 modifiers)241 bool KeyEventUtil::HasCtrl(uint32 modifiers) {
242   return Any(modifiers, kCtrlMask);
243 }
244 
HasShift(uint32 modifiers)245 bool KeyEventUtil::HasShift(uint32 modifiers) {
246   return Any(modifiers, kShiftMask);
247 }
248 
HasCaps(uint32 modifiers)249 bool KeyEventUtil::HasCaps(uint32 modifiers) {
250   return Any(modifiers, kCapsMask);
251 }
252 
IsAlt(uint32 modifiers)253 bool KeyEventUtil::IsAlt(uint32 modifiers) {
254   if (!HasAlt(modifiers)) {
255     return false;
256   }
257   return None(Ignore(modifiers, kCapsMask), ~kAltMask);
258 }
259 
IsCtrl(uint32 modifiers)260 bool KeyEventUtil::IsCtrl(uint32 modifiers) {
261   if (!HasCtrl(modifiers)) {
262     return false;
263   }
264   return None(Ignore(modifiers, kCapsMask), ~kCtrlMask);
265 }
266 
IsShift(uint32 modifiers)267 bool KeyEventUtil::IsShift(uint32 modifiers) {
268   if (!HasShift(modifiers)) {
269     return false;
270   }
271   return None(Ignore(modifiers, kCapsMask), ~kShiftMask);
272 }
273 
IsAltCtrl(uint32 modifiers)274 bool KeyEventUtil::IsAltCtrl(uint32 modifiers) {
275   if (!HasAlt(modifiers) || !HasCtrl(modifiers)) {
276     return false;
277   }
278   return None(Ignore(modifiers, kCapsMask), ~(kAltMask | kCtrlMask));
279 }
280 
IsAltShift(uint32 modifiers)281 bool KeyEventUtil::IsAltShift(uint32 modifiers) {
282   if (!HasAlt(modifiers) || !HasShift(modifiers)) {
283     return false;
284   }
285   return None(Ignore(modifiers, kCapsMask), ~(kAltMask | kShiftMask));
286 }
287 
IsCtrlShift(uint32 modifiers)288 bool KeyEventUtil::IsCtrlShift(uint32 modifiers) {
289   if (!HasCtrl(modifiers) || !HasShift(modifiers)) {
290     return false;
291   }
292   return None(Ignore(modifiers, kCapsMask), ~(kCtrlMask | kShiftMask));
293 }
294 
IsAltCtrlShift(uint32 modifiers)295 bool KeyEventUtil::IsAltCtrlShift(uint32 modifiers) {
296   if (!HasAlt(modifiers) || !HasCtrl(modifiers) || !HasShift(modifiers)) {
297     return false;
298   }
299   const auto kAltCtrlShiftMask = kAltMask | kCtrlMask | kShiftMask;
300   return None(Ignore(modifiers, kCapsMask), ~kAltCtrlShiftMask);
301 }
302 
IsLowerAlphabet(const KeyEvent & key_event)303 bool KeyEventUtil::IsLowerAlphabet(const KeyEvent &key_event) {
304   if (!key_event.has_key_code()) {
305     return false;
306   }
307 
308   const uint32 key_code = key_event.key_code();
309   const uint32 modifier_keys = GetModifiers(key_event);
310   const bool change_case = (HasShift(modifier_keys) != HasCaps(modifier_keys));
311 
312   if (change_case) {
313     return isupper(key_code) != 0;
314   } else {
315     return islower(key_code) != 0;
316   }
317 }
318 
IsUpperAlphabet(const KeyEvent & key_event)319 bool KeyEventUtil::IsUpperAlphabet(const KeyEvent &key_event) {
320   if (!key_event.has_key_code()) {
321     return false;
322   }
323 
324   const uint32 key_code = key_event.key_code();
325   const uint32 modifier_keys = GetModifiers(key_event);
326   const bool change_case = (HasShift(modifier_keys) != HasCaps(modifier_keys));
327 
328   if (change_case) {
329     return islower(key_code) != 0;
330   } else {
331     return isupper(key_code) != 0;
332   }
333 }
334 
IsNumpadKey(const KeyEvent & key_event)335 bool KeyEventUtil::IsNumpadKey(const KeyEvent &key_event) {
336   if (!key_event.has_special_key()) {
337     return false;
338   }
339 
340   const KeyEvent::SpecialKey special_key = key_event.special_key();
341   if (KeyEvent::NUMPAD0 <= special_key && special_key <= KeyEvent::EQUALS) {
342     return true;
343   }
344   if (special_key == KeyEvent::COMMA) {
345     return true;
346   }
347   return false;
348 }
349 
350 }  // namespace mozc
351