mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
We currently use a mix of C standard includes (e.g. limits.h) and their C++ variants (e.g. climits). This migrates to a consistent style for all cases where the C++ variants are acceptable, but leaves the C equivalents in place where they are required, such as in the embedder API and other headers that may be used from C.
288 lines
11 KiB
C++
288 lines
11 KiB
C++
// 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.
|
|
|
|
#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
|
|
|
|
#include <cstring>
|
|
|
|
#include "flutter/fml/logging.h"
|
|
|
|
namespace flutter {
|
|
|
|
PointerDataPacketConverter::PointerDataPacketConverter() : pointer_(0) {}
|
|
|
|
PointerDataPacketConverter::~PointerDataPacketConverter() = default;
|
|
|
|
std::unique_ptr<PointerDataPacket> PointerDataPacketConverter::Convert(
|
|
std::unique_ptr<PointerDataPacket> packet) {
|
|
size_t kBytesPerPointerData = kPointerDataFieldCount * kBytesPerField;
|
|
auto buffer = packet->data();
|
|
size_t buffer_length = buffer.size();
|
|
|
|
std::vector<PointerData> converted_pointers;
|
|
// Converts each pointer data in the buffer and stores it in the
|
|
// converted_pointers.
|
|
for (size_t i = 0; i < buffer_length / kBytesPerPointerData; i++) {
|
|
PointerData pointer_data;
|
|
memcpy(&pointer_data, &buffer[i * kBytesPerPointerData],
|
|
sizeof(PointerData));
|
|
ConvertPointerData(pointer_data, converted_pointers);
|
|
}
|
|
|
|
// Writes converted_pointers into converted_packet.
|
|
auto converted_packet =
|
|
std::make_unique<flutter::PointerDataPacket>(converted_pointers.size());
|
|
size_t count = 0;
|
|
for (auto& converted_pointer : converted_pointers) {
|
|
converted_packet->SetPointerData(count++, converted_pointer);
|
|
}
|
|
|
|
return converted_packet;
|
|
}
|
|
|
|
void PointerDataPacketConverter::ConvertPointerData(
|
|
PointerData pointer_data,
|
|
std::vector<PointerData>& converted_pointers) {
|
|
if (pointer_data.signal_kind == PointerData::SignalKind::kNone) {
|
|
switch (pointer_data.change) {
|
|
case PointerData::Change::kCancel: {
|
|
// Android's three finger gesture will send a cancel event
|
|
// to a non-existing pointer. Drops the cancel if pointer
|
|
// is not previously added.
|
|
// https://github.com/flutter/flutter/issues/20517
|
|
auto iter = states_.find(pointer_data.device);
|
|
if (iter != states_.end()) {
|
|
PointerState state = iter->second;
|
|
FML_DCHECK(state.isDown);
|
|
UpdatePointerIdentifier(pointer_data, state, false);
|
|
|
|
if (LocationNeedsUpdate(pointer_data, state)) {
|
|
// Synthesizes a move event if the location does not match.
|
|
PointerData synthesized_move_event = pointer_data;
|
|
synthesized_move_event.change = PointerData::Change::kMove;
|
|
synthesized_move_event.synthesized = 1;
|
|
|
|
UpdateDeltaAndState(synthesized_move_event, state);
|
|
converted_pointers.push_back(synthesized_move_event);
|
|
}
|
|
|
|
state.isDown = false;
|
|
states_[pointer_data.device] = state;
|
|
converted_pointers.push_back(pointer_data);
|
|
}
|
|
break;
|
|
}
|
|
case PointerData::Change::kAdd: {
|
|
FML_DCHECK(states_.find(pointer_data.device) == states_.end());
|
|
EnsurePointerState(pointer_data);
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
case PointerData::Change::kRemove: {
|
|
// Makes sure we have an existing pointer
|
|
auto iter = states_.find(pointer_data.device);
|
|
FML_DCHECK(iter != states_.end());
|
|
PointerState state = iter->second;
|
|
|
|
if (state.isDown) {
|
|
// Synthesizes cancel event if the pointer is down.
|
|
PointerData synthesized_cancel_event = pointer_data;
|
|
synthesized_cancel_event.change = PointerData::Change::kCancel;
|
|
synthesized_cancel_event.synthesized = 1;
|
|
UpdatePointerIdentifier(synthesized_cancel_event, state, false);
|
|
|
|
state.isDown = false;
|
|
states_[synthesized_cancel_event.device] = state;
|
|
converted_pointers.push_back(synthesized_cancel_event);
|
|
}
|
|
|
|
if (LocationNeedsUpdate(pointer_data, state)) {
|
|
// Synthesizes a hover event if the location does not match.
|
|
PointerData synthesized_hover_event = pointer_data;
|
|
synthesized_hover_event.change = PointerData::Change::kHover;
|
|
synthesized_hover_event.synthesized = 1;
|
|
|
|
UpdateDeltaAndState(synthesized_hover_event, state);
|
|
converted_pointers.push_back(synthesized_hover_event);
|
|
}
|
|
|
|
states_.erase(pointer_data.device);
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
case PointerData::Change::kHover: {
|
|
auto iter = states_.find(pointer_data.device);
|
|
PointerState state;
|
|
if (iter == states_.end()) {
|
|
// Synthesizes add event if the pointer is not previously added.
|
|
PointerData synthesized_add_event = pointer_data;
|
|
synthesized_add_event.change = PointerData::Change::kAdd;
|
|
synthesized_add_event.synthesized = 1;
|
|
state = EnsurePointerState(synthesized_add_event);
|
|
converted_pointers.push_back(synthesized_add_event);
|
|
} else {
|
|
state = iter->second;
|
|
}
|
|
|
|
FML_DCHECK(!state.isDown);
|
|
if (LocationNeedsUpdate(pointer_data, state)) {
|
|
UpdateDeltaAndState(pointer_data, state);
|
|
converted_pointers.push_back(pointer_data);
|
|
}
|
|
break;
|
|
}
|
|
case PointerData::Change::kDown: {
|
|
auto iter = states_.find(pointer_data.device);
|
|
PointerState state;
|
|
if (iter == states_.end()) {
|
|
// Synthesizes a add event if the pointer is not previously added.
|
|
PointerData synthesized_add_event = pointer_data;
|
|
synthesized_add_event.change = PointerData::Change::kAdd;
|
|
synthesized_add_event.synthesized = 1;
|
|
state = EnsurePointerState(synthesized_add_event);
|
|
converted_pointers.push_back(synthesized_add_event);
|
|
} else {
|
|
state = iter->second;
|
|
}
|
|
|
|
FML_DCHECK(!state.isDown);
|
|
if (LocationNeedsUpdate(pointer_data, state)) {
|
|
// Synthesizes a hover event if the location does not match.
|
|
PointerData synthesized_hover_event = pointer_data;
|
|
synthesized_hover_event.change = PointerData::Change::kHover;
|
|
synthesized_hover_event.synthesized = 1;
|
|
|
|
UpdateDeltaAndState(synthesized_hover_event, state);
|
|
converted_pointers.push_back(synthesized_hover_event);
|
|
}
|
|
|
|
UpdatePointerIdentifier(pointer_data, state, true);
|
|
state.isDown = true;
|
|
states_[pointer_data.device] = state;
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
case PointerData::Change::kMove: {
|
|
// Makes sure we have an existing pointer in down state
|
|
auto iter = states_.find(pointer_data.device);
|
|
FML_DCHECK(iter != states_.end());
|
|
PointerState state = iter->second;
|
|
FML_DCHECK(state.isDown);
|
|
|
|
UpdatePointerIdentifier(pointer_data, state, false);
|
|
UpdateDeltaAndState(pointer_data, state);
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
case PointerData::Change::kUp: {
|
|
// Makes sure we have an existing pointer in down state
|
|
auto iter = states_.find(pointer_data.device);
|
|
FML_DCHECK(iter != states_.end());
|
|
PointerState state = iter->second;
|
|
FML_DCHECK(state.isDown);
|
|
|
|
UpdatePointerIdentifier(pointer_data, state, false);
|
|
|
|
if (LocationNeedsUpdate(pointer_data, state)) {
|
|
// Synthesizes a move event if the location does not match.
|
|
PointerData synthesized_move_event = pointer_data;
|
|
synthesized_move_event.change = PointerData::Change::kMove;
|
|
synthesized_move_event.synthesized = 1;
|
|
|
|
UpdateDeltaAndState(synthesized_move_event, state);
|
|
converted_pointers.push_back(synthesized_move_event);
|
|
}
|
|
|
|
state.isDown = false;
|
|
states_[pointer_data.device] = state;
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
default: {
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
switch (pointer_data.signal_kind) {
|
|
case PointerData::SignalKind::kScroll: {
|
|
// Makes sure we have an existing pointer
|
|
auto iter = states_.find(pointer_data.device);
|
|
FML_DCHECK(iter != states_.end());
|
|
|
|
PointerState state = iter->second;
|
|
if (LocationNeedsUpdate(pointer_data, state)) {
|
|
if (state.isDown) {
|
|
// Synthesizes a move event if the pointer is down.
|
|
PointerData synthesized_move_event = pointer_data;
|
|
synthesized_move_event.signal_kind = PointerData::SignalKind::kNone;
|
|
synthesized_move_event.change = PointerData::Change::kMove;
|
|
synthesized_move_event.synthesized = 1;
|
|
|
|
UpdateDeltaAndState(synthesized_move_event, state);
|
|
converted_pointers.push_back(synthesized_move_event);
|
|
} else {
|
|
// Synthesizes a hover event if the pointer is up.
|
|
PointerData synthesized_hover_event = pointer_data;
|
|
synthesized_hover_event.signal_kind =
|
|
PointerData::SignalKind::kNone;
|
|
synthesized_hover_event.change = PointerData::Change::kHover;
|
|
synthesized_hover_event.synthesized = 1;
|
|
|
|
UpdateDeltaAndState(synthesized_hover_event, state);
|
|
converted_pointers.push_back(synthesized_hover_event);
|
|
}
|
|
}
|
|
|
|
converted_pointers.push_back(pointer_data);
|
|
break;
|
|
}
|
|
default: {
|
|
// Ignores unknown signal kind.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PointerState PointerDataPacketConverter::EnsurePointerState(
|
|
PointerData pointer_data) {
|
|
PointerState state;
|
|
state.pointer_identifier = 0;
|
|
state.isDown = false;
|
|
state.physical_x = pointer_data.physical_x;
|
|
state.physical_y = pointer_data.physical_y;
|
|
states_[pointer_data.device] = state;
|
|
return state;
|
|
}
|
|
|
|
void PointerDataPacketConverter::UpdateDeltaAndState(PointerData& pointer_data,
|
|
PointerState& state) {
|
|
pointer_data.physical_delta_x = pointer_data.physical_x - state.physical_x;
|
|
pointer_data.physical_delta_y = pointer_data.physical_y - state.physical_y;
|
|
state.physical_x = pointer_data.physical_x;
|
|
state.physical_y = pointer_data.physical_y;
|
|
states_[pointer_data.device] = state;
|
|
}
|
|
|
|
bool PointerDataPacketConverter::LocationNeedsUpdate(
|
|
const PointerData pointer_data,
|
|
const PointerState state) {
|
|
return state.physical_x != pointer_data.physical_x ||
|
|
state.physical_y != pointer_data.physical_y;
|
|
}
|
|
|
|
void PointerDataPacketConverter::UpdatePointerIdentifier(
|
|
PointerData& pointer_data,
|
|
PointerState& state,
|
|
bool start_new_pointer) {
|
|
if (start_new_pointer) {
|
|
state.pointer_identifier = ++pointer_;
|
|
states_[pointer_data.device] = state;
|
|
}
|
|
pointer_data.pointer_identifier = state.pointer_identifier;
|
|
}
|
|
|
|
} // namespace flutter
|