DWORD WINAPI InitEgClientDemo(void *pv) { /* This is a separate thread that initializes the Eyegaze functions and a */ /* few support functions for fonts and terminates. The thread should live */ /* for just a few seconds. */ HMENU hMenu; int rc; _TCHAR achText[260]; /* Set up the structures to pass to EgInit(). */ stEgControl.iNDataSetsInRingBuffer = BUFFER_LEN; stEgControl.bEgCameraDisplayActive = FALSE; stEgControl.bTrackingActive = TRUE; stEgControl.iScreenWidthPix = iScreenWidth; stEgControl.iScreenHeightPix = iScreenHeight; stEgControl.iEyeImagesScreenPos = 1; stEgControl.iCommType = EG_COMM_TYPE_SOCKET; stEgControl.pszCommName = achCommAddress; rc = EgInit(&stEgControl); if (rc != 0) { swprintf_s(achText, _countof(achText), TEXT("Error opening socket\nBe sure to start EgServer before starting EgClientDemo\nProvide the server IP address on the EgClientDemo command line.")); MessageBox(hwndEyegaze, achText, szAppName, MB_ICONEXCLAMATION | MB_OK); bCommEstablished = FALSE; exit(1); // Kill the process on terminal error } hMenu = GetMenu(hwndEyegaze); EnableMenuItem(hMenu, ID_COMMUNICATIONS_CALIBRATE, MF_ENABLED); EnableMenuItem(hMenu, ID_COMMUNICATIONS_BEGIN, MF_ENABLED); bCommEstablished = TRUE; lct_clearscreen(BLACK); /* Initialize the fonts. */ lct_fontinit(); lctFontLoad(LCT_FONT_1); stGazeVergence.ulCameraFieldCount = 0; if (stEgControl.hEyegaze != NULL) EgSetScreenDimensions( &stEgControl, iScreenWidth, iScreenHeight, 0, // iEgMonHorzOffset 0, // iEgMonVertOffset iWindowWidthPix, iWindowHeightPix, iWindowHorzOffset, iWindowVertOffset); return 0; }
DWORD WINAPI GazeDemo(void *pvoid) { /* This function is the core of the Eyegaze application that is executed */ /* as a separate thread when the program starts. */ #define EG_BUFFER_LEN 60 /* The constant EG_BUFFER_LEN sets the */ /* number of past samples stored in */ /* its gazepoint data ring buffer. */ /* Assuming an Eyegaze sample rate of */ /* 60 Hz, the value 60 means that one */ /* second's worth of past Eyegaze data */ /* is always available in the buffer. */ /* The application can get up to 60 */ /* samples behind the Eyegaze image */ /* processing without losing eyetracking */ /* data. */ /* Demonstration Program variables: */ int iIGazeSmooth; /* smoothed values of the eyegaze */ /* coordinates (pixels) */ int iJGazeSmooth; int iVis; /* The vision system returning data */ int rc; /* Return code from EgInit function call */ /*---------------------------- Function Code -------------------------------*/ /* Calibrate to the Eyegaze user (test subject). */ /* Since an Eyegaze thread has not yet been started, execute the external */ /* Eyegaze Calibration program (CALIBRATE.EXE), which starts and terminates */ /* its own Eyegaze thread. */ /* (See discussion of alternative calibration calls in the Eyegaze System */ /* Programmer's Manual. NOTE: If using the double computer configuration, */ /* spawning the external CALIBRATE.EXE is not an option. EgCalibrate must */ /* be used. See Programmer's Manual) */ /* P_WAIT causes the calibration program to terminate before this program */ /* proceeds. */ //_spawnl(P_WAIT, "Calibrate.exe", "Calibrate.exe", NULL); /* Set the input control constants in stEgControl required for starting */ /* the Eyegaze thread. */ stEgControl.iNDataSetsInRingBuffer = EG_BUFFER_LEN; /* Tell Eyegaze the length of the Eyegaze */ /* data ring buffer */ stEgControl.bTrackingActive = FALSE; /* Tell Eyegaze not to begin image */ /* processing yet (so no past gazepoint */ /* data samples will have accumulated */ /* in the ring buffer when the tracking */ /* loop begins). */ stEgControl.bEgCameraDisplayActive = FALSE; /* Tell Eyegaze not to display the full */ /* camera image in a separate window. */ stEgControl.iScreenWidthPix = iScreenWidth; stEgControl.iScreenHeightPix = iScreenHeight; /* Tell the image processing software what */ /* the physical screen dimensions are */ /* in pixels. */ stEgControl.iEyeImagesScreenPos = 1; #if defined RUN_LOCALLY stEgControl.iCommType = EG_COMM_TYPE_LOCAL; /* We are calibrating on the local */ /* computer, not over a serial or TCP/IP */ /* link. */ #else stEgControl.iCommType = EG_COMM_TYPE_SOCKET; stEgControl.pszCommName = achIPAddress; #endif /* Create the Eyegaze image processing thread. */ rc = EgInit(&stEgControl); if (rc != 0) { _TCHAR achErrorText[120]; swprintf_s(achErrorText, _countof(achErrorText), _T("Error %i Initializing Eyegaze"), rc); MessageBox(NULL, achErrorText, _T("GazeDemo"), MB_ICONEXCLAMATION | MB_OK); } EgCalibrate2(&stEgControl, EG_CALIBRATE_NONDISABILITY_APP); /* Push the GazeDemo program window up into the upper right corner of the */ /* screen. */ SetWindowPos(hwndEyegaze, // handle to window HWND_TOP, // placement-order handle iScreenWidth-160, // horizontal position 0, // vertical position 160, // width 50, // height 0); // Flags /* Tell Eyegaze to start eyetracking, i.e. to begin image processing. */ /* Note: No eyetracking takes place until this flag is set to true, and */ /* eye image processing stops when this flag is reset to false. */ stEgControl.bTrackingActive = TRUE; /* Loop for ever until the program is terminated. */ for (EVER) { /*----------------------- Synchronize to Eyegaze --------------------------*/ /* This code keeps the GazeDemo loop synchronized with the real-time */ /* Eyegaze image processing, i.e. looping at 60 Hz, but insures that all */ /* gazepoint data samples are processed, even if the GazeDemo loop gets */ /* a little behind the real-time Eyegaze image processing. Data */ /* buffers allow the GazeDemo loop to process all past gazepoint data */ /* samples even if the loop falls up to EG_BUFFER_LEN samples behind */ /* real time. */ /* If the ring buffer has overflowed, */ if (stEgControl.iNBufferOverflow > 0) { /* The application program acts on data loss if necessary. */ // (appropriate application code) } /* The image processing software, running independently of this */ /* application, produces a new eyegaze data sample every 16.67 milli- */ /* seconds. If an unprocessed Eyegaze data sample is still available */ /* for processing, EgGetData() returns immediately, allowing the */ /* application to catch up with the Eyegaze image processing. If the */ /* next unprocessd sample has not yet arrived, EgGetData blocks until */ /* data is available and then returns. This call effectively puts the */ /* application to sleep until new Eyegaze data is available to be */ /* processed. */ iVis = EgGetData(&stEgControl); /*-------------------- Process Next Eyegaze Data Sample --------------------*/ /* Compute the smoothed gazepoint, averaging over the last 12 samples. */ SmoothGazepoint(stEgControl.pstEgData->bGazeVectorFound, stEgControl.pstEgData->iIGaze, stEgControl.pstEgData->iJGaze, &iIGazeSmooth, &iJGazeSmooth, 12); /* If the gazepoint was found this iteration, */ if (stEgControl.pstEgData->bGazeVectorFound == TRUE) { /* Move the mouse to the smoothed gazpoint location. */ mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, iIGazeSmooth*65535/iScreenWidth, iJGazeSmooth*65535/iScreenHeight, 0, 0); } } return 0; if (pvoid); // quiet the compiler. }