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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <ibus.h>
6
7 #include "base/logging.h"
8 #include "base/utf_string_conversions.h"
9 #include "gfx/rect.h"
10 #include "third_party/skia/include/core/SkColor.h"
11 #include "ui/base/gtk/gtk_signal.h"
12 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h"
13 #include "views/events/event.h"
14 #include "views/ime/ime_context.h"
15
16 namespace {
17
18 class IBusIMEContext;
19
20 struct ProcessKeyEventData {
21 ProcessKeyEventData(IBusIMEContext* context,
22 const views::KeyEvent& event)
23 : context(context),
24 event(event.type(), event.key_code(), event.flags()) {
25 }
26
27 IBusIMEContext* context;
28 views::KeyEvent event;
29 };
30
31 // Implements IMEContext to integrate ibus input method framework
32 class IBusIMEContext : public views::IMEContext {
33 public:
34 explicit IBusIMEContext(views::View* view);
35 virtual ~IBusIMEContext();
36
37 // views::IMEContext implementations:
38 virtual void Focus();
39 virtual void Blur();
40 virtual void Reset();
41 virtual bool FilterKeyEvent(const views::KeyEvent& event);
42 virtual void SetCursorLocation(const gfx::Rect& caret_rect);
43 virtual void SetSurrounding(const string16& text, int cursor_pos);
44
45 private:
46 void CreateContext();
47 void DestroyContext();
48
49 // Event handlers for IBusBus:
50 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnConnected, IBusBus*);
51 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDisconnected, IBusBus*);
52
53 // Event handlers for IBusIMEContext:
54 CHROMEG_CALLBACK_1(IBusIMEContext, void, OnCommitText,
55 IBusInputContext*, IBusText*);
56 CHROMEG_CALLBACK_3(IBusIMEContext, void, OnForwardKeyEvent,
57 IBusInputContext*, guint, guint, guint);
58 CHROMEG_CALLBACK_3(IBusIMEContext, void, OnUpdatePreeditText,
59 IBusInputContext*, IBusText*, guint, gboolean);
60 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnShowPreeditText,
61 IBusInputContext*);
62 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnHidePreeditText,
63 IBusInputContext*);
64 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnEnable, IBusInputContext*);
65 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDisable, IBusInputContext*);
66 CHROMEG_CALLBACK_0(IBusIMEContext, void, OnDestroy, IBusInputContext*);
67
68 static void ProcessKeyEventDone(IBusInputContext* context,
69 GAsyncResult* res,
70 ProcessKeyEventData *data);
71
72 IBusInputContext* context_;
73 bool is_focused_;
74 gfx::Rect caret_rect_;
75
76 static IBusBus* bus_;
77
78 DISALLOW_COPY_AND_ASSIGN(IBusIMEContext);
79 };
80
81 IBusBus* IBusIMEContext::bus_ = NULL;
82
83 IBusIMEContext::IBusIMEContext(views::View* view)
84 : views::IMEContext(view),
85 context_(NULL),
86 is_focused_(false) {
87 // init ibus
88 if (!bus_) {
89 ibus_init();
90 bus_ = ibus_bus_new();
91 }
92
93 // connect bus signals
94 g_signal_connect(bus_,
95 "connected",
96 G_CALLBACK(OnConnectedThunk),
97 this);
98 g_signal_connect(bus_,
99 "disconnected",
100 G_CALLBACK(OnDisconnectedThunk),
101 this);
102
103 if (ibus_bus_is_connected(bus_))
104 CreateContext();
105 }
106
107 IBusIMEContext::~IBusIMEContext() {
108 // disconnect bus signals
109 g_signal_handlers_disconnect_by_func(bus_,
110 reinterpret_cast<gpointer>(OnConnectedThunk), this);
111 g_signal_handlers_disconnect_by_func(bus_,
112 reinterpret_cast<gpointer>(OnDisconnectedThunk), this);
113
114 DestroyContext();
115 }
116
117 void IBusIMEContext::Focus() {
118 if (is_focused_)
119 return;
120 is_focused_ = true;
121
122 if (context_)
123 ibus_input_context_focus_in(context_);
124 }
125
126 void IBusIMEContext::Blur() {
127 if (!is_focused_)
128 return;
129
130 is_focused_ = false;
131
132 if (context_)
133 ibus_input_context_focus_out(context_);
134 }
135
136 void IBusIMEContext::Reset() {
137 if (context_)
138 ibus_input_context_reset(context_);
139 }
140
141 bool IBusIMEContext::FilterKeyEvent(const views::KeyEvent& event) {
142 guint keyval = ui::GdkKeyCodeForWindowsKeyCode(event.key_code(),
143 event.IsShiftDown() ^ event.IsCapsLockDown());
144
145 if (context_) {
146 guint modifiers = 0;
147
148 if (event.type() == ui::ET_KEY_RELEASED)
149 modifiers |= IBUS_RELEASE_MASK;
150
151 if (event.IsShiftDown())
152 modifiers |= IBUS_SHIFT_MASK;
153 if (event.IsControlDown())
154 modifiers |= IBUS_CONTROL_MASK;
155 if (event.IsAltDown())
156 modifiers |= IBUS_MOD1_MASK;
157 if (event.IsCapsLockDown())
158 modifiers |= IBUS_LOCK_MASK;
159
160 ibus_input_context_process_key_event(context_,
161 keyval, 0, modifiers,
162 -1,
163 NULL,
164 reinterpret_cast<GAsyncReadyCallback>(ProcessKeyEventDone),
165 new ProcessKeyEventData(this, event));
166 return true;
167 }
168
169 return false;
170 }
171
172 void IBusIMEContext::SetCursorLocation(const gfx::Rect& caret_rect) {
173 if (context_ && caret_rect_ != caret_rect) {
174 caret_rect_ = caret_rect;
175 ibus_input_context_set_cursor_location(context_,
176 caret_rect_.x(),
177 caret_rect_.y(),
178 caret_rect_.width(),
179 caret_rect_.height());
180 }
181 }
182
183 void IBusIMEContext::SetSurrounding(const string16& text,
184 int cursor_pos) {
185 // TODO(penghuang) support surrounding
186 }
187
188 void IBusIMEContext::CreateContext() {
189 DCHECK(bus_ != NULL);
190 DCHECK(ibus_bus_is_connected(bus_));
191
192 context_ = ibus_bus_create_input_context(bus_, "chrome");
193
194 // connect input context signals
195 g_signal_connect(context_,
196 "commit-text",
197 G_CALLBACK(OnCommitTextThunk),
198 this);
199 g_signal_connect(context_,
200 "forward-key-event",
201 G_CALLBACK(OnForwardKeyEventThunk),
202 this);
203 g_signal_connect(context_,
204 "update-preedit-text",
205 G_CALLBACK(OnUpdatePreeditTextThunk),
206 this);
207 g_signal_connect(context_,
208 "show-preedit-text",
209 G_CALLBACK(OnShowPreeditTextThunk),
210 this);
211 g_signal_connect(context_,
212 "hide-preedit-text",
213 G_CALLBACK(OnHidePreeditTextThunk),
214 this);
215 g_signal_connect(context_,
216 "enabled",
217 G_CALLBACK(OnEnableThunk),
218 this);
219 g_signal_connect(context_,
220 "disabled",
221 G_CALLBACK(OnDisableThunk),
222 this);
223 g_signal_connect(context_,
224 "destroy",
225 G_CALLBACK(OnDestroyThunk),
226 this);
227
228 guint32 caps = IBUS_CAP_PREEDIT_TEXT |
229 IBUS_CAP_FOCUS |
230 IBUS_CAP_SURROUNDING_TEXT;
231 ibus_input_context_set_capabilities(context_, caps);
232
233 if (is_focused_)
234 ibus_input_context_focus_in(context_);
235
236 ibus_input_context_set_cursor_location(context_,
237 caret_rect_.x(),
238 caret_rect_.y(),
239 caret_rect_.width(),
240 caret_rect_.height());
241 }
242
243 void IBusIMEContext::DestroyContext() {
244 if (!context_)
245 return;
246
247 ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(context_));
248
249 DCHECK(!context_);
250 }
251
252 void IBusIMEContext::OnConnected(IBusBus *bus) {
253 DCHECK(bus_ == bus);
254 DCHECK(ibus_bus_is_connected(bus_));
255
256 if (context_)
257 DestroyContext();
258 CreateContext();
259 }
260
261 void IBusIMEContext::OnDisconnected(IBusBus *bus) {
262 }
263
264 void IBusIMEContext::OnCommitText(IBusInputContext *context,
265 IBusText* text) {
266 DCHECK(context_ == context);
267 views::IMEContext::CommitText(UTF8ToUTF16(text->text));
268 }
269
270 void IBusIMEContext::OnForwardKeyEvent(IBusInputContext *context,
271 guint keyval,
272 guint keycode,
273 guint state) {
274 DCHECK(context_ == context);
275
276 int flags = 0;
277
278 if (state & IBUS_LOCK_MASK)
279 flags |= ui::EF_CAPS_LOCK_DOWN;
280 if (state & IBUS_CONTROL_MASK)
281 flags |= ui::EF_CONTROL_DOWN;
282 if (state & IBUS_SHIFT_MASK)
283 flags |= ui::EF_SHIFT_DOWN;
284 if (state & IBUS_MOD1_MASK)
285 flags |= ui::EF_ALT_DOWN;
286 if (state & IBUS_BUTTON1_MASK)
287 flags |= ui::EF_LEFT_BUTTON_DOWN;
288 if (state & IBUS_BUTTON2_MASK)
289 flags |= ui::EF_MIDDLE_BUTTON_DOWN;
290 if (state & IBUS_BUTTON3_MASK)
291 flags |= ui::EF_RIGHT_BUTTON_DOWN;
292
293 ForwardKeyEvent(views::KeyEvent(
294 state & IBUS_RELEASE_MASK ?
295 ui::ET_KEY_RELEASED : ui::ET_KEY_PRESSED,
296 ui::WindowsKeyCodeForGdkKeyCode(keyval),
297 flags));
298 }
299
300 void IBusIMEContext::OnUpdatePreeditText(IBusInputContext *context,
301 IBusText* text,
302 guint cursor_pos,
303 gboolean visible) {
304 DCHECK(context_ == context);
305 DCHECK(IBUS_IS_TEXT(text));
306
307 if (visible) {
308 views::CompositionAttributeList attributes;
309 IBusAttrList *attrs = text->attrs;
310 if (attrs) {
311 int i = 0;
312 while (1) {
313 IBusAttribute *attr = ibus_attr_list_get(attrs, i++);
314 if (!attr)
315 break;
316 if (attr->type == IBUS_ATTR_TYPE_UNDERLINE ||
317 attr->type == IBUS_ATTR_TYPE_BACKGROUND) {
318 views::CompositionAttribute attribute(attr->start_index,
319 attr->end_index,
320 SK_ColorBLACK,
321 false);
322 if (attr->type == IBUS_ATTR_TYPE_BACKGROUND) {
323 attribute.thick = true;
324 } else if (attr->type == IBUS_ATTR_TYPE_UNDERLINE) {
325 if (attr->value == IBUS_ATTR_UNDERLINE_DOUBLE) {
326 attribute.thick = true;
327 } else if (attr->value == IBUS_ATTR_UNDERLINE_ERROR) {
328 attribute.color = SK_ColorRED;
329 }
330 }
331 attributes.push_back(attribute);
332 }
333 }
334 }
335
336 SetComposition(UTF8ToUTF16(text->text),
337 attributes,
338 cursor_pos);
339 } else {
340 EndComposition();
341 }
342 }
343
344 void IBusIMEContext::OnShowPreeditText(IBusInputContext *context) {
345 DCHECK(context_ == context);
346 }
347
348 void IBusIMEContext::OnHidePreeditText(IBusInputContext *context) {
349 DCHECK(context_ == context);
350
351 EndComposition();
352 }
353
354 void IBusIMEContext::OnEnable(IBusInputContext *context) {
355 DCHECK(context_ == context);
356 }
357
358 void IBusIMEContext::OnDisable(IBusInputContext *context) {
359 DCHECK(context_ == context);
360 }
361
362 void IBusIMEContext::OnDestroy(IBusInputContext *context) {
363 DCHECK(context_ == context);
364
365 g_object_unref(context_);
366 context_ = NULL;
367
368 EndComposition();
369 }
370
371 void IBusIMEContext::ProcessKeyEventDone(IBusInputContext *context,
372 GAsyncResult* res,
373 ProcessKeyEventData *data) {
374 DCHECK(data->context->context_ == context);
375
376 gboolean processed = FALSE;
377
378 if (!ibus_input_context_process_key_event_finish(context,
379 res,
380 &processed,
381 NULL))
382 processed = FALSE;
383
384 if (processed == FALSE)
385 data->context->ForwardKeyEvent(data->event);
386
387 delete data;
388 }
389
390 } // namespace
391
392 namespace views {
393
394 IMEContext* IMEContext::Create(View* view) {
395 return new IBusIMEContext(view);
396 }
397
398 } // namespace views
OLDNEW
« 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