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