Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: chrome/browser/renderer_host/gtk_im_context_wrapper.cc

Issue 6336003: Workaround a nasty ibus issue. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix MENU key. Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/renderer_host/gtk_im_context_wrapper.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/renderer_host/gtk_im_context_wrapper.h" 5 #include "chrome/browser/renderer_host/gtk_im_context_wrapper.h"
6 6
7 #include <gdk/gdk.h> 7 #include <gdk/gdk.h>
8 #include <gdk/gdkkeysyms.h> 8 #include <gdk/gdkkeysyms.h>
9 #include <gtk/gtk.h> 9 #include <gtk/gtk.h>
10 #include <algorithm> 10 #include <algorithm>
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 : host_view_(host_view), 48 : host_view_(host_view),
49 context_(gtk_im_multicontext_new()), 49 context_(gtk_im_multicontext_new()),
50 context_simple_(gtk_im_context_simple_new()), 50 context_simple_(gtk_im_context_simple_new()),
51 is_focused_(false), 51 is_focused_(false),
52 is_composing_text_(false), 52 is_composing_text_(false),
53 is_enabled_(false), 53 is_enabled_(false),
54 is_in_key_event_handler_(false), 54 is_in_key_event_handler_(false),
55 preedit_selection_start_(0), 55 preedit_selection_start_(0),
56 preedit_selection_end_(0), 56 preedit_selection_end_(0),
57 is_preedit_changed_(false), 57 is_preedit_changed_(false),
58 suppress_next_commit_(false) { 58 suppress_next_commit_(false),
59 last_key_code_(0),
60 last_key_was_up_(false),
61 last_key_filtered_no_result_(false) {
59 DCHECK(context_); 62 DCHECK(context_);
60 DCHECK(context_simple_); 63 DCHECK(context_simple_);
61 64
62 // context_ and context_simple_ share the same callback handlers. 65 // context_ and context_simple_ share the same callback handlers.
63 // All data come from them are treated equally. 66 // All data come from them are treated equally.
64 // context_ is for full input method support. 67 // context_ is for full input method support.
65 // context_simple_ is for supporting dead/compose keys when input method is 68 // context_simple_ is for supporting dead/compose keys when input method is
66 // disabled by webkit, eg. in password input box. 69 // disabled by webkit, eg. in password input box.
67 g_signal_connect(context_, "preedit_start", 70 g_signal_connect(context_, "preedit_start",
68 G_CALLBACK(HandlePreeditStartThunk), this); 71 G_CALLBACK(HandlePreeditStartThunk), this);
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 154
152 // Reset this flag here, as it's only used in input method callbacks. 155 // Reset this flag here, as it's only used in input method callbacks.
153 is_in_key_event_handler_ = false; 156 is_in_key_event_handler_ = false;
154 157
155 NativeWebKeyboardEvent wke(event); 158 NativeWebKeyboardEvent wke(event);
156 159
157 // If the key event was handled by the input method, then we need to prevent 160 // If the key event was handled by the input method, then we need to prevent
158 // RenderView::UnhandledKeyboardEvent() from processing it. 161 // RenderView::UnhandledKeyboardEvent() from processing it.
159 // Otherwise unexpected result may occur. For example if it's a 162 // Otherwise unexpected result may occur. For example if it's a
160 // Backspace key event, the browser may go back to previous page. 163 // Backspace key event, the browser may go back to previous page.
161 if (filtered) 164 // We just send all keyup events to the browser to avoid breaking the
165 // browser's MENU key function, which is actually the only keyup event
166 // handled in the browser.
167 if (filtered && event->type == GDK_KEY_PRESS)
162 wke.skip_in_browser = true; 168 wke.skip_in_browser = true;
163 169
170 const int key_code = wke.windowsKeyCode;
171 const bool has_result = HasInputMethodResult();
172
164 // Send filtered keydown event before sending IME result. 173 // Send filtered keydown event before sending IME result.
165 if (event->type == GDK_KEY_PRESS && filtered) 174 // In order to workaround http://crosbug.com/6582, we only send a filtered
175 // keydown event if it generated any input method result.
176 if (event->type == GDK_KEY_PRESS && filtered && has_result)
166 ProcessFilteredKeyPressEvent(&wke); 177 ProcessFilteredKeyPressEvent(&wke);
167 178
168 // Send IME results. In most cases, it's only available if the key event 179 // Send IME results. In most cases, it's only available if the key event
169 // is filtered by IME. But in rare cases, an unfiltered key event may also 180 // is filtered by IME. But in rare cases, an unfiltered key event may also
170 // generate IME results. 181 // generate IME results.
171 // Any IME results generated by a unfiltered key down event must be sent 182 // Any IME results generated by a unfiltered key down event must be sent
172 // before the key down event, to avoid some tricky issues. For example, 183 // before the key down event, to avoid some tricky issues. For example,
173 // when using latin-post input method, pressing 'a' then Backspace, may 184 // when using latin-post input method, pressing 'a' then Backspace, may
174 // generate following events in sequence: 185 // generate following events in sequence:
175 // 1. keydown 'a' (filtered) 186 // 1. keydown 'a' (filtered)
176 // 2. preedit changed to "a" 187 // 2. preedit changed to "a"
177 // 3. keyup 'a' (unfiltered) 188 // 3. keyup 'a' (unfiltered)
178 // 4. keydown Backspace (unfiltered) 189 // 4. keydown Backspace (unfiltered)
179 // 5. commit "a" 190 // 5. commit "a"
180 // 6. preedit end 191 // 6. preedit end
181 // 7. keyup Backspace (unfiltered) 192 // 7. keyup Backspace (unfiltered)
182 // 193 //
183 // In this case, the input box will be in a strange state if keydown 194 // In this case, the input box will be in a strange state if keydown
184 // Backspace is sent to webkit before commit "a" and preedit end. 195 // Backspace is sent to webkit before commit "a" and preedit end.
185 ProcessInputMethodResult(event, filtered); 196 if (has_result)
197 ProcessInputMethodResult(event, filtered);
186 198
187 // Send unfiltered keydown and keyup events after sending IME result. 199 // Send unfiltered keydown and keyup events after sending IME result.
188 if (event->type == GDK_KEY_PRESS && !filtered) 200 if (event->type == GDK_KEY_PRESS && !filtered) {
189 ProcessUnfilteredKeyPressEvent(&wke); 201 ProcessUnfilteredKeyPressEvent(&wke);
190 else if (event->type == GDK_KEY_RELEASE) 202 } else if (event->type == GDK_KEY_RELEASE) {
191 host_view_->ForwardKeyboardEvent(wke); 203 // In order to workaround http://crosbug.com/6582, we need to suppress
204 // the keyup event if corresponding keydown event was suppressed, or
205 // the last key event was a keyup event with the same keycode.
206 const bool suppress = (last_key_code_ == key_code) &&
207 (last_key_was_up_ || last_key_filtered_no_result_);
208
209 if (!suppress)
210 host_view_->ForwardKeyboardEvent(wke);
211 }
212
213 last_key_code_ = key_code;
214 last_key_was_up_ = (event->type == GDK_KEY_RELEASE);
215 last_key_filtered_no_result_ = (filtered && !has_result);
192 } 216 }
193 217
194 void GtkIMContextWrapper::UpdateInputMethodState(WebKit::WebTextInputType type, 218 void GtkIMContextWrapper::UpdateInputMethodState(WebKit::WebTextInputType type,
195 const gfx::Rect& caret_rect) { 219 const gfx::Rect& caret_rect) {
196 suppress_next_commit_ = false; 220 suppress_next_commit_ = false;
197 221
198 // The renderer has updated its IME status. 222 // The renderer has updated its IME status.
199 // Control the GtkIMContext object according to this status. 223 // Control the GtkIMContext object according to this status.
200 if (!context_ || !is_focused_) 224 if (!context_ || !is_focused_)
201 return; 225 return;
(...skipping 20 matching lines...) Expand all
222 } 246 }
223 247
224 void GtkIMContextWrapper::OnFocusIn() { 248 void GtkIMContextWrapper::OnFocusIn() {
225 if (is_focused_) 249 if (is_focused_)
226 return; 250 return;
227 251
228 // Tracks the focused state so that we can give focus to the 252 // Tracks the focused state so that we can give focus to the
229 // GtkIMContext object correctly later when IME is enabled by WebKit. 253 // GtkIMContext object correctly later when IME is enabled by WebKit.
230 is_focused_ = true; 254 is_focused_ = true;
231 255
256 last_key_code_ = 0;
257 last_key_was_up_ = false;
258 last_key_filtered_no_result_ = false;
259
232 // Notify the GtkIMContext object of this focus-in event only if IME is 260 // Notify the GtkIMContext object of this focus-in event only if IME is
233 // enabled by WebKit. 261 // enabled by WebKit.
234 if (is_enabled_) 262 if (is_enabled_)
235 gtk_im_context_focus_in(context_); 263 gtk_im_context_focus_in(context_);
236 264
237 // context_simple_ is always enabled. 265 // context_simple_ is always enabled.
238 // Actually it doesn't care focus state at all. 266 // Actually it doesn't care focus state at all.
239 gtk_im_context_focus_in(context_simple_); 267 gtk_im_context_focus_in(context_simple_);
240 268
241 // Enables RenderWidget's IME related events, so that we can be notified 269 // Enables RenderWidget's IME related events, so that we can be notified
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 } 343 }
316 344
317 is_composing_text_ = false; 345 is_composing_text_ = false;
318 preedit_text_.clear(); 346 preedit_text_.clear();
319 preedit_underlines_.clear(); 347 preedit_underlines_.clear();
320 commit_text_.clear(); 348 commit_text_.clear();
321 349
322 is_in_key_event_handler_ = false; 350 is_in_key_event_handler_ = false;
323 } 351 }
324 352
325 bool GtkIMContextWrapper::NeedCommitByForwardingCharEvent() { 353 bool GtkIMContextWrapper::NeedCommitByForwardingCharEvent() const {
326 // If there is no composition text and has only one character to be 354 // If there is no composition text and has only one character to be
327 // committed, then the character will be send to webkit as a Char event 355 // committed, then the character will be send to webkit as a Char event
328 // instead of a confirmed composition text. 356 // instead of a confirmed composition text.
329 // It should be fine to handle BMP character only, as non-BMP characters 357 // It should be fine to handle BMP character only, as non-BMP characters
330 // can always be committed as confirmed composition text. 358 // can always be committed as confirmed composition text.
331 return !is_composing_text_ && commit_text_.length() == 1; 359 return !is_composing_text_ && commit_text_.length() == 1;
332 } 360 }
333 361
362 bool GtkIMContextWrapper::HasInputMethodResult() const {
363 return commit_text_.length() || is_preedit_changed_;
364 }
365
334 void GtkIMContextWrapper::ProcessFilteredKeyPressEvent( 366 void GtkIMContextWrapper::ProcessFilteredKeyPressEvent(
335 NativeWebKeyboardEvent* wke) { 367 NativeWebKeyboardEvent* wke) {
336 // If IME has filtered this event, then replace virtual key code with 368 // If IME has filtered this event, then replace virtual key code with
337 // VK_PROCESSKEY. See comment in ProcessKeyEvent() for details. 369 // VK_PROCESSKEY. See comment in ProcessKeyEvent() for details.
338 // It's only required for keydown events. 370 // It's only required for keydown events.
339 // To emulate windows behavior, when input method is enabled, if the commit 371 // To emulate windows behavior, when input method is enabled, if the commit
340 // text can be emulated by a Char event, then don't do this replacement. 372 // text can be emulated by a Char event, then don't do this replacement.
341 if (!NeedCommitByForwardingCharEvent()) { 373 if (!NeedCommitByForwardingCharEvent()) {
342 wke->windowsKeyCode = kCompositionEventKeyCode; 374 wke->windowsKeyCode = kCompositionEventKeyCode;
343 // keyidentifier must be updated accordingly, otherwise this key event may 375 // keyidentifier must be updated accordingly, otherwise this key event may
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 } while (pango_attr_iterator_next(iter)); 701 } while (pango_attr_iterator_next(iter));
670 pango_attr_iterator_destroy(iter); 702 pango_attr_iterator_destroy(iter);
671 } 703 }
672 704
673 // Use a black thin underline by default. 705 // Use a black thin underline by default.
674 if (underlines->empty()) { 706 if (underlines->empty()) {
675 underlines->push_back( 707 underlines->push_back(
676 WebKit::WebCompositionUnderline(0, length, SK_ColorBLACK, false)); 708 WebKit::WebCompositionUnderline(0, length, SK_ColorBLACK, false));
677 } 709 }
678 } 710 }
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/gtk_im_context_wrapper.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698