This component transforms input events originating from multiple sources.


Configuration
-------------

An event-filter configuration consists of two parts, a declaration of
input sources ("Input" connections) that the component should request,
and the definition of a filter chain. Each input source is defined via
an '<input>' node with the name of the input source as 'name' attribute and
the session label as 'label' attribute. The latter can be used to route
several input sources to different components, i.e, input device drivers.

The filter chain is defined via one '<output>' node. It contains exactly
one of the following filters:

:<input name="..."/>:

  Refers to the input source with the matching 'name'.

:<remap>:

  Applies low-level key remapping to the events produced by another filter
  that is embedded as a child node.

  It may contain any number of '<key>' nodes. Each of those key nodes has
  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 '<remap>' node may contain '<include>' nodes, which include further
  content into the '<remap>' node. The included ROM must have a '<remap>'
  top-level node.

:<merge>:

  Merges the results of any number of filters that appear as child nodes.

:<chargen>:

  Supplements the input-event stream of another filter with artificial
  'CHARACTER' events by applying character mapping rules. The originating
  filter is defined as a child node.

:<button-scroll>:

  Turns relative motion events into wheel events while a special button
  (i.e., the middle mouse button) is pressed. The button and rate of generated
  wheel events can be configured per axis via the sub nodes '<vertical>' and
  '<horizontal>'. The button of each axis can be specified via the 'button'
  attribute. By default, "BTN_MIDDLE" is used. The rate of generated wheel
  events can be defined by the 'speed_percent' attribute. A value of "100"
  uses relative motion vectors directly as wheel motion vectors. In practice,
  this is results in overly fast wheel motion. By lowering the value, the rate
  can be reduced to practical levels. By specifying a negative value, the
  direction of the generated wheel motion can be inverted.

  The consumed relative motion events are filtered out from the event stream
  such that pointer movements are inhibited while the wheel emulation is
  active. All other events are passed along unmodified.

:<accelerate>:

  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
-------------------------

The character-generator ('<chargen>') rules are defined via the following
sub nodes:

:<mod1>/<mod2>/<mod3>/<mod4>:

  Defines which physical keys are interpreted as modifier keys. Usually,
  '<mod1>' corresponds to shift, '<mod2>' to control, '<mod3>' to altgr
  (on German keyboards), and '<mod4>' to Caps Lock. Each modifier node
  may host any number of '<key>' nodes with their corresponding 'name'
  attribute. For example:

  ! <mod1>
  !   <key name="KEY_LEFTSHIFT"/> <key name="KEY_RIGHTSHIFT"/>
  ! </mod1>
  ! <mod4>
  !   <rom name="capslock"/>
  ! </mod4>

  The '<rom>' node incorporates the content of the ROM module of the
  specified name into the modifier state. If the ROM module contains a
  top-level node with the attribute 'enabled' set to "yes", the modifier
  is enabled. This is useful for handling a system-global capslock state.

:<map mod1="..." mod2="..." mod3="..." mod4="...">:

  A '<map>' node contains a list of keys that emit a specified character when
  pressed. Any number of '<map>' nodes can be present. For each map node, the
  attributes 'mod1' to 'mod4' denote the condition, under which it is
  considered. Each 'mod' attribute has three possible values. If the attribute
  is not present, the state of the modifier does not matter. If set to 'yes',
  the modifier must be active. If set to 'no', the modifier must not be active.

  Each '<map>' may contain any number of '<key>' subnodes. Each '<key>'
  must have the key name as 'name' attribute. The to-be-emitted character
  is defined by the attributes 'ascii', 'char', 'code', or 'b0/b1/b2/b3'.

  :'ascii': accepts an integer value between 0 and 127
  :'char': accepts a single ASCII character
  :'code': defines the Unicode codepoint as integer value
  :'b0'/'b1'/'b2'/'b3': define the individual bytes of an UTF-8 character

:<sequence first="..." second="..." third="..." fourth="..." code="..."/>:

  A sequence node permits the definition of dead-key/composing
  character sequences. With such sequences the character is not
  generated instantly on key press but only after the sequence is
  completed. If an unfinished sequence can't be completed due to an
  unmatched character, the sequence is aborted and no character is
  generated. Sequences of up to four characters are supported.

  For example, the French AZERTY keyboard layout [1] has a dead key
  for Circumflex Accent "^" right of the P key (which is bracket left
  "[" on US keyboards). When Circumflex is pressed no visible
  character should be generated instantly but the accent must be
  combined with a follow-up character, e.g., Circumflex plus "a"
  generates â.

  [1] https://docs.microsoft.com/en-us/globalization/keyboards/kbdfr.html

  Dead keys can be defined in the <key> nodes of any <map> by using
  codepoints not used for direct output, for example, Combining
  Diacritical Marks beginning at U+0300. The French Circumflex example
  can be configured like follows.

  ! <mod1>
  !   <key name="KEY_LEFTSHIFT"/> <key name="KEY_RIGHTSHIFT"/>
  ! </mod1>
  ! <map>
  !   <key name="KEY_Q"         code="0x0061"/> <!-- a -->
  !   <key name="KEY_LEFTBRACE" code="0x0302"/> <!-- dead_circumflex -->
  ! </map>
  ! <map mod1="true">
  !   <key name="KEY_Q"         code="0x0041"/> <!-- A -->
  ! </map>
  ! <sequence first="0x0302" second="0x0061" code="0x00e2"/> <!-- â -->
  ! <sequence first="0x0302" second="0x0041" code="0x00c2"/> <!-- Â -->

:<repeat delay_ms="500" rate_ms="250">:

  The '<repeat>' node defines the character-repeat delay and rate that
  triggers the periodic emission of the last produced character while
  the corresponding key is held.

:<include rom="...">:

  The '<include>' node includes further content into the '<chargen>' node
  and thereby allows the easy reuse of common rules. The included ROM must
  have an '<chargen>' top-level node.


Additional features
-------------------

The event filter is able to respond to configuration updates as well as updates
of included ROM modules. However, a new configuration is applied only if the
input sources are in their idle state - that is, no key is pressed. This
ensures the consistency of the generated key events (for each press event there
must be a corresponding release event), on which clients of the event filter
may depend. However, this deferred reconfiguration can be overridden by setting
the 'force' attribute of the '<config>' node to 'yes'. If forced, the new
configuration is applied immediately.


Examples
--------

An automated test that exercises various corner cases of the event filter
can be found at _os/run/event_filter.run_. For a practical example of how
to use the event filter with the terminal, please refer to the
_gems/run/terminal_echo.run_ script.
