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

Side by Side Diff: views/ime/input_method_win.cc

Issue 6688049: New InputMethod api for Views. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add InputMethodWin. Created 9 years, 9 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
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 "views/ime/input_method_win.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/string_util.h"
10 #include "ui/base/keycodes/keyboard_codes.h"
11 #include "views/events/event.h"
12
13 namespace views {
14
15 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate)
16 : delegate_(delegate),
17 widget_(NULL),
18 focused_view_(NULL),
19 widget_focused_(false),
20 active_(false),
21 direction_(base::i18n::UNKNOWN_DIRECTION),
22 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION) {
23 }
24
25 InputMethodWin::~InputMethodWin() {
26 if (widget_) {
27 ime_input_.DisableIME(hwnd());
28 widget_->GetFocusManager()->RemoveFocusChangeListener(this);
29 widget_ = NULL;
30 }
31 }
32
33 void InputMethodWin::set_delegate(internal::InputMethodDelegate* delegate) {
34 delegate_ = delegate;
35 }
36
37 void InputMethodWin::Init(Widget* widget) {
38 DCHECK(widget);
39 DCHECK(widget->GetFocusManager());
40 DCHECK(widget->GetNativeView());
41
42 if (widget_ == widget) {
43 DLOG(ERROR) << "Already initialized.";
44 return;
45 }
46
47 DCHECK(!widget_);
48
49 widget_ = widget;
50 widget->GetFocusManager()->AddFocusChangeListener(this);
51
52 // Gets the initial input locale and text direction information.
53 OnInputLangChange(0, 0);
54 }
55
56 void InputMethodWin::DispatchKeyEvent(const KeyEvent& key) {
57 // Handles ctrl-shift key to change text direction and layout alignment.
58 if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() &&
59 GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
60 ui::KeyboardCode code = key.key_code();
61 if (key.type() == ui::ET_KEY_PRESSED) {
62 if (code == ui::VKEY_SHIFT) {
63 base::i18n::TextDirection dir;
64 if (ui::ImeInput::IsCtrlShiftPressed(&dir))
65 pending_requested_direction_ = dir;
66 } else if (code != ui::VKEY_CONTROL) {
67 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
68 }
69 } else if (key.type() == ui::ET_KEY_RELEASED &&
70 (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) &&
71 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) {
72 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment(
73 pending_requested_direction_);
74 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
75 }
76 }
77
78 DispatchKeyEventPostIME(key);
79 }
80
81 void InputMethodWin::OnTextInputTypeChanged(View* view) {
82 if (IsViewFocused(view)) {
83 ime_input_.CancelIME(hwnd());
84 UpdateIMEState();
85 }
86 }
87
88 void InputMethodWin::OnCaretBoundsChanged(View* view) {
89 if (!IsViewFocused(view))
90 return;
91
92 TextInputClient* client = view->GetTextInputClient();
93 if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
94 return;
95
96 gfx::Rect rect = client->GetCaretBounds();
97 gfx::Point origin = rect.origin();
98 gfx::Point end = gfx::Point(rect.right(), rect.bottom());
99
100 View::ConvertPointToWidget(view, &origin);
101 View::ConvertPointToWidget(view, &end);
102
103 // We need to translate the coordinates to the toplevel widget if the view is
104 // inside a child widget.
105 if (view->GetWidget() != widget_) {
106 RECT win_rect;
107 win_rect.left = origin.x();
108 win_rect.top = origin.y();
109 win_rect.right = end.x();
110 win_rect.bottom = end.y();
111
112 ::MapWindowPoints(view->GetWidget()->GetNativeView(), hwnd(),
113 reinterpret_cast<LPPOINT>(&win_rect),
114 sizeof(RECT)/sizeof(POINT));
115 rect = win_rect;
116 } else {
117 rect = gfx::Rect(origin, gfx::Size(end.x() - origin.x(),
118 end.y() - origin.y()));
119 }
120
121 ime_input_.UpdateCaretRect(hwnd(), rect);
122 }
123
124 void InputMethodWin::CancelComposition(View* view) {
125 if (IsViewFocused(view))
126 ime_input_.CancelIME(hwnd());
127 }
128
129 std::string InputMethodWin::GetInputLocale() {
oshima 2011/03/21 20:30:56 std::string&
James Su 2011/03/21 21:21:16 Different implementation may use different approac
130 return locale_;
131 }
132
133 base::i18n::TextDirection InputMethodWin::GetInputTextDirection() {
134 return direction_;
135 }
136
137 bool InputMethodWin::IsActive() {
138 return active_;
139 }
140
141 void InputMethodWin::FocusWillChange(View* focused_before, View* focused) {
142 DCHECK_EQ(focused_view_, focused_before);
143 ConfirmComposition();
144 focused_view_ = focused;
145 UpdateIMEState();
146 }
147
148 void InputMethodWin::OnSetFocus() {
149 if (!widget_focused_) {
150 widget_focused_ = true;
151 UpdateIMEState();
152 }
153 }
154
155 void InputMethodWin::OnKillFocus() {
156 if (widget_focused_) {
157 ConfirmComposition();
158 widget_focused_ = false;
159 }
160 }
161
162 void InputMethodWin::OnInputLangChange(DWORD character_set,
163 HKL input_language_id) {
164 active_ = ime_input_.SetInputLanguage();
165 locale_ = ime_input_.GetInputLanguageName();
166 direction_ = ime_input_.GetTextDirection();
oshima 2011/03/21 20:30:56 look like these two (locale_, direction_) is just
James Su 2011/03/21 21:21:16 ime_input_ doesn't cache the result. And how these
167 OnInputMethodChanged();
168 }
169
170 LRESULT InputMethodWin::OnImeSetContext(
171 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
172 active_ = (wparam == TRUE);
173 if (active_)
174 ime_input_.CreateImeWindow(hwnd());
175
176 OnInputMethodChanged();
177 return ime_input_.SetImeWindowStyle(hwnd(), message, wparam, lparam, handled);
178 }
179
180 LRESULT InputMethodWin::OnImeStartComposition(
181 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
182 // We have to prevent WTL from calling ::DefWindowProc() because the function
183 // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
184 // over-write the position of IME windows.
185 *handled = TRUE;
186
187 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
188 return 0;
189
190 // Reset the composition status and create IME windows.
191 ime_input_.CreateImeWindow(hwnd());
192 ime_input_.ResetComposition(hwnd());
193 return 0;
194 }
195
196 LRESULT InputMethodWin::OnImeComposition(
197 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
198 // We have to prevent WTL from calling ::DefWindowProc() because we do not
199 // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
200 *handled = TRUE;
201
202 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
203 return 0;
204
205 // At first, update the position of the IME window.
206 ime_input_.UpdateImeWindow(hwnd());
207
208 // Retrieve the result string and its attributes of the ongoing composition
209 // and send it to a renderer process.
210 ui::Composition composition;
211 if (ime_input_.GetResult(hwnd(), lparam, &composition.text)) {
212 GetTextInputClient()->InsertText(composition.text);
213 ime_input_.ResetComposition(hwnd());
214 // Fall though and try reading the composition string.
215 // Japanese IMEs send a message containing both GCS_RESULTSTR and
216 // GCS_COMPSTR, which means an ongoing composition has been finished
217 // by the start of another composition.
218 }
219 // Retrieve the composition string and its attributes of the ongoing
220 // composition and send it to a renderer process.
221 if (ime_input_.GetComposition(hwnd(), lparam, &composition))
222 GetTextInputClient()->SetComposition(composition);
223
224 return 0;
225 }
226
227 LRESULT InputMethodWin::OnImeEndComposition(
228 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
229 // Let WTL call ::DefWindowProc() and release its resources.
230 *handled = FALSE;
231
232 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
233 return 0;
234
235 if (GetTextInputClient()->HasComposition())
236 GetTextInputClient()->ClearComposition();
237
238 ime_input_.ResetComposition(hwnd());
239 ime_input_.DestroyImeWindow(hwnd());
240 return 0;
241 }
242
243 LRESULT InputMethodWin::OnChar(
244 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
245 *handled = TRUE;
246
247 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
248 return 0;
249
250 int flags = 0;
251 flags |= (::GetKeyState(VK_MENU) & 0x80)? ui::EF_ALT_DOWN : 0;
252 flags |= (::GetKeyState(VK_SHIFT) & 0x80)? ui::EF_SHIFT_DOWN : 0;
253 flags |= (::GetKeyState(VK_CONTROL) & 0x80)? ui::EF_CONTROL_DOWN : 0;
254 GetTextInputClient()->InsertChar(static_cast<char16>(wparam), flags);
255 return 0;
256 }
257
258 LRESULT InputMethodWin::OnDeadChar(
259 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
260 *handled = TRUE;
261
262 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
263 return 0;
264
265 // Shows the dead character as a composition text, so that the user can know
266 // what dead key was pressed.
267 ui::Composition composition;
268 composition.text.assign(1, static_cast<char16>(wparam));
269 composition.selection = ui::Range(0, 1);
270 composition.underlines.push_back(
271 ui::CompositionUnderline(0, 1, SK_ColorBLACK, false));
272 GetTextInputClient()->SetComposition(composition);
273 return 0;
274 }
275
276 void InputMethodWin::ConfirmComposition() {
277 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
278 ime_input_.CleanupComposition(hwnd());
279 if (GetTextInputClient()->HasComposition())
280 GetTextInputClient()->ConfirmComposition();
281 }
282 }
283
284 void InputMethodWin::UpdateIMEState() {
285 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_TEXT)
286 ime_input_.EnableIME(hwnd());
287 else
288 ime_input_.DisableIME(hwnd());
289 }
290
291 TextInputClient* InputMethodWin::GetTextInputClient() const {
292 return (widget_focused_ && focused_view_) ?
293 focused_view_->GetTextInputClient() : NULL;
294 }
295
296 ui::TextInputType InputMethodWin::GetTextInputType() const {
297 TextInputClient* client = GetTextInputClient();
298 return client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
299 }
300
301 bool InputMethodWin::IsViewFocused(View* view) const {
302 return widget_focused_ && view && focused_view_ == view;
303 }
304
305 void InputMethodWin::DispatchKeyEventPostIME(const KeyEvent& key) const {
306 if (delegate_)
307 delegate_->DispatchKeyEventPostIME(key);
308 }
309
310 void InputMethodWin::OnInputMethodChanged() const {
311 TextInputClient* client = GetTextInputClient();
312 if (client && client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
313 client->OnInputMethodChanged();
314 }
oshima 2011/03/21 20:30:56 Looks like these are can be shared Win and Gtk. Wo
James Su 2011/03/21 21:21:16 Make sense. I'll do it asap.
315
316 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698