|  | // Copyright 2014 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 "base/bind.h" | 
|  | #include "base/logging.h" | 
|  | #include "ui/aura/client/screen_position_client.h" | 
|  | #include "ui/aura/env.h" | 
|  | #include "ui/aura/test/aura_test_utils.h" | 
|  | #include "ui/aura/test/ui_controls_factory_aura.h" | 
|  | #include "ui/aura/window_tree_host.h" | 
|  | #include "ui/base/test/ui_controls_aura.h" | 
|  |  | 
|  | namespace aura { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | class UIControlsOzone : public ui_controls::UIControlsAura { | 
|  | public: | 
|  | UIControlsOzone(WindowTreeHost* host) : host_(host) {} | 
|  |  | 
|  | virtual bool SendKeyPress(gfx::NativeWindow window, | 
|  | ui::KeyboardCode key, | 
|  | bool control, | 
|  | bool shift, | 
|  | bool alt, | 
|  | bool command) override { | 
|  | return SendKeyPressNotifyWhenDone( | 
|  | window, key, control, shift, alt, command, base::Closure()); | 
|  | } | 
|  | virtual bool SendKeyPressNotifyWhenDone( | 
|  | gfx::NativeWindow window, | 
|  | ui::KeyboardCode key, | 
|  | bool control, | 
|  | bool shift, | 
|  | bool alt, | 
|  | bool command, | 
|  | const base::Closure& closure) override { | 
|  | int flags = button_down_mask_; | 
|  |  | 
|  | if (control) { | 
|  | flags |= ui::EF_CONTROL_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL, flags); | 
|  | } | 
|  |  | 
|  | if (shift) { | 
|  | flags |= ui::EF_SHIFT_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_SHIFT, flags); | 
|  | } | 
|  |  | 
|  | if (alt) { | 
|  | flags |= ui::EF_ALT_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_MENU, flags); | 
|  | } | 
|  |  | 
|  | if (command) { | 
|  | flags |= ui::EF_COMMAND_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_LWIN, flags); | 
|  | } | 
|  |  | 
|  | PostKeyEvent(ui::ET_KEY_PRESSED, key, flags); | 
|  | PostKeyEvent(ui::ET_KEY_RELEASED, key, flags); | 
|  |  | 
|  | if (alt) { | 
|  | flags &= ~ui::EF_ALT_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_MENU, flags); | 
|  | } | 
|  |  | 
|  | if (shift) { | 
|  | flags &= ~ui::EF_SHIFT_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_SHIFT, flags); | 
|  | } | 
|  |  | 
|  | if (control) { | 
|  | flags &= ~ui::EF_CONTROL_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL, flags); | 
|  | } | 
|  |  | 
|  | if (command) { | 
|  | flags &= ~ui::EF_COMMAND_DOWN; | 
|  | PostKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_LWIN, flags); | 
|  | } | 
|  |  | 
|  | RunClosureAfterAllPendingUIEvents(closure); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | virtual bool SendMouseMove(long screen_x, long screen_y) override { | 
|  | return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure()); | 
|  | } | 
|  | virtual bool SendMouseMoveNotifyWhenDone( | 
|  | long screen_x, | 
|  | long screen_y, | 
|  | const base::Closure& closure) override { | 
|  | gfx::Point root_location(screen_x, screen_y); | 
|  | aura::client::ScreenPositionClient* screen_position_client = | 
|  | aura::client::GetScreenPositionClient(host_->window()); | 
|  | if (screen_position_client) { | 
|  | screen_position_client->ConvertPointFromScreen(host_->window(), | 
|  | &root_location); | 
|  | } | 
|  | gfx::Point root_current_location = | 
|  | QueryLatestMousePositionRequestInHost(host_); | 
|  | host_->ConvertPointFromHost(&root_current_location); | 
|  |  | 
|  | if (button_down_mask_) | 
|  | PostMouseEvent(ui::ET_MOUSE_DRAGGED, root_location, 0, 0); | 
|  | else | 
|  | PostMouseEvent(ui::ET_MOUSE_MOVED, root_location, 0, 0); | 
|  |  | 
|  | RunClosureAfterAllPendingUIEvents(closure); | 
|  | return true; | 
|  | } | 
|  | virtual bool SendMouseEvents(ui_controls::MouseButton type, | 
|  | int state) override { | 
|  | return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); | 
|  | } | 
|  | virtual bool SendMouseEventsNotifyWhenDone( | 
|  | ui_controls::MouseButton type, | 
|  | int state, | 
|  | const base::Closure& closure) override { | 
|  | gfx::Point loc = aura::Env::GetInstance()->last_mouse_location(); | 
|  | aura::client::ScreenPositionClient* screen_position_client = | 
|  | aura::client::GetScreenPositionClient(host_->window()); | 
|  | if (screen_position_client) { | 
|  | screen_position_client->ConvertPointFromScreen(host_->window(), &loc); | 
|  | } | 
|  | int flag = 0; | 
|  |  | 
|  | switch (type) { | 
|  | case ui_controls::LEFT: | 
|  | flag = ui::EF_LEFT_MOUSE_BUTTON; | 
|  | break; | 
|  | case ui_controls::MIDDLE: | 
|  | flag = ui::EF_MIDDLE_MOUSE_BUTTON; | 
|  | break; | 
|  | case ui_controls::RIGHT: | 
|  | flag = ui::EF_RIGHT_MOUSE_BUTTON; | 
|  | break; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (state & ui_controls::DOWN) { | 
|  | button_down_mask_ |= flag; | 
|  | PostMouseEvent(ui::ET_MOUSE_PRESSED, loc, button_down_mask_ | flag, flag); | 
|  | } | 
|  | if (state & ui_controls::UP) { | 
|  | button_down_mask_ &= ~flag; | 
|  | PostMouseEvent( | 
|  | ui::ET_MOUSE_RELEASED, loc, button_down_mask_ | flag, flag); | 
|  | } | 
|  |  | 
|  | RunClosureAfterAllPendingUIEvents(closure); | 
|  | return true; | 
|  | } | 
|  | virtual bool SendMouseClick(ui_controls::MouseButton type) override { | 
|  | return SendMouseEvents(type, ui_controls::UP | ui_controls::DOWN); | 
|  | } | 
|  | virtual void RunClosureAfterAllPendingUIEvents( | 
|  | const base::Closure& closure) override { | 
|  | if (!closure.is_null()) | 
|  | base::MessageLoop::current()->PostTask(FROM_HERE, closure); | 
|  | } | 
|  |  | 
|  | private: | 
|  | void PostKeyEvent(ui::EventType type, ui::KeyboardCode key_code, int flags) { | 
|  | base::MessageLoop::current()->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&UIControlsOzone::PostKeyEventTask, | 
|  | base::Unretained(this), | 
|  | type, | 
|  | key_code, | 
|  | flags)); | 
|  | } | 
|  |  | 
|  | void PostKeyEventTask(ui::EventType type, | 
|  | ui::KeyboardCode key_code, | 
|  | int flags) { | 
|  | // Do not rewrite injected events. See crbug.com/136465. | 
|  | flags |= ui::EF_FINAL; | 
|  |  | 
|  | ui::KeyEvent key_event(type, key_code, flags); | 
|  | host_->PostNativeEvent(&key_event); | 
|  | } | 
|  |  | 
|  | void PostMouseEvent(ui::EventType type, | 
|  | const gfx::PointF& location, | 
|  | int flags, | 
|  | int changed_button_flags) { | 
|  | base::MessageLoop::current()->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&UIControlsOzone::PostMouseEventTask, | 
|  | base::Unretained(this), | 
|  | type, | 
|  | location, | 
|  | flags, | 
|  | changed_button_flags)); | 
|  | } | 
|  |  | 
|  | void PostMouseEventTask(ui::EventType type, | 
|  | const gfx::PointF& location, | 
|  | int flags, | 
|  | int changed_button_flags) { | 
|  | ui::MouseEvent mouse_event( | 
|  | type, location, location, flags, changed_button_flags); | 
|  |  | 
|  | // This hack is necessary to set the repeat count for clicks. | 
|  | ui::MouseEvent mouse_event2(&mouse_event); | 
|  |  | 
|  | host_->PostNativeEvent(&mouse_event2); | 
|  | } | 
|  |  | 
|  | WindowTreeHost* host_; | 
|  |  | 
|  | // Mask of the mouse buttons currently down. | 
|  | unsigned button_down_mask_ = 0; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(UIControlsOzone); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | ui_controls::UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) { | 
|  | return new UIControlsOzone(host); | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace aura |