blob: 996130ef4d957f90bb7fc72ebd1acbc421e02e29 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_POINTER_DELEGATE_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_POINTER_DELEGATE_H_
#include <fuchsia/ui/pointer/cpp/fidl.h>
#include <array>
#include <functional>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "flutter/lib/ui/window/pointer_data.h"
namespace flutter_runner {
// Helper class for keying into a map.
struct IxnHasher {
std::size_t operator()(
const fuchsia::ui::pointer::TouchInteractionId& ixn) const {
return std::hash<uint32_t>()(ixn.device_id) ^
std::hash<uint32_t>()(ixn.pointer_id) ^
std::hash<uint32_t>()(ixn.interaction_id);
}
};
// Channel processors for fuchsia.ui.pointer.TouchSource and MouseSource
// protocols. It manages the channel state, collects touch and mouse events, and
// surfaces them to PlatformView as flutter::PointerData events for further
// processing and dispatch.
class PointerDelegate {
public:
PointerDelegate(fuchsia::ui::pointer::TouchSourceHandle touch_source,
fuchsia::ui::pointer::MouseSourceHandle mouse_source);
// This function collects Fuchsia's TouchPointerSample and MousePointerSample
// data and transforms them into flutter::PointerData structs. It then calls
// the supplied callback with a vector of flutter::PointerData, which (1) does
// last processing (applies metrics), and (2) packs these flutter::PointerData
// in a flutter::PointerDataPacket for transport to the Engine.
void WatchLoop(
std::function<void(std::vector<flutter::PointerData>)> callback);
private:
/***** TOUCH STATE *****/
// Channel for touch events from Scenic.
fuchsia::ui::pointer::TouchSourcePtr touch_source_;
// Receive touch events from Scenic. Must be copyable.
std::function<void(std::vector<fuchsia::ui::pointer::TouchEvent>)>
touch_responder_;
// Per-interaction buffer of touch events from Scenic. When an interaction
// starts with event.pointer_sample.phase == ADD, we allocate a buffer and
// store samples. When interaction ownership becomes
// event.interaction_result.status == GRANTED, we flush the buffer to client,
// delete the buffer, and all future events in this interaction are flushed
// direct to client. When interaction ownership becomes DENIED, we delete the
// buffer, and the client does not get any previous or future events in this
// interaction.
//
// There are three basic interaction forms that we need to handle, and the API
// guarantees we see only these three forms. S=sample, R(g)=result-granted,
// R(d)=result-denied, and + means packaged in the same table. Time flows from
// left to right. Samples start with ADD, and end in REMOVE or CANCEL. Each
// interaction receives just one ownership result.
// (1) Late grant. S S S R(g) S S S
// (1-a) Combo. S S S+R(g) S S S
// (2) Early grant. S+R(g) S S S S S
// (3) Late deny. S S S R(d)
// (3-a) Combo. S S S+R(d)
//
// This results in the following high-level algorithm to correctly deal with
// buffer allocation and deletion, and event flushing or event dropping based
// on ownership.
// if event.sample.phase == ADD && !event.result
// allocate buffer[event.sample.interaction]
// if buffer[event.sample.interaction]
// buffer[event.sample.interaction].push(event.sample)
// else
// flush_to_client(event.sample)
// if event.result
// if event.result == GRANTED
// flush_to_client(buffer[event.result.interaction])
// delete buffer[event.result.interaction]
std::unordered_map<fuchsia::ui::pointer::TouchInteractionId,
std::vector<flutter::PointerData>,
IxnHasher>
touch_buffer_;
// The fuchsia.ui.pointer.TouchSource protocol allows one in-flight
// hanging-get Watch() call to gather touch events, and the client is expected
// to respond with consumption intent on the following hanging-get Watch()
// call. Store responses here for the next call.
std::vector<fuchsia::ui::pointer::TouchResponse> touch_responses_;
// The fuchsia.ui.pointer.TouchSource protocol issues channel-global view
// parameters on connection and on change. Events must apply these view
// parameters to correctly map to logical view coordinates. The "nullopt"
// state represents the absence of view parameters, early in the protocol
// lifecycle.
std::optional<fuchsia::ui::pointer::ViewParameters> touch_view_parameters_;
/***** MOUSE STATE *****/
// Channel for mouse events from Scenic.
fuchsia::ui::pointer::MouseSourcePtr mouse_source_;
// Receive mouse events from Scenic. Must be copyable.
std::function<void(std::vector<fuchsia::ui::pointer::MouseEvent>)>
mouse_responder_;
// The set of mouse devices that are currently interacting with the UI.
// A mouse is considered flutter::PointerData::Change::kDown if any button is
// pressed. This set is used to correctly set the phase in
// flutter::PointerData.change, with this high-level algorithm:
// if !mouse_down[id] && !button then: change = kHover
// if !mouse_down[id] && button then: change = kDown; mouse_down.add(id)
// if mouse_down[id] && button then: change = kMove
// if mouse_down[id] && !button then: change = kUp; mouse_down.remove(id)
std::unordered_set</*mouse device ID*/ uint32_t> mouse_down_;
// For each mouse device, its device-specific information, such as mouse
// button priority order.
std::unordered_map</*mouse device ID*/ uint32_t,
fuchsia::ui::pointer::MouseDeviceInfo>
mouse_device_info_;
// The fuchsia.ui.pointer.MouseSource protocol issues channel-global view
// parameters on connection and on change. Events must apply these view
// parameters to correctly map to logical view coordinates. The "nullopt"
// state represents the absence of view parameters, early in the protocol
// lifecycle.
std::optional<fuchsia::ui::pointer::ViewParameters> mouse_view_parameters_;
};
} // namespace flutter_runner
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_POINTER_DELEGATE_H_