- add sources.
[platform/framework/web/crosswalk.git] / src / ui / aura / remote_root_window_host_win.cc
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_root_window_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/cursor_client.h"
15 #include "ui/aura/root_window.h"
16 #include "ui/base/cursor/cursor_loader_win.h"
17 #include "ui/events/event_utils.h"
18 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
19 #include "ui/base/view_prop.h"
20 #include "ui/gfx/insets.h"
21 #include "ui/metro_viewer/metro_viewer_messages.h"
22
23 namespace aura {
24
25 namespace {
26
27 const char* kRootWindowHostWinKey = "__AURA_REMOTE_ROOT_WINDOW_HOST_WIN__";
28
29 // Sets the keystate for the virtual key passed in to down or up.
30 void SetKeyState(uint8* key_states, bool key_down, uint32 virtual_key_code) {
31   DCHECK(key_states);
32
33   if (key_down)
34     key_states[virtual_key_code] |= 0x80;
35   else
36     key_states[virtual_key_code] &= 0x7F;
37 }
38
39 // Sets the keyboard states for the Shift/Control/Alt/Caps lock keys.
40 void SetVirtualKeyStates(uint32 flags) {
41   uint8 keyboard_state[256] = {0};
42   ::GetKeyboardState(keyboard_state);
43
44   SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT);
45   SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL);
46   SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU);
47   SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_DOWN), VK_CAPITAL);
48   SetKeyState(keyboard_state, !!(flags & ui::EF_LEFT_MOUSE_BUTTON), VK_LBUTTON);
49   SetKeyState(keyboard_state, !!(flags & ui::EF_RIGHT_MOUSE_BUTTON),
50               VK_RBUTTON);
51   SetKeyState(keyboard_state, !!(flags & ui::EF_MIDDLE_MOUSE_BUTTON),
52               VK_MBUTTON);
53
54   ::SetKeyboardState(keyboard_state);
55 }
56
57 }  // namespace
58
59 void HandleOpenFile(const base::string16& title,
60                     const base::FilePath& default_path,
61                     const base::string16& filter,
62                     const OpenFileCompletion& on_success,
63                     const FileSelectionCanceled& on_failure) {
64   DCHECK(aura::RemoteRootWindowHostWin::Instance());
65   aura::RemoteRootWindowHostWin::Instance()->HandleOpenFile(title,
66                                                             default_path,
67                                                             filter,
68                                                             on_success,
69                                                             on_failure);
70 }
71
72 void HandleOpenMultipleFiles(const base::string16& title,
73                              const base::FilePath& default_path,
74                              const base::string16& filter,
75                              const OpenMultipleFilesCompletion& on_success,
76                              const FileSelectionCanceled& on_failure) {
77   DCHECK(aura::RemoteRootWindowHostWin::Instance());
78   aura::RemoteRootWindowHostWin::Instance()->HandleOpenMultipleFiles(
79       title,
80       default_path,
81       filter,
82       on_success,
83       on_failure);
84 }
85
86 void HandleSaveFile(const base::string16& title,
87                     const base::FilePath& default_path,
88                     const base::string16& filter,
89                     int filter_index,
90                     const base::string16& default_extension,
91                     const SaveFileCompletion& on_success,
92                     const FileSelectionCanceled& on_failure) {
93   DCHECK(aura::RemoteRootWindowHostWin::Instance());
94   aura::RemoteRootWindowHostWin::Instance()->HandleSaveFile(title,
95                                                             default_path,
96                                                             filter,
97                                                             filter_index,
98                                                             default_extension,
99                                                             on_success,
100                                                             on_failure);
101 }
102
103 void HandleSelectFolder(const base::string16& title,
104                         const SelectFolderCompletion& on_success,
105                         const FileSelectionCanceled& on_failure) {
106   DCHECK(aura::RemoteRootWindowHostWin::Instance());
107   aura::RemoteRootWindowHostWin::Instance()->HandleSelectFolder(title,
108                                                                 on_success,
109                                                                 on_failure);
110 }
111
112 void HandleActivateDesktop(const base::FilePath& shortcut,
113                            const ActivateDesktopCompleted& on_success) {
114   DCHECK(aura::RemoteRootWindowHostWin::Instance());
115   aura::RemoteRootWindowHostWin::Instance()->HandleActivateDesktop(shortcut,
116                                                                    on_success);
117 }
118
119 RemoteRootWindowHostWin* g_instance = NULL;
120
121 RemoteRootWindowHostWin* RemoteRootWindowHostWin::Instance() {
122   if (g_instance)
123     return g_instance;
124   return Create(gfx::Rect());
125 }
126
127 RemoteRootWindowHostWin* RemoteRootWindowHostWin::Create(
128     const gfx::Rect& bounds) {
129   g_instance = g_instance ? g_instance : new RemoteRootWindowHostWin(bounds);
130   return g_instance;
131 }
132
133 RemoteRootWindowHostWin::RemoteRootWindowHostWin(const gfx::Rect& bounds)
134     : remote_window_(NULL),
135       delegate_(NULL),
136       host_(NULL),
137       ignore_mouse_moves_until_set_cursor_ack_(false),
138       event_flags_(0) {
139   prop_.reset(new ui::ViewProp(NULL, kRootWindowHostWinKey, this));
140 }
141
142 RemoteRootWindowHostWin::~RemoteRootWindowHostWin() {
143   g_instance = NULL;
144 }
145
146 void RemoteRootWindowHostWin::Connected(IPC::Sender* host, HWND remote_window) {
147   CHECK(host_ == NULL);
148   host_ = host;
149   remote_window_ = remote_window;
150 }
151
152 void RemoteRootWindowHostWin::Disconnected() {
153   // Don't CHECK here, Disconnected is called on a channel error which can
154   // happen before we're successfully Connected.
155   host_ = NULL;
156   remote_window_ = NULL;
157 }
158
159 bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) {
160   bool handled = true;
161   IPC_BEGIN_MESSAGE_MAP(RemoteRootWindowHostWin, message)
162     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved)
163     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton)
164     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown)
165     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp)
166     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar)
167     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated,
168                         OnWindowActivated)
169     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown,
170                         OnTouchDown)
171     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp,
172                         OnTouchUp)
173     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved,
174                         OnTouchMoved)
175     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone,
176                         OnFileSaveAsDone)
177     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone,
178                         OnFileOpenDone)
179     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone,
180                         OnMultiFileOpenDone)
181     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone,
182                         OnSelectFolderDone)
183     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck,
184                         OnSetCursorPosAck)
185     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged,
186                         OnWindowSizeChanged)
187     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ActivateDesktopDone,
188                         OnDesktopActivated)
189     IPC_MESSAGE_UNHANDLED(handled = false)
190   IPC_END_MESSAGE_MAP()
191   return handled;
192 }
193
194 void RemoteRootWindowHostWin::HandleOpenURLOnDesktop(
195     const base::FilePath& shortcut,
196     const base::string16& url) {
197   if (!host_)
198     return;
199   host_->Send(new MetroViewerHostMsg_OpenURLOnDesktop(shortcut, url));
200 }
201
202 void RemoteRootWindowHostWin::HandleActivateDesktop(
203     const base::FilePath& shortcut,
204     const ActivateDesktopCompleted& on_success) {
205   if (!host_)
206     return;
207   DCHECK(activate_completed_callback_.is_null());
208   activate_completed_callback_ = on_success;
209   host_->Send(new MetroViewerHostMsg_ActivateDesktop(shortcut));
210 }
211
212 void RemoteRootWindowHostWin::HandleOpenFile(
213     const base::string16& title,
214     const base::FilePath& default_path,
215     const base::string16& filter,
216     const OpenFileCompletion& on_success,
217     const FileSelectionCanceled& on_failure) {
218   if (!host_)
219     return;
220
221   // Can only have one of these operations in flight.
222   DCHECK(file_open_completion_callback_.is_null());
223   DCHECK(failure_callback_.is_null());
224
225   file_open_completion_callback_ = on_success;
226   failure_callback_ = on_failure;
227
228   host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title,
229                                                      filter,
230                                                      default_path,
231                                                      false));
232 }
233
234 void RemoteRootWindowHostWin::HandleOpenMultipleFiles(
235     const base::string16& title,
236     const base::FilePath& default_path,
237     const base::string16& filter,
238     const OpenMultipleFilesCompletion& on_success,
239     const FileSelectionCanceled& on_failure) {
240   if (!host_)
241     return;
242
243   // Can only have one of these operations in flight.
244   DCHECK(multi_file_open_completion_callback_.is_null());
245   DCHECK(failure_callback_.is_null());
246   multi_file_open_completion_callback_ = on_success;
247   failure_callback_ = on_failure;
248
249   host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title,
250                                                      filter,
251                                                      default_path,
252                                                      true));
253 }
254
255 void RemoteRootWindowHostWin::HandleSaveFile(
256     const base::string16& title,
257     const base::FilePath& default_path,
258     const base::string16& filter,
259     int filter_index,
260     const base::string16& default_extension,
261     const SaveFileCompletion& on_success,
262     const FileSelectionCanceled& on_failure) {
263   if (!host_)
264     return;
265
266   MetroViewerHostMsg_SaveAsDialogParams params;
267   params.title = title;
268   params.default_extension = default_extension;
269   params.filter = filter;
270   params.filter_index = filter_index;
271   params.suggested_name = default_path;
272
273   // Can only have one of these operations in flight.
274   DCHECK(file_saveas_completion_callback_.is_null());
275   DCHECK(failure_callback_.is_null());
276   file_saveas_completion_callback_ = on_success;
277   failure_callback_ = on_failure;
278
279   host_->Send(new MetroViewerHostMsg_DisplayFileSaveAs(params));
280 }
281
282 void RemoteRootWindowHostWin::HandleSelectFolder(
283     const base::string16& title,
284     const SelectFolderCompletion& on_success,
285     const FileSelectionCanceled& on_failure) {
286   if (!host_)
287     return;
288
289   // Can only have one of these operations in flight.
290   DCHECK(select_folder_completion_callback_.is_null());
291   DCHECK(failure_callback_.is_null());
292   select_folder_completion_callback_ = on_success;
293   failure_callback_ = on_failure;
294
295   host_->Send(new MetroViewerHostMsg_DisplaySelectFolder(title));
296 }
297
298 Window* RemoteRootWindowHostWin::GetAshWindow() {
299   return GetRootWindow();
300 }
301
302 void RemoteRootWindowHostWin::SetDelegate(RootWindowHostDelegate* delegate) {
303   delegate_ = delegate;
304 }
305
306 RootWindow* RemoteRootWindowHostWin::GetRootWindow() {
307   return delegate_->AsRootWindow();
308 }
309
310 gfx::AcceleratedWidget RemoteRootWindowHostWin::GetAcceleratedWidget() {
311   if (remote_window_)
312     return remote_window_;
313   // Getting here should only happen for ash_unittests.exe and related code.
314   return ::GetDesktopWindow();
315 }
316
317 void RemoteRootWindowHostWin::Show() {
318 }
319
320 void RemoteRootWindowHostWin::Hide() {
321   NOTIMPLEMENTED();
322 }
323
324 void RemoteRootWindowHostWin::ToggleFullScreen() {
325 }
326
327 gfx::Rect RemoteRootWindowHostWin::GetBounds() const {
328   gfx::Rect r(gfx::Point(0, 0), aura::RootWindowHost::GetNativeScreenSize());
329   return r;
330 }
331
332 void RemoteRootWindowHostWin::SetBounds(const gfx::Rect& bounds) {
333   delegate_->OnHostResized(bounds.size());
334 }
335
336 gfx::Insets RemoteRootWindowHostWin::GetInsets() const {
337   return gfx::Insets();
338 }
339
340 void RemoteRootWindowHostWin::SetInsets(const gfx::Insets& insets) {
341 }
342
343 gfx::Point RemoteRootWindowHostWin::GetLocationOnNativeScreen() const {
344   return gfx::Point(0, 0);
345 }
346
347 void RemoteRootWindowHostWin::SetCursor(gfx::NativeCursor native_cursor) {
348   if (!host_)
349     return;
350   host_->Send(
351       new MetroViewerHostMsg_SetCursor(uint64(native_cursor.platform())));
352 }
353
354 void RemoteRootWindowHostWin::SetCapture() {
355 }
356
357 void RemoteRootWindowHostWin::ReleaseCapture() {
358 }
359
360 bool RemoteRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
361   aura::client::CursorClient* cursor_client =
362       aura::client::GetCursorClient(GetRootWindow());
363   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
364     *location_return = gfx::Point(0, 0);
365     return false;
366   }
367   POINT pt;
368   GetCursorPos(&pt);
369   *location_return =
370       gfx::Point(static_cast<int>(pt.x), static_cast<int>(pt.y));
371   return true;
372 }
373
374 bool RemoteRootWindowHostWin::ConfineCursorToRootWindow() {
375   return true;
376 }
377
378 void RemoteRootWindowHostWin::UnConfineCursor() {
379 }
380
381 void RemoteRootWindowHostWin::OnCursorVisibilityChanged(bool show) {
382   NOTIMPLEMENTED();
383 }
384
385 void RemoteRootWindowHostWin::MoveCursorTo(const gfx::Point& location) {
386   VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y();
387   if (!host_)
388     return;
389
390   // This function can be called in cases like when the mouse cursor is
391   // restricted within a viewport (For e.g. LockCursor) which assumes that
392   // subsequent mouse moves would be received starting with the new cursor
393   // coordinates. This is a challenge for Windows ASH for the reasons
394   // outlined below.
395   // Other cases which don't expect this behavior should continue to work
396   // without issues.
397
398   // The mouse events are received by the viewer process and sent to the
399   // browser. If we invoke the SetCursor API here we continue to receive
400   // mouse messages from the viewer which were posted before the SetCursor
401   // API executes which messes up the state in the browser. To workaround
402   // this we invoke the SetCursor API in the viewer process and ignore
403   // mouse messages until we received an ACK from the viewer indicating that
404   // the SetCursor operation completed.
405   ignore_mouse_moves_until_set_cursor_ack_ = true;
406   VLOG(1) << "In MoveCursorTo. Sending IPC";
407   host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y()));
408 }
409
410 void RemoteRootWindowHostWin::SetFocusWhenShown(bool focus_when_shown) {
411   NOTIMPLEMENTED();
412 }
413
414 void RemoteRootWindowHostWin::PostNativeEvent(
415     const base::NativeEvent& native_event) {
416 }
417
418 void RemoteRootWindowHostWin::OnDeviceScaleFactorChanged(
419     float device_scale_factor) {
420   NOTIMPLEMENTED();
421 }
422
423 void RemoteRootWindowHostWin::PrepareForShutdown() {
424 }
425
426 void RemoteRootWindowHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) {
427   if (ignore_mouse_moves_until_set_cursor_ack_)
428     return;
429
430   gfx::Point location(x, y);
431   ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags);
432   delegate_->OnHostMouseEvent(&event);
433 }
434
435 void RemoteRootWindowHostWin::OnMouseButton(
436     int32 x,
437     int32 y,
438     int32 extra,
439     ui::EventType type,
440     ui::EventFlags flags) {
441   gfx::Point location(x, y);
442   ui::MouseEvent mouse_event(type, location, location, flags);
443
444   SetEventFlags(flags | key_event_flags());
445   if (type == ui::ET_MOUSEWHEEL) {
446     ui::MouseWheelEvent wheel_event(mouse_event, 0, extra);
447     delegate_->OnHostMouseEvent(&wheel_event);
448   } else if (type == ui::ET_MOUSE_PRESSED) {
449     // TODO(shrikant): Ideally modify code in event.cc by adding automatic
450     // tracking of double clicks in synthetic MouseEvent constructor code.
451     // Non-synthetic MouseEvent constructor code does automatically track
452     // this. Need to use some caution while modifying synthetic constructor
453     // as many tests and other code paths depend on it and apparently
454     // specifically depend on non implicit tracking of previous mouse event.
455     if (last_mouse_click_event_ &&
456         ui::MouseEvent::IsRepeatedClickEvent(mouse_event,
457                                              *last_mouse_click_event_)) {
458       mouse_event.SetClickCount(2);
459     } else {
460       mouse_event.SetClickCount(1);
461     }
462     last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event));
463     delegate_->OnHostMouseEvent(&mouse_event);
464   } else {
465     delegate_->OnHostMouseEvent(&mouse_event);
466   }
467 }
468
469 void RemoteRootWindowHostWin::OnKeyDown(uint32 vkey,
470                                         uint32 repeat_count,
471                                         uint32 scan_code,
472                                         uint32 flags) {
473   DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code,
474                           flags, false);
475 }
476
477 void RemoteRootWindowHostWin::OnKeyUp(uint32 vkey,
478                                       uint32 repeat_count,
479                                       uint32 scan_code,
480                                       uint32 flags) {
481   DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code,
482                           flags, false);
483 }
484
485 void RemoteRootWindowHostWin::OnChar(uint32 key_code,
486                                      uint32 repeat_count,
487                                      uint32 scan_code,
488                                      uint32 flags) {
489   DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count,
490                           scan_code, flags, true);
491 }
492
493 void RemoteRootWindowHostWin::OnWindowActivated() {
494   delegate_->OnHostActivated();
495 }
496
497 void RemoteRootWindowHostWin::OnTouchDown(int32 x,
498                                           int32 y,
499                                           uint64 timestamp,
500                                           uint32 pointer_id) {
501   ui::TouchEvent event(ui::ET_TOUCH_PRESSED,
502                        gfx::Point(x, y),
503                        pointer_id,
504                        base::TimeDelta::FromMicroseconds(timestamp));
505   delegate_->OnHostTouchEvent(&event);
506 }
507
508 void RemoteRootWindowHostWin::OnTouchUp(int32 x,
509                                         int32 y,
510                                         uint64 timestamp,
511                                         uint32 pointer_id) {
512   ui::TouchEvent event(ui::ET_TOUCH_RELEASED,
513                        gfx::Point(x, y),
514                        pointer_id,
515                        base::TimeDelta::FromMicroseconds(timestamp));
516   delegate_->OnHostTouchEvent(&event);
517 }
518
519 void RemoteRootWindowHostWin::OnTouchMoved(int32 x,
520                                            int32 y,
521                                            uint64 timestamp,
522                                            uint32 pointer_id) {
523   ui::TouchEvent event(ui::ET_TOUCH_MOVED,
524                        gfx::Point(x, y),
525                        pointer_id,
526                        base::TimeDelta::FromMicroseconds(timestamp));
527   delegate_->OnHostTouchEvent(&event);
528 }
529
530 void RemoteRootWindowHostWin::OnFileSaveAsDone(bool success,
531                                                const base::FilePath& filename,
532                                                int filter_index) {
533   if (success)
534     file_saveas_completion_callback_.Run(filename, filter_index, NULL);
535   else
536     failure_callback_.Run(NULL);
537   file_saveas_completion_callback_.Reset();
538   failure_callback_.Reset();
539 }
540
541
542 void RemoteRootWindowHostWin::OnFileOpenDone(bool success,
543                                              const base::FilePath& filename) {
544   if (success)
545     file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL);
546   else
547     failure_callback_.Run(NULL);
548   file_open_completion_callback_.Reset();
549   failure_callback_.Reset();
550 }
551
552 void RemoteRootWindowHostWin::OnMultiFileOpenDone(
553     bool success,
554     const std::vector<base::FilePath>& files) {
555   if (success)
556     multi_file_open_completion_callback_.Run(files, NULL);
557   else
558     failure_callback_.Run(NULL);
559   multi_file_open_completion_callback_.Reset();
560   failure_callback_.Reset();
561 }
562
563 void RemoteRootWindowHostWin::OnSelectFolderDone(
564     bool success,
565     const base::FilePath& folder) {
566   if (success)
567     select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL);
568   else
569     failure_callback_.Run(NULL);
570   select_folder_completion_callback_.Reset();
571   failure_callback_.Reset();
572 }
573
574 void RemoteRootWindowHostWin::OnSetCursorPosAck() {
575   DCHECK(ignore_mouse_moves_until_set_cursor_ack_);
576   ignore_mouse_moves_until_set_cursor_ack_ = false;
577 }
578
579 void RemoteRootWindowHostWin::OnWindowSizeChanged(uint32 width, uint32 height) {
580   SetBounds(gfx::Rect(0, 0, width, height));
581 }
582
583 void RemoteRootWindowHostWin::OnDesktopActivated() {
584   ActivateDesktopCompleted temp = activate_completed_callback_;
585   activate_completed_callback_.Reset();
586   temp.Run();
587 }
588
589 void RemoteRootWindowHostWin::DispatchKeyboardMessage(ui::EventType type,
590                                                       uint32 vkey,
591                                                       uint32 repeat_count,
592                                                       uint32 scan_code,
593                                                       uint32 flags,
594                                                       bool is_character) {
595   SetEventFlags(flags | mouse_event_flags());
596   if (base::MessageLoop::current()->IsNested()) {
597     uint32 message = is_character ? WM_CHAR :
598         (type == ui::ET_KEY_PRESSED ? WM_KEYDOWN : WM_KEYUP);
599     ::PostThreadMessage(::GetCurrentThreadId(),
600                         message,
601                         vkey,
602                         repeat_count | scan_code >> 15);
603   } else {
604     ui::KeyEvent event(type,
605                        ui::KeyboardCodeForWindowsKeyCode(vkey),
606                        flags,
607                        is_character);
608     delegate_->OnHostKeyEvent(&event);
609   }
610 }
611
612 void RemoteRootWindowHostWin::SetEventFlags(uint32 flags) {
613   if (flags == event_flags_)
614     return;
615   event_flags_ = flags;
616   SetVirtualKeyStates(event_flags_);
617 }
618
619 }  // namespace aura