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_event_handler.h"
31 
32 #include "base/logging.h"
33 #include "base/port.h"
34 #include "base/singleton.h"
35 
36 namespace mozc {
37 namespace ibus {
38 
39 namespace {
IsModifierToBeSentOnKeyUp(const commands::KeyEvent & key_event)40 bool IsModifierToBeSentOnKeyUp(const commands::KeyEvent &key_event) {
41   if (key_event.modifier_keys_size() == 0) {
42     return false;
43   }
44 
45   if (key_event.modifier_keys_size() == 1 &&
46       key_event.modifier_keys(0) == commands::KeyEvent::CAPS) {
47     return false;
48   }
49 
50   return true;
51 }
52 }  // namespace
53 
KeyEventHandler()54 KeyEventHandler::KeyEventHandler() : key_translator_(new KeyTranslator) {
55   Clear();
56 }
57 
GetKeyEvent(guint keyval,guint keycode,guint modifiers,config::Config::PreeditMethod preedit_method,bool layout_is_jp,commands::KeyEvent * key)58 bool KeyEventHandler::GetKeyEvent(
59     guint keyval, guint keycode, guint modifiers,
60     config::Config::PreeditMethod preedit_method,
61     bool layout_is_jp, commands::KeyEvent *key) {
62   DCHECK(key);
63   key->Clear();
64 
65   if (!key_translator_->Translate(
66           keyval, keycode, modifiers, preedit_method, layout_is_jp, key)) {
67     LOG(ERROR) << "Translate failed";
68     return false;
69   }
70 
71   const bool is_key_up = ((modifiers & IBUS_RELEASE_MASK) != 0);
72   return ProcessModifiers(is_key_up, keyval, key);
73 }
74 
Clear()75 void KeyEventHandler::Clear() {
76   is_non_modifier_key_pressed_ = false;
77   currently_pressed_modifiers_.clear();
78   modifiers_to_be_sent_.clear();
79 }
80 
ProcessModifiers(bool is_key_up,guint keyval,commands::KeyEvent * key_event)81 bool KeyEventHandler::ProcessModifiers(bool is_key_up, guint keyval,
82                                        commands::KeyEvent *key_event) {
83   // Manage modifier key event.
84   // Modifier key event is sent on key up if non-modifier key has not been
85   // pressed since key down of modifier keys and no modifier keys are pressed
86   // anymore.
87   // Following examples are expected behaviors.
88   //
89   // E.g.) Shift key is special. If Shift + printable key is pressed, key event
90   //       does NOT have shift modifiers. It is handled by KeyTranslator class.
91   //    <Event from ibus> <Event to server>
92   //     Shift down      | None
93   //     "a" down        | A
94   //     "a" up          | None
95   //     Shift up        | None
96   //
97   // E.g.) Usual key is sent on key down.  Modifier keys are not sent if usual
98   //       key is sent.
99   //    <Event from ibus> <Event to server>
100   //     Ctrl down       | None
101   //     "a" down        | Ctrl+a
102   //     "a" up          | None
103   //     Ctrl up         | None
104   //
105   // E.g.) Modifier key is sent on key up.
106   //    <Event from ibus> <Event to server>
107   //     Shift down      | None
108   //     Shift up        | Shift
109   //
110   // E.g.) Multiple modifier keys are sent on the last key up.
111   //    <Event from ibus> <Event to server>
112   //     Shift down      | None
113   //     Control down    | None
114   //     Shift up        | None
115   //     Control up      | Control+Shift
116   //
117   // Essentialy we cannot handle modifier key evnet perfectly because
118   // - We cannot get current keyboard status with ibus. If some modifiers
119   //   are pressed or released without focusing the target window, we
120   //   cannot handle it.
121   // E.g.)
122   //    <Event from ibus> <Event to server>
123   //     Ctrl down       | None
124   //     (focuses out, Ctrl up, focuses in)
125   //     Shift down      | None
126   //     Shift up        | None (But we should send Shift key)
127   // To avoid a inconsistent state as much as possible, we clear states
128   // when key event without modifier keys is sent.
129 
130   const bool is_modifier_only =
131       !(key_event->has_key_code() || key_event->has_special_key());
132 
133   // We may get only up/down key event when a user moves a focus.
134   // This code handles such situation as much as possible.
135   // This code has a bug. If we send Shift + 'a', KeyTranslator removes a shift
136   // modifier and converts 'a' to 'A'. This codes does NOT consider these
137   // situation since we don't have enough data to handle it.
138   // TODO(hsumita): Moves the logic about a handling of Shift or Caps keys from
139   // KeyTranslator to MozcEngine.
140   if (key_event->modifier_keys_size() == 0) {
141     Clear();
142   }
143 
144   if (!currently_pressed_modifiers_.empty() && !is_modifier_only) {
145     is_non_modifier_key_pressed_ = true;
146   }
147   if (is_non_modifier_key_pressed_) {
148     modifiers_to_be_sent_.clear();
149   }
150 
151   if (is_key_up) {
152     currently_pressed_modifiers_.erase(keyval);
153     if (!is_modifier_only) {
154       return false;
155     }
156     if (!currently_pressed_modifiers_.empty() ||
157         modifiers_to_be_sent_.empty()) {
158       is_non_modifier_key_pressed_ = false;
159       return false;
160     }
161     if (is_non_modifier_key_pressed_) {
162       return false;
163     }
164     DCHECK(!is_non_modifier_key_pressed_);
165 
166     // Modifier key event fires
167     key_event->mutable_modifier_keys()->Clear();
168     for (std::set<commands::KeyEvent::ModifierKey>::const_iterator it =
169              modifiers_to_be_sent_.begin();
170          it != modifiers_to_be_sent_.end();
171          ++it) {
172       key_event->add_modifier_keys(*it);
173     }
174     modifiers_to_be_sent_.clear();
175   } else if (is_modifier_only) {
176     // TODO(hsumita): Supports a key sequence below.
177     // - Ctrl down
178     // - a down
179     // - Alt down
180     // We should add Alt key to |currently_pressed_modifiers|, but current
181     // implementation does NOT do it.
182     if (currently_pressed_modifiers_.empty() ||
183         !modifiers_to_be_sent_.empty()) {
184       for (size_t i = 0; i < key_event->modifier_keys_size(); ++i) {
185         modifiers_to_be_sent_.insert(key_event->modifier_keys(i));
186       }
187     }
188     currently_pressed_modifiers_.insert(keyval);
189     return false;
190   }
191 
192   // Clear modifier data just in case if |key| has no modifier keys.
193   if (!IsModifierToBeSentOnKeyUp(*key_event)) {
194     Clear();
195   }
196 
197   return true;
198 }
199 
200 }  // namespace ibus
201 }  // namespace mozc
202