diff --git a/repos/os/src/server/input_filter/README b/repos/os/src/server/input_filter/README index f29780cec9..bd2ebaab26 100644 --- a/repos/os/src/server/input_filter/README +++ b/repos/os/src/server/input_filter/README @@ -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 '' node may contain '' nodes, which include further + content into the '' node. The included ROM must have a '' + top-level node. + :: Merges the results of any number of filters that appear as child nodes. diff --git a/repos/os/src/server/input_filter/main.cc b/repos/os/src/server/input_filter/main.cc index 46b35b6f50..c58d3e98bf 100644 --- a/repos/os/src/server/input_filter/main.cc +++ b/repos/os/src/server/input_filter/main.cc @@ -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); diff --git a/repos/os/src/server/input_filter/remap_source.h b/repos/os/src/server/input_filter/remap_source.h index e3095a4983..4e297b07f3 100644 --- a/repos/os/src/server/input_filter/remap_source.h +++ b/repos/os/src/server/input_filter/remap_source.h @@ -18,6 +18,7 @@ #include /* local includes */ +#include #include #include @@ -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(); }