142 lines
3.0 KiB
C++
142 lines
3.0 KiB
C++
/*
|
|
* \brief Input event merger
|
|
* \author Christian Prochaska
|
|
* \date 2014-09-29
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2014-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <input/component.h>
|
|
#include <input_session/connection.h>
|
|
#include <os/static_root.h>
|
|
#include <base/component.h>
|
|
#include <base/attached_rom_dataspace.h>
|
|
#include <base/attached_dataspace.h>
|
|
#include <base/heap.h>
|
|
#include <base/session_label.h>
|
|
#include <util/list.h>
|
|
|
|
|
|
namespace Input_merger
|
|
{
|
|
using namespace Genode;
|
|
|
|
struct Input_source;
|
|
struct Main;
|
|
|
|
typedef List<Input_source> Input_sources;
|
|
typedef String<Session_label::capacity()> Label;
|
|
}
|
|
|
|
|
|
struct Input_merger::Input_source : Input_sources::Element
|
|
{
|
|
Input::Connection conn;
|
|
Input::Session_component &sink;
|
|
|
|
Genode::Signal_handler<Input_source> event_handler;
|
|
|
|
void handle_events()
|
|
{
|
|
conn.for_each_event([&] (Input::Event const &e) { sink.submit(e); });
|
|
}
|
|
|
|
Input_source(Genode::Env &env, Label const &label, Input::Session_component &sink)
|
|
:
|
|
conn(env, label.string()), sink(sink),
|
|
event_handler(env.ep(), *this, &Input_source::handle_events)
|
|
{
|
|
conn.sigh(event_handler);
|
|
}
|
|
};
|
|
|
|
|
|
/******************
|
|
** Main program **
|
|
******************/
|
|
|
|
struct Input_merger::Main
|
|
{
|
|
Env &env;
|
|
|
|
Attached_rom_dataspace config_rom { env, "config" };
|
|
|
|
Heap heap { env.ram(), env.rm() };
|
|
|
|
Input_sources input_source_list { };
|
|
|
|
/*
|
|
* Input session provided to our client
|
|
*/
|
|
Input::Session_component input_session_component { env, env.ram() };
|
|
|
|
/*
|
|
* Attach root interface to the entry point
|
|
*/
|
|
Static_root<Input::Session> input_root { env.ep().manage(input_session_component) };
|
|
|
|
void handle_config_update()
|
|
{
|
|
config_rom.update();
|
|
|
|
while (Input_source *input_source = input_source_list.first()) {
|
|
input_source_list.remove(input_source);
|
|
destroy(heap, input_source);
|
|
}
|
|
|
|
config_rom.xml().for_each_sub_node("input", [&] (Xml_node input_node) {
|
|
try {
|
|
Label label = input_node.attribute_value("label", Label());
|
|
|
|
try {
|
|
Input_source *input_source = new (heap)
|
|
Input_source(env, label.string(), input_session_component);
|
|
|
|
input_source_list.insert(input_source);
|
|
|
|
} catch (Genode::Service_denied) {
|
|
error("parent denied input source '", label, "'");
|
|
}
|
|
} catch (Xml_node::Nonexistent_attribute) {
|
|
error("ignoring invalid input node '", input_node);
|
|
}
|
|
});
|
|
}
|
|
|
|
Signal_handler<Main> config_update_handler
|
|
{ env.ep(), *this, &Main::handle_config_update };
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Main(Genode::Env &env) : env(env)
|
|
{
|
|
input_session_component.event_queue().enabled(true);
|
|
|
|
/*
|
|
* Apply initial configuration
|
|
*/
|
|
handle_config_update();
|
|
|
|
/*
|
|
* Register signal handler
|
|
*/
|
|
config_rom.sigh(config_update_handler);
|
|
|
|
/*
|
|
* Announce service
|
|
*/
|
|
env.parent().announce(env.ep().manage(input_root));
|
|
}
|
|
|
|
};
|
|
|
|
|
|
void Component::construct(Genode::Env &env) { static Input_merger::Main inst(env); }
|