input_filter: support <include> in <remap> nodes

This commit is contained in:
Norman Feske 2017-11-20 20:41:02 +01:00 committed by Christian Helmuth
parent e204b9532b
commit 3ea960932e
3 changed files with 60 additions and 16 deletions

View File

@ -27,6 +27,10 @@ one of the following filters:
the key name as 'name' attribute, may feature an optional 'to' attribute
with the name of the key that should be reported instead of 'name'.
A '<remap>' node may contain '<include>' nodes, which include further
content into the '<remap>' node. The included ROM must have a '<remap>'
top-level node.
:<merge>:
Merges the results of any number of filters that appear as child nodes.

View File

@ -243,7 +243,8 @@ struct Input_filter::Main : Input_connection::Avail_handler,
/* create regular filter */
if (node.type() == Remap_source::name())
return *new (_heap) Remap_source(owner, node, sink, *this);
return *new (_heap) Remap_source(owner, node, sink, *this,
_include_accessor);
if (node.type() == Merge_source::name())
return *new (_heap) Merge_source(owner, node, sink, *this);

View File

@ -18,6 +18,7 @@
#include <input/keycodes.h>
/* local includes */
#include <include_accessor.h>
#include <source.h>
#include <key_code_by_name.h>
@ -28,6 +29,8 @@ class Input_filter::Remap_source : public Source, Source::Sink
{
private:
Include_accessor &_include_accessor;
struct Key
{
Input::Keycode code = Input::KEY_UNKNOWN;
@ -66,23 +69,39 @@ class Input_filter::Remap_source : public Source, Source::Sink
_destination.submit_event(Event(event.type(), key.code, 0, 0, 0, 0));
}
public:
static char const *name() { return "remap"; }
Remap_source(Owner &owner, Xml_node config, Source::Sink &destination,
Source::Factory &factory)
:
Source(owner),
_owner(factory),
_source(factory.create_source(_owner, input_sub_node(config), *this)),
_destination(destination)
void _apply_config(Xml_node const config, unsigned const max_recursion = 4)
{
for (unsigned i = 0; i < Input::KEY_MAX; i++)
_keys[i].code = Input::Keycode(i);
config.for_each_sub_node([&] (Xml_node node) {
_apply_sub_node(node, max_recursion); });
}
config.for_each_sub_node("key", [&] (Xml_node node) {
void _apply_sub_node(Xml_node const node, unsigned const max_recursion)
{
if (max_recursion == 0) {
warning("too deeply nested includes");
throw Invalid_config();
}
/*
* Handle includes
*/
if (node.type() == "include") {
try {
Include_accessor::Name const rom =
node.attribute_value("rom", Include_accessor::Name());
_include_accessor.apply_include(rom, name(), [&] (Xml_node inc) {
_apply_config(inc, max_recursion - 1); });
return;
}
catch (Include_accessor::Include_unavailable) {
throw Invalid_config(); }
}
/*
* Handle key nodes
*/
if (node.type() == "key") {
Key_name const key_name = node.attribute_value("name", Key_name());
try {
@ -96,7 +115,27 @@ class Input_filter::Remap_source : public Source, Source::Sink
}
catch (Unknown_key) {
warning("invalid key name ", key_name); }
});
return;
}
}
public:
static char const *name() { return "remap"; }
Remap_source(Owner &owner, Xml_node config, Source::Sink &destination,
Source::Factory &factory, Include_accessor &include_accessor)
:
Source(owner),
_include_accessor(include_accessor),
_owner(factory),
_source(factory.create_source(_owner, input_sub_node(config), *this)),
_destination(destination)
{
for (unsigned i = 0; i < Input::KEY_MAX; i++)
_keys[i].code = Input::Keycode(i);
_apply_config(config);
}
void generate() override { _source.generate(); }