Um mich erstmal wieder in Cocoa einzufinden und in das Framework einzuarbeiten habe ich mir vorgenommen ein kleines, einfaches Projekt anzugehen. Mir kam die Idee, dass es doch ganz gut wäre, wenn man mit dem Tisch auch ganz normal im Finder navigieren kann. Also wäre eine "MT-Maus" ganz gut. Nachdem ich ein wenig im Internet nach bisherigen Lösungen gesucht hatte und keine zufrieden stellende Lösung gefunden habe, war für mich klar, dass ich versuchen werde eine gute "MT-Maus" für den MT-Tisch zu entwickeln.

Das Framework von Touché ist recht einfach aufgebaut. Nachdem man den TFTrackingClient instanziert hat, setzt man einen Delegate der das TFTrackingClientDelegate-Protokoll unterstützen muss.

Um einen Mausklick zu simulieren gibt es eine sehr einfache CoreGraphics-Funktion:

CGPoint hit = CGPointMake(450, 345);
CGEventRef mouseDownEv = CGEventCreateMouseEvent (
                          NULL, //CGEventSourceRef source
                          kCGEventLeftMouseDown, //CGEventType mouseType
                                        //kCGEventNull
                                        //kCGEventMouseMoved
                                        //kCGEventLeftMouseDragged
                                        //kCGEventLeftMouseDown
                                        //kCGEventLeftMouseUp
                          hit, //CGPoint mouseCursorPosition
                          kCGMouseButtonLeft //CGMouseButton mouseButton
                                        //kCGMouseButtonLeft
                                        //kCGMouseButtonRight
                                        //kCGMouseButtonCenter
                          );
CGEventPost(kCGHIDEventTap, mouseDownEv);

Wenn jetzt an der gleichen Position ein MouseUp-Event geschickt wird, ist es ein einfacher Links-Klick.

CGPoint hit = CGPointMake(450, 345);
CGEventRef mouseUpEv = CGEventCreateMouseEvent (NULL,kCGEventLeftMouseUp,hit,kCGMouseButtonLeft);
CGEventPost (kCGHIDEventTap, mouseUpEv );

Wird aber nach dem MouseDown-Event kein MouseUp-Event sondern ein MouseDragged-Event geschickt, kann man mit der Maus z.B. Fenster ziehen.

CGPoint hit = CGPointMake(512, 412);
CGEventRef mouseMovedEv = CGEventCreateMouseEvent (NULL,kCGEventLeftMouseDragged,hit,kCGMouseButtonLeft);
CGEventPost (kCGHIDEventTap, mouseMovedEv);

Mit den drei Mousevents sollte man erst einmal ausreichend im Finder navigieren können.

Während des Programmierens und Testens habe ich gemerkt, dass Touché leider nicht 100% zuverlässig läuft, auf jeden Fall hat die Wii-Remote-Implementation noch einige Fehler. Deshalb habe ich mich entschlossen die Abhängigkeit von Touché zu verringern und auf ein generelles TUIO-Framework umzusteigen.

Bridger Maxwell hat ein ObjC TUIO-Framework geschrieben auf das ich schonmal im Zusammenhang mit dem Wiimote Whiteboard gestoßen bin.

Ich habe die Maus noch mal neu angefangen und sie mit dem TUIO-Framework aufgebaut. Daher auch der Name "TUIO Mouse".

Ich habe "TUIO Mouse" als reines Kommandozeilen-Tool geschrieben, es kann aus dem Terminal gestartet werden, oder was meine eigentliche Idee ist, als LaunchAgent im Hintergrund laufen sobald sich der Benutzer anmeldet.
Damit man trotzdem noch ein paar Sachen konfigurieren kann habe ich beschlossen sie mit dem Default-System von OS-X zu speichern. So kann ich auch relativ einfach von einem anderen (Konfigurations-)Programm auf die Einstellungen von "TUIO Mouse" zugreifen.

Leider hatte ich anfangs Probleme auf die Defaults-Domain zuzugreifen, da ein Kommandozeilen-Tool kein Bundle ist und auch kein Bundle-Identifier hat, der aber von dem NSUserDefaults-Objekt als Standard-Domain gewählt wird. Mit einiger Bastelei und der Hilfe eines Bekannten habe ich es dann doch geschafft auf die "fremde" Domain zuzugreifen ohne auf CFPreferences zugreifen zu müssen.
Durch folgenden Code bekommt man ein NSDictionary mit den momentanen Defaults aus der angegebenen Domain.

NSDictionary *currentDefaults = [userDefaults persistentDomainForName:kDomainName];

Nachdem man das Dictionary bearbeitet hat kann man die Defaults der Domain wieder überschreiben. Leider werden alle Defaults, die nicht im Dictionary vorhanden sind überschrieben!

[userDefaults setPersistentDomain:newDefaults forName:kDomainName];