/** \file * \brief IupTuioClient control * * See Copyright Notice in "iup.h" */ #include "TuioListener.h" #include "TuioClient.h" #include "iup.h" #include "iuptuio.h" #include "iupcbs.h" #include #include #include #include #include "iup_object.h" #include "iup_assert.h" #include "iup_str.h" #include "iup_register.h" #include "iup_drv.h" #include "iup_drvinfo.h" using namespace TUIO; struct iTuioCursorEnvent{ int id; float x, y; char state; iTuioCursorEnvent(int _id, float _x, float _y, char _state); }; iTuioCursorEnvent::iTuioCursorEnvent(int _id, float _x, float _y, char _state) :id(_id), x(_x), y(_y), state(_state) { } class IupTuioListener : public TuioListener { int changed, locked; TuioClient* client; Ihandle* ih; std::list cursor_events; void processCursor(TuioCursor *tcur, const char* state, const char* action); void initCursorInfo(std::list &cursorList, int cursor_count, int* pid, int* pstate); void finishCursorInfo(std::list &cursorList, int cursor_count, int* px, int* py, int* pstate, int w, int h, int use_client_coord, Ihandle* ih_canvas); void updateCursorInfo(int *cursor_count, int* pid, int* px, int* py, int* pstate, int id, int x, int y, int state); int GetMainCursor(std::list &cursorList); static int timer_action_cb(Ihandle *timer); public: int debug; Ihandle* timer; IupTuioListener(Ihandle* _ih, TuioClient* _client); void addTuioObject(TuioObject *tobj); void updateTuioObject(TuioObject *tobj); void removeTuioObject(TuioObject *tobj); void addTuioCursor(TuioCursor *tcur); void updateTuioCursor(TuioCursor *tcur); void removeTuioCursor(TuioCursor *tcur); void addTuioBlob(TuioBlob *tblb); void updateTuioBlob(TuioBlob *tblb); void removeTuioBlob(TuioBlob *tblb); void refresh(TuioTime frameTime); }; IupTuioListener::IupTuioListener(Ihandle* _ih, TuioClient* _client) :changed(0), locked(0), client(_client), ih(_ih), debug(0) { timer = IupTimer(); IupSetAttribute(timer, "TIME", "50"); IupSetAttribute(timer, "_IUP_TUIOLISTENER", (char*)this); IupSetCallback(timer, "ACTION_CB", timer_action_cb); } void IupTuioListener::addTuioObject(TuioObject*) { /* unused */ } void IupTuioListener::updateTuioObject(TuioObject*) { /* unused */ } void IupTuioListener::removeTuioObject(TuioObject*) { /* unused */ } void IupTuioListener::addTuioBlob(TuioBlob*) { /* unused */ } void IupTuioListener::updateTuioBlob(TuioBlob*) { /* unused */ } void IupTuioListener::removeTuioBlob(TuioBlob*) { /* unused */ } void IupTuioListener::addTuioCursor(TuioCursor *tcur) { IupTuioListener::processCursor(tcur, "DOWN", "AddCursor"); } void IupTuioListener::updateTuioCursor(TuioCursor *tcur) { IupTuioListener::processCursor(tcur, "MOVE", "UpdateCursor"); } void IupTuioListener::removeTuioCursor(TuioCursor *tcur) { IupTuioListener::processCursor(tcur, "UP", "RemoveCursor"); } void IupTuioListener::processCursor(TuioCursor *tcur, const char* state, const char* action) { float x = tcur->getX(); float y = tcur->getY(); int id = (int)tcur->getSessionID(); cursor_events.push_back(iTuioCursorEnvent(id, x, y, state[0])); this->changed = 1; if (this->debug) printf("IupTuioClient-%s(id=%d sid=%d x=%d y=%d)\n", action, tcur->getCursorID(), (int)tcur->getSessionID(), (int)tcur->getX(), (int)tcur->getY()); } void IupTuioListener::refresh(TuioTime frameTime) { if (this->changed) { Ihandle* ih_canvas = IupGetAttributeHandle(this->ih, "TARGETCANVAS"); if (!ih_canvas) ih_canvas = this->ih; this->changed = 0; IFniiis cb = (IFniiis)IupGetCallback(ih_canvas, "TOUCH_CB"); IFniIIII mcb = (IFniIIII)IupGetCallback(ih_canvas, "MULTITOUCH_CB"); if (cb || mcb) { this->client->lockCursorList(); this->locked = 1; } if (this->debug) printf("IupTuioClient-RefreshChanged(time=%d)\n", (int)frameTime.getTotalMilliseconds()); } } void IupTuioListener::initCursorInfo(std::list &cursorList, int cursor_count, int* pid, int* pstate) { std::list ::iterator iter; int i; for (i = 0, iter = cursorList.begin() ; igetSessionID(); pstate[i] = 0; /* mark to be updated later */ } } int IupTuioListener::GetMainCursor(std::list &cursorList) { std::list ::iterator iter; std::list ::iterator end = cursorList.end(); int min_id = -1; for (iter = cursorList.begin(); iter!=end; iter++) { TuioCursor* tcur = (*iter); int id = (int)tcur->getSessionID(); if (min_id == -1 || id < min_id) min_id = id; } return min_id; } void IupTuioListener::finishCursorInfo(std::list &cursorList, int cursor_count, int* px, int* py, int* pstate, int w, int h, int use_client_coord, Ihandle* ih_canvas) { std::list ::iterator iter; std::list ::iterator end = cursorList.end(); int i; for (i = 0, iter = cursorList.begin(); igetScreenX(w); int y = tcur->getScreenY(h); if (use_client_coord) iupdrvScreenToClient(ih_canvas, &x, &y); px[i] = x; py[i] = y; pstate[i] = 'M'; /* mark as MOVE */ } } } void IupTuioListener::updateCursorInfo(int *cursor_count, int* pid, int* px, int* py, int* pstate, int id, int x, int y, int state) { int i; for(i = 0; i < *cursor_count; i++) { if (pid[i] == id) { px[i] = x; py[i] = y; pstate[i] = state; return; } } if (state == 'U') /* UP - not in the cursorList, add it */ { pid[i] = id; px[i] = x; py[i] = y; pstate[i] = state; (*cursor_count)++; } } int IupTuioListener::timer_action_cb(Ihandle *timer) { IupTuioListener* listener = reinterpret_cast(IupGetAttribute(timer, "_IUP_TUIOLISTENER")); if (!listener->locked) return IUP_DEFAULT; std::list cursorList = listener->client->getTuioCursors(); int events_count = (int)listener->cursor_events.size(); int cursor_count = (int)cursorList.size(); int total_count = events_count+cursor_count; if (!total_count) { listener->locked = 0; listener->client->unlockCursorList(); return IUP_DEFAULT; } int use_client_coord = 0; Ihandle* ih_canvas = IupGetAttributeHandle(listener->ih, "TARGETCANVAS"); if (ih_canvas) use_client_coord = 1; else ih_canvas = listener->ih; IFniiis cb = (IFniiis)IupGetCallback(ih_canvas, "TOUCH_CB"); IFniIIII mcb = (IFniIIII)IupGetCallback(ih_canvas, "MULTITOUCH_CB"); int w, h, x, y; iupdrvGetFullSize(&w, &h); int *px=NULL, *py=NULL, *pid=NULL, *pstate=NULL; if (mcb) { px = new int[total_count]; py = new int[total_count]; pid = new int[total_count]; pstate = new int[total_count]; listener->initCursorInfo(cursorList, cursor_count, pid, pstate); } int min_id = -1; if (cb) min_id = listener->GetMainCursor(cursorList); for (int i = 0; icursor_events.front(); const char* state = (evt.state=='D')? "DOWN": ((evt.state=='U')? "UP": "MOVE"); x = (int)floor(evt.x*w+0.5f); y = (int)floor(evt.y*h+0.5f); if (use_client_coord) iupdrvScreenToClient(ih_canvas, &x, &y); if (cb) { if (min_id == evt.id) state = (evt.state=='D')? "DOWN-PRIMARY": ((evt.state=='U')? "UP-PRIMARY": "MOVE-PRIMARY"); if (cb(ih_canvas, evt.id, x, y, (char*)state)==IUP_CLOSE) IupExitLoop(); } if (mcb) listener->updateCursorInfo(&cursor_count, pid, px, py, pstate, evt.id, x, y, state[0]); listener->cursor_events.pop_front(); } if (mcb) { listener->finishCursorInfo(cursorList, cursor_count, px, py, pstate, w, h, use_client_coord, ih_canvas); if (mcb(ih_canvas, cursor_count, pid, px, py, pstate)==IUP_CLOSE) IupExitLoop(); delete[] px; delete[] py; delete[] pid; delete[] pstate; } listener->locked = 0; listener->client->unlockCursorList(); return IUP_DEFAULT; } /**************************************************************************************/ struct _IcontrolData { IupTuioListener* listener; TuioClient* client; }; static int iTuioSetConnectAttrib(Ihandle* ih, const char* value) { if (ih->data->client->isConnected()) { IupSetAttribute(ih->data->listener->timer, "RUN", "NO"); ih->data->client->disconnect(); } if (iupStrEqualNoCase(value, "YES")) { ih->data->client->connect(false); IupSetAttribute(ih->data->listener->timer, "RUN", "YES"); } else if (iupStrEqualNoCase(value, "LOCKED")) { ih->data->client->connect(true); IupSetAttribute(ih->data->listener->timer, "RUN", "YES"); } return 0; } static char* iTuioGetConnectAttrib(Ihandle *ih) { if (ih->data->client->isConnected()) return (char*)"Yes"; else return (char*)"No"; } static int iTuioSetDebugAttrib(Ihandle* ih, const char* value) { ih->data->listener->debug = iupStrBoolean(value); return 0; } static char* iTuioGetDebugAttrib(Ihandle *ih) { if (ih->data->listener->debug) return (char*)"Yes"; else return (char*)"No"; } static int iTuioCreateMethod(Ihandle* ih, void** params) { int port = 3333; if (params && params[0]) #if defined (WIN32) && defined (_M_X64) port = (int)(long long)(params[0]); #else port = (int)(long)(params[0]); /* must cast to long first to avoid 64bit C++ compiler error */ #endif ih->data = iupALLOCCTRLDATA(); ih->data->client = new TuioClient(port); ih->data->listener = new IupTuioListener(ih, ih->data->client); ih->data->client->addTuioListener(ih->data->listener); return IUP_NOERROR; } static void iTuioDestroyMethod(Ihandle* ih) { IupDestroy(ih->data->listener->timer); delete ih->data->client; delete ih->data->listener; } Ihandle* IupTuioClient(int port) { void *params[2]; params[0] = (void*)port; params[1] = NULL; return IupCreatev("tuioclient", params); } static Iclass* iTuioNewClass(void) { Iclass* ic = iupClassNew(NULL); ic->name = (char*)"tuioclient"; ic->cons = (char*)"TuioClient"; ic->format = (char*)"i"; /* (int) */ ic->nativetype = IUP_TYPEVOID; ic->childtype = IUP_CHILDNONE; ic->is_interactive = 0; ic->New = iTuioNewClass; ic->Create = iTuioCreateMethod; ic->Destroy = iTuioDestroyMethod; /* Base Callbacks */ iupBaseRegisterBaseCallbacks(ic); iupClassRegisterCallback(ic, "TOUCH_CB", "iiis"); iupClassRegisterCallback(ic, "MULTITOUCH_CB", "iIIII"); iupClassRegisterAttribute(ic, "CONNECT", iTuioGetConnectAttrib, iTuioSetConnectAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "DEBUG", iTuioGetDebugAttrib, iTuioSetDebugAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); return ic; } int IupTuioOpen(void) { if (!IupIsOpened()) return IUP_ERROR; if (IupGetGlobal("_IUP_TUIO_OPEN")) return IUP_OPENED; iupRegisterClass(iTuioNewClass()); IupSetGlobal("_IUP_TUIO_OPEN", "1"); return IUP_NOERROR; }