diff --git a/repos/os/run/input_filter.run b/repos/os/run/input_filter.run
index f9b6b8e400..8d25aa7f4f 100644
--- a/repos/os/run/input_filter.run
+++ b/repos/os/run/input_filter.run
@@ -306,6 +306,51 @@ append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/repos/os/src/server/input_filter/README b/repos/os/src/server/input_filter/README
index f8d9814fe5..f29780cec9 100644
--- a/repos/os/src/server/input_filter/README
+++ b/repos/os/src/server/input_filter/README
@@ -54,6 +54,16 @@ one of the following filters:
such that pointer movements are inhibited while the wheel emulation is
active. All other events are passed along unmodified.
+::
+
+ Applies acceleration to relative motion values. The 'max' attribute
+ defines the maximum value added to the incoming motion values. The
+ 'sensitivity_percent' attribute scales incoming motion values before
+ applying the (potentially non-linear) acceleration function. The 'curve'
+ attribute defines the degree of non-linearity of the acceleration. The value
+ "0" corresponds to a linear function whereas the maximum value "255" applies
+ a curved function. The default value is "127".
+
Character generator rules
-------------------------
diff --git a/repos/os/src/server/input_filter/accelerate_source.h b/repos/os/src/server/input_filter/accelerate_source.h
new file mode 100644
index 0000000000..4f16566f2f
--- /dev/null
+++ b/repos/os/src/server/input_filter/accelerate_source.h
@@ -0,0 +1,121 @@
+/*
+ * \brief Input-event source that accelerates relative motion events
+ * \author Norman Feske
+ * \date 2017-11-03
+ */
+
+/*
+ * Copyright (C) 2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _INPUT_FILTER__ACCELERATE_SOURCE_H_
+#define _INPUT_FILTER__ACCELERATE_SOURCE_H_
+
+/* Genode includes */
+#include
+#include
+
+/* local includes */
+#include
+#include
+
+namespace Input_filter { class Accelerate_source; }
+
+
+class Input_filter::Accelerate_source : public Source, Source::Sink
+{
+ private:
+
+ Owner _owner;
+
+ Source &_source;
+
+ Source::Sink &_destination;
+
+ /**
+ * Look-up table used for the non-linear acceleration of motion values
+ */
+ struct Lut
+ {
+ unsigned char values[256];
+
+ Lut(long curve)
+ {
+ /* clamp parameter to valid range */
+ curve = min(255, max(0, curve));
+
+ auto fill_segment = [&] (long x1, long y1, long x2, long y2)
+ {
+ for (long i = x1 >> 8; i <= (x2 >> 8); i++) values[i] = y1 >> 8;
+ };
+
+ long const x0 = 0, y0 = 0, x1 = curve, y1 = 0,
+ x2 = 255 - curve, y2 = 255, x3 = 255, y3 = 255;
+
+ bezier(x0<<8, y0<<8, x1<<8, y1<<8, x2<<8, y2<<8, x3<<8, y3<<8,
+ fill_segment, 8);
+ }
+ };
+
+ Lut const _lut;
+
+ /**
+ * Scale factor applied to incoming motion values before they are
+ * used as index into the LUT.
+ */
+ long const _sensitivity_percent;
+
+ /**
+ * Scale factor of values obtained from the LUT. It corresponds to the
+ * maximum increase of motion values.
+ */
+ long const _max;
+
+ long _apply_acceleration(long v) const
+ {
+ long const sign = (v < 0) ? -1 : 1,
+ index = max(0, min(255, (sign*v*_sensitivity_percent)/100)),
+ accel = (_lut.values[index]*_max)/256;
+
+ return v + sign*accel;
+ }
+
+ /**
+ * Sink interface
+ */
+ void submit_event(Input::Event const &event) override
+ {
+ /* forward unrelated events */
+ if (!event.relative_motion()) {
+ _destination.submit_event(event);
+ return;
+ }
+
+ _destination.submit_event(Input::Event(Input::Event::MOTION, 0, 0, 0,
+ _apply_acceleration(event.rx()),
+ _apply_acceleration(event.ry())));
+ }
+
+ public:
+
+ static char const *name() { return "accelerate"; }
+
+ Accelerate_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),
+ _lut (config.attribute_value("curve", 127L)),
+ _sensitivity_percent(config.attribute_value("sensitivity_percent", 100L)),
+ _max (config.attribute_value("max", 20L))
+ { }
+
+ void generate() override { _source.generate(); }
+};
+
+#endif /* _INPUT_FILTER__ACCELERATE_SOURCE_H_ */
diff --git a/repos/os/src/server/input_filter/main.cc b/repos/os/src/server/input_filter/main.cc
index 0734432255..e291ecf101 100644
--- a/repos/os/src/server/input_filter/main.cc
+++ b/repos/os/src/server/input_filter/main.cc
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
namespace Input_filter { struct Main; }
@@ -254,6 +255,9 @@ struct Input_filter::Main : Input_connection::Avail_handler,
if (node.type() == Button_scroll_source::name())
return *new (_heap) Button_scroll_source(owner, node, sink, *this);
+ if (node.type() == Accelerate_source::name())
+ return *new (_heap) Accelerate_source(owner, node, sink, *this);
+
warning("unknown <", node.type(), "> input-source node type");
throw Source::Invalid_config();
}
diff --git a/repos/os/src/server/input_filter/source.h b/repos/os/src/server/input_filter/source.h
index 3f8bc009ca..c0ef40ea75 100644
--- a/repos/os/src/server/input_filter/source.h
+++ b/repos/os/src/server/input_filter/source.h
@@ -42,7 +42,8 @@ class Input_filter::Source
|| node.type() == "remap"
|| node.type() == "chargen"
|| node.type() == "merge"
- || node.type() == "button-scroll";
+ || node.type() == "button-scroll"
+ || node.type() == "accelerate";
return false;
}