Implement input event forwarding
This commit is contained in:
parent
309fd3021d
commit
f75a9f4f1c
18 changed files with 590 additions and 38 deletions
|
|
@ -40,6 +40,7 @@ set(SOURCES
|
|||
anbox/network/socket_connection.cpp
|
||||
anbox/network/socket_messenger.cpp
|
||||
anbox/network/delegate_message_processor.h
|
||||
anbox/network/delegate_connection_creator.h
|
||||
|
||||
anbox/graphics/opengles_message_processor.cpp
|
||||
anbox/graphics/mir_display_connection.cpp
|
||||
|
|
@ -47,6 +48,9 @@ set(SOURCES
|
|||
anbox/graphics/mir_native_window_creator.cpp
|
||||
anbox/graphics/gl_renderer_server.cpp
|
||||
|
||||
anbox/input/manager.cpp
|
||||
anbox/input/device.cpp
|
||||
|
||||
anbox/support/null_message_processor.cpp
|
||||
anbox/support/qemud_message_processor.cpp
|
||||
anbox/support/boot_properties_message_processor.cpp
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include "anbox/network/published_socket_connector.h"
|
||||
#include "anbox/network/qemu_pipe_connection_creator.h"
|
||||
#include "anbox/graphics/gl_renderer_server.h"
|
||||
#include "anbox/input_channel.h"
|
||||
#include "anbox/input/manager.h"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
|
|
@ -67,9 +67,9 @@ anbox::cmds::Run::Run()
|
|||
|
||||
auto rt = Runtime::create();
|
||||
|
||||
auto input_channel = std::make_shared<InputChannel>();
|
||||
auto input_manager = std::make_shared<input::Manager>(rt);
|
||||
|
||||
auto renderer = std::make_shared<graphics::GLRendererServer>(input_channel);
|
||||
auto renderer = std::make_shared<graphics::GLRendererServer>(input_manager);
|
||||
renderer->start();
|
||||
|
||||
// Socket which will be used by the qemud service inside the Android
|
||||
|
|
@ -91,6 +91,8 @@ anbox::cmds::Run::Run()
|
|||
spec.bind_paths.insert({qemud_connector->socket_file(), "/dev/qemud"});
|
||||
spec.bind_paths.insert({qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"});
|
||||
|
||||
input_manager->generate_mappings(spec.bind_paths);
|
||||
|
||||
spec.temporary_dirs.push_back("/data");
|
||||
spec.temporary_dirs.push_back("/cache");
|
||||
spec.temporary_dirs.push_back("/storage");
|
||||
|
|
@ -102,16 +104,6 @@ anbox::cmds::Run::Run()
|
|||
// Required for shared memory allocations. TODO(morphis): Letting the guest
|
||||
// access should be ok but needs more investigation.
|
||||
spec.dev_bind_paths.push_back("/dev/ashmem");
|
||||
// Our uinput based event node should get root:android_input assigned on Ubuntu
|
||||
// which is enough for our phablet user (being root inside the container) to
|
||||
// read event data from it.
|
||||
// FIXME(morphis): Need to reenable this once we have both sides prepared
|
||||
// for an socket based approach.
|
||||
// spec.dev_bind_paths.push_back({input_channel->dev_path()});
|
||||
// Until then we forward just the host input device which needs to have
|
||||
// proper permissions (insecure!!!) for this.
|
||||
// $ sudo chmod 666 /dev/input/event7
|
||||
spec.dev_bind_paths.push_back({"/dev/input/event7"});
|
||||
|
||||
auto container = Container::create(spec);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
GLRendererServer::GLRendererServer(const std::shared_ptr<InputChannel> &input_channel) :
|
||||
window_creator_(std::make_shared<MirNativeWindowCreator>(input_channel)) {
|
||||
GLRendererServer::GLRendererServer(const std::shared_ptr<input::Manager> &input_manager) :
|
||||
window_creator_(std::make_shared<MirNativeWindowCreator>(input_manager)) {
|
||||
|
||||
// Force the host EGL/GLES libraries as translator implementation
|
||||
::setenv("ANDROID_EGL_LIB", "libEGL.so.1", 1);
|
||||
|
|
|
|||
|
|
@ -22,13 +22,15 @@
|
|||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel;
|
||||
namespace input {
|
||||
class Manager;
|
||||
}
|
||||
namespace graphics {
|
||||
class MirNativeWindowCreator;
|
||||
|
||||
class GLRendererServer {
|
||||
public:
|
||||
GLRendererServer(const std::shared_ptr<InputChannel> &input_channel);
|
||||
GLRendererServer(const std::shared_ptr<input::Manager> &input_manager);
|
||||
~GLRendererServer();
|
||||
|
||||
void start();
|
||||
|
|
|
|||
|
|
@ -18,18 +18,15 @@
|
|||
#include "anbox/graphics/mir_native_window_creator.h"
|
||||
#include "anbox/graphics/mir_display_connection.h"
|
||||
#include "anbox/graphics/mir_window.h"
|
||||
#include "anbox/input_channel.h"
|
||||
#include "anbox/input/manager.h"
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr<InputChannel> &input_channel) :
|
||||
input_channel_(input_channel),
|
||||
MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr<input::Manager> &input_manager) :
|
||||
input_manager_(input_manager),
|
||||
display_connection_(std::make_shared<MirDisplayConnection>()) {
|
||||
|
||||
input_channel_->setup(display_connection_->horizontal_resolution(),
|
||||
display_connection_->vertical_resolution());
|
||||
}
|
||||
|
||||
MirNativeWindowCreator::~MirNativeWindowCreator() {
|
||||
|
|
@ -44,7 +41,7 @@ EGLNativeWindowType MirNativeWindowCreator::create_window(int x, int y, int widt
|
|||
if (windows_.size() > 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("We currently only allow a single native window"));
|
||||
|
||||
auto window = std::make_shared<MirWindow>(display_connection_, input_channel_);
|
||||
auto window = std::make_shared<MirWindow>(display_connection_, input_manager_);
|
||||
windows_.insert({window->native_window(), window});
|
||||
|
||||
return window->native_window();
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@
|
|||
#include <map>
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel;
|
||||
|
||||
namespace input {
|
||||
class Manager;
|
||||
}
|
||||
namespace graphics {
|
||||
|
||||
class MirDisplayConnection;
|
||||
|
|
@ -33,7 +34,7 @@ class MirWindow;
|
|||
|
||||
class MirNativeWindowCreator : public SubWindowHandler {
|
||||
public:
|
||||
MirNativeWindowCreator(const std::shared_ptr<InputChannel> &input_channel);
|
||||
MirNativeWindowCreator(const std::shared_ptr<input::Manager> &input_channel);
|
||||
virtual ~MirNativeWindowCreator();
|
||||
|
||||
EGLNativeWindowType create_window(int x, int y, int width, int height) override;
|
||||
|
|
@ -42,7 +43,7 @@ public:
|
|||
std::shared_ptr<MirDisplayConnection> display() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<InputChannel> input_channel_;
|
||||
std::shared_ptr<input::Manager> input_manager_;
|
||||
std::shared_ptr<MirDisplayConnection> display_connection_;
|
||||
std::map<EGLNativeWindowType,std::shared_ptr<MirWindow>> windows_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@
|
|||
#include "anbox/graphics/mir_window.h"
|
||||
#include "anbox/graphics/mir_display_connection.h"
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/input_channel.h"
|
||||
#include "anbox/input/manager.h"
|
||||
#include "anbox/input/device.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
MirWindow::MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<InputChannel> &input_channel) :
|
||||
input_channel_(input_channel),
|
||||
MirWindow::MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<input::Manager> &input_manager) :
|
||||
native_window_(0),
|
||||
surface_(nullptr) {
|
||||
|
||||
|
|
@ -60,13 +60,119 @@ MirWindow::MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const
|
|||
auto surface_buffer_stream = mir_surface_get_buffer_stream(surface_);
|
||||
native_window_ = reinterpret_cast<EGLNativeWindowType>(
|
||||
mir_buffer_stream_get_egl_native_window(surface_buffer_stream));
|
||||
|
||||
// Create our touch panel input device
|
||||
input_device_ = input_manager->create_device();
|
||||
input_device_->set_name("mir-touchpanel");
|
||||
input_device_->set_driver_version(1);
|
||||
input_device_->set_input_id({ BUS_VIRTUAL, 1, 1, 1 });
|
||||
input_device_->set_physical_location("none");
|
||||
input_device_->set_abs_bit(ABS_MT_TRACKING_ID);
|
||||
input_device_->set_abs_bit(ABS_MT_SLOT);
|
||||
input_device_->set_abs_bit(ABS_MT_POSITION_X);
|
||||
input_device_->set_abs_bit(ABS_MT_POSITION_Y);
|
||||
input_device_->set_prop_bit(INPUT_PROP_DIRECT);
|
||||
input_device_->set_abs_min(ABS_MT_POSITION_X, 0);
|
||||
input_device_->set_abs_max(ABS_MT_POSITION_X, display->horizontal_resolution());
|
||||
input_device_->set_abs_min(ABS_MT_POSITION_Y, 0);
|
||||
input_device_->set_abs_max(ABS_MT_POSITION_Y, display->vertical_resolution());
|
||||
input_device_->set_abs_max(ABS_MT_SLOT, 10);
|
||||
input_device_->set_abs_max(ABS_MT_TRACKING_ID, 255);
|
||||
input_device_->set_key_bit(BTN_TOUCH);
|
||||
input_device_->set_key_bit(BTN_TOOL_FINGER);
|
||||
}
|
||||
|
||||
MirWindow::~MirWindow() {
|
||||
}
|
||||
|
||||
static std::vector<int> slot_to_fingerId;
|
||||
|
||||
int find_slot(int id)
|
||||
{
|
||||
auto iter = std::find(slot_to_fingerId.begin(), slot_to_fingerId.end(), id);
|
||||
if (iter != slot_to_fingerId.end())
|
||||
return std::distance(slot_to_fingerId.begin(), iter);
|
||||
|
||||
std::vector<int>::size_type i;
|
||||
for(i = 0;i < slot_to_fingerId.size();i++) {
|
||||
if (slot_to_fingerId[i] == -1) {
|
||||
slot_to_fingerId[i] = id;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
slot_to_fingerId.resize(slot_to_fingerId.size()+1);
|
||||
slot_to_fingerId[slot_to_fingerId.size()-1] = id;
|
||||
|
||||
return slot_to_fingerId.size() - 1;
|
||||
}
|
||||
|
||||
void erase_slot(int id)
|
||||
{
|
||||
auto it = find(slot_to_fingerId.begin(), slot_to_fingerId.end(), id);
|
||||
|
||||
if (it != slot_to_fingerId.end()) {
|
||||
auto index = std::distance(slot_to_fingerId.begin(), it);
|
||||
slot_to_fingerId[index] = -1;
|
||||
if (index == slot_to_fingerId.size()-1) {
|
||||
while (slot_to_fingerId[index] == -1) {
|
||||
slot_to_fingerId.resize(index);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MirWindow::handle_touch_event(MirTouchEvent const* touch_event) {
|
||||
const auto action = mir_touch_event_action(touch_event, 0);
|
||||
const auto point_count = mir_touch_event_point_count(touch_event);
|
||||
|
||||
for (int n = 0; n < point_count; n++) {
|
||||
const auto id = mir_touch_event_id(touch_event, n);
|
||||
const auto slot = find_slot(id);
|
||||
const auto x = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_x);
|
||||
const auto y = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_y);
|
||||
const auto pressure = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_pressure);
|
||||
const auto touch_major = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_touch_major);
|
||||
const auto touch_minor = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_touch_minor);
|
||||
|
||||
DEBUG("Event: id %d, slot %d, x %f, y %f, pressure %f",
|
||||
id, slot, x, y, pressure);
|
||||
|
||||
std::vector<input::Device::Event> events;
|
||||
|
||||
switch (mir_touch_event_action(touch_event, n)) {
|
||||
case mir_touch_action_up:
|
||||
events.push_back({ EV_ABS, ABS_MT_SLOT, slot });
|
||||
events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, -1 });
|
||||
events.push_back({ EV_KEY, BTN_TOUCH, 0 });
|
||||
events.push_back({ EV_KEY, BTN_TOOL_FINGER, 0 });
|
||||
events.push_back({ EV_SYN, SYN_REPORT, 0 });
|
||||
erase_slot(id);
|
||||
break;
|
||||
case mir_touch_action_down:
|
||||
events.push_back({ EV_ABS, ABS_MT_SLOT, slot });
|
||||
events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, id });
|
||||
events.push_back({ EV_ABS, ABS_MT_POSITION_X, static_cast<std::int32_t>(x) });
|
||||
events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast<std::int32_t>(y) });
|
||||
events.push_back({ EV_ABS, ABS_MT_TOUCH_MAJOR, static_cast<std::int32_t>(touch_major) });
|
||||
events.push_back({ EV_ABS, ABS_MT_TOUCH_MINOR, static_cast<std::int32_t>(touch_minor) });
|
||||
events.push_back({ EV_SYN, SYN_REPORT, 0 });
|
||||
break;
|
||||
case mir_touch_action_change:
|
||||
events.push_back({ EV_ABS, ABS_MT_SLOT, slot });
|
||||
events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, id });
|
||||
events.push_back({ EV_KEY, BTN_TOUCH, 1 });
|
||||
events.push_back({ EV_KEY, BTN_TOOL_FINGER, 1 });
|
||||
events.push_back({ EV_ABS, ABS_MT_POSITION_X, static_cast<std::int32_t>(x) });
|
||||
events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast<std::int32_t>(y) });
|
||||
events.push_back({ EV_ABS, ABS_MT_TOUCH_MAJOR, static_cast<std::int32_t>(touch_major) });
|
||||
events.push_back({ EV_ABS, ABS_MT_TOUCH_MINOR, static_cast<std::int32_t>(touch_minor) });
|
||||
events.push_back({ EV_SYN, SYN_REPORT, 0 });
|
||||
break;
|
||||
}
|
||||
|
||||
input_device_->send_events(events);
|
||||
}
|
||||
}
|
||||
|
||||
void MirWindow::handle_input_event(MirInputEvent const* input_event) {
|
||||
|
|
|
|||
|
|
@ -27,14 +27,16 @@
|
|||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel;
|
||||
|
||||
namespace input {
|
||||
class Manager;
|
||||
class Device;
|
||||
}
|
||||
namespace graphics {
|
||||
class MirDisplayConnection;
|
||||
|
||||
class MirWindow {
|
||||
public:
|
||||
MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<InputChannel> &input_channel);
|
||||
MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<input::Manager> &input_manager);
|
||||
~MirWindow();
|
||||
|
||||
EGLNativeWindowType native_window() const;
|
||||
|
|
@ -45,7 +47,7 @@ private:
|
|||
void handle_input_event(MirInputEvent const* input_event);
|
||||
void handle_touch_event(MirTouchEvent const* touch_event);
|
||||
|
||||
std::shared_ptr<InputChannel> input_channel_;
|
||||
std::shared_ptr<input::Device> input_device_;
|
||||
EGLNativeWindowType native_window_;
|
||||
MirSurface *surface_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ void OpenGlesMessageProcessor::connect_and_attach(const std::string &socket_path
|
|||
|
||||
messenger_ = std::make_shared<network::SocketMessenger>(socket);
|
||||
renderer_ = std::make_shared<network::SocketConnection>(
|
||||
messenger_,
|
||||
messenger_,
|
||||
0,
|
||||
std::make_shared<network::Connections<network::SocketConnection>>(),
|
||||
|
|
|
|||
173
src/anbox/input/device.cpp
Normal file
173
src/anbox/input/device.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/input/device.h"
|
||||
#include "anbox/network/delegate_connection_creator.h"
|
||||
#include "anbox/network/delegate_message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/support/null_message_processor.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace input {
|
||||
std::shared_ptr<Device> Device::create(const std::string &path, const std::shared_ptr<Runtime> &runtime) {
|
||||
auto sp = std::make_shared<Device>();
|
||||
|
||||
auto delegate_connector = std::make_shared<network::DelegateConnectionCreator>(
|
||||
[sp](std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
|
||||
sp->new_client(socket);
|
||||
});
|
||||
|
||||
sp->connector_ = std::make_shared<network::PublishedSocketConnector>(path, runtime, delegate_connector);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
Device::Device() :
|
||||
next_connection_id_(0),
|
||||
connections_(std::make_shared<network::Connections<network::SocketConnection>>()) {
|
||||
::memset(&info_, 0, sizeof(info_));
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
}
|
||||
|
||||
void Device::send_events(const std::vector<Event> &events) {
|
||||
struct CompatEvent {
|
||||
// NOTE: A bit dirty but as we're running currently a 64 bit container
|
||||
// struct input_event has a different size. We rebuild the struct here
|
||||
// to reach the correct size.
|
||||
std::uint64_t sec;
|
||||
std::uint64_t usec;
|
||||
std::uint16_t type;
|
||||
std::uint16_t code;
|
||||
std::uint32_t value;
|
||||
};
|
||||
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||
|
||||
auto data = new CompatEvent[events.size()];
|
||||
int n = 0;
|
||||
for (const auto &event : events) {
|
||||
data[n].sec = spec.tv_sec;
|
||||
data[n].usec = spec.tv_nsec / 1000;
|
||||
data[n].type = event.type;
|
||||
data[n].code = event.code;
|
||||
data[n].value = event.value;
|
||||
|
||||
DEBUG("Event: time %lld, type %d, code %d, value %d",
|
||||
data[n].sec * 1000000000LL + data[n].usec * 1000LL,
|
||||
event.type, event.code, event.value);
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
for (auto n = 0; n < connections_->size(); n++) {
|
||||
connections_->at(n)->send(reinterpret_cast<const char*>(data),
|
||||
events.size() * sizeof(struct CompatEvent));
|
||||
}
|
||||
}
|
||||
|
||||
void Device::set_name(const std::string &name) {
|
||||
snprintf(info_.name, 80, "%s", name.c_str());
|
||||
}
|
||||
|
||||
void Device::set_driver_version(const int &version) {
|
||||
info_.driver_version = version;
|
||||
}
|
||||
|
||||
void Device::set_input_id(const struct input_id &id) {
|
||||
info_.id.bustype = id.bustype;
|
||||
info_.id.product = id.product;
|
||||
info_.id.vendor = id.vendor;
|
||||
info_.id.version = id.version;
|
||||
}
|
||||
|
||||
void Device::set_physical_location(const std::string &physical_location) {
|
||||
snprintf(info_.physical_location, 80, "%s", physical_location.c_str());
|
||||
}
|
||||
|
||||
void Device::set_key_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.key_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_abs_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.abs_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_rel_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.rel_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_sw_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.sw_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_led_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.led_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_ff_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.ff_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_prop_bit(const std::uint8_t &bit) {
|
||||
set_bit(info_.prop_bitmask, bit);
|
||||
}
|
||||
|
||||
void Device::set_abs_min(const std::uint8_t &bit, const std::uint32_t &value) {
|
||||
info_.abs_min[bit] = value;
|
||||
}
|
||||
|
||||
void Device::set_abs_max(const std::uint8_t &bit, const std::uint32_t &value) {
|
||||
info_.abs_max[bit] = value;
|
||||
}
|
||||
|
||||
void Device::set_bit(std::uint8_t *array, const std::uint8_t &bit) {
|
||||
array[bit/8] |= (1 << (bit % 8));
|
||||
}
|
||||
|
||||
void Device::set_unique_id(const std::string &unique_id) {
|
||||
snprintf(info_.unique_id, 80, "%s", unique_id.c_str());
|
||||
}
|
||||
|
||||
std::string Device::socket_path() const {
|
||||
return connector_->socket_file();
|
||||
}
|
||||
|
||||
int Device::next_id()
|
||||
{
|
||||
return next_connection_id_++;
|
||||
}
|
||||
|
||||
void Device::new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
|
||||
auto const messenger = std::make_shared<network::SocketMessenger>(socket);
|
||||
auto const& connection = std::make_shared<network::SocketConnection>(
|
||||
messenger, messenger, next_id(), connections_,
|
||||
std::make_shared<support::NullMessageProcessor>());
|
||||
|
||||
connections_->add(connection);
|
||||
|
||||
// Send all necessary information about our device so that the remote
|
||||
// side can properly configure itself for this input device
|
||||
connection->send(reinterpret_cast<char const*>(&info_), sizeof(info_));
|
||||
}
|
||||
} // namespace input
|
||||
} // namespace anbox
|
||||
99
src/anbox/input/device.h
Normal file
99
src/anbox/input/device.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_INPUT_DEVICE_H_
|
||||
#define ANBOX_INPUT_DEVICE_H_
|
||||
|
||||
#include "anbox/network/published_socket_connector.h"
|
||||
#include "anbox/network/connections.h"
|
||||
#include "anbox/network/socket_connection.h"
|
||||
#include "anbox/runtime.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace input {
|
||||
class Device : public std::enable_shared_from_this<Device> {
|
||||
public:
|
||||
static std::shared_ptr<Device> create(const std::string &path, const std::shared_ptr<Runtime> &runtime);
|
||||
|
||||
Device();
|
||||
~Device();
|
||||
|
||||
struct Event {
|
||||
std::uint16_t type;
|
||||
std::uint16_t code;
|
||||
std::int32_t value;
|
||||
};
|
||||
|
||||
void send_events(const std::vector<Event> &events);
|
||||
void send_event(const std::uint16_t &code, const std::uint16_t &event, const std::int32_t &value);
|
||||
|
||||
void set_name(const std::string &name);
|
||||
void set_driver_version(const int &version);
|
||||
void set_input_id(const struct input_id &id);
|
||||
void set_physical_location(const std::string &physical_location);
|
||||
void set_unique_id(const std::string &unique_id);
|
||||
void set_key_bit(const std::uint8_t &bit);
|
||||
void set_abs_bit(const std::uint8_t &bit);
|
||||
void set_rel_bit(const std::uint8_t &bit);
|
||||
void set_sw_bit(const std::uint8_t &bit);
|
||||
void set_led_bit(const std::uint8_t &bit);
|
||||
void set_ff_bit(const std::uint8_t &bit);
|
||||
void set_prop_bit(const std::uint8_t &bit);
|
||||
|
||||
void set_abs_min(const std::uint8_t &bit, const std::uint32_t &value);
|
||||
void set_abs_max(const std::uint8_t &bit, const std::uint32_t &value);
|
||||
|
||||
std::string socket_path() const;
|
||||
|
||||
private:
|
||||
int next_id();
|
||||
void new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket);
|
||||
|
||||
// NOTE: If you modify this struct you have to modify the version on
|
||||
// the Android side too. See frameworks/native/services/inputflinger/EventHub.cpp
|
||||
struct Info {
|
||||
char name[80];
|
||||
int driver_version;
|
||||
struct input_id id;
|
||||
char physical_location[80];
|
||||
char unique_id[80];
|
||||
std::uint8_t key_bitmask[(KEY_MAX + 1) / 8];
|
||||
std::uint8_t abs_bitmask[(ABS_MAX + 1) / 8];
|
||||
std::uint8_t rel_bitmask[(REL_MAX + 1) / 8];
|
||||
std::uint8_t sw_bitmask[(SW_MAX + 1) / 8];
|
||||
std::uint8_t led_bitmask[(LED_MAX + 1) / 8];
|
||||
std::uint8_t ff_bitmask[(FF_MAX + 1) / 8];
|
||||
std::uint8_t prop_bitmask[(INPUT_PROP_MAX + 1) / 8];
|
||||
std::uint32_t abs_max[ABS_CNT];
|
||||
std::uint32_t abs_min[ABS_CNT];
|
||||
};
|
||||
|
||||
void set_bit(std::uint8_t *array, const std::uint8_t &bit);
|
||||
|
||||
std::shared_ptr<network::PublishedSocketConnector> connector_;
|
||||
std::atomic<int> next_connection_id_;
|
||||
std::shared_ptr<network::Connections<network::SocketConnection>> const connections_;
|
||||
Info info_;
|
||||
};
|
||||
} // namespace input
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
61
src/anbox/input/manager.cpp
Normal file
61
src/anbox/input/manager.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/input/manager.h"
|
||||
#include "anbox/input/device.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/config.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace input {
|
||||
Manager::Manager(const std::shared_ptr<Runtime> &runtime) :
|
||||
runtime_(runtime) {
|
||||
}
|
||||
|
||||
Manager::~Manager() {
|
||||
}
|
||||
|
||||
std::shared_ptr<Device> Manager::create_device() {
|
||||
const auto id = next_id();
|
||||
const auto path = build_device_path(id);
|
||||
auto device = Device::create(path, runtime_);
|
||||
devices_.insert({id, device});
|
||||
return device;
|
||||
}
|
||||
|
||||
void Manager::generate_mappings(std::map<std::string,std::string> &target) {
|
||||
for (const auto &iter : devices_) {
|
||||
target.insert({
|
||||
iter.second->socket_path(),
|
||||
(boost::format("/dev/input/event%1%") % iter.first).str(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t Manager::next_id() {
|
||||
static std::uint32_t next_id = 0;
|
||||
return next_id++;
|
||||
}
|
||||
|
||||
std::string Manager::build_device_path(const std::uint32_t &id) {
|
||||
return (boost::format("%1%/input_device_%2%") % config::data_path() % id).str();
|
||||
}
|
||||
|
||||
} // namespace input
|
||||
} // namespace anbox
|
||||
47
src/anbox/input/manager.h
Normal file
47
src/anbox/input/manager.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_INPUT_MANAGER_H_
|
||||
#define ANBOX_INPUT_MANAGER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
namespace anbox {
|
||||
class Runtime;
|
||||
namespace input {
|
||||
class Device;
|
||||
class Manager {
|
||||
public:
|
||||
Manager(const std::shared_ptr<Runtime> &runtime);
|
||||
~Manager();
|
||||
|
||||
std::shared_ptr<Device> create_device();
|
||||
|
||||
void generate_mappings(std::map<std::string,std::string> &target);
|
||||
|
||||
private:
|
||||
std::uint32_t next_id();
|
||||
std::string build_device_path(const std::uint32_t &id);
|
||||
|
||||
std::shared_ptr<Runtime> runtime_;
|
||||
std::map<std::uint32_t,std::shared_ptr<Device>> devices_;
|
||||
};
|
||||
} // namespace input
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -35,7 +35,7 @@ public:
|
|||
void add(std::shared_ptr<Connection> const& connection)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
connections[connection->id()] = connection;
|
||||
connections.insert({connection->id(), connection});
|
||||
}
|
||||
|
||||
void remove(int id)
|
||||
|
|
@ -56,6 +56,15 @@ public:
|
|||
connections.clear();
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return connections.size();
|
||||
}
|
||||
|
||||
std::shared_ptr<Connection> at(size_t n)
|
||||
{
|
||||
return connections.at(n);
|
||||
}
|
||||
|
||||
private:
|
||||
Connections(Connections const&) = delete;
|
||||
|
|
|
|||
47
src/anbox/network/delegate_connection_creator.h
Normal file
47
src/anbox/network/delegate_connection_creator.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_NETWORK_DELEGATE_CONNECTION_CREATOR_H_
|
||||
#define ANBOX_NETWORK_DELEGATE_CONNECTION_CREATOR_H_
|
||||
|
||||
#include "anbox/network/connection_creator.h"
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
class DelegateConnectionCreator : public ConnectionCreator {
|
||||
public:
|
||||
DelegateConnectionCreator(std::function<void(std::shared_ptr<boost::asio::local::stream_protocol::socket> const&)> delegate) :
|
||||
delegate_(delegate) {
|
||||
}
|
||||
|
||||
void create_connection_for(
|
||||
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) override {
|
||||
if (delegate_)
|
||||
delegate_(socket);
|
||||
else
|
||||
socket->close();
|
||||
}
|
||||
private:
|
||||
std::function<void(std::shared_ptr<boost::asio::local::stream_protocol::socket> const&)> delegate_;
|
||||
};
|
||||
} // namespace network
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -52,7 +52,8 @@ void QemuPipeConnectionCreator::create_connection_for(
|
|||
if (!processor)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unhandled client type"));
|
||||
|
||||
auto const& connection = std::make_shared<SocketConnection>(messenger, next_id(), connections_, processor);
|
||||
auto const& connection = std::make_shared<SocketConnection>(
|
||||
messenger, messenger, next_id(), connections_, processor);
|
||||
connections_->add(connection);
|
||||
connection->read_next_message();
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,12 @@ namespace anbox {
|
|||
namespace network {
|
||||
SocketConnection::SocketConnection(
|
||||
std::shared_ptr<MessageReceiver> const& message_receiver,
|
||||
std::shared_ptr<MessageSender> const& message_sender,
|
||||
int id_,
|
||||
std::shared_ptr<Connections<SocketConnection>> const& connections,
|
||||
std::shared_ptr<MessageProcessor> const& processor)
|
||||
: message_receiver_(message_receiver),
|
||||
message_sender_(message_sender),
|
||||
id_(id_),
|
||||
connections_(connections),
|
||||
processor_(processor)
|
||||
|
|
@ -51,6 +53,10 @@ SocketConnection::~SocketConnection() noexcept
|
|||
{
|
||||
}
|
||||
|
||||
void SocketConnection::send(char const* data, size_t length) {
|
||||
message_sender_->send(data, length);
|
||||
}
|
||||
|
||||
void SocketConnection::read_next_message()
|
||||
{
|
||||
auto callback = std::bind(&SocketConnection::on_read_size,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "anbox/network/connections.h"
|
||||
#include "anbox/network/message_receiver.h"
|
||||
#include "anbox/network/message_sender.h"
|
||||
#include "anbox/network/message_processor.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
|
@ -34,6 +35,7 @@ class SocketConnection
|
|||
public:
|
||||
SocketConnection(
|
||||
std::shared_ptr<MessageReceiver> const& message_receiver,
|
||||
std::shared_ptr<MessageSender> const& message_sender,
|
||||
int id,
|
||||
std::shared_ptr<Connections<SocketConnection>> const& connections,
|
||||
std::shared_ptr<MessageProcessor> const& processor);
|
||||
|
|
@ -42,6 +44,7 @@ public:
|
|||
|
||||
int id() const { return id_; }
|
||||
|
||||
void send(char const* data, size_t length);
|
||||
void read_next_message();
|
||||
|
||||
private:
|
||||
|
|
@ -49,6 +52,7 @@ private:
|
|||
void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read);
|
||||
|
||||
std::shared_ptr<MessageReceiver> const message_receiver_;
|
||||
std::shared_ptr<MessageSender> const message_sender_;
|
||||
int const id_;
|
||||
std::shared_ptr<Connections<SocketConnection>> const connections_;
|
||||
std::shared_ptr<MessageProcessor> const processor_;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue