server/input_remap
General purpose component for remapping input codes. Fixes #25
This commit is contained in:
committed by
Norman Feske
parent
a09410cd09
commit
1e0fa7571c
14
src/server/input_remap/README
Normal file
14
src/server/input_remap/README
Normal file
@@ -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.
|
||||
! <config>
|
||||
! <map from="BTN_X" to="BTN_A"/>
|
||||
! <map from="BTN_Y" to="BTN_B"/>
|
||||
! <map from="BTN_Z" to="BTN_C"/>
|
||||
! <map from="BTN_A" to="BTN_X"/>
|
||||
! <map from="BTN_B" to="BTN_Y"/>
|
||||
! <map from="BTN_C" to="BTN_Z"/>
|
||||
! <map from="KEY_SPACE" to="KEY_BACKSPACE"/>
|
||||
! </config>
|
||||
147
src/server/input_remap/component.cc
Normal file
147
src/server/input_remap/component.cc
Normal file
@@ -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 <input/keycodes.h>
|
||||
#include <input/component.h>
|
||||
#include <input_session/connection.h>
|
||||
#include <os/static_root.h>
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
|
||||
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<Input::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::Session> input_root
|
||||
{ env.ep().manage(input_session_component) };
|
||||
|
||||
void event_flush()
|
||||
{
|
||||
Input::Event const * const events =
|
||||
input_dataspace.local_addr<Input::Event>();
|
||||
|
||||
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<Remap> 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<Remap> 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); }
|
||||
3
src/server/input_remap/target.mk
Normal file
3
src/server/input_remap/target.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
TARGET = input_remap
|
||||
SRC_CC = component.cc
|
||||
LIBS = base
|
||||
Reference in New Issue
Block a user