Routing
Routing in map2 refers to linking nodes such as Reader and Writer, defining the input event flow chain.
Let’s look at a basic example:
import map2
reader_kbd = map2.Reader(patterns=["/dev/input/by-id/example-keyboard"])
reader_mouse = map2.Reader(patterns=["/dev/input/by-id/example-mouse"])
mapper_kbd = map2.Mapper()
mapper_mouse = map2.Mapper()
writer_kbd = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard")
writer_mouse = map2.Writer(clone_from = "/dev/input/by-id/example-mouse")
map2.link([reader_kbd, mapper_kbd, writer_kbd])
map2.link([reader_mouse, mapper_mouse, writer_mouse])
Here, we define two separate event chains, one for each input device, routing events from the respective reader, through a mapper and to a writer.
Nodes
Each object that can be placed in a chain is called a node.
There exist 3 types of nodes:
- input: needs to be at the beginning of a chain
- passthrough: can’t be at the beginning or end of a chain
- output: needs to be at the end of a chain
A good example for the 3 types of nodes are Reader, Mapper and Writer respectively.
Input nodes
Input nodes collect input events, either from a physical device or from other inputs, and pass them on to the next node in the chain.
Currently every input node can only appear in a single chain. This means the following code is invalid:
import map2
reader = map2.Reader(patterns=["/dev/input/by-id/example-keyboard"])
writer1 = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard1")
writer2 = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard1")
# error: every reader can only appear in a single chain
map2.link([reader, writer1])
map2.link([reader, writer2])
Passthrough nodes
Passthrough nodes receive input events from the previous node in the chain, and pass them on to the next node in the chain, potentially modifying, removing or creating new input events.
A passtrhough node can appear in more than one chain at a time, let’s look at an example:
import map2
reader1 = map2.Reader(patterns=["/dev/input/by-id/example-keyboard-1"])
reader2 = map2.Reader(patterns=["/dev/input/by-id/example-keyboard-1"])
mapper = map2.Mapper()
writer1 = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard-1")
writer2 = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard-1")
map2.link([reader1, mapper, writer1])
map2.link([reader2, mapper, writer2])
In this example, events from reader1
flow through mapper
and into writer1
, while
events from reader2
flow through mapper
into writer2
.
An important thing to note is, that the modifier state for each chain is separate, i.e.
emitting shift down
from reader1
does not affect the mapping behaviour of
inputs coming from reader2
.
It’s also possible to chain multiple passthrough nodes.
import map2
reader = map2.Reader(patterns=["/dev/input/by-id/example-keyboard-1"])
mapper1 = map2.Mapper()
mapper2 = map2.Mapper()
mapper3 = map2.Mapper()
writer = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard-1")
map2.link([reader, mapper1, mapper2, mapper3, writer])
This can be useful for creating mapping layers, where each layer maps independently on the inputs received from the previous layer.
Output nodes
Output nodes consume events and usually pass them to a physical device, to the desktop environment, etc.
Linking multiple chains to an output node is allowed, let’s look at an example:
import map2
reader1 = map2.Reader(patterns=["/dev/input/by-id/example-keyboard-1"])
reader2 = map2.Reader(patterns=["/dev/input/by-id/example-keyboard-1"])
writer = map2.Writer(clone_from = "/dev/input/by-id/example-keyboard-1")
map2.link([reader1, writer])
map2.link([reader2, writer])
In this example, a single writer consumes events from multiple chains.