/// <summary> /// The <see cref="PresenterModule.TrialEventOccured"/> event handler. /// Stores the new trial event into the list. /// </summary> /// <param name="sender"> /// Source of the event. /// </param> /// <param name="e"> /// A <see cref="TrialEventOccuredEventArgs"/> with the event data. /// </param> private void ObjPresenterSlideChanged(object sender, SlideChangedEventArgs e) { if (e.NextSlide.IsDisabled) { return; } long time = this.counterChangedTime - this.recordingStarttime - this.currentTrialStarttime; // Store slide changed event var slideChangedEvent = new MediaEvent { EventID = this.trialEventList.Count, Param = e.SlideCounter + "#" + e.NextSlide.Name, Task = MediaEventTask.Show, Time = time, Type = EventType.Slide, SubjectName = this.currentTracker.Subject.SubjectName, TrialSequence = this.trialSequenceCounter }; if (this.trialSequenceCounter >= 0) { this.trialEventList.Add(slideChangedEvent); this.WriteTrialEventToRawData(slideChangedEvent); } // Store subjects response event var inputEvent = new InputEvent { EventID = this.trialEventList.Count }; if (e.Response != null) { inputEvent.Param = e.Response.ToString(); } inputEvent.SubjectName = this.currentTracker.Subject.SubjectName; inputEvent.Task = InputEventTask.SlideChange; inputEvent.Time = time; inputEvent.TrialSequence = this.trialSequenceCounter; inputEvent.Type = EventType.Response; if (this.trialSequenceCounter >= 0) { this.trialEventList.Add(inputEvent); this.WriteTrialEventToRawData(slideChangedEvent); } this.Invoke(this.delegateNewSlideAvailable); }
/// <summary> /// The <see cref="PresenterModule.TrialChanged"/> event handler. /// Stores the trial information into the database /// and updates the live viewer with the new slide. /// </summary> /// <param name="sender"> /// Source of the event. /// </param> /// <param name="e"> /// A <see cref="TrialChangedEventArgs"/> with the event data. /// </param> private void ObjPresenterTrialChanged(object sender, TrialChangedEventArgs e) { // Set time critical values long currentTime = this.counterChangedTime; this.xScrollOffset = 0; this.yScrollOffset = 0; // If the last trial was a disabled trial (PreFixationSlide) // Only update start times if (e.FinishedTrial[e.FinishedTrial.Count - 1].IsDisabled) { // Update new trial this.currentTrialStarttime = currentTime - this.recordingStarttime; if (this.chbRecordAudio.Checked || this.chbRecordVideo.Checked) { this.currentTrialVideoStartTime = e.WebcamTime; } this.Invoke(this.delegateNewSlideAvailable); return; } if (e.FinishedTrial.Name != "DummyTrial") { // Update current trial this.precedingTrial = e.FinishedTrial; // When rawData list exceeds sample limit or this was the last trial // write the samples into the database if (this.rawDataLists[this.listCounter].Count > MINSAMPLESFORWRITINGTODATABASE || e.NextTrial == null) { // Stop recording if this was the last trial or cancelled if (e.NextTrial == null) { // Stop tracking this.currentTracker.Stop(); // Give the presentation thread time to close. Application.DoEvents(); } // switch to next raw data list for writing lock (this) { // Save copy to dataset table in new thread AsyncHelper.FireAndForget( new WaitCallback(StoreRecordsInDataSetTable), new DataToTable(this.rawDataLists[this.listCounter], this.subjectRawDataTable)); // Clear list, cause its content was copied during creation of DataToTable this.rawDataLists[this.listCounter].Clear(); this.listCounter++; if (this.listCounter == NUMWRITINGTHREADS) { this.listCounter = 0; } } } // Write new trial information var trialData = new TrialsData { SubjectName = this.currentTracker.Subject.SubjectName, TrialName = this.precedingTrial.Name, TrialSequence = this.trialSequenceCounter - 1, TrialID = this.precedingTrial.ID, Category = this.precedingTrial[0].Category, TrialStartTime = this.currentTrialStarttime, Duration = (int)(currentTime - this.recordingStarttime - this.currentTrialStarttime) }; if (this.trialSequenceCounter > 0) { this.trialDataList.Add(trialData); } // Store usercam start event if applicable if (this.chbRecordAudio.Checked || this.chbRecordVideo.Checked) { var usercamVideoEvent = new MediaEvent { EventID = this.trialEventList.Count, Param = this.currentTrialVideoStartTime.ToString(CultureInfo.InvariantCulture), Task = MediaEventTask.Start, Time = 0, Type = EventType.Usercam, SubjectName = this.currentTracker.Subject.SubjectName, TrialSequence = this.trialSequenceCounter - 1 }; if (this.trialSequenceCounter > 0) { this.trialEventList.Add(usercamVideoEvent); } } // Store subjects response event var inputEvent = new InputEvent { EventID = this.trialEventList.Count, SubjectName = this.currentTracker.Subject.SubjectName, Task = InputEventTask.SlideChange, Time = trialData.Duration, TrialSequence = this.trialSequenceCounter - 1, Type = EventType.Response }; if (e.Response != null) { inputEvent.Param = e.Response.ToString(); } if (this.trialSequenceCounter >= 0) { this.trialEventList.Add(inputEvent); } } // Update new trial this.currentTrialStarttime = currentTime - this.recordingStarttime; if (this.chbRecordAudio.Checked || this.chbRecordVideo.Checked) { this.currentTrialVideoStartTime = e.WebcamTime; } // Update recorder modules viewer var updateLiveViewerThread = new Thread(this.NewSlideAvailable); updateLiveViewerThread.SetApartmentState(ApartmentState.STA); updateLiveViewerThread.Start(); }
/// <summary> /// This method scans the <see cref="SlidePresentationContainer.ElementsWithAudioOnClick"/> /// for an element that was clicked and plays it if it was the case. /// </summary> /// <param name="slideContainer"> /// The <see cref="SlidePresentationContainer"/> to search for audio files. /// </param> /// <param name="point"> /// A <see cref="Point"/> with the click location. /// </param> /// <param name="eventTime"> /// A <see cref="Int64"/> with the timestamp of the mouse click. /// </param> private void CheckforAudioStimulusOnClick(SlidePresentationContainer slideContainer, Point point, long eventTime) { foreach (VGElement element in slideContainer.ElementsWithAudioOnClick) { if (element.Contains(point)) { slideContainer.AudioPlayer.AddAudioChannel(element.Sound.FullFilename); if (slideContainer.AudioPlayer.PlayState != PlayState.Running) { slideContainer.AudioPlayer.Play(); } var soundEvent = new MediaEvent(); soundEvent.Type = EventType.Audio; soundEvent.Task = MediaEventTask.Start; soundEvent.Param = Path.GetFileName(element.Sound.Filename); this.OnTrialEventOccured(new TrialEventOccuredEventArgs(soundEvent, eventTime)); break; } } }
/// <summary> /// Overridden <see cref="ProcessCmdKey(ref Message,Keys)"/> method. /// Captures all pressed keys including /// Alt, Ctrl, Space, Esc that are normally not raised as KeyDown in a form. /// </summary> /// <param name="msg"> /// This parameter contains the Windows Message, such as WM_KEYDOWN /// </param> /// <param name="keyData"> /// The keyData parameter contains the key code of the key that was pressed. If CTRL or ALT was also /// pressed, the keyData parameter contains the ModifierKey information. /// </param> /// <returns> /// True if Key should be processed ? /// </returns> protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { const int WM_KEYDOWN = 0x100; const int WM_SYSKEYDOWN = 0x104; if (((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN)) && (!this.closing)) { long eventTime = -1; if (this.getTimeMethod != null) { eventTime = this.getTimeMethod(); } if (this.watch.ElapsedMilliseconds > MINIMUMKEYPRESSINTERVALLMS) { // Check for markers if (keyData == Keys.F12) { // Store marker event var keyEvent = new MediaEvent { Type = EventType.Marker, Task = MediaEventTask.None, Param = string.Empty }; this.OnTrialEventOccured(new TrialEventOccuredEventArgs(keyEvent, eventTime)); } else { this.currentKey = keyData; if (!this.CheckforSlideChange(false)) { // Store key event only when slide has not changed // otherwise the event will be stored during // trialchanged event. var keyEvent = new InputEvent { Type = EventType.Key, Task = InputEventTask.Down }; var ksc = new KeyStopCondition(keyData, false, null); keyEvent.Param = ksc.ToString(); this.OnTrialEventOccured(new TrialEventOccuredEventArgs(keyEvent, eventTime)); } this.watch.Reset(); this.watch.Start(); } } } return base.ProcessCmdKey(ref msg, keyData); }
/// <summary> /// The Scroll event handler of the web Document in which the scroll /// position is sent to the recorder as a trial event. /// </summary> /// <param name="sender"> /// Source of the event. /// </param> /// <param name="e"> /// A <see cref="HtmlElementEventArgs"/> with the event data. /// </param> private void WebBrowserScroll(object sender, EventArgs e) { var browserControl = this.currentVgBrowser.WebBrowser; if (browserControl == null) { return; } if (browserControl.Document == null) { return; } var htmlElement = browserControl.Document.GetElementsByTagName("HTML")[0]; var bodyElement = browserControl.Document.Body; if (bodyElement == null) { return; } var scrollTop = htmlElement.ScrollTop > bodyElement.ScrollTop ? htmlElement.ScrollTop : bodyElement.ScrollTop; var scrollLeft = htmlElement.ScrollLeft > bodyElement.ScrollLeft ? htmlElement.ScrollLeft : bodyElement.ScrollLeft; // Avoid double scroll events. var newScrollPosition = new Point(scrollLeft, scrollTop); if (!this.lastScrollEventPosition.Equals(newScrollPosition)) { this.lastScrollEventPosition = newScrollPosition; long eventTime = -1; if (this.getTimeMethod != null) { eventTime = this.getTimeMethod(); } // Store marker event var scrollEvent = new MediaEvent(); scrollEvent.Type = EventType.Scroll; scrollEvent.Task = MediaEventTask.Seek; scrollEvent.Param = scrollLeft.ToString("N0", this.nfi) + ";" + scrollTop.ToString("N0", this.nfi); this.OnTrialEventOccured(new TrialEventOccuredEventArgs(scrollEvent, eventTime)); } }
/// <summary> /// The <see cref="Control.Click"/> event handler for the /// <see cref="Button"/> <see cref="btnAddMarker"/>. /// User pressed add marker event button, /// so add a trial event at the current time. /// </summary> /// <param name="sender">Source of the event.</param> /// <param name="e">An empty <see cref="EventArgs"/></param> private void btnAddMarker_Click(object sender, EventArgs e) { // Skip if there is no data if (Document.ActiveDocument.SelectionState.SubjectName == null) { return; } long time = this.currentTrialTime; MediaEvent markerEvent = new MediaEvent(); int? maxID = Document.ActiveDocument.DocDataSet.TrialEventsAdapter.GetMaxEventID(); markerEvent.EventID = maxID.HasValue ? maxID.Value + 1 : 0; markerEvent.Param = string.Empty; markerEvent.SubjectName = Document.ActiveDocument.SelectionState.SubjectName; markerEvent.Task = MediaEventTask.None; markerEvent.Time = time; markerEvent.TrialSequence = Document.ActiveDocument.SelectionState.TrialSequence; markerEvent.Type = EventType.Marker; // Insert Data in TrialEvents Table SQLiteOgamaDataSet.TrialEventsRow workTrialEventRow; workTrialEventRow = Document.ActiveDocument.DocDataSet.TrialEvents.NewTrialEventsRow(); workTrialEventRow.EventID = markerEvent.EventID; workTrialEventRow.EventParam = markerEvent.Param; workTrialEventRow.SubjectName = markerEvent.SubjectName; workTrialEventRow.EventTime = markerEvent.Time; workTrialEventRow.TrialSequence = markerEvent.TrialSequence; workTrialEventRow.EventTask = markerEvent.Task.ToString(); workTrialEventRow.EventType = markerEvent.Type.ToString(); Document.ActiveDocument.DocDataSet.TrialEvents.AddTrialEventsRow(workTrialEventRow); // Update Database int affectedRows = Document.ActiveDocument.DocDataSet.TrialEventsAdapter.Update(Document.ActiveDocument.DocDataSet.TrialEvents); this.TrialEvents.Add(markerEvent.EventID, markerEvent); this.trialTimeLine.TrialEvents = this.TrialEvents; }
/// <summary> /// Extracts the events in a sorted trial events list for the given subject and trial /// events data table. /// </summary> /// <param name="subjectName">A <see cref="String"/> with the subject name.</param> /// <param name="table">The trial events data table containing the data from /// the database, can be for one or more trials.</param> /// <param name="usercamID">Out. The event id of the user camera start time.</param> /// <returns>A <see cref="SortedList{Int32, TrialEvent}"/> /// with the events occured in this experiment.</returns> private static SortedList<int, TrialEvent> ExtractEvents( string subjectName, DataTable table, out int usercamID) { usercamID = -1; int lastTrialSequence = -1; long timeToAdd = 0; SortedList<int, TrialEvent> returnList = new SortedList<int, TrialEvent>(); if (table.Rows.Count > 0) { lastTrialSequence = Convert.ToInt32(table.Rows[0]["TrialSequence"]); } foreach (DataRow row in table.Rows) { string typeString = row["EventType"].ToString(); EventType type = EventType.None; try { type = (EventType)Enum.Parse(typeof(EventType), typeString, true); } catch (ArgumentException) { continue; } int trialSequence = Convert.ToInt32(row["TrialSequence"]); if (trialSequence != lastTrialSequence) { DataTable trialTable = Document.ActiveDocument.DocDataSet.TrialsAdapter.GetDataBySubjectAndSequence(subjectName, trialSequence); // Check for deleted trials, but left raw data... if (trialTable.Rows.Count == 0) { continue; } lastTrialSequence = trialSequence; long trialStartTime = Convert.ToInt64(trialTable.Rows[0]["TrialStartTime"]); timeToAdd = trialStartTime; } int eventID = Convert.ToInt32(row["EventID"]); long time = Convert.ToInt64(row["EventTime"]) + timeToAdd; string taskString = row["EventTask"].ToString(); string param = row["EventParam"].ToString(); TrialEvent newEvent = null; switch (type) { case EventType.None: break; case EventType.Mouse: newEvent = new InputEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((InputEvent)newEvent).Task = (InputEventTask)Enum.Parse(typeof(InputEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Key: newEvent = new InputEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((InputEvent)newEvent).Task = (InputEventTask)Enum.Parse(typeof(InputEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Slide: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Flash: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Audio: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Video: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Usercam: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; usercamID = eventID; returnList.Add(eventID, newEvent); break; case EventType.Response: newEvent = new InputEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((InputEvent)newEvent).Task = (InputEventTask)Enum.Parse(typeof(InputEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; if (!returnList.ContainsKey(eventID)) { returnList.Add(eventID, newEvent); } break; case EventType.Marker: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Scroll: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; case EventType.Webpage: newEvent = new MediaEvent(); newEvent.SubjectName = subjectName; newEvent.TrialSequence = trialSequence; newEvent.EventID = eventID; newEvent.Param = param; ((MediaEvent)newEvent).Task = (MediaEventTask)Enum.Parse(typeof(MediaEventTask), taskString, true); newEvent.Time = time; newEvent.Type = type; returnList.Add(eventID, newEvent); break; default: break; } } return returnList; }