v0.2.0
TobiiLinux v0.2.0 — head tracking into games
Games. v0.1.0 could send head pose to opentrack, and only to opentrack. This
release adds two routes that need nothing else installed, and fixes a bug that
made one axis useless in every output the program has.
This is a testing release. The tracking paths below are verified end to
end on hardware — through SDL, through joydev, through DirectInput under a
real Proton prefix — but no game has consumed any of it yet, and no real
head has driven the axes. If something feels wrong, it probably is; see
Reporting a problem.
Unofficial. Not affiliated with, endorsed by, or supported by Tobii.
Use at your own risk.
New: a virtual joystick, needing nothing else
Most games have never heard of head tracking, but nearly all of them can bind a
joystick axis. So game output now presents one, on /dev/uinput:
| Axis | Carries | Full scale |
|---|---|---|
| X, Y, Z | head displacement from where you sit | ±500 mm |
| RX, RY, RZ | yaw, pitch, roll | ±180°, ±90°, ±180° |
| Throttle, Rudder | gaze on screen, left→right and top→bottom | the whole screen |
No opentrack, no Wine. Because it is an ordinary evdev joystick it is read by
SDL, by the legacy /dev/input/js* interface, and by Wine's winebus — so
Proton games see it as a DirectInput joystick too. The last two axes are
gaze, which no other head tracker offers.
Turn it on with the hub's Head tracking for games switch, or:
tobii games set enabled true
tobii game -- %command% # Steam: paste into Launch OptionsIf the axes feel weak, this is the knob. The number is the head angle that
reaches full deflection:
tobii games set joystick_yaw_full_deg 45 # default 70New: the Wine/Proton bridge needs nothing running
tobii bridge games # what is installed, and what has a prefix
tobii bridge install --steam elite # by name, or by app idThe client DLL the game loads receives the tracking itself, in a background
thread inside the game's own process. There is no second program to leave
running. That is not a convenience: a Proton game runs under its own wineserver,
so an external tobii bridge run created its shared memory in a different
session and the game never saw it — for a Steam title the old design could not
have worked at all.
install --steam finds the prefix from Steam's own library files and writes the
registry with the Proton build that prefix records, not whatever wine is
on your $PATH — a foreign wine would run wineboot -u and upgrade the prefix
out from under the game.
Fixed: one translation axis was dead in every output
Z carried the head's distance from the sensor — 650–700 mm for anyone
sitting normally — against a ±500 mm scale. It was pinned hard at maximum, for
every user, in both the joystick and the TrackIR/FreeTrack output that
shipped in v0.1.0. In a game that reads as a camera permanently leaned all the
way in. Translation is displacement from where you sit now, taken when the
tracker picks you up.
Also in this release
- X-Plane 11/12 works with no extra sink. The plugin Linux users actually
run (amyinorbit/headtrack) reads exactly what our opentrack output already
emits, on the port it already uses. Just turn game output on. tobii game -- <command>holds the tracker for a game's lifetime, and says so
when game output is switched off rather than lighting the tracker silently.- Closing the hub window minimises it instead of quitting, so the tracker
stays available to a running game. - Another program can take the device from the hub and hand it back.
tobii games [set KEY VALUE]for every game-output setting.tobii debugreports/dev/uinput, separating the three ways it fails —
they are indistinguishable from inside a game.- The packaged udev rule now also grants
/dev/uinput, as one clearly-marked
line the file explains how to remove.
Upgrading — read this one
tobii update replaces binaries and nothing else, so it will not deliver
the new udev rule. If the virtual joystick reports a permission error, install
the rule by hand:
sudo cp assets/60-tobii.rules /etc/udev/rules.d/
sudo udevadm control --reload
sudo udevadm trigger --subsystem-match=usb --subsystem-match=miscthen log out and back in — the grant is a logind ACL applied at session start.
tobii debug says installed without a warning once it has taken. Distribution
packages (deb, rpm, PKGBUILD) do this for you.
If you set bridge_port to something other than the default, launch through
tobii game: it passes the port to the Wine side, and nothing else can.
Known limitations
- Some games' "look" axis is a rate control, not a position: the camera
keeps turning while the axis is deflected. The bind takes, the axis moves in
the test display, and the view still spins away from you. Elite Dangerous has
an explicit Headlook Axis Mode: Direct precisely because its default is
incremental. Where only a rate axis is offered, the joystick cannot drive the
view however it is tuned. - Steam Input can take the device away, silently, from a Steam-launched
game. Fix per game: Properties → Controller → Disable Steam Input. - The bridge is 64-bit only. A 32-bit game asks for
freetrackclient.dll
without the64and finds nothing whileinstallreports success. Falcon
BMS, IL-2 1946 and the FSX generation are 32-bit. - TrackIR still needs a signed client DLL.
NP_GetSignatureis answered
from NaturalPoint's own signature data, which we do not ship, so
tobii bridge installpoints TrackIR at an installed opentrack client — and
that one does needtobii bridge run. FreeTrack has no signature check and
works with our own DLL. - XInput does not see the virtual joystick — measured under Wine 11.17.
Its two-stick layout has nowhere to put eight axes. - Flatpak Steam is half-supported. The install finds its prefix, but the
launch option runs inside the sandbox where our binary is not onPATH.
flatpak-spawn --host tobii game -- %command%is the shape to try. - [UNKNOWN] the per-axis signs of the TrackIR encoding, and whether a game
ignores a frame whosewPFrameSignaturedid not change. - The gaze axes sit on Throttle and Rudder. A flight sim that auto-binds a
throttle could pick one up; no sim has been observed doing so.
How this was tested
Everything below was measured on hardware, not inferred:
- SDL2 2.32 enumerates the device with 8 axes and 2 buttons. A known pose
survives the whole chain exactly: composed yaw +35° of the 70° default arrives
as16384— half deflection — pitch −17.5° as−16385, gaze at the
right-hand screen edge as32767. - joydev (
/dev/input/js*) reports every axis at exactly0at rest. - Wine 11.17 DirectInput8 enumerates it as
DI8DEVTYPE_JOYSTICK; XInput
reports zero controllers in all four slots, with and without it present. - udev classification was established by building the device four ways and
reading/run/udev/data/. Without anEV_KEYcapability the kernel calls it
an accelerometer and hands it toiio-sensor-proxy— the service that rotates
laptop screens. - The bridge, on a real Elite Dangerous Proton prefix, with nothing else
running. The game's own load path (LoadLibraryon the registry directory,
thenGetProcAddress) resolves all five FreeTrack exports, and a pose sent
from Linux as yaw 7.5°, pitch −3.25°, roll 1.5°, (11, 22, 33) mm reads back
throughFTGetDataasyaw=0.1309, pitch=-0.0567, roll=0.0262radians and
pos=(11.0, 22.0, 33.0), withDataIDadvancing. With nothing sending it
reports no data rather than a tracker frozen at centre.
793 tests, zero clippy warnings, both workspaces building.
Two full adversarial review rounds were run over this change and every finding
from both was adjudicated — 55 findings, 22 confirmed and fixed. Several were
defects in behaviour that shipped in v0.1.0.
The full list, including what is untested and what is merely believed to work,
is in Quality-and-Risks — see 11.3a Game
output. That page is written to be uncomfortable to read.
Reporting a problem
tobii debug prints the report an issue asks for, and the hub's cogwheel can
copy or save it. It names the state of the udev rule, /dev/uinput, the display
area and the calibration. If a game sees nothing, say which game, which route
(joystick, opentrack, or the bridge), and paste that report.
Credits
The FreeTrack and TrackIR interfaces are public ABIs; opentrack was read for
interface facts — which axes, which classification bits, which packet shapes —
and the files that use them say so and say which fact. No opentrack code was
copied. The clean-room claim covers the ET5's USB protocol, which was
derived from captured traffic and nothing else.