// ###################################################################### Point2D<int> EyeTrackerEyeLink::getEyePos() const { #ifndef HAVE_EYELINK LFATAL("Proprietary EyeLink developer API not installed"); return Point2D<int>(-1,-1); #else // get gaze position eyelink_newest_float_sample(&evt); // make sure pupil is present if(evt.fs.gx[RIGHT_EYE]!=MISSING_DATA && evt.fs.gy[RIGHT_EYE]!=MISSING_DATA && evt.fs.pa[RIGHT_EYE]>0){ return Point2D<int>((int)evt.fs.gx[RIGHT_EYE], (int)evt.fs.gy[RIGHT_EYE]); } else { return Point2D<int>(-1, -1); } #endif }
// Run gaze-contingent window trial // <fgbm> is bitmap to display within window // <bgbm> is bitmap to display outside window // <wwidth, wheight> is size of window in pixels // <mask> flags whether to treat window as a mask // <time_limit> is the maximum time the stimuli are displayed int gc_window_trial(HBITMAP fgbm, HBITMAP bgbm, int wwidth, int wheight, int mask, UINT32 time_limit) { UINT32 trial_start=0; // trial start time (for timeout) UINT32 drawing_time; // retrace-to-draw delay int button; // the button pressed (0 if timeout) int error; // trial result code ALLF_DATA evt; // buffer to hold sample and event data int first_display = 1; // used to determine first drawing of display int eye_used = 0; // indicates which eye's data to display float x, y; // gaze position // NOTE: TRIALID AND TITLE MUST HAVE BEEN SET BEFORE DRIFT CORRECTION! // FAILURE TO INCLUDE THESE MAY CAUSE INCOMPATIBILITIES WITH ANALYSIS SOFTWARE! // Set size and type of gaze-contingent window RECT display_rect; display_rect.top = dispinfo.top; display_rect.bottom = dispinfo.bottom; display_rect.left = dispinfo.left; display_rect.right = dispinfo.right; initialize_gc_window(wwidth, wheight, fgbm, bgbm, full_screen_window, display_rect, mask, SCRWIDTH/300); // sets 0.1 degree deadband // DO PRE-TRIAL DRIFT CORRECTION // We repeat if ESC key pressed to do setup. while(1) { // Check link often so we can exit if tracker stopped if(!eyelink_is_connected()) return ABORT_EXPT; // We let do_drift_correct() draw target in this example // 3rd argument would be 0 if we already drew the display error = do_drift_correct((INT16)(SCRWIDTH/2), (INT16)(SCRHEIGHT/2), 1, 1); // repeat if ESC was pressed to access Setup menu if(error!=27) break; } clear_full_screen_window(target_background_color); // make sure display is blank // Start data recording to EDF file, BEFORE DISPLAYING STIMULUS // You should always start recording 50-100 msec before required // otherwise you may lose a few msec of data // tell start_recording() to send link data error = start_recording(1,1,1,1); // record with link data enabled if(error != 0) return error; // ERROR: couldn't start recording // record for 100 msec before displaying stimulus begin_realtime_mode(100); // Windows 2000/XP: no interruptions from now on // DONT DISPLAY OUR IMAGES TO SUBJECT until we have first gaze postion! if(!eyelink_wait_for_block_start(100, 1, 0)) // wait for link sample data { end_trial(); alert_printf("ERROR: No link samples received!"); return TRIAL_ERROR; } eye_used = eyelink_eye_available(); // determine which eye(s) are available switch(eye_used) // select eye, add annotation to EDF file { case RIGHT_EYE: eyemsg_printf("EYE_USED 1 RIGHT"); break; case BINOCULAR: // both eye's data present: use left eye only eye_used = LEFT_EYE; case LEFT_EYE: eyemsg_printf("EYE_USED 0 LEFT"); break; } // Now get ready for trial loop eyelink_flush_keybuttons(0); // reset keys and buttons from tracker // we don't use getkey() especially in a time-critical trial // as Windows may interrupt us and cause an unpredicatable delay // so we would use buttons or tracker keys only // Trial loop: till timeout or response -- added code for reading samples and moving cursor while(1) { // First, check if recording aborted if((error=check_recording())!=0) return error; // Check if trial time limit expired if(current_time() > trial_start+time_limit && trial_start!=0) { eyemsg_printf("TIMEOUT"); // message to log the timeout end_trial(); // local function to stop recording button = 0; // trial result message is 0 if timeout break; // exit trial loop } if(break_pressed()) // check for program termination or ALT-F4 or CTRL-C keys { end_trial(); // local function to stop recording return ABORT_EXPT; // return this code to terminate experiment } if(escape_pressed()) // check for local ESC key to abort trial (useful in debugging) { end_trial(); // local function to stop recording return SKIP_TRIAL; // return this code if trial terminated } /* BUTTON RESPONSE TEST */ // Check for eye-tracker buttons pressed // This is the preferred way to get response data or end trials button = eyelink_last_button_press(NULL); if(button!=0) // button number, or 0 if none pressed { eyemsg_printf("ENDBUTTON %d", button); // message to log the button press end_trial(); // local function to stop recording break; // exit trial loop } // NEW CODE FOR GAZE CONTINGENT WINDOW if(eyelink_newest_float_sample(NULL)>0) // check for new sample update { eyelink_newest_float_sample(&evt); // get the sample x = evt.fs.gx[eye_used]; // yes: get gaze position from sample y = evt.fs.gy[eye_used]; if(x!=MISSING_DATA && y!=MISSING_DATA && evt.fs.pa[eye_used]>0) // make sure pupil is present { if(first_display) // mark display start AFTER first drawing of window { wait_for_video_refresh(); // synchronize before drawing so all seen at once drawing_time = current_msec(); // time of retrace trial_start = drawing_time; // record the display onset time } redraw_gc_window((int)x, (int)y); // move window if visible if(first_display) // mark display start AFTER first drawing of window { first_display = 0; drawing_time = current_msec() - drawing_time; // delay from retrace eyemsg_printf("%d DISPLAY ON", drawing_time); // message for RT recording in analysis eyemsg_printf("SYNCTIME %d", drawing_time); // message marks zero-plot time for EDFVIEW } } else { // Don't move window during blink // To hide window, use: redraw_gc_window(MISSING, MISSING); } } } // END OF RECORDING LOOP end_realtime_mode(); // safety cleanup code while(getkey()); // dump any accumulated key presses // report response result: 0=timeout, else button number eyemsg_printf("TRIAL_RESULT %d", button); // Call this at the end of the trial, to handle special conditions return check_record_exit(); }
int record_mode_display(void) { ALLF_DATA evt; UINT16 key; int eye_used = -1; /* which eye to show gaze for */ float x, y; /* gaze position */ float ox=-1, oy=-1; /* old gaze position (to determine change) */ /* create font for position display */ get_new_font( "Arial", SCRWIDTH/50, 0); while(getkey()); /* dump any pending local keys */ /*enable link data reception without changing tracker mode */ eyelink_reset_data(1); initialize_cursor(window, SCRWIDTH/50); eyelink_data_switch(RECORD_LINK_SAMPLES | RECORD_LINK_EVENTS); while(1) /* loop while in record mode */ { if(eyelink_tracker_mode() != EL_RECORD_MODE) break; key = getkey(); /* Local keys/abort test */ if(key==TERMINATE_KEY) /* test ALT-F4 or end of execution */ break; else if(key) /* OTHER: echo to tracker for control */ eyelink_send_keybutton(key,0,KB_PRESS); /* CODE FOR PLOTTING GAZE CURSOR */ if(eyelink_newest_float_sample(NULL)>0) /* new sample? */ { eyelink_newest_float_sample(&evt); /* get the sample data */ if(eye_used == -1) /* set which eye to track by first sample */ { eye_used = eyelink_eye_available(); if(eye_used == BINOCULAR) /* use left eye if both tracked */ eye_used = LEFT_EYE; } else { x = evt.fs.gx[eye_used]; /* get gaze position from sample */ y = evt.fs.gy[eye_used]; if(x!=MISSING_DATA && y!=MISSING_DATA && evt.fs.pa[eye_used]>0) /* plot if not in blink */ { /* plot in local coords */ draw_gaze_cursor(track2local_x(x), track2local_y(y)); /* report gaze position (tracker coords) */ { SDL_Rect r = {(INT16)(SCRWIDTH*0.87), 0, (INT16)(window->w -SCRWIDTH*0.87), 50}; SDL_FillRect(window,&r,SDL_MapRGB(window->format,0, 0, 0)); graphic_printf(window, target_foreground_color, NONE, (int)(SCRWIDTH*0.87), 0, " %4.0f ", x); graphic_printf(window, target_foreground_color, NONE, (int)(SCRWIDTH*0.93), 0, " %4.0f ", y); } ox = x; oy = y; } else { erase_gaze_cursor(); /* hide cursor during blink */ } /* print tracker timestamp of sample */ { SDL_Rect r = {(INT16)(SCRWIDTH*0.75), 0, (INT16)(SCRWIDTH*0.87 -SCRWIDTH*0.75), 50}; SDL_FillRect(window,&r,SDL_MapRGB(window->format,0, 0, 0)); graphic_printf(window,target_foreground_color, NONE, (int)(SCRWIDTH*0.75), 0, " % 8d ", evt.fs.time); } } } } erase_gaze_cursor(); /* erase gaze cursor if visible */ return 0; }