blob: 1bd3e978da0bbbd3f93845bffeaad9eec72129b3 [file] [log] [blame]
// Copyright 2016 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 "ash/components/autoclick/autoclick_application.h"
#include <utility>
#include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/ui/public/cpp/property_type_converters.h"
#include "services/ui/public/interfaces/constants.mojom.h"
#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
#include "ui/aura/mus/property_converter.h"
#include "ui/base/ui_base_types.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/base_event_utils.h"
#include "ui/views/mus/aura_init.h"
#include "ui/views/mus/mus_client.h"
#include "ui/views/mus/pointer_watcher_event_router.h"
#include "ui/views/pointer_watcher.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace autoclick {
// AutoclickUI handles events to the autoclick app.
class AutoclickUI : public views::WidgetDelegateView,
public views::PointerWatcher {
public:
explicit AutoclickUI(
ash::AutoclickControllerCommon* autoclick_controller_common)
: autoclick_controller_common_(autoclick_controller_common) {
views::MusClient::Get()->pointer_watcher_event_router()->AddPointerWatcher(
this, true /* want_moves */);
}
~AutoclickUI() override {
views::MusClient::Get()
->pointer_watcher_event_router()
->RemovePointerWatcher(this);
}
private:
// Overridden from views::WidgetDelegate:
base::string16 GetWindowTitle() const override {
// TODO(beng): use resources.
return base::ASCIIToUTF16("Autoclick");
}
// Overridden from views::PointerWatcher:
void OnPointerEventObserved(const ui::PointerEvent& event,
const gfx::Point& location_in_screen,
gfx::NativeView target) override {
// AutoclickControllerCommon won't work correctly with a target.
DCHECK(!event.target());
if (event.IsTouchPointerEvent()) {
autoclick_controller_common_->CancelAutoclick();
} else if (event.IsMousePointerEvent()) {
if (event.type() == ui::ET_POINTER_WHEEL_CHANGED) {
autoclick_controller_common_->HandleMouseEvent(
ui::MouseWheelEvent(event));
} else {
ui::MouseEvent mouse_event(event);
// AutoclickControllerCommon wants screen coordinates when there isn't a
// target.
mouse_event.set_location(location_in_screen);
autoclick_controller_common_->HandleMouseEvent(mouse_event);
}
}
}
ash::AutoclickControllerCommon* autoclick_controller_common_;
DISALLOW_COPY_AND_ASSIGN(AutoclickUI);
};
AutoclickApplication::AutoclickApplication()
: launchable_binding_(this), autoclick_binding_(this) {
registry_.AddInterface<mash::mojom::Launchable>(base::BindRepeating(
&AutoclickApplication::BindLaunchableRequest, base::Unretained(this)));
registry_.AddInterface<mojom::AutoclickController>(
base::BindRepeating(&AutoclickApplication::BindAutoclickControllerRequest,
base::Unretained(this)));
}
AutoclickApplication::~AutoclickApplication() = default;
void AutoclickApplication::OnStart() {
views::AuraInit::InitParams params;
params.connector = context()->connector();
params.identity = context()->identity();
params.register_path_provider = running_standalone_;
aura_init_ = views::AuraInit::Create(params);
if (!aura_init_) {
context()->QuitNow();
return;
}
autoclick_controller_common_ =
std::make_unique<ash::AutoclickControllerCommon>(
base::TimeDelta::FromMilliseconds(ash::kDefaultAutoclickDelayMs),
this);
}
void AutoclickApplication::OnBindInterface(
const service_manager::BindSourceInfo& remote_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
registry_.BindInterface(interface_name, std::move(interface_pipe));
}
void AutoclickApplication::Launch(uint32_t what, mash::mojom::LaunchMode how) {
if (!widget_) {
widget_.reset(new views::Widget);
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
params.accept_events = false;
params.delegate = new AutoclickUI(autoclick_controller_common_.get());
params.mus_properties[ui::mojom::WindowManager::kContainerId_InitProperty] =
mojo::ConvertTo<std::vector<uint8_t>>(
static_cast<int32_t>(ash::kShellWindowId_OverlayContainer));
params.show_state = ui::SHOW_STATE_FULLSCREEN;
widget_->Init(params);
} else {
widget_->Close();
context()->QuitNow();
}
}
void AutoclickApplication::SetAutoclickDelay(uint32_t delay_in_milliseconds) {
autoclick_controller_common_->SetAutoclickDelay(
base::TimeDelta::FromMilliseconds(delay_in_milliseconds));
}
void AutoclickApplication::BindLaunchableRequest(
mash::mojom::LaunchableRequest request) {
launchable_binding_.Close();
launchable_binding_.Bind(std::move(request));
}
void AutoclickApplication::BindAutoclickControllerRequest(
mojom::AutoclickControllerRequest request) {
autoclick_binding_.Close();
autoclick_binding_.Bind(std::move(request));
}
views::Widget* AutoclickApplication::CreateAutoclickRingWidget(
const gfx::Point& point_in_screen) {
return widget_.get();
}
void AutoclickApplication::UpdateAutoclickRingWidget(
views::Widget* widget,
const gfx::Point& point_in_screen) {
// Not used in mus.
}
void AutoclickApplication::DoAutoclick(const gfx::Point& point_in_screen,
const int mouse_event_flags) {
// The window service expects display pixel coordinates for events.
display::Display display =
display::Screen::GetScreen()->GetDisplayNearestPoint(point_in_screen);
gfx::Point point_in_root(point_in_screen);
point_in_root -= display.bounds().OffsetFromOrigin();
gfx::Point point_in_pixels =
gfx::ScaleToFlooredPoint(point_in_root, display.device_scale_factor());
// Connect to the window service event generation interface.
ui::mojom::EventInjectorPtr event_injector;
context()->connector()->BindInterface(ui::mojom::kServiceName,
&event_injector);
// Inject a synthetic click.
ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, point_in_pixels,
point_in_pixels, ui::EventTimeForNow(),
mouse_event_flags | ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, point_in_pixels,
point_in_pixels, ui::EventTimeForNow(),
mouse_event_flags | ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
event_injector->InjectEvent(
display.id(), std::make_unique<ui::PointerEvent>(press_event),
base::BindOnce([](bool result) { DCHECK(result); }));
// Don't check the next dispatch result because it's possible the first event
// will initiate shutdown.
event_injector->InjectEvent(display.id(),
std::make_unique<ui::PointerEvent>(release_event),
base::DoNothing());
}
void AutoclickApplication::OnAutoclickCanceled() {
// Not used in mus.
}
} // namespace autoclick