mirror of
https://github.com/encounter/engine.git
synced 2026-03-30 11:09:55 -07:00
241 lines
6.1 KiB
C++
241 lines
6.1 KiB
C++
// Copyright 2017 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 "flutter/content_handler/direct_input.h"
|
|
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <hid/acer12.h>
|
|
#include <hid/usages.h>
|
|
#include <magenta/device/device.h>
|
|
#include <magenta/device/input.h>
|
|
#include <sys/types.h>
|
|
#include <sys/uio.h>
|
|
#include <unistd.h>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "lib/fidl/cpp/waiter/default.h"
|
|
#include "lib/ftl/time/time_point.h"
|
|
|
|
namespace flutter_runner {
|
|
|
|
static constexpr char kDevInput[] = "/dev/class/input";
|
|
|
|
DirectInput::DirectInput(DirectInputCallback callback)
|
|
: callback_(callback), valid_(false), last_wait_(0) {
|
|
FTL_DCHECK(callback_ != nullptr);
|
|
|
|
// Setup the touch file descriptor.
|
|
|
|
touch_fd_ = GetTouchFileDescriptor();
|
|
|
|
if (!touch_fd_.is_valid()) {
|
|
FTL_DLOG(INFO) << "Could not get the touch file descriptor on the Acer.";
|
|
return;
|
|
}
|
|
|
|
// Get device event handle.
|
|
|
|
mx_handle_t input_event = 0;
|
|
ssize_t ret = mxio_ioctl(touch_fd_.get(), IOCTL_DEVICE_GET_EVENT_HANDLE,
|
|
nullptr, 0, &input_event, sizeof(input_event));
|
|
|
|
if (ret < 0) {
|
|
FTL_DLOG(INFO) << "Could not get device event handle.";
|
|
return;
|
|
}
|
|
|
|
input_event_.reset(input_event);
|
|
|
|
// Prepare buffer that we read into from the touch file descriptor.
|
|
|
|
size_t max_report_len = 0;
|
|
ret = mxio_ioctl(touch_fd_.get(), IOCTL_INPUT_GET_MAX_REPORTSIZE, nullptr, 0,
|
|
&max_report_len, sizeof(max_report_len));
|
|
if (ret < 0) {
|
|
FTL_DLOG(INFO)
|
|
<< "Could not read the max report size on the touch file descriptor";
|
|
return;
|
|
}
|
|
|
|
read_buffer_.resize(max_report_len);
|
|
|
|
valid_ = true;
|
|
}
|
|
|
|
DirectInput::~DirectInput() {
|
|
CancelWaitForReadAvailability();
|
|
}
|
|
|
|
bool DirectInput::IsValid() const {
|
|
return valid_;
|
|
}
|
|
|
|
void DirectInput::WaitForReadAvailability() {
|
|
CancelWaitForReadAvailability();
|
|
|
|
FidlAsyncWaitCallback callback = [](mx_status_t result, mx_signals_t pending,
|
|
void* baton) {
|
|
if (result != NO_ERROR) {
|
|
FTL_DLOG(INFO) << "Error while waiting on read availablility.";
|
|
return;
|
|
}
|
|
|
|
if (!(pending & DEVICE_SIGNAL_READABLE)) {
|
|
FTL_DLOG(INFO) << "Wait callback fired but not read pending.";
|
|
return;
|
|
}
|
|
|
|
reinterpret_cast<DirectInput*>(baton)->OnReadAvailable();
|
|
};
|
|
|
|
last_wait_ = fidl::GetDefaultAsyncWaiter()->AsyncWait(
|
|
input_event_.get(), DEVICE_SIGNAL_READABLE, MX_TIME_INFINITE, callback,
|
|
this);
|
|
}
|
|
|
|
void DirectInput::CancelWaitForReadAvailability() {
|
|
if (last_wait_ == 0) {
|
|
return;
|
|
}
|
|
|
|
fidl::GetDefaultAsyncWaiter()->CancelWait(last_wait_);
|
|
last_wait_ = 0;
|
|
}
|
|
|
|
void DirectInput::OnReadAvailable() {
|
|
last_wait_ = 0;
|
|
PerformRead();
|
|
WaitForReadAvailability();
|
|
}
|
|
|
|
void DirectInput::PerformRead() {
|
|
ssize_t ret =
|
|
::read(touch_fd_.get(), read_buffer_.data(), read_buffer_.size());
|
|
|
|
if (ret < 0) {
|
|
return;
|
|
}
|
|
|
|
if (read_buffer_[0] != ACER12_RPT_ID_TOUCH) {
|
|
return;
|
|
}
|
|
|
|
acer12_touch_t* report =
|
|
reinterpret_cast<acer12_touch_t*>(read_buffer_.data());
|
|
|
|
size_t fingers_count = std::min<size_t>(5, report->contact_count);
|
|
|
|
int64_t timestamp = ftl::TimePoint::Now().ToEpochDelta().ToMilliseconds();
|
|
|
|
if (fingers_count == 0) {
|
|
return;
|
|
}
|
|
|
|
blink::PointerDataPacket packet(fingers_count);
|
|
|
|
for (uint8_t i = 0; i < fingers_count; i++) {
|
|
const acer12_finger& finger = report->fingers[i];
|
|
|
|
int64_t touch_identifier = acer12_finger_id_contact(finger.finger_id);
|
|
|
|
blink::PointerData pointer_data;
|
|
pointer_data.Clear();
|
|
|
|
pointer_data.time_stamp = timestamp;
|
|
pointer_data.kind = blink::PointerData::DeviceKind::kTouch;
|
|
pointer_data.device = touch_identifier;
|
|
|
|
pointer_data.physical_x = ((static_cast<float>(finger.x) / ACER12_X_MAX) *
|
|
viewport_metrics_.physical_width);
|
|
pointer_data.physical_y = ((static_cast<float>(finger.y) / ACER12_Y_MAX) *
|
|
viewport_metrics_.physical_height);
|
|
|
|
bool down = !!acer12_finger_id_tswitch(finger.finger_id);
|
|
|
|
if (down) {
|
|
auto insertion_result = touch_ids_.insert(touch_identifier);
|
|
// If we could add the touch indentifier to the set of tracked touches, it
|
|
// means that we were not already tracking it before. That means it is
|
|
// kDown. In not, it is a kMove of a previous report.
|
|
pointer_data.change = insertion_result.second
|
|
? blink::PointerData::Change::kDown
|
|
: blink::PointerData::Change::kMove;
|
|
} else {
|
|
touch_ids_.erase(touch_identifier);
|
|
pointer_data.change = blink::PointerData::Change::kUp;
|
|
}
|
|
|
|
packet.SetPointerData(i, pointer_data);
|
|
}
|
|
|
|
callback_(packet);
|
|
}
|
|
|
|
ftl::UniqueFD DirectInput::GetTouchFileDescriptor() {
|
|
DIR* dir = ::opendir(kDevInput);
|
|
|
|
if (!dir) {
|
|
return {};
|
|
}
|
|
|
|
std::string device_dir = kDevInput;
|
|
|
|
device_dir += "/";
|
|
|
|
struct dirent* dir_entry = nullptr;
|
|
|
|
while ((dir_entry = readdir(dir)) != nullptr) {
|
|
std::string device_path = device_dir + dir_entry->d_name;
|
|
|
|
ftl::UniqueFD fd(::open(device_path.c_str(), O_RDONLY));
|
|
|
|
if (!fd.is_valid()) {
|
|
continue;
|
|
}
|
|
|
|
size_t report_desc_len = 0;
|
|
|
|
ssize_t ret =
|
|
mxio_ioctl(fd.get(), IOCTL_INPUT_GET_REPORT_DESC_SIZE, nullptr, 0,
|
|
&report_desc_len, sizeof(report_desc_len));
|
|
|
|
if (ret < 0) {
|
|
continue;
|
|
}
|
|
|
|
if (report_desc_len != ACER12_RPT_DESC_LEN) {
|
|
continue;
|
|
}
|
|
|
|
std::vector<uint8_t> report_desc(report_desc_len);
|
|
|
|
ret = mxio_ioctl(fd.get(), IOCTL_INPUT_GET_REPORT_DESC, nullptr, 0,
|
|
report_desc.data(), report_desc.size());
|
|
|
|
if (ret < 0) {
|
|
continue;
|
|
}
|
|
|
|
if (!memcmp(report_desc.data(), acer12_touch_report_desc,
|
|
ACER12_RPT_DESC_LEN)) {
|
|
::closedir(dir);
|
|
return fd;
|
|
}
|
|
}
|
|
|
|
::closedir(dir);
|
|
return {};
|
|
}
|
|
|
|
void DirectInput::SetViewportMetrics(blink::ViewportMetrics metrics) {
|
|
viewport_metrics_ = metrics;
|
|
}
|
|
|
|
} // namespace flutter_runner
|