1 // Copyright 2010-2012, Google Inc.
2 // Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "unix/fcitx/fcitx_key_event_handler.h"
32 
33 #include <map>
34 
35 #include "base/logging.h"
36 #include "base/singleton.h"
37 
38 namespace mozc {
39 namespace fcitx {
40 
41 namespace {
42 // TODO(hsumita): Removes this class, and moves |data_| into member
43 // variables of KeyEventhandler.
44 class AdditionalModifiersData {
45  public:
AdditionalModifiersData()46   AdditionalModifiersData() {
47     data_[commands::KeyEvent::LEFT_ALT] = commands::KeyEvent::ALT;
48     data_[commands::KeyEvent::RIGHT_ALT] = commands::KeyEvent::ALT;
49     data_[commands::KeyEvent::LEFT_CTRL] = commands::KeyEvent::CTRL;
50     data_[commands::KeyEvent::RIGHT_CTRL] = commands::KeyEvent::CTRL;
51     data_[commands::KeyEvent::LEFT_SHIFT] = commands::KeyEvent::SHIFT;
52     data_[commands::KeyEvent::RIGHT_SHIFT] = commands::KeyEvent::SHIFT;
53   }
data()54   const std::map<uint32, commands::KeyEvent::ModifierKey> &data() {
55     return data_;
56   }
57 
58  private:
59   std::map<uint32, commands::KeyEvent::ModifierKey> data_;
60 };
61 
62 // TODO(hsumita): Moves this function into member functions of
63 // KeyEventHandler.
AddAdditionalModifiers(std::set<commands::KeyEvent::ModifierKey> * modifier_keys_set)64 void AddAdditionalModifiers(
65     std::set<commands::KeyEvent::ModifierKey> *modifier_keys_set) {
66   DCHECK(modifier_keys_set);
67 
68   const std::map<uint32, commands::KeyEvent::ModifierKey> &data =
69       Singleton<AdditionalModifiersData>::get()->data();
70 
71   // Adds MODIFIER if there are (LEFT|RIGHT)_MODIFIER like LEFT_SHIFT.
72   for (std::set<commands::KeyEvent::ModifierKey>::const_iterator it =
73            modifier_keys_set->begin(); it != modifier_keys_set->end(); ++it) {
74     std::map<uint32, commands::KeyEvent::ModifierKey>::const_iterator item =
75         data.find(*it);
76     if (item != data.end()) {
77       modifier_keys_set->insert(item->second);
78     }
79   }
80 }
81 
IsModifierToBeSentOnKeyUp(const commands::KeyEvent & key_event)82 bool IsModifierToBeSentOnKeyUp(const commands::KeyEvent &key_event) {
83   if (key_event.modifier_keys_size() == 0) {
84     return false;
85   }
86 
87   if (key_event.modifier_keys_size() == 1 &&
88       key_event.modifier_keys(0) == commands::KeyEvent::CAPS) {
89     return false;
90   }
91 
92   return true;
93 }
94 }  // namespace
95 
KeyEventHandler()96 KeyEventHandler::KeyEventHandler() : key_translator_(new KeyTranslator) {
97   Clear();
98 }
99 
GetKeyEvent(FcitxKeySym keyval,uint32 keycode,uint32 modifiers,config::Config::PreeditMethod preedit_method,bool layout_is_jp,bool is_key_up,commands::KeyEvent * key)100 bool KeyEventHandler::GetKeyEvent(
101     FcitxKeySym keyval, uint32 keycode, uint32 modifiers,
102     config::Config::PreeditMethod preedit_method,
103     bool layout_is_jp, bool is_key_up, commands::KeyEvent *key) {
104   DCHECK(key);
105   key->Clear();
106 
107   if (!key_translator_->Translate(
108           keyval, keycode, modifiers, preedit_method, layout_is_jp, key)) {
109     LOG(ERROR) << "Translate failed";
110     return false;
111   }
112 
113   return ProcessModifiers(is_key_up, keyval, key);
114 }
115 
Clear()116 void KeyEventHandler::Clear() {
117   is_non_modifier_key_pressed_ = false;
118   currently_pressed_modifiers_.clear();
119   modifiers_to_be_sent_.clear();
120 }
121 
ProcessModifiers(bool is_key_up,uint32 keyval,commands::KeyEvent * key_event)122 bool KeyEventHandler::ProcessModifiers(bool is_key_up, uint32 keyval,
123                                        commands::KeyEvent *key_event) {
124   // Manage modifier key event.
125   // Modifier key event is sent on key up if non-modifier key has not been
126   // pressed since key down of modifier keys and no modifier keys are pressed
127   // anymore.
128   // Following examples are expected behaviors.
129   //
130   // E.g.) Shift key is special. If Shift + printable key is pressed, key event
131   //       does NOT have shift modifiers. It is handled by KeyTranslator class.
132   //    <Event from ibus> <Event to server>
133   //     Shift down      | None
134   //     "a" down        | A
135   //     "a" up          | None
136   //     Shift up        | None
137   //
138   // E.g.) Usual key is sent on key down.  Modifier keys are not sent if usual
139   //       key is sent.
140   //    <Event from ibus> <Event to server>
141   //     Ctrl down       | None
142   //     "a" down        | Ctrl+a
143   //     "a" up          | None
144   //     Ctrl up         | None
145   //
146   // E.g.) Modifier key is sent on key up.
147   //    <Event from ibus> <Event to server>
148   //     Shift down      | None
149   //     Shift up        | Shift
150   //
151   // E.g.) Multiple modifier keys are sent on the last key up.
152   //    <Event from ibus> <Event to server>
153   //     Shift down      | None
154   //     Control down    | None
155   //     Shift up        | None
156   //     Control up      | Control+Shift
157   //
158   // Essentialy we cannot handle modifier key evnet perfectly because
159   // - We cannot get current keyboard status with ibus. If some modifiers
160   //   are pressed or released without focusing the target window, we
161   //   cannot handle it.
162   // E.g.)
163   //    <Event from ibus> <Event to server>
164   //     Ctrl down       | None
165   //     (focuses out, Ctrl up, focuses in)
166   //     Shift down      | None
167   //     Shift up        | None (But we should send Shift key)
168   // To avoid a inconsistent state as much as possible, we clear states
169   // when key event without modifier keys is sent.
170 
171   const bool is_modifier_only =
172       !(key_event->has_key_code() || key_event->has_special_key());
173 
174   // We may get only up/down key event when a user moves a focus.
175   // This code handles such situation as much as possible.
176   // This code has a bug. If we send Shift + 'a', KeyTranslator removes a shift
177   // modifier and converts 'a' to 'A'. This codes does NOT consider these
178   // situation since we don't have enough data to handle it.
179   // TODO(hsumita): Moves the logic about a handling of Shift or Caps keys from
180   // KeyTranslator to MozcEngine.
181   if (key_event->modifier_keys_size() == 0) {
182     Clear();
183   }
184 
185   if (!currently_pressed_modifiers_.empty() && !is_modifier_only) {
186     is_non_modifier_key_pressed_ = true;
187   }
188   if (is_non_modifier_key_pressed_) {
189     modifiers_to_be_sent_.clear();
190   }
191 
192   if (is_key_up) {
193     currently_pressed_modifiers_.erase(keyval);
194     if (!is_modifier_only) {
195       return false;
196     }
197     if (!currently_pressed_modifiers_.empty() ||
198         modifiers_to_be_sent_.empty()) {
199       is_non_modifier_key_pressed_ = false;
200       return false;
201     }
202     if (is_non_modifier_key_pressed_) {
203       return false;
204     }
205     DCHECK(!is_non_modifier_key_pressed_);
206 
207     // Modifier key event fires
208     key_event->mutable_modifier_keys()->Clear();
209     for (std::set<commands::KeyEvent::ModifierKey>::const_iterator it =
210              modifiers_to_be_sent_.begin();
211          it != modifiers_to_be_sent_.end();
212          ++it) {
213       key_event->add_modifier_keys(*it);
214     }
215     modifiers_to_be_sent_.clear();
216   } else if (is_modifier_only) {
217     // TODO(hsumita): Supports a key sequence below.
218     // - Ctrl down
219     // - a down
220     // - Alt down
221     // We should add Alt key to |currently_pressed_modifiers|, but current
222     // implementation does NOT do it.
223     if (currently_pressed_modifiers_.empty() ||
224         !modifiers_to_be_sent_.empty()) {
225       for (size_t i = 0; i < key_event->modifier_keys_size(); ++i) {
226         modifiers_to_be_sent_.insert(key_event->modifier_keys(i));
227       }
228       AddAdditionalModifiers(&modifiers_to_be_sent_);
229     }
230     currently_pressed_modifiers_.insert(keyval);
231     return false;
232   }
233 
234   // Clear modifier data just in case if |key| has no modifier keys.
235   if (!IsModifierToBeSentOnKeyUp(*key_event)) {
236     Clear();
237   }
238 
239   return true;
240 }
241 
242 }  // namespace ibus
243 }  // namespace mozc
244