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