OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "ui/aura/remote_window_tree_host_win.h" | |
6 | |
7 #include <windows.h> | |
8 | |
9 #include <algorithm> | |
10 | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "ipc/ipc_message.h" | |
13 #include "ipc/ipc_sender.h" | |
14 #include "ui/aura/client/aura_constants.h" | |
15 #include "ui/aura/client/cursor_client.h" | |
16 #include "ui/aura/window_event_dispatcher.h" | |
17 #include "ui/aura/window_property.h" | |
18 #include "ui/base/cursor/cursor_loader_win.h" | |
19 #include "ui/base/ime/composition_text.h" | |
20 #include "ui/base/ime/input_method.h" | |
21 #include "ui/base/ime/remote_input_method_win.h" | |
22 #include "ui/base/ime/text_input_client.h" | |
23 #include "ui/base/view_prop.h" | |
24 #include "ui/events/event_utils.h" | |
25 #include "ui/events/keycodes/keyboard_code_conversion_win.h" | |
26 #include "ui/gfx/insets.h" | |
27 #include "ui/gfx/win/dpi.h" | |
28 #include "ui/metro_viewer/metro_viewer_messages.h" | |
29 | |
30 namespace aura { | |
31 | |
32 namespace { | |
33 | |
34 const char* kWindowTreeHostWinKey = "__AURA_REMOTE_WINDOW_TREE_HOST_WIN__"; | |
35 | |
36 // Sets the keystate for the virtual key passed in to down or up. | |
37 void SetKeyState(uint8* key_states, bool key_down, uint32 virtual_key_code) { | |
38 DCHECK(key_states); | |
39 | |
40 if (key_down) | |
41 key_states[virtual_key_code] |= 0x80; | |
42 else | |
43 key_states[virtual_key_code] &= 0x7F; | |
44 } | |
45 | |
46 // Sets the keyboard states for the Shift/Control/Alt/Caps lock keys. | |
47 void SetVirtualKeyStates(uint32 flags) { | |
48 uint8 keyboard_state[256] = {0}; | |
49 ::GetKeyboardState(keyboard_state); | |
50 | |
51 SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT); | |
52 SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL); | |
53 SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU); | |
54 SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_DOWN), VK_CAPITAL); | |
55 SetKeyState(keyboard_state, !!(flags & ui::EF_LEFT_MOUSE_BUTTON), VK_LBUTTON); | |
56 SetKeyState(keyboard_state, !!(flags & ui::EF_RIGHT_MOUSE_BUTTON), | |
57 VK_RBUTTON); | |
58 SetKeyState(keyboard_state, !!(flags & ui::EF_MIDDLE_MOUSE_BUTTON), | |
59 VK_MBUTTON); | |
60 | |
61 ::SetKeyboardState(keyboard_state); | |
62 } | |
63 | |
64 void FillCompositionText( | |
65 const base::string16& text, | |
66 int32 selection_start, | |
67 int32 selection_end, | |
68 const std::vector<metro_viewer::UnderlineInfo>& underlines, | |
69 ui::CompositionText* composition_text) { | |
70 composition_text->Clear(); | |
71 composition_text->text = text; | |
72 composition_text->selection.set_start(selection_start); | |
73 composition_text->selection.set_end(selection_end); | |
74 composition_text->underlines.resize(underlines.size()); | |
75 for (size_t i = 0; i < underlines.size(); ++i) { | |
76 composition_text->underlines[i].start_offset = underlines[i].start_offset; | |
77 composition_text->underlines[i].end_offset = underlines[i].end_offset; | |
78 composition_text->underlines[i].color = SK_ColorBLACK; | |
79 composition_text->underlines[i].thick = underlines[i].thick; | |
80 composition_text->underlines[i].background_color = SK_ColorTRANSPARENT; | |
81 } | |
82 } | |
83 | |
84 } // namespace | |
85 | |
86 RemoteWindowTreeHostWin* g_instance = NULL; | |
87 | |
88 // static | |
89 RemoteWindowTreeHostWin* RemoteWindowTreeHostWin::Instance() { | |
90 return g_instance; | |
91 } | |
92 | |
93 RemoteWindowTreeHostWin::RemoteWindowTreeHostWin() | |
94 : remote_window_(NULL), | |
95 host_(NULL), | |
96 ignore_mouse_moves_until_set_cursor_ack_(0), | |
97 event_flags_(0), | |
98 window_size_(aura::WindowTreeHost::GetNativeScreenSize()) { | |
99 CHECK(!g_instance); | |
100 g_instance = this; | |
101 prop_.reset(new ui::ViewProp(NULL, kWindowTreeHostWinKey, this)); | |
102 CreateCompositor(GetAcceleratedWidget()); | |
103 } | |
104 | |
105 RemoteWindowTreeHostWin::~RemoteWindowTreeHostWin() { | |
106 DestroyCompositor(); | |
107 DestroyDispatcher(); | |
108 DCHECK_EQ(g_instance, this); | |
109 g_instance = NULL; | |
110 } | |
111 | |
112 // static | |
113 bool RemoteWindowTreeHostWin::IsValid() { | |
114 return Instance()->remote_window_ != NULL; | |
115 } | |
116 | |
117 void RemoteWindowTreeHostWin::SetRemoteWindowHandle(HWND remote_window) { | |
118 remote_window_ = remote_window; | |
119 } | |
120 | |
121 void RemoteWindowTreeHostWin::Connected(IPC::Sender* host) { | |
122 CHECK(host_ == NULL); | |
123 DCHECK(remote_window_); | |
124 host_ = host; | |
125 // Recreate the compositor for the target surface represented by the | |
126 // remote_window HWND. | |
127 CreateCompositor(remote_window_); | |
128 InitCompositor(); | |
129 } | |
130 | |
131 void RemoteWindowTreeHostWin::Disconnected() { | |
132 // Don't CHECK here, Disconnected is called on a channel error which can | |
133 // happen before we're successfully Connected. | |
134 if (!host_) | |
135 return; | |
136 ui::RemoteInputMethodPrivateWin* remote_input_method_private = | |
137 GetRemoteInputMethodPrivate(); | |
138 if (remote_input_method_private) | |
139 remote_input_method_private->SetRemoteDelegate(NULL); | |
140 host_ = NULL; | |
141 remote_window_ = NULL; | |
142 } | |
143 | |
144 bool RemoteWindowTreeHostWin::OnMessageReceived(const IPC::Message& message) { | |
145 bool handled = true; | |
146 IPC_BEGIN_MESSAGE_MAP(RemoteWindowTreeHostWin, message) | |
147 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved) | |
148 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton) | |
149 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown) | |
150 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp) | |
151 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar) | |
152 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated, | |
153 OnWindowActivated) | |
154 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_EdgeGesture, OnEdgeGesture) | |
155 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown, | |
156 OnTouchDown) | |
157 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp, | |
158 OnTouchUp) | |
159 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved, | |
160 OnTouchMoved) | |
161 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck, | |
162 OnSetCursorPosAck) | |
163 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCandidatePopupChanged, | |
164 OnImeCandidatePopupChanged) | |
165 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeCompositionChanged, | |
166 OnImeCompositionChanged) | |
167 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextCommitted, | |
168 OnImeTextCommitted) | |
169 IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeInputSourceChanged, | |
170 OnImeInputSourceChanged) | |
171 IPC_MESSAGE_UNHANDLED(handled = false) | |
172 IPC_END_MESSAGE_MAP() | |
173 return handled; | |
174 } | |
175 | |
176 void RemoteWindowTreeHostWin::HandleOpenURLOnDesktop( | |
177 const base::FilePath& shortcut, | |
178 const base::string16& url) { | |
179 if (!host_) | |
180 return; | |
181 host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url)); | |
182 } | |
183 | |
184 void RemoteWindowTreeHostWin::HandleWindowSizeChanged(uint32 width, | |
185 uint32 height) { | |
186 SetBounds(gfx::Rect(0, 0, width, height)); | |
187 } | |
188 | |
189 bool RemoteWindowTreeHostWin::IsForegroundWindow() { | |
190 return ::GetForegroundWindow() == remote_window_; | |
191 } | |
192 | |
193 Window* RemoteWindowTreeHostWin::GetAshWindow() { | |
194 return window(); | |
195 } | |
196 | |
197 ui::EventSource* RemoteWindowTreeHostWin::GetEventSource() { | |
198 return this; | |
199 } | |
200 | |
201 gfx::AcceleratedWidget RemoteWindowTreeHostWin::GetAcceleratedWidget() { | |
202 if (remote_window_) | |
203 return remote_window_; | |
204 // Getting here should only happen for ash_unittests.exe and related code. | |
205 return ::GetDesktopWindow(); | |
206 } | |
207 | |
208 void RemoteWindowTreeHostWin::Show() { | |
209 ui::RemoteInputMethodPrivateWin* remote_input_method_private = | |
210 GetRemoteInputMethodPrivate(); | |
211 if (remote_input_method_private) | |
212 remote_input_method_private->SetRemoteDelegate(this); | |
213 } | |
214 | |
215 void RemoteWindowTreeHostWin::Hide() { | |
216 NOTIMPLEMENTED(); | |
217 } | |
218 | |
219 gfx::Rect RemoteWindowTreeHostWin::GetBounds() const { | |
220 return gfx::Rect(window_size_); | |
221 } | |
222 | |
223 void RemoteWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) { | |
224 window_size_ = bounds.size(); | |
225 OnHostResized(bounds.size()); | |
226 } | |
227 | |
228 gfx::Point RemoteWindowTreeHostWin::GetLocationOnNativeScreen() const { | |
229 return gfx::Point(0, 0); | |
230 } | |
231 | |
232 void RemoteWindowTreeHostWin::SetCapture() { | |
233 } | |
234 | |
235 void RemoteWindowTreeHostWin::ReleaseCapture() { | |
236 } | |
237 | |
238 void RemoteWindowTreeHostWin::SetCursorNative(gfx::NativeCursor native_cursor) { | |
239 if (!host_) | |
240 return; | |
241 host_->Send( | |
242 new MetroViewerHostMsg_SetCursor(uint64(native_cursor.platform()))); | |
243 } | |
244 | |
245 void RemoteWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) { | |
246 VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y(); | |
247 if (!host_) | |
248 return; | |
249 | |
250 // This function can be called in cases like when the mouse cursor is | |
251 // restricted within a viewport (For e.g. LockCursor) which assumes that | |
252 // subsequent mouse moves would be received starting with the new cursor | |
253 // coordinates. This is a challenge for Windows ASH for the reasons | |
254 // outlined below. | |
255 // Other cases which don't expect this behavior should continue to work | |
256 // without issues. | |
257 | |
258 // The mouse events are received by the viewer process and sent to the | |
259 // browser. If we invoke the SetCursor API here we continue to receive | |
260 // mouse messages from the viewer which were posted before the SetCursor | |
261 // API executes which messes up the state in the browser. To workaround | |
262 // this we invoke the SetCursor API in the viewer process and ignore | |
263 // mouse messages until we received an ACK from the viewer indicating that | |
264 // the SetCursor operation completed. | |
265 ignore_mouse_moves_until_set_cursor_ack_++; | |
266 VLOG(1) << "In MoveCursorTo. Sending IPC"; | |
267 host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y())); | |
268 } | |
269 | |
270 void RemoteWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) { | |
271 NOTIMPLEMENTED(); | |
272 } | |
273 | |
274 void RemoteWindowTreeHostWin::PostNativeEvent( | |
275 const base::NativeEvent& native_event) { | |
276 } | |
277 | |
278 ui::EventProcessor* RemoteWindowTreeHostWin::GetEventProcessor() { | |
279 return dispatcher(); | |
280 } | |
281 | |
282 void RemoteWindowTreeHostWin::CancelComposition() { | |
283 if (!host_) | |
284 return; | |
285 host_->Send(new MetroViewerHostMsg_ImeCancelComposition); | |
286 } | |
287 | |
288 void RemoteWindowTreeHostWin::OnTextInputClientUpdated( | |
289 const std::vector<int32>& input_scopes, | |
290 const std::vector<gfx::Rect>& composition_character_bounds) { | |
291 if (!host_) | |
292 return; | |
293 std::vector<metro_viewer::CharacterBounds> character_bounds; | |
294 for (size_t i = 0; i < composition_character_bounds.size(); ++i) { | |
295 const gfx::Rect& rect = composition_character_bounds[i]; | |
296 metro_viewer::CharacterBounds bounds; | |
297 bounds.left = rect.x(); | |
298 bounds.top = rect.y(); | |
299 bounds.right = rect.right(); | |
300 bounds.bottom = rect.bottom(); | |
301 character_bounds.push_back(bounds); | |
302 } | |
303 host_->Send(new MetroViewerHostMsg_ImeTextInputClientUpdated( | |
304 input_scopes, character_bounds)); | |
305 } | |
306 | |
307 gfx::Point PointFromNativeEvent(int32 x, int32 y) { | |
308 static float scale_factor = gfx::GetDPIScale(); | |
309 gfx::Point result( x * scale_factor, y * scale_factor); | |
310 return result; | |
311 } | |
312 | |
313 void RemoteWindowTreeHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) { | |
314 if (ignore_mouse_moves_until_set_cursor_ack_) | |
315 return; | |
316 | |
317 gfx::Point location = PointFromNativeEvent(x, y); | |
318 ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags, 0); | |
319 SendEventToProcessor(&event); | |
320 } | |
321 | |
322 void RemoteWindowTreeHostWin::OnMouseButton( | |
323 const MetroViewerHostMsg_MouseButtonParams& params) { | |
324 gfx::Point location = PointFromNativeEvent(params.x, params.y); | |
325 ui::MouseEvent mouse_event(params.event_type, location, location, | |
326 static_cast<int>(params.flags), | |
327 static_cast<int>(params.changed_button)); | |
328 | |
329 SetEventFlags(params.flags | key_event_flags()); | |
330 if (params.event_type == ui::ET_MOUSEWHEEL) { | |
331 int x_offset = params.is_horizontal_wheel ? params.extra : 0; | |
332 int y_offset = !params.is_horizontal_wheel ? params.extra : 0; | |
333 ui::MouseWheelEvent wheel_event(mouse_event, x_offset, y_offset); | |
334 SendEventToProcessor(&wheel_event); | |
335 } else if (params.event_type == ui::ET_MOUSE_PRESSED) { | |
336 // TODO(shrikant): Ideally modify code in event.cc by adding automatic | |
337 // tracking of double clicks in synthetic MouseEvent constructor code. | |
338 // Non-synthetic MouseEvent constructor code does automatically track | |
339 // this. Need to use some caution while modifying synthetic constructor | |
340 // as many tests and other code paths depend on it and apparently | |
341 // specifically depend on non implicit tracking of previous mouse event. | |
342 if (last_mouse_click_event_ && | |
343 ui::MouseEvent::IsRepeatedClickEvent(mouse_event, | |
344 *last_mouse_click_event_)) { | |
345 mouse_event.SetClickCount(2); | |
346 } else { | |
347 mouse_event.SetClickCount(1); | |
348 } | |
349 last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event)); | |
350 SendEventToProcessor(&mouse_event); | |
351 } else { | |
352 SendEventToProcessor(&mouse_event); | |
353 } | |
354 } | |
355 | |
356 void RemoteWindowTreeHostWin::OnKeyDown(uint32 vkey, | |
357 uint32 repeat_count, | |
358 uint32 scan_code, | |
359 uint32 flags) { | |
360 DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code, | |
361 flags, false); | |
362 } | |
363 | |
364 void RemoteWindowTreeHostWin::OnKeyUp(uint32 vkey, | |
365 uint32 repeat_count, | |
366 uint32 scan_code, | |
367 uint32 flags) { | |
368 DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code, | |
369 flags, false); | |
370 } | |
371 | |
372 void RemoteWindowTreeHostWin::OnChar(uint32 key_code, | |
373 uint32 repeat_count, | |
374 uint32 scan_code, | |
375 uint32 flags) { | |
376 DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count, | |
377 scan_code, flags, true); | |
378 } | |
379 | |
380 void RemoteWindowTreeHostWin::OnWindowActivated(bool repaint) { | |
381 OnHostActivated(); | |
382 if (repaint && compositor()) | |
383 compositor()->ScheduleFullRedraw(); | |
384 } | |
385 | |
386 void RemoteWindowTreeHostWin::OnEdgeGesture() { | |
387 ui::GestureEvent event( | |
388 0, | |
389 0, | |
390 0, | |
391 ui::EventTimeForNow(), | |
392 ui::GestureEventDetails(ui::ET_GESTURE_WIN8_EDGE_SWIPE)); | |
393 SendEventToProcessor(&event); | |
394 } | |
395 | |
396 void RemoteWindowTreeHostWin::OnTouchDown(int32 x, | |
397 int32 y, | |
398 uint64 timestamp, | |
399 uint32 pointer_id) { | |
400 gfx::Point location = PointFromNativeEvent(x, y); | |
401 ui::TouchEvent event(ui::ET_TOUCH_PRESSED, | |
402 location, | |
403 pointer_id, | |
404 base::TimeDelta::FromMicroseconds(timestamp)); | |
405 SendEventToProcessor(&event); | |
406 } | |
407 | |
408 void RemoteWindowTreeHostWin::OnTouchUp(int32 x, | |
409 int32 y, | |
410 uint64 timestamp, | |
411 uint32 pointer_id) { | |
412 gfx::Point location = PointFromNativeEvent(x, y); | |
413 ui::TouchEvent event(ui::ET_TOUCH_RELEASED, | |
414 location, | |
415 pointer_id, | |
416 base::TimeDelta::FromMicroseconds(timestamp)); | |
417 SendEventToProcessor(&event); | |
418 } | |
419 | |
420 void RemoteWindowTreeHostWin::OnTouchMoved(int32 x, | |
421 int32 y, | |
422 uint64 timestamp, | |
423 uint32 pointer_id) { | |
424 gfx::Point location = PointFromNativeEvent(x, y); | |
425 ui::TouchEvent event(ui::ET_TOUCH_MOVED, | |
426 location, | |
427 pointer_id, | |
428 base::TimeDelta::FromMicroseconds(timestamp)); | |
429 SendEventToProcessor(&event); | |
430 } | |
431 | |
432 void RemoteWindowTreeHostWin::OnSetCursorPosAck() { | |
433 DCHECK_GT(ignore_mouse_moves_until_set_cursor_ack_, 0); | |
434 ignore_mouse_moves_until_set_cursor_ack_--; | |
435 } | |
436 | |
437 ui::RemoteInputMethodPrivateWin* | |
438 RemoteWindowTreeHostWin::GetRemoteInputMethodPrivate() { | |
439 ui::InputMethod* input_method = GetAshWindow()->GetProperty( | |
440 aura::client::kRootWindowInputMethodKey); | |
441 return ui::RemoteInputMethodPrivateWin::Get(input_method); | |
442 } | |
443 | |
444 void RemoteWindowTreeHostWin::OnImeCandidatePopupChanged(bool visible) { | |
445 ui::RemoteInputMethodPrivateWin* remote_input_method_private = | |
446 GetRemoteInputMethodPrivate(); | |
447 if (!remote_input_method_private) | |
448 return; | |
449 remote_input_method_private->OnCandidatePopupChanged(visible); | |
450 } | |
451 | |
452 void RemoteWindowTreeHostWin::OnImeCompositionChanged( | |
453 const base::string16& text, | |
454 int32 selection_start, | |
455 int32 selection_end, | |
456 const std::vector<metro_viewer::UnderlineInfo>& underlines) { | |
457 ui::RemoteInputMethodPrivateWin* remote_input_method_private = | |
458 GetRemoteInputMethodPrivate(); | |
459 if (!remote_input_method_private) | |
460 return; | |
461 ui::CompositionText composition_text; | |
462 FillCompositionText( | |
463 text, selection_start, selection_end, underlines, &composition_text); | |
464 remote_input_method_private->OnCompositionChanged(composition_text); | |
465 } | |
466 | |
467 void RemoteWindowTreeHostWin::OnImeTextCommitted(const base::string16& text) { | |
468 ui::RemoteInputMethodPrivateWin* remote_input_method_private = | |
469 GetRemoteInputMethodPrivate(); | |
470 if (!remote_input_method_private) | |
471 return; | |
472 remote_input_method_private->OnTextCommitted(text); | |
473 } | |
474 | |
475 void RemoteWindowTreeHostWin::OnImeInputSourceChanged(uint16 language_id, | |
476 bool is_ime) { | |
477 ui::RemoteInputMethodPrivateWin* remote_input_method_private = | |
478 GetRemoteInputMethodPrivate(); | |
479 if (!remote_input_method_private) | |
480 return; | |
481 remote_input_method_private->OnInputSourceChanged(language_id, is_ime); | |
482 } | |
483 | |
484 void RemoteWindowTreeHostWin::DispatchKeyboardMessage(ui::EventType type, | |
485 uint32 vkey, | |
486 uint32 repeat_count, | |
487 uint32 scan_code, | |
488 uint32 flags, | |
489 bool is_character) { | |
490 SetEventFlags(flags | mouse_event_flags()); | |
491 if (base::MessageLoop::current()->IsNested()) { | |
492 int index = (flags & ui::EF_ALT_DOWN) ? 1 : 0; | |
493 const int char_message[] = {WM_CHAR, WM_SYSCHAR}; | |
494 const int keydown_message[] = {WM_KEYDOWN, WM_SYSKEYDOWN}; | |
495 const int keyup_message[] = {WM_KEYUP, WM_SYSKEYUP}; | |
496 uint32 message = is_character | |
497 ? char_message[index] | |
498 : (type == ui::ET_KEY_PRESSED ? keydown_message[index] | |
499 : keyup_message[index]); | |
500 ::PostThreadMessage(::GetCurrentThreadId(), | |
501 message, | |
502 vkey, | |
503 repeat_count | scan_code >> 15); | |
504 } else if (is_character) { | |
505 ui::KeyEvent event(static_cast<base::char16>(vkey), | |
506 ui::KeyboardCodeForWindowsKeyCode(vkey), | |
507 flags); | |
508 SendEventToProcessor(&event); | |
509 } else { | |
510 ui::KeyEvent event(type, | |
511 ui::KeyboardCodeForWindowsKeyCode(vkey), | |
512 flags); | |
513 SendEventToProcessor(&event); | |
514 } | |
515 } | |
516 | |
517 void RemoteWindowTreeHostWin::SetEventFlags(uint32 flags) { | |
518 if (flags == event_flags_) | |
519 return; | |
520 event_flags_ = flags; | |
521 SetVirtualKeyStates(event_flags_); | |
522 } | |
523 | |
524 } // namespace aura | |
OLD | NEW |