Skip to content

Commit

Permalink
allow user to start and escape experiments with keyboard and vr cont…
Browse files Browse the repository at this point in the history
…rollers.
  • Loading branch information
pellet committed Dec 10, 2024
1 parent 192e347 commit 2e899b1
Showing 1 changed file with 80 additions and 5 deletions.
85 changes: 80 additions & 5 deletions eegnb/experiments/Experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from abc import abstractmethod
from typing import Callable
from psychopy import prefs
from psychopy.visual.rift import Rift
#change the pref libraty to PTB and set the latency mode to high precision
prefs.hardware['audioLib'] = 'PTB'
prefs.hardware['audioLatencyMode'] = 3
Expand Down Expand Up @@ -50,8 +51,11 @@ def __init__(self, exp_name, duration, eeg, save_fn, n_trials: int, iti: float,
self.soa = soa
self.jitter = jitter
self.use_vr = use_vr
if use_vr:
# VR interface accessible by specific experiment classes for customizing and using controllers.
self.rift: Rift = visual.Rift(monoscopic=True, headLocked=True)
self.use_fullscr = use_fullscr
self.window_size = [1600,800]
self.window_size = [1600,800]

@abstractmethod
def load_stimulus(self):
Expand Down Expand Up @@ -86,7 +90,7 @@ def setup(self, instructions=True):

# Setting up Graphics
self.window = (
visual.Rift(monoscopic=True, headLocked=True) if self.use_vr
self.rift if self.use_vr
else visual.Window(self.window_size, monitor="testMonitor", units="deg", fullscr=self.use_fullscr))

# Loading the stimulus from the specific experiment, throws an error if not overwritten in the specific experiment
Expand Down Expand Up @@ -123,15 +127,71 @@ def show_instructions(self):
# Disabling the cursor during display of instructions
self.window.mouseVisible = False

# Waiting for the user to press the spacebar to start the experiment
while len(event.getKeys(keyList="space")) == 0:
# clear/reset any old key/controller events
self.__clear_user_input()

# Waiting for the user to press the spacebar or controller button or trigger to start the experiment
while not self.__user_input('start'):
# Displaying the instructions on the screen
text = visual.TextStim(win=self.window, text=self.instruction_text, color=[-1, -1, -1])
self.__draw(lambda: self.__draw_instructions(text))

# Enabling the cursor again
self.window.mouseVisible = True

def __user_input(self, input_type):
if input_type == 'start':
key_input = 'spacebar'
vr_inputs = [
('RightTouch', 'A', True),
('LeftTouch', 'X', True),
('Xbox', 'A', None)
]

elif input_type == 'cancel':
key_input = 'escape'
vr_inputs = [
('RightTouch', 'B', False),
('LeftTouch', 'Y', False),
('Xbox', 'B', None)
]

if len(event.getKeys(keyList=key_input)) > 0:
return True

if self.use_vr:
for controller, button, trigger in vr_inputs:
if self.get_vr_input(controller, button, trigger):
return True

return False

def get_vr_input(self, vr_controller, button=None, trigger=False):
"""
Method that returns True if the user presses the corresponding vr controller button or trigger
Args:
vr_controller: 'Xbox', 'LeftTouch' or 'RightTouch'
button: None, 'A', 'B', 'X' or 'Y'
trigger (bool): Set to True for trigger
Returns:
"""
trigger_squeezed = False
if trigger:
for x in self.rift.getIndexTriggerValues(vr_controller):
if x > 0.0:
trigger_squeezed = True

button_pressed = False
if button is not None:
button_pressed, tsec = self.rift.getButtons([button], vr_controller, 'released')

if trigger_squeezed or button_pressed:
return True

return False

def __draw_instructions(self, text):
text.draw()
self.window.flip()
Expand All @@ -147,6 +207,17 @@ def __draw(self, present_stimulus: Callable):
self.window.setDefaultView()
present_stimulus()

def __clear_user_input(self):
event.getKeys()
self.clear_vr_input()

def clear_vr_input(self):
"""
Clears/resets input events from vr controllers
"""
if self.use_vr:
self.rift.updateInputState()

def run(self, instructions=True):
""" Do the present operation for a bunch of experiments """

Expand All @@ -171,7 +242,11 @@ def iti_with_jitter():

# Current trial being rendered
rendering_trial = -1
while len(event.getKeys()) == 0 and (time() - start) < self.record_duration:

# Clear/reset user input buffer
self.__clear_user_input()

while not self.__user_input('cancel') and (time() - start) < self.record_duration:

current_experiment_seconds = time() - start
# Do not present stimulus until current trial begins(Adhere to inter-trial interval).
Expand Down

0 comments on commit 2e899b1

Please sign in to comment.