diff --git a/src/server/input_remap/README b/src/server/input_remap/README new file mode 100644 index 0000000..00e9aa2 --- /dev/null +++ b/src/server/input_remap/README @@ -0,0 +1,14 @@ +Input_remap is a small shim server that remaps keys. It was intended for swapping +buttons on game controllers, but is suitable for any key code remapping. + +The configuration is simple, key codes can be discovered using the +'test/input' utility in the Genode os repository. +! +! +! +! +! +! +! +! +! diff --git a/src/server/input_remap/component.cc b/src/server/input_remap/component.cc new file mode 100644 index 0000000..5e49c0c --- /dev/null +++ b/src/server/input_remap/component.cc @@ -0,0 +1,147 @@ +/* + * \brief Input event remapper + * \author Emery Hemingway + * \date 2016-07-10 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + +namespace Input { struct Remap; } + +struct Input::Remap +{ + typedef Genode::String<32> Keyname; + + int code_map[Input::Keycode::KEY_MAX]; + + Genode::Env &env; + + Genode::Attached_rom_dataspace config_rom { env, "config" }; + + /* + * Input session provided by our parent + */ + Input::Session_client parent_input + { env.parent().session("ram_quota=16K") }; + Genode::Attached_dataspace input_dataspace { parent_input.dataspace() }; + + /* + * Input session provided to our client + */ + Input::Session_component input_session_component; + + /* + * Attach root interface to the entry point + */ + Genode::Static_root input_root + { env.ep().manage(input_session_component) }; + + void event_flush() + { + Input::Event const * const events = + input_dataspace.local_addr(); + + unsigned const num = parent_input.flush(); + for (unsigned i = 0; i < num; i++) { + Event e = events[i]; + if ((e.type() == Event::PRESS) || (e.type() == Event::RELEASE)) + input_session_component.submit(Event( + e.type(), code_map[e.code()], e.ax(), e.ay(), e.rx(), e.ry())); + else + input_session_component.submit(e); + } + } + + Genode::Signal_handler event_flusher + { env.ep(), *this, &Remap::event_flush }; + + static int lookup_code(Keyname const &name) + { + /* not the fastest way to do this, just the most terse */ + for (int code = 0; code < Input::Keycode::KEY_MAX; ++code) + if (name == key_name((Keycode)code)) return code; + return KEY_UNKNOWN; + } + + void remap() + { + using namespace Genode; + + /* load the default mappings */ + for (int code = 0; code < Input::Keycode::KEY_MAX; ++code) + code_map[code] = code; + + config_rom.xml().for_each_sub_node("map", [&] (Xml_node node) { + Keyname const from = node.attribute_value("from", Keyname()); + Keyname const to = node.attribute_value("to", Keyname()); + + if ((from == "") || (to == "")) { + char tmp[128]; + strncpy(tmp, node.addr(), min(sizeof(tmp), node.size()+1)); + error("ignoring mapping '", tmp, "'"); + return; + } + + int from_code = lookup_code(from); + int to_code = lookup_code(to); + + if (from_code == KEY_UNKNOWN) { + error("unknown key ", from.string()); + return; + } + if (to_code == KEY_UNKNOWN) { + error("unknown key ", to.string()); + return; + } + + code_map[from_code] = to_code; + }); + } + + Genode::Signal_handler config_handler + { env.ep(), *this, &Remap::remap }; + + /** + * Constructor + */ + Remap(Genode::Env &env) : env(env) + { + config_rom.sigh(config_handler); + parent_input.sigh(event_flusher); + + remap(); + + input_session_component.event_queue().enabled(true); + + env.parent().announce(env.ep().manage(input_root)); + } + + ~Remap() + { + env.parent().close(parent_input); + } + +}; + + +/*************** + ** Component ** + ***************/ + +Genode::size_t Component::stack_size() { return 4*1024*sizeof(Genode::addr_t); } + +void Component::construct(Genode::Env &env) { static Input::Remap inst(env); } diff --git a/src/server/input_remap/target.mk b/src/server/input_remap/target.mk new file mode 100644 index 0000000..e08eb0e --- /dev/null +++ b/src/server/input_remap/target.mk @@ -0,0 +1,3 @@ +TARGET = input_remap +SRC_CC = component.cc +LIBS = base