blob: c9426daf736ca04f5424c33d9f79876f6d80fc05 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 "src/ui/scenic/lib/input/input_command_dispatcher.h"
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/fidl/cpp/clone.h>
#include <lib/fostr/fidl/fuchsia/ui/input/formatting.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <memory>
#include <vector>
#include "src/ui/lib/escher/geometry/types.h"
#include "src/ui/scenic/lib/input/helper.h"
#include "src/ui/scenic/lib/input/input_system.h"
#include "src/ui/scenic/lib/scenic/event_reporter.h"
namespace scenic_impl {
namespace input {
using FocusChangeStatus = scenic_impl::gfx::ViewTree::FocusChangeStatus;
using InputCommand = fuchsia::ui::input::Command;
using ScenicCommand = fuchsia::ui::scenic::Command;
using fuchsia::ui::input::InputEvent;
using fuchsia::ui::input::PointerEvent;
using fuchsia::ui::input::PointerEventType;
using fuchsia::ui::input::SendPointerInputCmd;
InputCommandDispatcher::InputCommandDispatcher(scheduling::SessionId session_id,
std::shared_ptr<EventReporter> event_reporter,
fxl::WeakPtr<gfx::SceneGraph> scene_graph,
InputSystem* input_system)
: session_id_(session_id),
event_reporter_(std::move(event_reporter)),
scene_graph_(scene_graph),
input_system_(input_system) {
FX_CHECK(scene_graph_);
FX_CHECK(input_system_);
}
void InputCommandDispatcher::DispatchCommand(ScenicCommand command,
scheduling::PresentId present_id) {
TRACE_DURATION("input", "dispatch_command", "command", "ScenicCmd");
FX_DCHECK(command.Which() == ScenicCommand::Tag::kInput);
if (!scene_graph_)
return; // Scene graph does not exist. Can not dispatch input.
InputCommand& input = command.input();
if (input.is_send_keyboard_input()) {
DispatchCommand(input.send_keyboard_input());
} else if (input.is_send_pointer_input()) {
input_system_->DispatchPointerCommand(input.send_pointer_input(), session_id_,
/*parallel_dispatch*/ false);
} else if (input.is_set_hard_keyboard_delivery()) {
DispatchCommand(input.set_hard_keyboard_delivery());
} else if (input.is_set_parallel_dispatch()) {
if (input.set_parallel_dispatch().parallel_dispatch) {
FX_LOGS(WARNING) << "Scenic: Parallel dispatch request is ignored and disabled.";
}
}
}
void InputCommandDispatcher::DispatchCommand(
const fuchsia::ui::input::SendKeyboardInputCmd& command) {
TRACE_DURATION("input", "dispatch_command", "command", "SendKeyboardInputCmd");
// Expected (but soon to be deprecated) event flow.
ReportToImeService(input_system_->ime_service(), command.keyboard_event);
// Unusual: Clients may have requested direct delivery when focused.
const zx_koid_t focused_view = input_system_->focus();
if (focused_view == ZX_KOID_INVALID)
return; // No receiver.
const scenic_impl::gfx::ViewTree& view_tree = scene_graph_->view_tree();
EventReporterWeakPtr reporter = view_tree.EventReporterOf(focused_view);
scheduling::SessionId session_id = view_tree.SessionIdOf(focused_view);
if (reporter && input_system_->hard_keyboard_requested().count(session_id) > 0) {
ReportKeyboardEvent(reporter.get(), command.keyboard_event);
}
}
void InputCommandDispatcher::DispatchCommand(
const fuchsia::ui::input::SetHardKeyboardDeliveryCmd& command) {
// Can't easily retrieve owning view's ViewRef KOID from just the Session or SessionId.
FX_VLOGS(2) << "Hard keyboard events, session_id=" << session_id_
<< ", delivery_request=" << (command.delivery_request ? "on" : "off");
if (command.delivery_request) {
// Take this opportunity to remove dead sessions.
std::vector<scheduling::SessionId> dead_sessions;
for (auto& reporter : input_system_->hard_keyboard_requested()) {
if (!reporter.second) {
dead_sessions.push_back(reporter.first);
}
}
for (auto session_ids : dead_sessions) {
input_system_->hard_keyboard_requested().erase(session_id_);
}
// This code assumes one event reporter per session id.
if (input_system_->hard_keyboard_requested().count(session_id_) != 0) {
FX_LOGS(ERROR) << "Hard keyboard requested twice by session " << session_id_
<< ". Second request ignored.";
return;
}
if (event_reporter_)
input_system_->hard_keyboard_requested().insert({session_id_, event_reporter_->GetWeakPtr()});
} else {
input_system_->hard_keyboard_requested().erase(session_id_);
}
}
void InputCommandDispatcher::ReportKeyboardEvent(EventReporter* reporter,
fuchsia::ui::input::KeyboardEvent keyboard) {
FX_DCHECK(reporter) << "precondition";
InputEvent event;
event.set_keyboard(std::move(keyboard));
reporter->EnqueueEvent(std::move(event));
}
void InputCommandDispatcher::ReportToImeService(
const fuchsia::ui::input::ImeServicePtr& ime_service,
fuchsia::ui::input::KeyboardEvent keyboard) {
TRACE_DURATION("input", "dispatch_event_to_client", "event_type", "ime_keyboard_event");
if (ime_service && ime_service.is_bound()) {
InputEvent event;
event.set_keyboard(std::move(keyboard));
ime_service->InjectInput(std::move(event));
}
}
} // namespace input
} // namespace scenic_impl