def __init__(self, experiment, tracker): """ Constructor Arguments: experiment -- opensesame experiment tracker -- an eyelink instance """ pylink.EyeLinkCustomDisplay.__init__(self) self.experiment = experiment self.my_canvas = canvas(self.experiment) self.my_keyboard = keyboard(self.experiment, timeout=0) self.my_mouse = mouse(self.experiment) self.__target_beep__ = synth(self.experiment, length = 50) self.__target_beep__done__ = synth(self.experiment, freq = 880, length = 200) self.__target_beep__error__ = synth(self.experiment, freq = 220, length = 200) self.state = None self.imagebuffer = array.array('l') self.pal = None self.size = (0,0) self.tmp_file = os.path.join(tempfile.gettempdir(), '__eyelink__.jpg') self.set_tracker(tracker) self.last_mouse_state = -1 self.experiment.eyelink_esc_pressed = False
def _exec(self, focus_widget=None): """<DOC> Executes the form. Keyword arguments: focus_widget -- A widget that is in the form and should receive a # virtual mouse click when the form is opened. This allows # you to activate a text_input right away, for example, so # that the user doesn't have to click on it anymore. Returns: Gives the return value of the form, which depends on how the user has # interacted with the widgets. For example, if the user has pressed a # button, the button text will be returned. </DOC>""" i = 0 self.mouse = mouse(self.experiment) if focus_widget != None: self.render() resp = focus_widget.on_mouse_click(None) if resp != None: return while True: self.render() button, xy, time = self.mouse.get_click(visible=True) pos = self.xy_to_index(xy) if pos != None: w = self.widgets[pos] if w != None: resp = self.widgets[pos].on_mouse_click(xy) if resp != None: return resp
def prepare(self): """The preparation phase of the plug-in goes here.""" # Call the parent constructor. item.prepare(self) # User input self.responses = [self._yes, self._no] self.rows = [2] + [1]*len(self.responses) self.m = mouse(self.experiment) self.c = canvas(self.experiment)
def prepare_response_func(self): """See base_response_item.""" if self._allowed_responses is None: buttonlist = None else: buttonlist = [self.button_code(r) for r in self._allowed_responses] self._mouse = mouse(self.experiment, timeout=self._timeout, buttonlist=buttonlist) return self._mouse.get_click
def run(self): """Run the item""" # Initialize the item self.set_item_onset() self.sri = self.time() self.experiment.set("slider_percent", None) my_canvas = canvas(self.experiment) my_mouse = mouse(self.experiment, timeout=20) # Create the app while True: # Slider dimensions slider_w = self.slider_width slider_h = self.slider_heigth slider_x = self.get("width")/2-slider_w/2 slider_y = self.get("height")/2-slider_h/2 # Determine the slider fill based on the mouse position pos, time = my_mouse.get_pos() x, y = pos slider_fill = min(slider_w, max(0, x-slider_x)) my_canvas.set_bgcolor(self.get("bg_colour")) my_canvas.clear() # Draw the text my_canvas.text(self.get("question"), y=slider_y-100, color=self.get("txt_colour")) my_canvas.text(self.get("accept_text"), y=slider_y+slider_h+50, color=self.get("txt_colour")) # Draw the slider frame my_canvas.set_fgcolor(self.get("fg_colour")) my_canvas.rect(slider_x-1, slider_y-1, slider_w+2, slider_h+2) # Draw the slider fill my_canvas.rect(slider_x, slider_y, slider_fill, slider_h, fill=True, color=self.get("sf_colour")) # Draw the canvas my_canvas.show() # Poll the mouse for buttonclicks button, position, timestamp = my_mouse.get_click(timeout = 20) if button != None: break slider_percent = 100.0*slider_fill/slider_w # Set the response self.experiment.set("response", slider_percent) # Return success return True
def _exec(self, focus_widget=None): """ desc: Executes the form. keywords: focus_widget: desc: A widget that is in the form and should receive a virtual mouse click when the form is opened. This allows you to activate a text_input right away, for example, so that the user doesn't have to click on it anymore. type: [widget, NoneType] returns: desc: Gives the return value of the form, which depends on how the user interacted with the widgets. For example, if the user pressed a button, the button text will be returned. If a timeout occurred, None will be returned. """ self.start_time = None if len(self) == 0: raise osexception(u'The form contains no widgets') self.mouse = mouse(self.experiment, timeout=5) self.mouse.show_cursor() if focus_widget is not None: self.render() if self.timed_out(): self.experiment.var.form_response = None return None resp = focus_widget.on_mouse_click(None) if resp is not None: return while True: self.render() if self.timed_out(): self.experiment.var.form_response = None return None button, xy, time = self.mouse.get_click(visible=True) if xy is None: continue pos = self.xy_to_index(xy) if pos is not None: w = self.widgets[pos] if w is not None: resp = self.widgets[pos].on_mouse_click(xy) if resp is not None: self.experiment.var.form_response = resp return resp self.mouse.hide_cursor()
def prepare_response_func(self): """See base_response_item.""" if self._allowed_responses is None: buttonlist = None else: buttonlist = [self.button_code(r) for r in self._allowed_responses] self._mouse = mouse(self.experiment, timeout=self._timeout, buttonlist=buttonlist) if self.var.get(u'event_type', default=u'mouseclick') == u'mouseclick': return self._mouse.get_click if self.var.event_type == u'mouserelease': return self._mouse.get_click_release raise osexception( u'event_type should be "mouseclick" or "mouserelease"')
def __init__(self, mousebuttonlist=MOUSEBUTTONLIST, timeout=MOUSETIMEOUT, \ visible=False): # See _mouse.basemouse.BaseMouse # try to copy docstring (but ignore it if it fails, as we do # not need it for actual functioning of the code) try: copy_docstr(BaseMouse, OSMouse) except: # we're not even going to show a warning, since the copied # docstring is useful for code editors; these load the docs # in a non-verbose manner, so warning messages would be lost pass self.experiment = osexperiment self.mouse = mouse(self.experiment, buttonlist=mousebuttonlist, \ timeout=timeout)
def mouse(**resp_args): """ desc: | A convenience function that creates a new `mouse` object. For a description of possible keywords, see: - %link:manual/python/mouse% returns: desc: A `mouse` object. type: mouse example: | my_mouse = mouse(keylist=[1,3], timeout=5000) button, time = my_mouse.get_button() """ from openexp.mouse import mouse return mouse(experiment, **resp_args)
def Calibrate_Run(self): slmouse = mouse(self.experiment, timeout=20, visible=True) slmouse.show_cursor(True) slmouse.set_pos(pos=(0,0)) xperc = 0; self.canvas['Slider'].w = (xperc / 100) * ((2 * self.canvas.width / 2.2) - 12) self.canvas.show() while True: # Poll the mouse for buttonclicks button = None while button == None: button, position, timestamp = slmouse.get_click() button = None pos, mtime = slmouse.get_pos() x, y = pos if (x, y) in self.canvas['SliderBox']: xperc = min((x + self.canvas.width / 2.2) / (2 * ((self.canvas.width / 2.2) - 6)) * 100.0,100) self.canvas['Slider'].w = (xperc / 100) * ((2 * self.canvas.width / 2.2) - 12) self.canvas['ValuePerc'].text = "("+str(round(xperc,1)) + "%)" self.canvas['ValuemAh'].text = str(round(5*(xperc/100.0),1)) + "mAh" self.canvas.show() if (x, y) in self.canvas['TestBox']: #self.EE.SetLines(0) self.EE.PulseLines(math.floor((xperc/100.0) * 255), self.var._duration) self.canvas['TestBox'].color = "blue" self.canvas.show() time.sleep(8) self.canvas['TestBox'].color = "red" self.canvas.show() if (x, y) in self.canvas['OKBox']: self.var.ShockerCalibrationBinvalue = math.floor((xperc/100.0) * 255) self.var.ShockerCalibrationmAhvalue = round(5*(xperc/100.0),1) print((self.var.ShockerCalibrationBinvalue,self.var.ShockerCalibrationmAhvalue)) self.experiment.set("ShockerCalibration", self.var.ShockerCalibrationBinvalue) self.experiment.set("ShockermAhCalibration", self.var.ShockerCalibrationmAhvalue) break
def mouse(**resp_args): """ desc: | A convenience function that creates a new `mouse` object. For a description of possible keywords, see: - [/python/mouse/](/python/mouse/) returns: desc: A `mouse` object. type: mouse example: | my_mouse = mouse(keylist=[1,3], timeout=5000) button, time = my_mouse.get_button() """ from openexp.mouse import mouse return mouse(experiment, **resp_args)
def __init__(self, experiment, resolution, data_file="default.edf", fg_color=(255, 255, 255), bg_color=(0, 0, 0), saccade_velocity_threshold=35, saccade_acceleration_threshold=9500): """Initializes the eyelink dummy object""" self.experiment = experiment self.data_file = data_file self.resolution = resolution self.recording = False self.simulator = mouse(self.experiment) self.simulator.set_timeout(timeout=2) self.blinking = False # current 'blinking' condition (MOUSEBUTTONDOWN = eyes closed; MOUSEBUTTONUP = eyes open) self.bbpos = (resolution[0]/2,resolution[1]/2) # before 'blink' position # check if blinking functionality is possible if not hasattr(self.simulator, 'get_pressed') or not hasattr(self.simulator, 'set_poesje'): print("libeyelink_dummy: blink functionality not available due to missing openexp.mouse.get_pressed and/or openexp.mouse.set_pos methods") self.blinkfun = False else: self.blinkfun = True
def run(self): """Run the item""" # Initialize the item self.set_item_onset() self.sri = self.time() self.experiment.set("slider_percent", None) slmouse = mouse(self.experiment, timeout=20) # Run slider while True: # Determine the slider fill based on the mouse position pos, time = slmouse.get_pos() x, y = pos slider_fill = min(self.slider_w, max(0, x-self.slider_x)) # Draw the slider fill self.canvas.rect(self.slider_x, self.slider_y, slider_fill, self.slider_h, fill=True, color=self.get("sf_colour")) # Draw the canvas self.canvas.show() # Reset slider fill self.canvas.rect(self.slider_x, self.slider_y, slider_fill, self.slider_h, fill=True, color=self.get("bg_colour")) # Poll the mouse for buttonclicks button, position, timestamp = slmouse.get_click(timeout = 1) if button != None: break slider_percent = round(100.0 * (float(slider_fill)/float(self.slider_w)),2) # Set the response and response time self.experiment.set("response", slider_percent) # Return success return True
def run(self): mmouse = mouse(self.experiment) mmouse.show_cursor() self.c.show() runner = RunGame(mode=self.var.mode, \ frame = self.experiment.window, \ duration = self.var.duration, \ language = self.lang, \ fullscreen = self.fullscreen, \ show_timer = self.var.show_timer ) gameresults = runner.run()() if gameresults != "keyboard interrupt": cr = self.experiment.var.personal_record if 'personal_record' in self.experiment.var.vars( ) else 0 if self.var.show_feedbacks == 'yes': pr = runner.feedback_screen(gameresults, cr) self.experiment.var.set('personal_record', pr) for k, v in gameresults.iteritems(): self.experiment.var.set(k, v) else: self.experiment.pause()
def _exec(self, logging_resolution=10, timeout=None, reset_mouse=True, start_unit='grid', start_coordinates=(6.0, 4.5), click_required=True, mouse_buttons_allowed=[1, 3], track_clicks=False, max_initiation_time=None, warning_widget=None): # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Calculate start coordinates (if mouse should be reset) if reset_mouse: # Check if start_coordinates are in allowed range if start_unit in ['grid', 'widget']: if start_coordinates[0] > len(self.cols) - 1: raise osexception( 'start x coordinate exceeds number of colums - 1 (first column has value 0)' ) if start_coordinates[1] > len(self.rows) - 1: raise osexception( 'start y coordinate exceeds number of rows - 1 (first row has value 0)' ) # Unit: grid # move mouse cursor to the left upper corner of the grid position # (if float is given, linear interpolation is performed) if start_unit == 'grid': start_index = self.cell_index( (int(start_coordinates[0]), int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) # if form coordinates are provided as float, use linear interpolation # (as internal form function only accepts integers) if isinstance(start_coordinates[0], float): start_index_upper = self.cell_index( (int(start_coordinates[0]) + 1, int(start_coordinates[1]))) startx_upper, y, w, h = self.get_rect(start_index_upper) startx_mouse += int( (startx_upper - startx_mouse) * (start_coordinates[0] - int(start_coordinates[0]))) if isinstance(start_coordinates[1], float): start_index_upper = self.cell_index( (int(start_coordinates[0]), int(start_coordinates[1]) + 1)) x, starty_upper, w, h = self.get_rect(start_index_upper) starty_mouse += int( (starty_upper - starty_mouse) * (start_coordinates[1] - int(start_coordinates[1]))) # Unit: widget # move mouse cursor to the center of the widget for which starting coordinates are provided # (if no widget has the start coordinates for this position, mouse is centered on the position of the grid) elif start_unit == 'widget': start_index = self.cell_index( (int(start_coordinates[0]), int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) startx_mouse += w / 2 starty_mouse += h / 2 # Unit: pixel # move mouse cursor to the position specified in pixel elif start_unit == 'pixel': startx_mouse = start_coordinates[0] starty_mouse = start_coordinates[1] else: raise osexception( 'start_unit should be one of the following: grid, widget, pixel' ) # Convert pixel values to integers startx_mouse = int(startx_mouse) starty_mouse = int(starty_mouse) # Render form self.render() # Initialize mouse self.mouse = mouse(self.experiment, visible=True) # Initialize clock self.clock = self.experiment._clock # Reset mouse (if specified) if reset_mouse: # Set mouse position self.mouse.set_pos((startx_mouse, starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Get mouse position position, timestamp = self.mouse.get_pos() # Set up variables including their first values timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft > 0: # Collect mouse response if timeout == None: # (timeout corresponds to interval with which mouse coordinates are recored) mouse_button, xy, time = self.mouse.get_click( buttonlist=None, timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recored, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click( buttonlist=None, timeout=min([logging_resolution, timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2] - timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp - timestamps[0]) > max_initiation_time: self.set_widget(warning_widget[0], warning_widget[1], colspan=warning_widget[2], rowspan=warning_widget[3]) self.render() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If there was a mouse click, determine the button that was clicked # and if click was on a button, end tracking and finish form # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: pos = self.xy_to_index(position) if pos != None: w = self.widgets[pos] if w != None: resp = self.widgets[pos].on_mouse_click(xy) if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout - (timestamp - timestamps[0]) # Calculate response time resp_time = timestamps[-1] - timestamps[0] # Set form_response variable self.experiment.var.form_response = resp if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def _exec(self, logging_resolution=10, timeout=None, reset_mouse=True, start_unit='grid', start_coordinates=(6.0,4.5), click_required=True, mouse_buttons_allowed=[1,3], track_clicks=False, max_initiation_time=None, warning_widget=None): """Executes MT_form object and returns results. Executes the MT_form object to display the form, collect responses, and return the response, response time, and mouse-tracking data. Args: logging_resolution (int): Time interval (in ms) between recordings of the mouse position. timeout (int): Response timeout (in ms). Use None (default) if there is no timeout. reset_mouse (bool): Reset mouse position when tracking starts. start_coordinates (tuple): The x- and y- coordinates the cursor should be reset to. start_unit (str): The unit used to define the start coordinates. By default ("grid"), it corresponds to the form grid units, and the mouse cursor is reset to the left upper corner of the specified grid position (if a float is given, linear interpolation is performed). An alternative that also uses the form grid unit is "widget", whereby the mouse cursor is reset to the center of the widget for which starting coordinates are provided (if no widget has the start coordinates for this position, the mouse is centered on the position of the grid). Finally, "pixel" can be used to specify the start coordinates in pixel metric (in sketchpad metric). click_required (bool): Click required to indicate response. If False, a response can be indicated just by entering the area of one of the buttons with the mouse. mouse_buttons_allowed (list): The (physical) mouse buttons that can be used to click one of the buttons. track_clicks (bool): Enable separate tracking of mouse clicks. If True, the physical mouse button that was clicked will be returned along with a corresponding timestamp as a separate list. max_initiation_time (int): If specified, a custom warning message will be displayed if no mouse movement was initiated after the specified time limit (in ms). warning_widget (list): Custom widget that is displayed if the initiation time is exceeded. A list containing all the arguments required by the form.set_widget function. Returns: resp (str): The text of the buttton that was clicked. resp_time (int): Response time (in ms). initiation_time (int): Time (in ms) until a movement was initiated. timestamps (list): Timestamps (in ms) for each recorded position. xpos (list): x-positions for each recorded position. ypos (list): y-positions for each recorded position. clicks (list): (Physical) mouse button for each mouse click. Only returned if track_clicks is True. clicks_timestamps (list): Timestamp (in ms) for each mouse click. Only returned if track_clicks is True. """ # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Calculate start coordinates (if mouse should be reset) if reset_mouse: # Check if start_coordinates are in allowed range if start_unit in ['grid', 'widget']: if start_coordinates[0] > len(self.cols)-1: raise osexception('start x coordinate exceeds number of colums - 1 (first column has value 0)') if start_coordinates[1] > len(self.rows)-1: raise osexception('start y coordinate exceeds number of rows - 1 (first row has value 0)') # Unit: grid # move mouse cursor to the left upper corner of the grid position # (if float is given, linear interpolation is performed) if start_unit=='grid': start_index = self.cell_index((int(start_coordinates[0]),int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) # if form coordinates are provided as float, use linear interpolation # (as internal form function only accepts integers) if isinstance(start_coordinates[0], float): start_index_upper = self.cell_index((int(start_coordinates[0])+1,int(start_coordinates[1]))) startx_upper, y, w, h = self.get_rect(start_index_upper) startx_mouse += int((startx_upper-startx_mouse) * (start_coordinates[0]-int(start_coordinates[0]))) if isinstance(start_coordinates[1], float): start_index_upper = self.cell_index((int(start_coordinates[0]),int(start_coordinates[1])+1)) x, starty_upper, w, h = self.get_rect(start_index_upper) starty_mouse += int((starty_upper-starty_mouse) * (start_coordinates[1]-int(start_coordinates[1]))) # Unit: widget # move mouse cursor to the center of the widget for which starting coordinates are provided # (if no widget has the start coordinates for this position, mouse is centered on the position of the grid) elif start_unit=='widget': start_index = self.cell_index((int(start_coordinates[0]),int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) startx_mouse += w/2 starty_mouse += h/2 # Unit: pixel # move mouse cursor to the position specified in pixel elif start_unit=='pixel': startx_mouse = start_coordinates[0] starty_mouse = start_coordinates[1] else: raise osexception('start_unit should be one of the following: grid, widget, pixel') # Convert pixel values to integers startx_mouse = int(startx_mouse) starty_mouse = int(starty_mouse) # Render form self.render() # Initialize mouse self.mouse = mouse(self.experiment,visible=True) # Initialize clock self.clock = self.experiment._clock # Reset mouse (if specified) if reset_mouse: # Set mouse position self.mouse.set_pos((startx_mouse,starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Get mouse position position, timestamp = self.mouse.get_pos() # Set up variables including their first values timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft>0: # Collect mouse response if timeout==None: # (timeout corresponds to interval with which mouse coordinates are recored) mouse_button, xy, time = self.mouse.get_click(buttonlist=None,timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recored, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click(buttonlist=None,timeout=min([logging_resolution,timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2]-timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp-timestamps[0])>max_initiation_time: self.set_widget(warning_widget[0],warning_widget[1],colspan=warning_widget[2],rowspan=warning_widget[3]) self.render() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If there was a mouse click, determine the button that was clicked # and if click was on a button, end tracking and finish form # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: pos = self.xy_to_index(position) if pos != None: w = self.widgets[pos] if w != None: resp = self.widgets[pos].on_mouse_click(xy) if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout-(timestamp-timestamps[0]) # Calculate response time resp_time = timestamps[-1]-timestamps[0] # Set form_response variable self.experiment.var.form_response = resp if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def _exec(self, focus_widget=None): """ desc: Executes the form. keywords: focus_widget: desc: A widget that is in the form and should receive a virtual mouse click when the form is opened. This allows you to activate a text_input right away, for example, so that the user doesn't have to click on it anymore. type: [widget, NoneType] returns: desc: Gives the return value of the form, which depends on how the user interacted with the widgets. For example, if the user pressed a button, the button text will be returned. If a timeout occurred, None will be returned. """ if isinstance(focus_widget, WidgetFactory): focus_widget = focus_widget.construct(self) if len(self) == 0: raise osexception(u'The form contains no widgets') ms = mouse(self.experiment, timeout=0) ms.show_cursor() kb = keyboard(self.experiment, timeout=0) kb.show_virtual_keyboard() coroutines = {w: w.coroutine() for w in self.widgets if w is not None} for coroutine in coroutines.values(): coroutine.send(None) self.canvas.show() self.start_time = None mousedown = False while True: if self.timed_out(): resp = None break msg = None # Handle mouse clicks, including waiting until the mouse is released # after a mouse click. if mousedown: while any(ms.get_pressed()): pass mousedown = False button, xy, timestamp = ms.get_click(visible=True) if button is not None: mousedown = True # Switch the focus to the newly clicked widget (if any) widget = self.xy_to_widget(xy) if widget is None: continue if focus_widget is not None: focus_widget.focus = False widget.focus = True focus_widget = widget msg = { u'type': u'click', u'pos': xy, u'button': button, u'timestamp': timestamp } # Handle key presses clicks elif focus_widget is not None: key, timestamp = kb.get_key() if key is not None: msg = { u'type': u'key', u'key': key, u'timestamp': timestamp } # Send message (if any) if msg is None: continue resp = coroutines[focus_widget].send(msg) self.canvas.show() if resp is not None and self._validator(): break kb.show_virtual_keyboard(False) ms.show_cursor(False) for coroutine in coroutines.values(): try: coroutine.send({u'type': u'stop'}) except StopIteration: pass self.experiment.var.form_response = resp return resp
from openexp.mouse import mouse from openexp.canvas import canvas from openexp.keyboard import keyboard from openexp.sampler import sampler from random import random, shuffle # variables myMouse = mouse(exp, visible=True) index = 99 myCanvas = self.copy_sketchpad('planche1') myKeyboard = keyboard(exp, timeout=None) cases = [] for i in range(30): cases.append(0) startTime = self.time() totalTime = 0 interval = False complexity = False # true = easy duration = False # true = quick Interruption = False clicks = 0 numberInterruptions2 = 0 clickTrigger = clicks[numberInterruptions2] goodClicks = 0 isInterruption = False hasEndInterruption = False endInterruption = False currentInterruption = 0 displayResponseTime = 500 displayNumberTime = 1000
def _exec(self, logging_resolution=10, timeout=None, boundaries={'upper':None,'lower':None,'left':None,'right':None}, reset_mouse=True, start_coordinates=(0,0), click_required=True, mouse_buttons_allowed=[1, 3], track_clicks=False, max_initiation_time=None, warning_textline=None): """Executes MT_response object and returns results. Executes the MT_response object and returns the response, response time, and mouse-tracking data. Args: logging_resolution (int): Time interval (in ms) between recordings of the mouse position. timeout (int): Response timeout (in ms). Use None (default) if there is no timeout. boundaries (dict): Contains optional vertical and horizontal boundaries. Tracking stops if the cursor moves beyond one of these. reset_mouse (bool): Reset mouse position when tracking starts. start_coordinates (tuple): The x- and y- coordinates (in sketchpad metric) the cursor should be reset to. click_required (bool): Click required to indicate response. If False, a response can be indicated just by entering the area of one of the buttons with the mouse. mouse_buttons_allowed (list): The (physical) mouse buttons that can be used to click one of the buttons. track_clicks (bool): Enable separate tracking of mouse clicks. If True, the physical mouse button that was clicked will be returned along with a corresponding timestamp as a separate list. max_initiation_time (int): If specified, a custom warning message will be displayed if no mouse movement was initiated after the specified time limit (in ms). warning_textline (list): Custom warning message to be displayed. List containing the name of the currently displayed canvas/sketchpad as the first element and input for the canvas.text function as the second argument. Returns: resp (str): The name (key) of the buttton that was clicked. resp_time (int): Response time (in ms). initiation_time (int): Time (in ms) until a movement was initiated. timestamps (list): Timestamps (in ms) for each recorded position. xpos (list): x-positions for each recorded position. ypos (list): y-positions for each recorded position. clicks (list): (Physical) mouse button for each mouse click. Only returned if track_clicks is True. clicks_timestamps (list): Timestamp (in ms) for each mouse click. Only returned if track_clicks is True. """ # Initialize mouse self.mouse = mouse(self.experiment, visible=True) # Initialize clock self.clock = self.experiment._clock # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Check if any boundary values are specified check_boundaries = any(val!=None for val in boundaries.values()) # Check if timeout or boundaries are specified in case there are no buttons if self.buttons == None: if timeout == None and check_boundaries == False: raise osexception('As no buttons are specified, either a timeout or boundaries have to be specified.') # Prepare boundaries if boundary values are specified if check_boundaries: check_boundaries_x = False if any(boundaries[label] != None for label in ['left', 'right']): check_boundaries_x = True boundaries_x = [-float('Inf'), float('Inf')] if boundaries['left'] != None: boundaries_x[0] = int(boundaries['left']) if boundaries['right'] != None: boundaries_x[1] = int(boundaries['right']) check_boundaries_y = False if any(boundaries[label] != None for label in ['upper', 'lower']): check_boundaries_y = True boundaries_y = [-float('Inf'), float('Inf')] # As OpenSesame's screen coordinates increase when mouse moves toward the bottom of the screen # assign the value of 'upper' boundary as the lower value (and vice versa) if boundaries['upper'] != None: boundaries_y[0] = int(boundaries['upper']) if boundaries['lower'] != None: boundaries_y[1] = int(boundaries['lower']) # Reset mouse (if specified) if reset_mouse: # Move mouse cursor to the position specified in pixel startx_mouse = int(start_coordinates[0]) starty_mouse = int(start_coordinates[1]) # Set mouse position self.mouse.set_pos((startx_mouse, starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Set up variables including their first values position, timestamp = self.mouse.get_pos() timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft > 0: # Collect mouse response if timeout==None: # (timeout corresponds to interval with which mouse coordinates are recorded) mouse_button, xy, time = self.mouse.get_click(buttonlist=None, timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recorded, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click(buttonlist=None, timeout=min([logging_resolution, timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2]-timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp-timestamps[0]) > max_initiation_time: warning_canvas = self.experiment.items[warning_textline[0]].canvas warning_canvas.text(**warning_textline[1]) warning_canvas.show() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If boundaries should be checked, determine if mouse position is outside the boundaries if check_boundaries: if check_boundaries_x: if position[0] < boundaries_x[0] or position[0] > boundaries_x[1]: tracking = False if check_boundaries_y: if position[1] < boundaries_y[0] or position[1] > boundaries_y[1]: tracking = False # If there was a mouse click, determine if the click was in the range of one of the "buttons" # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: if self.buttons != None: if position != None: resp = None for button in self.buttons: vals = self.buttons[button] if position[0] >= vals[0] and position[0] <= vals[2] and position[1] >= vals[1] and position[1] <= vals[3]: resp = button if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout-(timestamp-timestamps[0]) # Calculate response time resp_time = timestamps[-1] - timestamps[0] if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def run(self): """The run phase of the plug-in goes here.""" # self.set_item_onset() sets the time_[item name] variable. Optionally, # you can pass a timestamp, such as returned by canvas.show(). # self.set_item_onset(self.c.show()) # The following is the opening screen of the experiment # Needs a good bit of work exp = self.experiment from openexp.mouse import mouse from openexp.canvas import canvas from openexp.keyboard import keyboard import urllib # import socket # import errno import os import time # Using more than one timing method? from pygame.mouse import get_pressed from random import randint subject_number = randint(1, 99999) try: import android except ImportError: android = None # Define global variables/methods my_mouse = mouse(exp, visible=True) self.c = canvas(exp, auto_prepare=False) self.c = canvas(self.experiment, self.get(u"background"), self.get(u"foreground")) my_keyboard = keyboard(exp) exp.set("run_experiment", 1) global my_mouse, my_canvas, my_keyboard, urllib, event global pickle, os, android, time, get_pressed, subject_number # print 'Path = '+str(os.path.curdir) sdcard_folders = ["/sdcard/", "/mnt/sdcard/"] for path in sdcard_folders: if os.path.isdir(path): print path break if os.path.exists(os.path.join(path, "datafile.txt")): data_path = os.path.join(path, "datafile.txt") elif os.path.exists("datafile.txt"): data_path = "datafile.txt" else: data_path = None global data_path if data_path: print "Unsent data detected" my_canvas.clear() self.c.text("Unsent data detected. Send now?") self.c.text("Yes", x=150, y=125) self.c.text("No", x=1050, y=125) self.c.show() while 1: button, position, timestamp = my_mouse.get_click() x, y = position if x < 350 and y < 200: # Yes try: print "Opening data..." execfile(data_path) global data_log print "Opened" # Try to send it send_data(data_log, True) except IOError as e: self.c.clear() self.c.text("No data found.\nTap to continue.") # Hopefully, this doesn't happen! self.c.show() my_mouse.get_click() break if x > 930 and y < 200: # No # This overwrites old data. # Add a warning about this. break self.c.clear() self.c.text("Continue to experiment?") self.c.text("Yes", x=150, y=125) self.c.text("No", x=1050, y=125) self.c.show() waiting = True while waiting: button, position, timestamp = my_mouse.get_click() x, y = position if x < 350 and y < 200: exp.set("run_experiment", 1) break if x > 930 and y < 200: exp.set("run_experiment", 0) break data_log = [] trial_id = 0 global data_log, trial_id
def _exec(self, logging_resolution=10, timeout=None, boundaries={ 'upper': None, 'lower': None, 'left': None, 'right': None }, reset_mouse=True, start_coordinates=(0, 0), click_required=True, mouse_buttons_allowed=[1, 3], track_clicks=False, max_initiation_time=None, warning_textline=None): # Initialize mouse self.mouse = mouse(self.experiment, visible=True) # Initialize clock self.clock = self.experiment._clock # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Check if any boundary values are specified check_boundaries = any(val != None for val in boundaries.values()) # Check if timeout or boundaries are specified in case there are no buttons if self.buttons == None: if timeout == None and check_boundaries == False: raise osexception( 'As no buttons are specified, either a timeout or boundaries have to be specified.' ) # Prepare boundaries if boundary values are specified if check_boundaries: check_boundaries_x = False if any(boundaries[label] != None for label in ['left', 'right']): check_boundaries_x = True boundaries_x = [-float('Inf'), float('Inf')] if boundaries['left'] != None: boundaries_x[0] = int(boundaries['left']) if boundaries['right'] != None: boundaries_x[1] = int(boundaries['right']) check_boundaries_y = False if any(boundaries[label] != None for label in ['upper', 'lower']): check_boundaries_y = True boundaries_y = [-float('Inf'), float('Inf')] # As OpenSesame's screen coordinates increase when mouse moves toward the bottom of the screen # assign the value of 'upper' boundary as the lower value (and vice versa) if boundaries['upper'] != None: boundaries_y[0] = int(boundaries['upper']) if boundaries['lower'] != None: boundaries_y[1] = int(boundaries['lower']) # Reset mouse (if specified) if reset_mouse: # Move mouse cursor to the position specified in pixel startx_mouse = int(start_coordinates[0]) starty_mouse = int(start_coordinates[1]) # Set mouse position self.mouse.set_pos((startx_mouse, starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Set up variables including their first values position, timestamp = self.mouse.get_pos() timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft > 0: # Collect mouse response if timeout == None: # (timeout corresponds to interval with which mouse coordinates are recorded) mouse_button, xy, time = self.mouse.get_click( buttonlist=None, timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recorded, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click( buttonlist=None, timeout=min([logging_resolution, timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2] - timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp - timestamps[0]) > max_initiation_time: warning_canvas = self.experiment.items[ warning_textline[0]].canvas warning_canvas.text(**warning_textline[1]) warning_canvas.show() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If boundaries should be checked, determine if mouse position is outside the boundaries if check_boundaries: if check_boundaries_x: if position[0] < boundaries_x[0] or position[ 0] > boundaries_x[1]: tracking = False if check_boundaries_y: if position[1] < boundaries_y[0] or position[ 1] > boundaries_y[1]: tracking = False # If there was a mouse click, determine if the click was in the range of one of the "buttons" # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: if self.buttons != None: if position != None: resp = None for button in self.buttons: vals = self.buttons[button] if position[0] >= vals[0] and position[0] <= vals[ 2] and position[1] >= vals[1] and position[ 1] <= vals[3]: resp = button if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout - (timestamp - timestamps[0]) # Calculate response time resp_time = timestamps[-1] - timestamps[0] if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def _exec(self, logging_resolution=10,timeout=None, reset_mouse=True,start_unit='grid',start_coordinates=(6.0,4.5), click_required=True,mouse_buttons_allowed=[1,3], track_clicks=False, max_initiation_time=None,warning_widget=None): # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Calculate start coordinates (if mouse should be reset) if reset_mouse: # Check if start_coordinates are in allowed range if start_unit in ['grid', 'widget']: if start_coordinates[0] > len(self.cols)-1: raise osexception('start x coordinate exceeds number of colums - 1 (first column has value 0)') if start_coordinates[1] > len(self.rows)-1: raise osexception('start y coordinate exceeds number of rows - 1 (first row has value 0)') # Unit: grid # move mouse cursor to the left upper corner of the grid position # (if float is given, linear interpolation is performed) if start_unit=='grid': start_index = self.cell_index((int(start_coordinates[0]),int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) # if form coordinates are provided as float, use linear interpolation # (as internal form function only accepts integers) if isinstance(start_coordinates[0], float): start_index_upper = self.cell_index((int(start_coordinates[0])+1,int(start_coordinates[1]))) startx_upper, y, w, h = self.get_rect(start_index_upper) startx_mouse += int((startx_upper-startx_mouse) * (start_coordinates[0]-int(start_coordinates[0]))) if isinstance(start_coordinates[1], float): start_index_upper = self.cell_index((int(start_coordinates[0]),int(start_coordinates[1])+1)) x, starty_upper, w, h = self.get_rect(start_index_upper) starty_mouse += int((starty_upper-starty_mouse) * (start_coordinates[1]-int(start_coordinates[1]))) # Unit: widget # move mouse cursor to the center of the widget for which starting coordinates are provided # (if no widget has the start coordinates for this position, mouse is centered on the position of the grid) elif start_unit=='widget': start_index = self.cell_index((int(start_coordinates[0]),int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) startx_mouse += w/2 starty_mouse += h/2 # Unit: pixel # move mouse cursor to the position specified in pixel elif start_unit=='pixel': startx_mouse = start_coordinates[0] starty_mouse = start_coordinates[1] else: raise osexception('start_unit should be one of the following: grid, widget, pixel') # Convert pixel values to integers startx_mouse = int(startx_mouse) starty_mouse = int(starty_mouse) # Render form self.render() # Initialize mouse self.mouse = mouse(self.experiment,visible=True) # Initialize clock self.clock = self.experiment._clock # Reset mouse (if specified) if reset_mouse: # Set mouse position self.mouse.set_pos((startx_mouse,starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Get mouse position position, timestamp = self.mouse.get_pos() # Set up variables including their first values timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft>0: # Collect mouse response if timeout==None: # (timeout corresponds to interval with which mouse coordinates are recored) mouse_button, xy, time = self.mouse.get_click(buttonlist=None,timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recored, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click(buttonlist=None,timeout=min([logging_resolution,timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2]-timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp-timestamps[0])>max_initiation_time: self.set_widget(warning_widget[0],warning_widget[1],colspan=warning_widget[2],rowspan=warning_widget[3]) self.render() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If there was a mouse click, determine the button that was clicked # and if click was on a button, end tracking and finish form # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: pos = self.xy_to_index(position) if pos != None: w = self.widgets[pos] if w != None: resp = self.widgets[pos].on_mouse_click(xy) if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout-(timestamp-timestamps[0]) # Calculate response time resp_time = timestamps[-1]-timestamps[0] # Set form_response variable self.experiment.var.form_response = resp if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def _exec(self, logging_resolution=10, timeout=None, boundaries={'upper':None,'lower':None,'left':None,'right':None}, reset_mouse=True, start_coordinates=(0,0), click_required=True, mouse_buttons_allowed=[1, 3], track_clicks=False, max_initiation_time=None, warning_textline=None): """Executes MT_response object and returns results. Executes the MT_response object and returns the response, response time, and mouse-tracking data. Args: logging_resolution (int): Time interval (in ms) between recordings of the mouse position. timeout (int): Response timeout (in ms). Use None (default) if there is no timeout. boundaries (dict): Contains optional vertical and horizontal boundaries. Tracking stops if the cursor moves beyond one of these. reset_mouse (bool): Reset mouse position when tracking starts. start_coordinates (tuple): The x- and y- coordinates (in sketchpad metric) the cursor should be reset to. click_required (bool): Click required to indicate response. If False, a response can be indicated just by entering the area of one of the buttons with the mouse. mouse_buttons_allowed (list): The (physical) mouse buttons that can be used to click one of the buttons. track_clicks (bool): Enable separate tracking of mouse clicks. If True, the physical mouse button that was clicked will be returned along with a corresponding timestamp as a separate list. max_initiation_time (int): If specified, a custom warning message will be displayed if no mouse movement was initiated after the specified time limit (in ms). warning_textline (list): Custom warning message to be displayed. List containing the name of the currently displayed canvas/sketchpad as the first element and input for the canvas.text function as the second argument. Returns: resp (str): The name (key) of the buttton that was clicked. resp_time (int): Response time (in ms). initiation_time (int): Time (in ms) until a movement was initiated. timestamps (list): Timestamps (in ms) for each recorded position. xpos (list): x-positions for each recorded position. ypos (list): y-positions for each recorded position. clicks (list): (Physical) mouse button for each mouse click. Only returned if track_clicks is True. clicks_timestamps (list): Timestamp (in ms) for each mouse click. Only returned if track_clicks is True. """ # Initialize mouse self.mouse = mouse(self.experiment, visible=True) self.mouse.show_cursor(show=True) # Initialize clock self.clock = self.experiment._clock # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Check if any boundary values are specified check_boundaries = any(val!=None for val in boundaries.values()) # Check if timeout or boundaries are specified in case there are no buttons if self.buttons == None: if timeout == None and check_boundaries == False: raise osexception('As no buttons are specified, either a timeout or boundaries have to be specified.') # Prepare boundaries if boundary values are specified if check_boundaries: check_boundaries_x = False if any(boundaries[label] != None for label in ['left', 'right']): check_boundaries_x = True boundaries_x = [-float('Inf'), float('Inf')] if boundaries['left'] != None: boundaries_x[0] = int(boundaries['left']) if boundaries['right'] != None: boundaries_x[1] = int(boundaries['right']) check_boundaries_y = False if any(boundaries[label] != None for label in ['upper', 'lower']): check_boundaries_y = True boundaries_y = [-float('Inf'), float('Inf')] # As OpenSesame's screen coordinates increase when mouse moves toward the bottom of the screen # assign the value of 'upper' boundary as the lower value (and vice versa) if boundaries['upper'] != None: boundaries_y[0] = int(boundaries['upper']) if boundaries['lower'] != None: boundaries_y[1] = int(boundaries['lower']) # Reset mouse (if specified) if reset_mouse: # Move mouse cursor to the position specified in pixel startx_mouse = int(start_coordinates[0]) starty_mouse = int(start_coordinates[1]) # Set mouse position self.mouse.set_pos((startx_mouse, starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Set up variables including their first values position, timestamp = self.mouse.get_pos() timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft > 0: # Collect mouse response if timeout==None: # (timeout corresponds to interval with which mouse coordinates are recorded) mouse_button, xy, time = self.mouse.get_click(buttonlist=None, timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recorded, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click(buttonlist=None, timeout=min([logging_resolution, timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2]-timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp-timestamps[0]) > max_initiation_time: warning_canvas = self.experiment.items[warning_textline[0]].canvas warning_canvas.text(**warning_textline[1]) warning_canvas.show() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If boundaries should be checked, determine if mouse position is outside the boundaries if check_boundaries: if check_boundaries_x: if position[0] < boundaries_x[0] or position[0] > boundaries_x[1]: tracking = False if check_boundaries_y: if position[1] < boundaries_y[0] or position[1] > boundaries_y[1]: tracking = False # If there was a mouse click, determine if the click was in the range of one of the "buttons" # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: if self.buttons != None: if position != None: resp = None for button in self.buttons: vals = self.buttons[button] if position[0] >= vals[0] and position[0] <= vals[2] and position[1] >= vals[1] and position[1] <= vals[3]: resp = button if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout-(timestamp-timestamps[0]) # Calculate response time resp_time = timestamps[-1] - timestamps[0] if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def _exec(self, logging_resolution=10,timeout=None, boundaries = {'upper':None,'lower':None,'left':None,'right':None}, reset_mouse=True,start_coordinates=(0,0), click_required=True,mouse_buttons_allowed=[1,3], track_clicks=False, max_initiation_time=None,warning_textline=None): # Initialize mouse self.mouse = mouse(self.experiment,visible=True) # Initialize clock self.clock = self.experiment._clock # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Check if any boundary values are specified check_boundaries = any(val!=None for val in boundaries.values()) # Check if timeout or boundaries are specified in case there are no buttons if self.buttons == None: if timeout == None and check_boundaries == False: raise osexception('As no buttons are specified, either a timeout or boundaries have to be specified.') # Prepare boundaries if boundary values are specified if check_boundaries: check_boundaries_x = False if any(boundaries[label]!= None for label in ['left','right']): check_boundaries_x = True boundaries_x = [-float('Inf'),float('Inf')] if boundaries['left'] != None: boundaries_x[0] = int(boundaries['left']) if boundaries['right'] != None: boundaries_x[1] = int(boundaries['right']) check_boundaries_y = False if any(boundaries[label]!= None for label in ['upper','lower']): check_boundaries_y = True boundaries_y = [-float('Inf'),float('Inf')] # As OpenSesame's screen coordinates increase when mouse moves toward the bottom of the screen # assign the value of 'upper' boundary as the lower value (and vice versa) if boundaries['upper'] != None: boundaries_y[0] = int(boundaries['upper']) if boundaries['lower'] != None: boundaries_y[1] = int(boundaries['lower']) # Reset mouse (if specified) if reset_mouse: # Move mouse cursor to the position specified in pixel startx_mouse = int(start_coordinates[0]) starty_mouse = int(start_coordinates[1]) # Set mouse position self.mouse.set_pos((startx_mouse,starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Set up variables including their first values position, timestamp = self.mouse.get_pos() timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft>0: # Collect mouse response if timeout==None: # (timeout corresponds to interval with which mouse coordinates are recorded) mouse_button, xy, time = self.mouse.get_click(buttonlist=None,timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recorded, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click(buttonlist=None,timeout=min([logging_resolution,timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2]-timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp-timestamps[0])>max_initiation_time: warning_canvas = self.experiment.items[warning_textline[0]].canvas warning_canvas.text(**warning_textline[1]) warning_canvas.show() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If boundaries should be checked, determine if mouse position is outside the boundaries if check_boundaries: if check_boundaries_x: if position[0] < boundaries_x[0] or position[0] > boundaries_x[1]: tracking = False if check_boundaries_y: if position[1] < boundaries_y[0] or position[1] > boundaries_y[1]: tracking = False # If there was a mouse click, determine if the click was in the range of one of the "buttons" # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: if self.buttons != None: if position != None: resp = None for button in self.buttons: vals = self.buttons[button] if position[0]>=vals[0] and position[0]<=vals[2] and position[1]>=vals[1] and position[1]<=vals[3]: resp = button if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout-(timestamp-timestamps[0]) # Calculate response time resp_time = timestamps[-1]-timestamps[0] if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps
def _exec(self, logging_resolution=10, timeout=None, reset_mouse=True, start_unit='grid', start_coordinates=(6.0, 4.5), click_required=True, mouse_buttons_allowed=[1, 3], track_clicks=False, max_initiation_time=None, warning_widget=None): """Executes MT_form object and returns results. Executes the MT_form object to display the form, collect responses, and return the response, response time, and mouse-tracking data. Args: logging_resolution (int): Time interval (in ms) between recordings of the mouse position. timeout (int): Response timeout (in ms). Use None (default) if there is no timeout. reset_mouse (bool): Reset mouse position when tracking starts. start_coordinates (tuple): The x- and y- coordinates the cursor should be reset to. start_unit (str): The unit used to define the start coordinates. By default ("grid"), it corresponds to the form grid units, and the mouse cursor is reset to the left upper corner of the specified grid position (if a float is given, linear interpolation is performed). An alternative that also uses the form grid unit is "widget", whereby the mouse cursor is reset to the center of the widget for which starting coordinates are provided (if no widget has the start coordinates for this position, the mouse is centered on the position of the grid). Finally, "pixel" can be used to specify the start coordinates in pixel metric (in sketchpad metric). click_required (bool): Click required to indicate response. If False, a response can be indicated just by entering the area of one of the buttons with the mouse. mouse_buttons_allowed (list): The (physical) mouse buttons that can be used to click one of the buttons. track_clicks (bool): Enable separate tracking of mouse clicks. If True, the physical mouse button that was clicked will be returned along with a corresponding timestamp as a separate list. max_initiation_time (int): If specified, a custom warning message will be displayed if no mouse movement was initiated after the specified time limit (in ms). warning_widget (list): Custom widget that is displayed if the initiation time is exceeded. A list containing all the arguments required by the form.set_widget function. Returns: resp (str): The text of the buttton that was clicked. resp_time (int): Response time (in ms). initiation_time (int): Time (in ms) until a movement was initiated. timestamps (list): Timestamps (in ms) for each recorded position. xpos (list): x-positions for each recorded position. ypos (list): y-positions for each recorded position. clicks (list): (Physical) mouse button for each mouse click. Only returned if track_clicks is True. clicks_timestamps (list): Timestamp (in ms) for each mouse click. Only returned if track_clicks is True. """ # Specify timeout settings if timeout != None: timeout = int(timeout) timeleft = timeout else: timeleft = logging_resolution # Calculate start coordinates (if mouse should be reset) if reset_mouse: # Check if start_coordinates are in allowed range if start_unit in ['grid', 'widget']: if start_coordinates[0] > len(self.cols) - 1: raise osexception( 'start x coordinate exceeds number of colums - 1 (first column has value 0)' ) if start_coordinates[1] > len(self.rows) - 1: raise osexception( 'start y coordinate exceeds number of rows - 1 (first row has value 0)' ) # Unit: grid # move mouse cursor to the left upper corner of the grid position # (if float is given, linear interpolation is performed) if start_unit == 'grid': start_index = self.cell_index( (int(start_coordinates[0]), int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) # if form coordinates are provided as float, use linear interpolation # (as internal form function only accepts integers) if isinstance(start_coordinates[0], float): start_index_upper = self.cell_index( (int(start_coordinates[0]) + 1, int(start_coordinates[1]))) startx_upper, y, w, h = self.get_rect(start_index_upper) startx_mouse += int( (startx_upper - startx_mouse) * (start_coordinates[0] - int(start_coordinates[0]))) if isinstance(start_coordinates[1], float): start_index_upper = self.cell_index( (int(start_coordinates[0]), int(start_coordinates[1]) + 1)) x, starty_upper, w, h = self.get_rect(start_index_upper) starty_mouse += int( (starty_upper - starty_mouse) * (start_coordinates[1] - int(start_coordinates[1]))) # Unit: widget # move mouse cursor to the center of the widget for which starting coordinates are provided # (if no widget has the start coordinates for this position, mouse is centered on the position of the grid) elif start_unit == 'widget': start_index = self.cell_index( (int(start_coordinates[0]), int(start_coordinates[1]))) startx_mouse, starty_mouse, w, h = self.get_rect(start_index) startx_mouse += w / 2 starty_mouse += h / 2 # Unit: pixel # move mouse cursor to the position specified in pixel elif start_unit == 'pixel': startx_mouse = start_coordinates[0] starty_mouse = start_coordinates[1] else: raise osexception( 'start_unit should be one of the following: grid, widget, pixel' ) # Convert pixel values to integers startx_mouse = int(startx_mouse) starty_mouse = int(starty_mouse) # Render form self.render() # Initialize mouse self.mouse = mouse(self.experiment, visible=True) # Initialize clock self.clock = self.experiment._clock # Reset mouse (if specified) if reset_mouse: # Set mouse position self.mouse.set_pos((startx_mouse, starty_mouse)) # Set up variables including their first values timestamps = [self.clock.time()] xpos = [startx_mouse] ypos = [starty_mouse] # Get mouse position otherwise else: # Get mouse position position, timestamp = self.mouse.get_pos() # Set up variables including their first values timestamps = [timestamp] xpos = [position[0]] ypos = [position[1]] # Show mouse self.mouse.show_cursor(show=True) # Set tracking variables tracking = True mouse_on_start = True warning_printed = False resp = None initiation_time = None if track_clicks: clicks = [] clicks_timestamps = [] # Start tracking while tracking and timeleft > 0: # Collect mouse response if timeout == None: # (timeout corresponds to interval with which mouse coordinates are recored) mouse_button, xy, time = self.mouse.get_click( buttonlist=None, timeout=logging_resolution) else: # (timeout corresponds to interval with which mouse coordinates are recored, # or time left - whatever is smaller) mouse_button, xy, time = self.mouse.get_click( buttonlist=None, timeout=min([logging_resolution, timeleft])) # Retrieve and save mouse coordinates and timestamp using get_pos if there was no click # (as get_click returns None for xy if there was no mouse click) if xy != None: position = xy timestamp = time else: position, timestamp = self.mouse.get_pos() # Append values timestamps.append(timestamp) xpos.append(position[0]) ypos.append(position[1]) # Check if mouse has left the starting position, and, if so, determine initiation time if mouse_on_start == True: mouse_on_start = (position[0] == xpos[0]) and (position[1] == ypos[0]) if mouse_on_start == False: # difference between last (not current) timestamp and timestamp at start initiation_time = timestamps[-2] - timestamps[0] # If mouse is still on starting position and initiation time is exceeded, show warning if max_initiation_time != None: if mouse_on_start == True and warning_printed == False: if (timestamp - timestamps[0]) > max_initiation_time: self.set_widget(warning_widget[0], warning_widget[1], colspan=warning_widget[2], rowspan=warning_widget[3]) self.render() warning_printed = True # If mouse clicks should be recorded, save them if track_clicks: if mouse_button != None: clicks.append(mouse_button) clicks_timestamps.append(timestamp) # If there was a mouse click, determine the button that was clicked # and if click was on a button, end tracking and finish form # (or check if mouse has "touched" a button even though there was no mouse click - if no mouse click was required) if click_required == False or mouse_button in mouse_buttons_allowed: pos = self.xy_to_index(position) if pos != None: w = self.widgets[pos] if w != None: resp = self.widgets[pos].on_mouse_click(xy) if resp != None: tracking = False # Update timeleft if timeout != None: timeleft = timeout - (timestamp - timestamps[0]) # Calculate response time resp_time = timestamps[-1] - timestamps[0] # Set form_response variable self.experiment.var.form_response = resp if track_clicks == False: return resp, resp_time, initiation_time, timestamps, xpos, ypos else: return resp, resp_time, initiation_time, timestamps, xpos, ypos, clicks, clicks_timestamps