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

  It may also contain any number of '<ignore-key>' nodes to completely mute
  certain keys. Each of those nodes has the key name as 'name' attribute.
  This rule is applied before remapping.

  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.

:<log>:

  Logs debug information about input events to the component's 'Log'
  session. Per default, only key presses and releases are logged. The
  optional 'motion' attribute (boolean) enables logging of motion and touch
  events too. An optional 'prefix' attribute can be provided in order to
  distinguish multiple '<log>' filters. The given prefix is placed at the
  beginning of each log message.

:<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".

:<touch-click>:

  Augments touch events with artificial absolute motion and mouse click/clack
  events as understood by regular GUI applications that are not aware of
  touch input. The original touch events are preserved, enabling touch-aware
  applications to interpet touch gestures.

:<touch-key>:

  Triggers an artificial key tap (a press event followed by a release event)
  when touching a preconfigured area on a touch screen. The filter node can
  host any number of '<tap>' sub nodes. Each sub node must define a
  rectangular area - using the attributes 'xpos', 'ypos', 'width', and
  'height' - and the name of the tapped key as 'key' attribute.

  A '<touch-key>' node may contain '<include>' nodes, which include further
  content into the '<touch-key>' node. The included ROM must have a
  '<touch-key>' top-level node.

:<touch-gesture>:

  Triggers artificial key sequences or key combos when (multi-)touch gestures
  are detected. Gesture detection is configured by the following primitives
  expressed as sub-nodes (with specified default attributes).

  :<hold fingers="1" delay_ms="1000" width="30" height="30">:

    Triggers when the specified number of fingers touch and hold for at least
    'delay_ms' milliseconds. All fingers must reside in a specified area defined
    by the 'width' and 'height' attributes around the first touch event.
    When this gesture has been triggered, it translates touch events into
    relative motion events. This can be used for dragging or scrolling.

  :<swipe fingers="1" duration_ms="1000" distance="100" direction="any">:

    Triggers when the specified number of fingers move for at least 'distance'
    in the specified 'direction' and within 'duration_ms' milliseconds.
    Supported values for the 'direction' attribute are: "up", "down", "left",
    "right". The rect in which the gesture is valid can be restricted by
    providing the 'xpos', 'ypos', 'width' and 'height' attributes.

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

    The '<include>' node includes further content into the '<touch-gesture>'
    node. The included ROM must have an '<touch-gesture>' top-level node.

  Key sequences are specified as '<key>' sub-nodes to the gesture
  primitives. Key combos are specified by nesting the '<key>' sub-nodes. The
  'name' attribute specifies the name of the pressed key. An optional 'hold'
  attribute can be used for postponing the key release event until the touch
  release. This is useful for dragging gestures; for example:

  ! <hold>
  !   <key name="KEY_SCREEN" hold="yes">
  !     <key name="BTN_MIDDLE" hold="yes"/>
  !   </key>
  ! </hold>


:<transform>:

  Transforms touch and absolute-motion event coordinates by a sequence of
  the following primitives expressed as sub-nodes.

  :<translate>:

    Moves coordinates by 'x' and 'y' attributes.

  :<scale>:

    Scales horizontal and vertical axis by 'x' and 'y' attributes.

  :<rotate>:

    Rotates clockwise (around origin (0,0) by 90, 180, or 270 degrees in
    attribute 'angle'. For example with rotate set to 90 degrees, point
    (0,5) is reported as (-5,0).

  :<reorient>:

    Rotates clockwise (like 'rotate') but also translates results for
    desired target 'width' and 'height' attributes effectively moving the
    origin to the upper-left corner after reorientation. The following
    example, corrects coordinates for a FullHD touchscreen rotated 90
    degrees clockwise from landscape to portrait orientation.

    ! <reorient angle="90" width="1080" height="1920"/>

    Thus, point (20,10) in the upper-left corner is reported as (1069, 20)
    in the upper-right corner. For counter-clockwise 90 degree
    reorientation, 'angle' must be set to 270.

  :<hflip>/<vflip>:

    Flip coordinates horizontally/vertically and translate into
    'width'/'height'.

  :<include rom="...">:
    The '<include>' node includes further content into the '<transform>' node.
    The included ROM must have an '<transform>' top-level node.

:<report>:

  Reports the configured list of key combinations as distinct shortcut
  reports that are labeled by the 'name' attribute. The key events are
  preserved for further processing (resp. not filtered out).

  ! <report>
  !   <shortcut name="screenshot">
  !     <key name="KEY_LEFTMETA"/> <key name="KEY_S"/>
  !   </shortcut>
  !   <shortcut name="screenlock">
  !     <key name="KEY_LEFTMETA"/> <key name="KEY_L"/>
  !   </shortcut>
  ! </report>

  The shortcut node permits the declaration of keys that when pressed
  simultaneously update the shortcut report. The report provides the
  shortcut 'name' and a unique 'serial' number as attributes like follows.

  ! <shortcut name="screenshot" serial="7"/>

  Users must record the last observed serial number for comparison on later
  report updates. The first serial number and future changes of its value
  shall be interpreted as shortcut events. Note, reports missing a valid
  'serial' attribute must be ignored.

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.
