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

Unified Diff: views/ime/ibus_ime_context.cc

Issue 6480036: Add input method support for views and integrate ibus input framework (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 9 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/renderer_host/render_widget_host_view_views.cc ('k') | views/ime/ime_context.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: views/ime/ibus_ime_context.cc
diff --git a/views/ime/ibus_ime_context.cc b/views/ime/ibus_ime_context.cc
new file mode 100644
index 0000000000000000000000000000000000000000..130d863d3491249598b718502ecdbd5ad6c984ee
--- /dev/null
+++ b/views/ime/ibus_ime_context.cc
@@ -0,0 +1,398 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ibus.h>
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "gfx/rect.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/gtk/gtk_signal.h"
+#include "ui/base/keycodes/keyboard_code_conversion_gtk.h"
+#include "views/events/event.h"
+#include "views/ime/ime_context.h"
+
+namespace {
+
+class IBusIMEContext;
+
+struct ProcessKeyEventData {
+ ProcessKeyEventData(IBusIMEContext* context,
+ const views::KeyEvent& event)
+ : context(context),
+ event(event.type(), event.key_code(), event.flags()) {
+ }
+
+ IBusIMEContext* context;
+ views::KeyEvent event;
+};
+
+// Implements IMEContext to integrate ibus input method framework
+class IBusIMEContext : public views::IMEContext {
+ public:
+ explicit IBusIMEContext(views::View* view);
+ virtual ~IBusIMEContext();
+
+ // views::IMEContext implementations:
+ virtual void Focus();
+ virtual void Blur();
+ virtual void Reset();
+ virtual bool FilterKeyEvent(const views::KeyEvent& event);
+ virtual void SetCursorLocation(const gfx::Rect& caret_rect);
+ virtual void SetSurrounding(const string16& text, int cursor_pos);
+
+ private:
+ void CreateContext();
+ void DestroyContext();
+
+ // Event handlers for IBusBus:
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnConnected, IBusBus*);
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDisconnected, IBusBus*);
+
+ // Event handlers for IBusIMEContext:
+ CHROMEG_CALLBACK_1(IBusIMEContext, void, OnCommitText,
+ IBusInputContext*, IBusText*);
+ CHROMEG_CALLBACK_3(IBusIMEContext, void, OnForwardKeyEvent,
+ IBusInputContext*, guint, guint, guint);
+ CHROMEG_CALLBACK_3(IBusIMEContext, void, OnUpdatePreeditText,
+ IBusInputContext*, IBusText*, guint, gboolean);
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnShowPreeditText,
+ IBusInputContext*);
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnHidePreeditText,
+ IBusInputContext*);
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnEnable, IBusInputContext*);
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDisable, IBusInputContext*);
+ CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDestroy, IBusInputContext*);
+
+ static void ProcessKeyEventDone(IBusInputContext* context,
+ GAsyncResult* res,
+ ProcessKeyEventData *data);
+
+ IBusInputContext* context_;
+ bool is_focused_;
+ gfx::Rect caret_rect_;
+
+ static IBusBus* bus_;
+
+ DISALLOW_COPY_AND_ASSIGN(IBusIMEContext);
+};
+
+IBusBus* IBusIMEContext::bus_ = NULL;
+
+IBusIMEContext::IBusIMEContext(views::View* view)
+ : views::IMEContext(view),
+ context_(NULL),
+ is_focused_(false) {
+ // init ibus
+ if (!bus_) {
+ ibus_init();
+ bus_ = ibus_bus_new();
+ }
+
+ // connect bus signals
+ g_signal_connect(bus_,
+ "connected",
+ G_CALLBACK(OnConnectedThunk),
+ this);
+ g_signal_connect(bus_,
+ "disconnected",
+ G_CALLBACK(OnDisconnectedThunk),
+ this);
+
+ if (ibus_bus_is_connected(bus_))
+ CreateContext();
+}
+
+IBusIMEContext::~IBusIMEContext() {
+ // disconnect bus signals
+ g_signal_handlers_disconnect_by_func(bus_,
+ reinterpret_cast<gpointer>(OnConnectedThunk), this);
+ g_signal_handlers_disconnect_by_func(bus_,
+ reinterpret_cast<gpointer>(OnDisconnectedThunk), this);
+
+ DestroyContext();
+}
+
+void IBusIMEContext::Focus() {
+ if (is_focused_)
+ return;
+ is_focused_ = true;
+
+ if (context_)
+ ibus_input_context_focus_in(context_);
+}
+
+void IBusIMEContext::Blur() {
+ if (!is_focused_)
+ return;
+
+ is_focused_ = false;
+
+ if (context_)
+ ibus_input_context_focus_out(context_);
+}
+
+void IBusIMEContext::Reset() {
+ if (context_)
+ ibus_input_context_reset(context_);
+}
+
+bool IBusIMEContext::FilterKeyEvent(const views::KeyEvent& event) {
+ guint keyval = ui::GdkKeyCodeForWindowsKeyCode(event.key_code(),
+ event.IsShiftDown() ^ event.IsCapsLockDown());
+
+ if (context_) {
+ guint modifiers = 0;
+
+ if (event.type() == ui::ET_KEY_RELEASED)
+ modifiers |= IBUS_RELEASE_MASK;
+
+ if (event.IsShiftDown())
+ modifiers |= IBUS_SHIFT_MASK;
+ if (event.IsControlDown())
+ modifiers |= IBUS_CONTROL_MASK;
+ if (event.IsAltDown())
+ modifiers |= IBUS_MOD1_MASK;
+ if (event.IsCapsLockDown())
+ modifiers |= IBUS_LOCK_MASK;
+
+ ibus_input_context_process_key_event(context_,
+ keyval, 0, modifiers,
+ -1,
+ NULL,
+ reinterpret_cast<GAsyncReadyCallback>(ProcessKeyEventDone),
+ new ProcessKeyEventData(this, event));
+ return true;
+ }
+
+ return false;
+}
+
+void IBusIMEContext::SetCursorLocation(const gfx::Rect& caret_rect) {
+ if (context_ && caret_rect_ != caret_rect) {
+ caret_rect_ = caret_rect;
+ ibus_input_context_set_cursor_location(context_,
+ caret_rect_.x(),
+ caret_rect_.y(),
+ caret_rect_.width(),
+ caret_rect_.height());
+ }
+}
+
+void IBusIMEContext::SetSurrounding(const string16& text,
+ int cursor_pos) {
+ // TODO(penghuang) support surrounding
+}
+
+void IBusIMEContext::CreateContext() {
+ DCHECK(bus_ != NULL);
+ DCHECK(ibus_bus_is_connected(bus_));
+
+ context_ = ibus_bus_create_input_context(bus_, "chrome");
+
+ // connect input context signals
+ g_signal_connect(context_,
+ "commit-text",
+ G_CALLBACK(OnCommitTextThunk),
+ this);
+ g_signal_connect(context_,
+ "forward-key-event",
+ G_CALLBACK(OnForwardKeyEventThunk),
+ this);
+ g_signal_connect(context_,
+ "update-preedit-text",
+ G_CALLBACK(OnUpdatePreeditTextThunk),
+ this);
+ g_signal_connect(context_,
+ "show-preedit-text",
+ G_CALLBACK(OnShowPreeditTextThunk),
+ this);
+ g_signal_connect(context_,
+ "hide-preedit-text",
+ G_CALLBACK(OnHidePreeditTextThunk),
+ this);
+ g_signal_connect(context_,
+ "enabled",
+ G_CALLBACK(OnEnableThunk),
+ this);
+ g_signal_connect(context_,
+ "disabled",
+ G_CALLBACK(OnDisableThunk),
+ this);
+ g_signal_connect(context_,
+ "destroy",
+ G_CALLBACK(OnDestroyThunk),
+ this);
+
+ guint32 caps = IBUS_CAP_PREEDIT_TEXT |
+ IBUS_CAP_FOCUS |
+ IBUS_CAP_SURROUNDING_TEXT;
+ ibus_input_context_set_capabilities(context_, caps);
+
+ if (is_focused_)
+ ibus_input_context_focus_in(context_);
+
+ ibus_input_context_set_cursor_location(context_,
+ caret_rect_.x(),
+ caret_rect_.y(),
+ caret_rect_.width(),
+ caret_rect_.height());
+}
+
+void IBusIMEContext::DestroyContext() {
+ if (!context_)
+ return;
+
+ ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(context_));
+
+ DCHECK(!context_);
+}
+
+void IBusIMEContext::OnConnected(IBusBus *bus) {
+ DCHECK(bus_ == bus);
+ DCHECK(ibus_bus_is_connected(bus_));
+
+ if (context_)
+ DestroyContext();
+ CreateContext();
+}
+
+void IBusIMEContext::OnDisconnected(IBusBus *bus) {
+}
+
+void IBusIMEContext::OnCommitText(IBusInputContext *context,
+ IBusText* text) {
+ DCHECK(context_ == context);
+ views::IMEContext::CommitText(UTF8ToUTF16(text->text));
+}
+
+void IBusIMEContext::OnForwardKeyEvent(IBusInputContext *context,
+ guint keyval,
+ guint keycode,
+ guint state) {
+ DCHECK(context_ == context);
+
+ int flags = 0;
+
+ if (state & IBUS_LOCK_MASK)
+ flags |= ui::EF_CAPS_LOCK_DOWN;
+ if (state & IBUS_CONTROL_MASK)
+ flags |= ui::EF_CONTROL_DOWN;
+ if (state & IBUS_SHIFT_MASK)
+ flags |= ui::EF_SHIFT_DOWN;
+ if (state & IBUS_MOD1_MASK)
+ flags |= ui::EF_ALT_DOWN;
+ if (state & IBUS_BUTTON1_MASK)
+ flags |= ui::EF_LEFT_BUTTON_DOWN;
+ if (state & IBUS_BUTTON2_MASK)
+ flags |= ui::EF_MIDDLE_BUTTON_DOWN;
+ if (state & IBUS_BUTTON3_MASK)
+ flags |= ui::EF_RIGHT_BUTTON_DOWN;
+
+ ForwardKeyEvent(views::KeyEvent(
+ state & IBUS_RELEASE_MASK ?
+ ui::ET_KEY_RELEASED : ui::ET_KEY_PRESSED,
+ ui::WindowsKeyCodeForGdkKeyCode(keyval),
+ flags));
+}
+
+void IBusIMEContext::OnUpdatePreeditText(IBusInputContext *context,
+ IBusText* text,
+ guint cursor_pos,
+ gboolean visible) {
+ DCHECK(context_ == context);
+ DCHECK(IBUS_IS_TEXT(text));
+
+ if (visible) {
+ views::CompositionAttributeList attributes;
+ IBusAttrList *attrs = text->attrs;
+ if (attrs) {
+ int i = 0;
+ while (1) {
+ IBusAttribute *attr = ibus_attr_list_get(attrs, i++);
+ if (!attr)
+ break;
+ if (attr->type == IBUS_ATTR_TYPE_UNDERLINE ||
+ attr->type == IBUS_ATTR_TYPE_BACKGROUND) {
+ views::CompositionAttribute attribute(attr->start_index,
+ attr->end_index,
+ SK_ColorBLACK,
+ false);
+ if (attr->type == IBUS_ATTR_TYPE_BACKGROUND) {
+ attribute.thick = true;
+ } else if (attr->type == IBUS_ATTR_TYPE_UNDERLINE) {
+ if (attr->value == IBUS_ATTR_UNDERLINE_DOUBLE) {
+ attribute.thick = true;
+ } else if (attr->value == IBUS_ATTR_UNDERLINE_ERROR) {
+ attribute.color = SK_ColorRED;
+ }
+ }
+ attributes.push_back(attribute);
+ }
+ }
+ }
+
+ SetComposition(UTF8ToUTF16(text->text),
+ attributes,
+ cursor_pos);
+ } else {
+ EndComposition();
+ }
+}
+
+void IBusIMEContext::OnShowPreeditText(IBusInputContext *context) {
+ DCHECK(context_ == context);
+}
+
+void IBusIMEContext::OnHidePreeditText(IBusInputContext *context) {
+ DCHECK(context_ == context);
+
+ EndComposition();
+}
+
+void IBusIMEContext::OnEnable(IBusInputContext *context) {
+ DCHECK(context_ == context);
+}
+
+void IBusIMEContext::OnDisable(IBusInputContext *context) {
+ DCHECK(context_ == context);
+}
+
+void IBusIMEContext::OnDestroy(IBusInputContext *context) {
+ DCHECK(context_ == context);
+
+ g_object_unref(context_);
+ context_ = NULL;
+
+ EndComposition();
+}
+
+void IBusIMEContext::ProcessKeyEventDone(IBusInputContext *context,
+ GAsyncResult* res,
+ ProcessKeyEventData *data) {
+ DCHECK(data->context->context_ == context);
+
+ gboolean processed = FALSE;
+
+ if (!ibus_input_context_process_key_event_finish(context,
+ res,
+ &processed,
+ NULL))
+ processed = FALSE;
+
+ if (processed == FALSE)
+ data->context->ForwardKeyEvent(data->event);
+
+ delete data;
+}
+
+} // namespace
+
+namespace views {
+
+IMEContext* IMEContext::Create(View* view) {
+ return new IBusIMEContext(view);
+}
+
+} // namespace views
« no previous file with comments | « chrome/browser/renderer_host/render_widget_host_view_views.cc ('k') | views/ime/ime_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698