Since the very beginning all the methods to make a multiseat Linux, perhaps with the exception of Backstreet Ruby (which I had never been able to run successfully) rely on having X servers read the so-called event interface rather than the traditional kernel interface to read keyboards and mice (which, I think, that by design are assumed to be single instance).
This event interface is exposed to user space in /dev/input/event<number>. The important thing here is to note that each mouse or keyboard has at least one corresponding node in /dev/input - my USB keyboard for example has two, but any node corresponds to exactly one device. So while running the multiple X servers (Xephyrs in this approach) one must specify which event interface to use as input for mouse and which for keyboard. Until fairly recently only the regular X had had an option of specifying the mouse/keyboard event interface. Things have changed and Xephyr now also supports this. It would seem that that is all we need. However, things are a little bit more complicated.
The envent interface node names (/dev/input/eventXX) might change across system reboot. They do tend to be the same, but there is no absolute guarantee. First, the USB devices might be plugged to different USB ports each time, and second you could boot your computer with or without your 5 pendrives plugged in. Both of the above can cause the USB enumeration to proceed differently and so the different names. It is not just theory. Until I learned how to cope with this situation I did sometimes experience this kind of problem.
On my Debian system, in the /dev/input directory there are 2 subdirectories: by-id and by-path. They contain symbolic links to actual /dev/input/eventXX nodes. The former does not include the PS/2 mouse/keyboard. The latter contains all the devices, but the node names are related to the actual ports the devices are connected to. Probably one could specify PS/2 mouse/keyboard using the respective by-path entries and USB mice/keyboards using the respective by-id entries. In fact this is not so bad. However, I thought that the by-id and by-path can be considered some special views on the event interface. And that multiseat setup deserves a view on its own. And thanks to such a view all the links would be gathered in one directory nicely named "/dev/input/multiseat".
Here you can find a tutorial on udev. I am not going to explain it. Rather I will concentrate on explaining just one rule:
KERNEL=="event[0-9]*" SUBSYSTEM=="input" PROGRAM="/etc/multiseat/scripts/match-and-name %k" SYMLINK+="input/multiseat/%c"
The KERNEL and SUBSYSTEM are clear. More interesting here is the PROGRAM. It specifies a program which is run every time the rule is tried. The %k parameter is automatically replaced with the actual event interface node name (e.g. /dev/input/event3) which is currently processed. If the program exits with 0, then the rule matches, and if not then the rule does not match. If the rule matches, then the SYMLINK action is taken, and what the program prints on its standard output is available in the %c. The symlink action creates a symbolic link relative to the /dev/input.
Armed with this tool we can design the PROGRAM in such a way that it matches the event interface node name passed as argument with the contents of some configuration file. If the match is successful, then print on standard output the configured name for the associated device. In this solution, the said configuration file is common to this udev rule and to the Xephyr-seat and multiseat-greeter scripts used to start Xephyrs and login screens.
This post is long enough ;) But prepare for the great feast. Stay hungry....that is... tuned.