TuioNet is a .Net implementation of the TUIO specification by Martin Kaltenbrunner. It provides packages to implement Tuio Sender and Tuio Receiver. (see Demo Projects)
It supports TUIO 1.1 and TUIO 2.0 for the following message profiles:
TUIO 1.1
/tuio/2Dobj
/tuio/2Dcur
/tuio/2Dblb
TUIO 2.0
/tuio2/frm
/tuio2/alv
/tuio2/tok
/tuio2/ptr
/tuio2/bnd
/tuio2/sym
There are two examples how one can implement a Tuio Sender and Tuio Receiver.
The Server simulates a Touch and an Object moving in circles. The server sends only 5 messages per second by default.
❯ ./TuioNet.ServerDemo --help
TuioNet.ServerDemo 1.0.0+f92ea0876914d47908d2f57c8c3265504e935f1f
Copyright (C) 2026 TuioNet.ServerDemo
-i, --ip (Default: 127.0.0.1) Set the ip address of the tuio sender.
-p, --port (Default: 3333) Set the port.
-l, --logLevel (Default: Information) Set the minimum log level [Trace, Debug, Information, Warning, Error, Critical, None].
-v, --tuioVersion (Default: Tuio11) Set the tuio version [Tuio11, Tuio20].
-c, --connection (Default: UDP) Set the connection type [UDP, Websocket].
-s, --sourceName (Default: TuioServerDemo) Set the source name for the Tuio Sender.
-r, --resolution (Default: 1280,720) Set the screen resolution as [x,y]. Only valid for Tuio 2.
--help Display this help screen.
--version Display version information.Example (for Tuio 2.0 over Websocket)
❯ ./TuioNet.ServerDemo -l Debug -c Websocket -v Tuio20
dbug: TuioNet.ServerDemo.Program[0]
/tuio2/frm 1 1/16/2026 4:12:35 PM 83886800 TuioServerDemo
/tuio2/ptr 0 0 0 0.89968 0.5159958 0 0 0 0 0 0 0 0 0
/tuio2/tok 1 0 5 0.8980017 0.5399335 0.10000035 0 0 0 0 0
/tuio2/alv 0 1
dbug: TuioNet.ServerDemo.Program[0]
/tuio2/frm 2 1/16/2026 4:12:35 PM 83886800 TuioServerDemo
/tuio2/ptr 0 0 0 0.8987207 0.531966 0 0 0 0 0 0 0 0 0
/tuio2/tok 1 0 5 0.8920266 0.5794679 0.2000004 0 0 0 0 0
/tuio2/alv 0 1
dbug: TuioNet.ServerDemo.Program[0]
/tuio2/frm 3 1/16/2026 4:12:35 PM 83886800 TuioServerDemo
/tuio2/ptr 0 0 0 0.89712316 0.5478873 0 0 0 0 0 0 0 0 0
/tuio2/tok 1 0 5 0.88213277 0.618214 0.30001557 0 0 0 0 0
/tuio2/alv 0 1 First run the TuioNet.ServerDemo. Then start the TuioNet.ClientDemo with the same parameters in order to receive Tuio messages.
❯ ./TuioNet.ClientDemo --help
TuioNet.ClientDemo 1.0.0+f92ea0876914d47908d2f57c8c3265504e935f1f
Copyright (C) 2026 TuioNet.ClientDemo
-i, --ip (Default: 127.0.0.1) Set the ip address of the tuio sender.
-p, --port (Default: 3333) Set the port.
-l, --logLevel (Default: Information) Set the minimum log level [Trace, Debug, Information, Warning, Error, Critical, None].
-v, --tuioVersion (Default: Tuio11) Set the tuio version [Tuio11, Tuio20].
-c, --connection (Default: UDP) Set the connection type [UDP, Websocket].
--help Display this help screen.
--version Display version information.Example (for Tuio 2.0 over Websocket)
❯ ./TuioNet.ClientDemo -l Debug -c Websocket -v Tuio20
info: TuioNet.ClientDemo.Program[0]
[WebsocketClient] Try to connect to: ws://127.0.0.1:3333/
info: TuioNet.ClientDemo.Program[0]
[TuioSession] Session initialized!
Connect...
info: TuioNet.ClientDemo.Program[0]
[WebsocketClient] Connected to ws://127.0.0.1:3333/.
[Tuio 2.0] Pointer added -> SessionId: 0
[Tuio 2.0] Token added -> SessionId: 1, ComponentId: 5
[Tuio 2.0] Pointer 0 -> Position: <0.40796626, 0.11073172>
[Tuio 2.0] Token 5 -> Position: <0.5814245, 0.1083751>, Angle: 11.200568
[Tuio 2.0] Pointer 0 -> Position: <0.42360643, 0.10736272>
[Tuio 2.0] Token 5 -> Position: <0.6201151, 0.118460536>, Angle: 11.300569
[Tuio 2.0] Pointer 0 -> Position: <0.43936884, 0.10462189>
[Tuio 2.0] Token 5 -> Position: <0.6576055, 0.1323582>, Angle: 11.400569In general there are four different kinds of events for TUIO 1.1 and 2.0: Add, Update, Remove and Refresh. The Refresh event gets triggered at the end of the current frame after all tuio messages were processed and it provides the current TuioTime. There are different Add, Update and Remove events for the different kinds of TUIO messages (cursor, object, blob, token...). All possible events are shown below.
The Refreshed event is triggered when a TUIO frame is completely processed. This event is useful to handle all updates contained in one TUIO frame together.
_processor.OnRefreshed += OnRefreshed;
private void OnRefreshed(object sender, TuioTime time)
{
// update stuff after the whole tuio frame got processed
}This event gets triggered when a new cursor was added this frame.
_processor.OnCursorAdded += OnCursorAdded;
private void OnCursorAdded(object sender, Tuio11Cursor cursor)
{
Console.WriteLine($"New cursor added -> ID: {cursor.CursorId}");
}This event gets triggered when an already known cursor gets updated, for example changes its position.
_processor.OnCursorUpdated += OnCursorUpdated;
private void OnCursorUpdated(object sender, Tuio11Cursor cursor)
{
Console.WriteLine($"Cursor {cursor.CursorId} -> Position: {cursor.Position}");
}This event gets triggered when a cursor was removed this frame.
_processor.OnCursorRemoved += OnCursorRemoved;
private void OnCursorAdded(object sender, Tuio11Cursor cursor)
{
Console.WriteLine($"Cursor {cursor.CursorId} removed");
}This event gets triggered when a new TUIO 1.1 object was added this frame.
_processor.OnObjectAdded += OnObjectAdded;
private void OnObjectAdded(object sender, Tuio11Object tuioObject)
{
Console.WriteLine($"New object added -> ID: {tuioObject.SymbolId}");
}This event gets triggered when an already known TUIO 1.1 object gets updated, for example changes its position or rotation.
_processor.OnObjectUpdated += OnObjectUpdated;
private void OnObjectUpdated(object sender, Tuio11Object tuioObject)
{
Console.WriteLine($"Object {tuioObject.SymbolId} -> Position: {tuioObject.Position}");
}This event gets triggered when a TUIO 1.1 object was removed this frame.
_processor.OnObjectRemoved += OnObjectRemoved;
private void OnObjectRemoved(object sender, Tuio11Object tuioObject)
{
Console.WriteLine($"Object {tuioObject.SymbolId} removed");
}This event gets triggered when a new TUIO 1.1 blob was added this frame.
_processor.OnBlobAdded += OnBlobAdded;
private void OnBlobAdded(object sender, Tuio11Blob blob)
{
Console.WriteLine($"New Blob added -> ID: {blob.BlobId}");
}This event gets triggered when an already known TUIO 1.1 blob gets updated, for example changes its position or rotation.
_processor.OnBlobUpdated += OnBlobUpdated;
private void OnBlobUpdated(object sender, Tuio11Blob blob)
{
Console.WriteLine($"Blob {blob.BlobId} -> Position: {blob.Position}");
}This event gets triggered when a TUIO 1.1 blob was removed this frame.
_processor.OnBlobRemoved += OnBlobRemoved;
private void OnBlobRemoved(object sender, Tuio11Blob blob)
{
Console.WriteLine($"Blob {blob.BlobId} removed");
}The Refreshed event is triggered when a TUIO frame is completely processed. This event is useful to handle all updates contained in one TUIO frame together.
_processor.OnRefreshed += OnRefreshed;
private void OnRefreshed(object sender, TuioTime time)
{
// update stuff after the whole tuio frame got processed
}This event gets triggered when a new TUIO 2.0 object was added this frame. This could be a pointer, token, bounds or symbol.
_processor.OnObjectAdded += OnObjectAdded;
private void OnObjectAdded(object sender, Tuio20Object tuioObject)
{
// if you expect the object to be a pointer you can check it and act accordingly
if(tuioObject.ContainsTuioPointer())
{
Console.WriteLine($"New Pointer added -> ID: {tuioObject.Pointer.ComponentId}");
}
}This event gets triggered when an already known TUIO 2.0 object gets updated, for example changes its position.
_processor.OnObjectUpdated += OnObjectUpdated;
private void OnObjectUpdated(object sender, Tuio20Object tuioObject)
{
// if you expect the object to be a token you can check it and act accordingly
if(tuioObject.ContainsTuioToken())
{
Console.WriteLine($"Token {tuioObject.Token.ComponentId} -> Position: {tuioObject.Token.Position}");
}
}This event gets triggered when a TUIO 2.0 object was removed this frame.
_processor.OnObjectRemoved += OnObjectRemoved;
private void OnObjectRemoved(object sender, Tuio20Object tuioObject)
{
// if you expect the object to be a symbol you can check it and act accordingly
if(tuioObject.ContainsTuioSymbol())
{
Console.WriteLine($"Symbol {tuioObject.Symbol.ComponentId} removed");
}
}Thanks goes to these wonderful people (emoji key):
Erich Querner 💻 |
Giles Coope 💻 |
Martin Kaltenbrunner 💻 |
This project follows the all-contributors specification. Contributions of any kind welcome!