OLD | NEW |
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 10 matching lines...) Expand all Loading... |
21 #endif | 21 #endif |
22 #include "chrome/browser/renderer_host/render_widget_host.h" | 22 #include "chrome/browser/renderer_host/render_widget_host.h" |
23 #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" | 23 #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" |
24 #include "chrome/common/native_web_keyboard_event.h" | 24 #include "chrome/common/native_web_keyboard_event.h" |
25 #include "chrome/common/render_messages.h" | 25 #include "chrome/common/render_messages.h" |
26 #include "gfx/gtk_util.h" | 26 #include "gfx/gtk_util.h" |
27 #include "gfx/rect.h" | 27 #include "gfx/rect.h" |
28 #include "grit/generated_resources.h" | 28 #include "grit/generated_resources.h" |
29 #include "third_party/skia/include/core/SkColor.h" | 29 #include "third_party/skia/include/core/SkColor.h" |
30 | 30 |
| 31 namespace { |
| 32 // Copied from third_party/WebKit/WebCore/page/EventHandler.cpp |
| 33 // |
| 34 // Match key code of composition keydown event on windows. |
| 35 // IE sends VK_PROCESSKEY which has value 229; |
| 36 // |
| 37 // Please refer to following documents for detals: |
| 38 // - Virtual-Key Codes |
| 39 // http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx |
| 40 // - How the IME System Works |
| 41 // http://msdn.microsoft.com/en-us/library/cc194848.aspx |
| 42 // - ImmGetVirtualKey Function |
| 43 // http://msdn.microsoft.com/en-us/library/dd318570(VS.85).aspx |
| 44 const int kCompositionEventKeyCode = 229; |
| 45 } // namespace |
| 46 |
31 GtkIMContextWrapper::GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view) | 47 GtkIMContextWrapper::GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view) |
32 : host_view_(host_view), | 48 : host_view_(host_view), |
33 context_(gtk_im_multicontext_new()), | 49 context_(gtk_im_multicontext_new()), |
34 context_simple_(gtk_im_context_simple_new()), | 50 context_simple_(gtk_im_context_simple_new()), |
35 is_focused_(false), | 51 is_focused_(false), |
36 is_composing_text_(false), | 52 is_composing_text_(false), |
37 is_enabled_(false), | 53 is_enabled_(false), |
38 is_in_key_event_handler_(false), | 54 is_in_key_event_handler_(false), |
39 preedit_selection_start_(0), | 55 preedit_selection_start_(0), |
40 preedit_selection_end_(0), | 56 preedit_selection_end_(0), |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 // If there is no composition text and has only one character to be | 326 // If there is no composition text and has only one character to be |
311 // committed, then the character will be send to webkit as a Char event | 327 // committed, then the character will be send to webkit as a Char event |
312 // instead of a confirmed composition text. | 328 // instead of a confirmed composition text. |
313 // It should be fine to handle BMP character only, as non-BMP characters | 329 // It should be fine to handle BMP character only, as non-BMP characters |
314 // can always be committed as confirmed composition text. | 330 // can always be committed as confirmed composition text. |
315 return !is_composing_text_ && commit_text_.length() == 1; | 331 return !is_composing_text_ && commit_text_.length() == 1; |
316 } | 332 } |
317 | 333 |
318 void GtkIMContextWrapper::ProcessFilteredKeyPressEvent( | 334 void GtkIMContextWrapper::ProcessFilteredKeyPressEvent( |
319 NativeWebKeyboardEvent* wke) { | 335 NativeWebKeyboardEvent* wke) { |
320 // Copied from third_party/WebKit/WebCore/page/EventHandler.cpp | |
321 // | |
322 // Match key code of composition keydown event on windows. | |
323 // IE sends VK_PROCESSKEY which has value 229; | |
324 // | |
325 // Please refer to following documents for detals: | |
326 // - Virtual-Key Codes | |
327 // http://msdn.microsoft.com/en-us/library/ms645540(VS.85).aspx | |
328 // - How the IME System Works | |
329 // http://msdn.microsoft.com/en-us/library/cc194848.aspx | |
330 // - ImmGetVirtualKey Function | |
331 // http://msdn.microsoft.com/en-us/library/dd318570(VS.85).aspx | |
332 const int kCompositionEventKeyCode = 229; | |
333 | |
334 // If IME has filtered this event, then replace virtual key code with | 336 // If IME has filtered this event, then replace virtual key code with |
335 // VK_PROCESSKEY. See comment in ProcessKeyEvent() for details. | 337 // VK_PROCESSKEY. See comment in ProcessKeyEvent() for details. |
336 // It's only required for keydown events. | 338 // It's only required for keydown events. |
337 // To emulate windows behavior, when input method is enabled, if the commit | 339 // To emulate windows behavior, when input method is enabled, if the commit |
338 // text can be emulated by a Char event, then don't do this replacement. | 340 // text can be emulated by a Char event, then don't do this replacement. |
339 if (!NeedCommitByForwardingCharEvent()) { | 341 if (!NeedCommitByForwardingCharEvent()) { |
340 wke->windowsKeyCode = kCompositionEventKeyCode; | 342 wke->windowsKeyCode = kCompositionEventKeyCode; |
341 // keyidentifier must be updated accordingly, otherwise this key event may | 343 // keyidentifier must be updated accordingly, otherwise this key event may |
342 // still be processed by webkit. | 344 // still be processed by webkit. |
343 wke->setKeyIdentifierFromWindowsKeyCode(); | 345 wke->setKeyIdentifierFromWindowsKeyCode(); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 | 445 |
444 // Append the text to the buffer, because commit signal might be fired | 446 // Append the text to the buffer, because commit signal might be fired |
445 // multiple times when processing a key event. | 447 // multiple times when processing a key event. |
446 commit_text_.append(text); | 448 commit_text_.append(text); |
447 // Nothing needs to do, if it's currently in ProcessKeyEvent() | 449 // Nothing needs to do, if it's currently in ProcessKeyEvent() |
448 // handler, which will send commit text to webkit later. Otherwise, | 450 // handler, which will send commit text to webkit later. Otherwise, |
449 // we need send it here. | 451 // we need send it here. |
450 // It's possible that commit signal is fired without a key event, for | 452 // It's possible that commit signal is fired without a key event, for |
451 // example when user input via a voice or handwriting recognition software. | 453 // example when user input via a voice or handwriting recognition software. |
452 // In this case, the text must be committed directly. | 454 // In this case, the text must be committed directly. |
453 if (!is_in_key_event_handler_ && host_view_->GetRenderWidgetHost()) | 455 if (!is_in_key_event_handler_ && host_view_->GetRenderWidgetHost()) { |
| 456 // Workaround http://crbug.com/45478 by sending fake key down/up events. |
| 457 SendFakeCompositionKeyEvent(WebKit::WebInputEvent::RawKeyDown); |
454 host_view_->GetRenderWidgetHost()->ImeConfirmComposition(text); | 458 host_view_->GetRenderWidgetHost()->ImeConfirmComposition(text); |
| 459 SendFakeCompositionKeyEvent(WebKit::WebInputEvent::KeyUp); |
| 460 } |
455 } | 461 } |
456 | 462 |
457 void GtkIMContextWrapper::HandlePreeditStart() { | 463 void GtkIMContextWrapper::HandlePreeditStart() { |
458 // Ignore preedit related signals triggered by CancelComposition() method. | 464 // Ignore preedit related signals triggered by CancelComposition() method. |
459 if (suppress_next_commit_) | 465 if (suppress_next_commit_) |
460 return; | 466 return; |
461 is_composing_text_ = true; | 467 is_composing_text_ = true; |
462 } | 468 } |
463 | 469 |
464 void GtkIMContextWrapper::HandlePreeditChanged(const gchar* text, | 470 void GtkIMContextWrapper::HandlePreeditChanged(const gchar* text, |
(...skipping 18 matching lines...) Expand all Loading... |
483 // In case we are using a buggy input method which doesn't fire | 489 // In case we are using a buggy input method which doesn't fire |
484 // "preedit_start" signal. | 490 // "preedit_start" signal. |
485 if (preedit_text_.length()) | 491 if (preedit_text_.length()) |
486 is_composing_text_ = true; | 492 is_composing_text_ = true; |
487 | 493 |
488 // Nothing needs to do, if it's currently in ProcessKeyEvent() | 494 // Nothing needs to do, if it's currently in ProcessKeyEvent() |
489 // handler, which will send preedit text to webkit later. | 495 // handler, which will send preedit text to webkit later. |
490 // Otherwise, we need send it here if it's been changed. | 496 // Otherwise, we need send it here if it's been changed. |
491 if (!is_in_key_event_handler_ && is_composing_text_ && | 497 if (!is_in_key_event_handler_ && is_composing_text_ && |
492 host_view_->GetRenderWidgetHost()) { | 498 host_view_->GetRenderWidgetHost()) { |
| 499 // Workaround http://crbug.com/45478 by sending fake key down/up events. |
| 500 SendFakeCompositionKeyEvent(WebKit::WebInputEvent::RawKeyDown); |
493 host_view_->GetRenderWidgetHost()->ImeSetComposition( | 501 host_view_->GetRenderWidgetHost()->ImeSetComposition( |
494 preedit_text_, preedit_underlines_, preedit_selection_start_, | 502 preedit_text_, preedit_underlines_, preedit_selection_start_, |
495 preedit_selection_end_); | 503 preedit_selection_end_); |
| 504 SendFakeCompositionKeyEvent(WebKit::WebInputEvent::KeyUp); |
496 } | 505 } |
497 } | 506 } |
498 | 507 |
499 void GtkIMContextWrapper::HandlePreeditEnd() { | 508 void GtkIMContextWrapper::HandlePreeditEnd() { |
500 if (preedit_text_.length()) { | 509 if (preedit_text_.length()) { |
501 // The composition session has been finished. | 510 // The composition session has been finished. |
502 preedit_text_.clear(); | 511 preedit_text_.clear(); |
503 preedit_underlines_.clear(); | 512 preedit_underlines_.clear(); |
504 is_preedit_changed_ = true; | 513 is_preedit_changed_ = true; |
505 | 514 |
(...skipping 16 matching lines...) Expand all Loading... |
522 gtk_im_context_set_client_window(context_, widget->window); | 531 gtk_im_context_set_client_window(context_, widget->window); |
523 gtk_im_context_set_client_window(context_simple_, widget->window); | 532 gtk_im_context_set_client_window(context_simple_, widget->window); |
524 } | 533 } |
525 } | 534 } |
526 | 535 |
527 void GtkIMContextWrapper::HandleHostViewUnrealize() { | 536 void GtkIMContextWrapper::HandleHostViewUnrealize() { |
528 gtk_im_context_set_client_window(context_, NULL); | 537 gtk_im_context_set_client_window(context_, NULL); |
529 gtk_im_context_set_client_window(context_simple_, NULL); | 538 gtk_im_context_set_client_window(context_simple_, NULL); |
530 } | 539 } |
531 | 540 |
| 541 void GtkIMContextWrapper::SendFakeCompositionKeyEvent( |
| 542 WebKit::WebInputEvent::Type type) { |
| 543 NativeWebKeyboardEvent fake_event; |
| 544 fake_event.windowsKeyCode = kCompositionEventKeyCode; |
| 545 fake_event.skip_in_browser = true; |
| 546 fake_event.type = type; |
| 547 host_view_->ForwardKeyboardEvent(fake_event); |
| 548 } |
| 549 |
532 void GtkIMContextWrapper::HandleCommitThunk( | 550 void GtkIMContextWrapper::HandleCommitThunk( |
533 GtkIMContext* context, gchar* text, GtkIMContextWrapper* self) { | 551 GtkIMContext* context, gchar* text, GtkIMContextWrapper* self) { |
534 self->HandleCommit(UTF8ToUTF16(text)); | 552 self->HandleCommit(UTF8ToUTF16(text)); |
535 } | 553 } |
536 | 554 |
537 void GtkIMContextWrapper::HandlePreeditStartThunk( | 555 void GtkIMContextWrapper::HandlePreeditStartThunk( |
538 GtkIMContext* context, GtkIMContextWrapper* self) { | 556 GtkIMContext* context, GtkIMContextWrapper* self) { |
539 self->HandlePreeditStart(); | 557 self->HandlePreeditStart(); |
540 } | 558 } |
541 | 559 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 } while (pango_attr_iterator_next(iter)); | 669 } while (pango_attr_iterator_next(iter)); |
652 pango_attr_iterator_destroy(iter); | 670 pango_attr_iterator_destroy(iter); |
653 } | 671 } |
654 | 672 |
655 // Use a black thin underline by default. | 673 // Use a black thin underline by default. |
656 if (underlines->empty()) { | 674 if (underlines->empty()) { |
657 underlines->push_back( | 675 underlines->push_back( |
658 WebKit::WebCompositionUnderline(0, length, SK_ColorBLACK, false)); | 676 WebKit::WebCompositionUnderline(0, length, SK_ColorBLACK, false)); |
659 } | 677 } |
660 } | 678 } |
OLD | NEW |