Пример #1
0
    def blur(self, level):
        """Blur the shape.

        This blurs the stimulus, by scaling it down and up by the factor of
        'level'.
        Notes
        -----
        Depending on the blur level and the size of your stimulus, this method
        may take some time!

        Parameters
        ----------
        level : int
            level of bluring

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = get_time()
        self.scale((1.0 / level, 1.0 / level))
        self.scale((level, level))
        return int((get_time() - start) * 1000)
Пример #2
0
    def blur(self, level):
        """Blur the shape.

        This blurs the stimulus, by scaling it down and up by the factor of
        'level'.
        Notes
        -----
        Depending on the blur level and the size of your stimulus, this method
        may take some time!

        Parameters
        ----------
        level : int
            level of bluring

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = get_time()
        self.scale((1.0 / level, 1.0 / level))
        self.scale((level, level))
        return int((get_time() - start) * 1000)
Пример #3
0
    def send(self, code=None, duration=None):
        """Send a marker.

        This sends a marker via the specified interface.
        If a duration is given, a 0 will be sent automatically after each
        code.

        Note for EEG/MEG systems:
        If the system is receiving the markers on a parallel port, the
        duration between sending a code an the subsequent 0 should be at least
        1000/samplerate!

        Parameters
        ----------
        code : int, optional
            a specific code
        duration : int, optional
            duration (in ms) for sending a 0 after a code

        """

        if not code:
            code = self.default_code
        if not duration:
            duration = self.default_duration
        self._interface.send(code)
        if duration:
            start = get_time()
            while (get_time() - start) * 1000 < duration:
                pass
        self._interface.send(0)
        if self._logging:
            expyriment._active_exp._event_file_log(
                                        "MarkerOutput,sent,{0}".format(code))
Пример #4
0
    def decompress(self):
        """Decompress the stimulus.

        This will decompress the stimulus.
        The surface will now be read from memory again.
        Depending on the size of the stimulus, this method may take some time
        to compute!

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = get_time()
        if self.is_compressed:
            self._surface = pygame.image.load(
                self._compression_filename).convert_alpha()
            self._is_compressed = False

            if self._logging:
                expyriment._active_exp._event_file_log(
                            "Stimulus,decompressed,{0}".format(self.id), 2)
        return int((get_time() - start) * 1000)
Пример #5
0
    def request_data(self, request, *args):
        """Request data from Turbo-Satori.

        Parameters:
        -----------
        request : str
            The request to be sent to Turbo-Satori.

        Returns:
        --------
        data : str
            The byte string of the received data.
        rt : int
            The time it took to get the data.

        """

        start = get_time()
        self._tcp.clear()
        request = unicode2byte(request)
        self._send(request, *args)
        data = self._wait()
        arg_length = sum([len(x) for x in args])
        arg = b"".join(args)
        if data is None:
            raise TurbosatoriNetworkInterface.TimeoutError(
                "Waiting for requested data timed out!")
        elif byte2unicode(data).startswith("Wrong request!"):
            raise TurbosatoriNetworkInterface.RequestError(
                "Wrong request '{0}'!".format(data[19:-1]))
        elif data[0:len(request) + 1 + arg_length] != request + b"\x00" + arg:
            raise TurbosatoriNetworkInterface.DataError(
                "Received data does not match request!")
        else:
            return data[len(request) + 1:], int((get_time() - start) * 1000)
Пример #6
0
    def move(self, offset):
        """Moves the stimulus in 2D space.

        When using OpenGL, this can take longer then 1ms!

        Parameters
        ----------
        offset : list, optional
            translation along x and y axis

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = get_time()
        moved = False
        x = offset[0]
        y = offset[1]
        if x > 0 or x < 0:
            self._position[0] = self._position[0] + x
            moved = True
        if y > 0 or y < 0:
            self._position[1] = self._position[1] + y
            moved = True
        if moved and self._ogl_screen is not None:
            self._ogl_screen.refresh_position()
        return int((get_time() - start) * 1000)
Пример #7
0
def readMouse(startTime, button, duration=None):
    iKeyboard = Keyboard()
    if duration is not None:
        while int((get_time() - startTime) * 1000) <= duration:
            alle = pygame.event.get()
            rt = int((get_time() - startTime)*1000)
            for e in alle:
                if e.type == pygame.MOUSEBUTTONDOWN and e.button == button:
                    return rt, coordinates2position(e.pos)

            if iKeyboard.process_control_keys():
                break

        return None, None

    else:
        while True:
            alle = pygame.event.get()
            rt = int((get_time() - startTime)*1000)
            for e in alle:
                if e.type == pygame.MOUSEBUTTONDOWN and e.button == button:
                    return rt, coordinates2position(e.pos)

            if iKeyboard.process_control_keys():
                break
Пример #8
0
    def flip(self, booleans):
        """Flip the stimulus.

        This is a surface operation. After this, a surface will be present!

        Parameters
        ----------
        booleans : (bool, bool)
            booleans to flip or not

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "flip()"))
        self.unload(keep_surface=True)
        self._set_surface(pygame.transform.flip(self._get_surface(),
                                                  booleans[0], booleans[1]))
        if self._logging:
            expyriment._active_exp._event_file_log(
            "Stimulus,flipped,{0}, booleans={1}".format(self.id, booleans), 2)
        return int((get_time() - start) * 1000)
Пример #9
0
    def present(self, clear=False, update=False):
        """
        Present the stimulus

        :param clear: Whether to clear the screen buffer prior to presenting. Default=False
        :type clear: bool
        :param update: Whether to flip buffer after plotting. Default=False
        :type update: bool
        :return: The time it took this function to run. (seconds)
        """
        start_time = get_time()

        self.preload()

        #-- Plot all visual elements on the canvas
        if self._visible:
            i = 0
            for k in self._visual_objects:
                do_clear = clear and i == 0
                do_update = update and i == len(self._visual_objects) - 1
                self._visual_objects[k].present(clear=do_clear,
                                                update=do_update)
                i += 1

        return get_time() - start_time
Пример #10
0
    def request_data(self, request, *args):
        """Request data from Turbo-Satori.

        Parameters:
        -----------
        request : str
            The request to be sent to Turbo-Satori.

        Returns:
        --------
        data : str
            The byte string of the received data.
        rt : int
            The time it took to get the data.

        """

        start = get_time()
        self._tcp.clear()
        self._send(request, *args)
        data = self._wait()
        if data is None:
            return None, None
        elif data[0:len(request)] != request:
            return data, None
        else:
            return data[len(request) + 1:], int((get_time() - start) * 1000)
Пример #11
0
    def blur(self, level):
        """Blur the stimulus.

        This blurs the stimulus, by scaling it down and up by the factor of
        'level'.

        Parameters
        ----------
        level : int
            level of bluring

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        self.scale((1.0 / level, 1.0 / level))
        self.scale((level, level))
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,blured,{0}, level={1}".format(self.id, level), 2)
        return int((get_time() - start) * 1000)
Пример #12
0
def readMouse(startTime, button, duration=None):
    iKeyboard = Keyboard()
    if duration is not None:
        while int((get_time() - startTime) * 1000) <= duration:
            alle = pygame.event.get()
            rt = int((get_time() - startTime) * 1000)
            for e in alle:
                if e.type == pygame.MOUSEBUTTONDOWN and e.button == button:
                    return rt, coordinates2position(e.pos)

            if iKeyboard.process_control_keys():
                break

        return None, None

    else:
        while True:
            alle = pygame.event.get()
            rt = int((get_time() - startTime) * 1000)
            for e in alle:
                if e.type == pygame.MOUSEBUTTONDOWN and e.button == button:
                    return rt, coordinates2position(e.pos)

            if iKeyboard.process_control_keys():
                break
Пример #13
0
    def rotate(self, degree):
        """Rotate the stimulus.

        This is a surface operation. After this, a surface will be present!
        Rotating goes along with a quality loss. Thus, rotating an already
        rotated stimulus is not a good idea.

        Parameters
        ----------
        degree : int
            degree to rotate counterclockwise

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "rotate()"))
        self.unload(keep_surface=True)
        self._set_surface(pygame.transform.rotate(self._get_surface(),
                                                  degree))
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,rotated,{0}, degree={1}".format(self.id, degree))
        return int((get_time() - start) * 1000)
Пример #14
0
    def move(self, offset):
        """Moves the stimulus in 2D space.

        When using OpenGL, this can take longer then 1ms!

        Parameters
        ----------
        offset : tuple (x,y)
            translation along x and y axis

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        --------
        see also reposition

        """

        start = get_time()
        moved = False
        if offset[0] != 0:
            self._position[0] = self._position[0] + offset[0]
            moved = True
        if offset[1] != 0:
            self._position[1] = self._position[1] + offset[1]
            moved = True
        if moved and self._ogl_screen is not None:
            self._ogl_screen.refresh_position()
        return int((get_time() - start) * 1000)
Пример #15
0
    def clear_surface(self):
        """Clear the stimulus surface.

        Surfaces are automatically created after any surface operation
        (presenting, plotting, rotating, scaling, flipping etc.) and preloading.
        If the stimulus was preloaded, this method unloads the stimulus.
        This method is functionally equivalent with unload(keep_surface=False).

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if self.is_preloaded:
            self.unload(keep_surface=False)
        self._is_compressed = False
        self._set_surface(None)
        if self._logging:
            expyriment._active_exp._event_file_log(
                            "Stimulus,surface cleared,{0}".format(self.id), 2)
        return int((get_time() - start) * 1000)
Пример #16
0
    def compress(self):
        """"Compress the stimulus.

        This will create a temporary file on the disk where the surface of the
        stimululs is written to.
        The surface will now be read from the disk to free memory.
        Compressed stimuli cannot do surface operations!
        Preloading comressed stimuli is possible and highly recommended.
        Depending on the size of the stimulus, this method may take some time
        to compute!

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = get_time()
        if self.is_compressed is False:
            if self._compression_filename is None:
                fid, self._compression_filename = tempfile.mkstemp(
                    dir=defaults.tempdir, suffix=".tga")
                os.close(fid)
            pygame.image.save(self._get_surface(), self._compression_filename)
            self._is_compressed = True
            self._surface = None

            if self._logging:
                expyriment._active_exp._event_file_log(
                                "Stimulus,compressed,{0}".format(self.id), 2)
        return int((get_time() - start) * 1000)
Пример #17
0
    def preload(self):
        """
        Pre-load the number line - prepare for plotting

        :return: The time it took this function to run. (seconds)
        """

        start_time = get_time()

        if self._preloaded:
            # Already pre-loaded
            return get_time() - start_time

        self.validate()
        self._preloaded = True

        if self._line_colour is not None:
            self._prepare_main_line()
            if self._end_tick_height != 0 and self._end_tick_height is not None:
                self._prepare_end_of_line_ticks()

        if self._labels_visible:
            self._prepare_labels()

        return get_time() - start_time
Пример #18
0
    def send(self, code=None, duration=None):
        """Send a marker.

        This sends a marker via the specified interface.
        If a duration is given, a 0 will be sent automatically after each
        code.

        Note for EEG/MEG systems:
        If the system is receiving the markers on a parallel port, the
        duration between sending a code an the subsequent 0 should be at least
        1000/samplerate!

        Parameters
        ----------
        code : int, optional
            a specific code
        duration : int, optional
            duration (in ms) for sending a 0 after a code

        """

        if not code:
            code = self.default_code
        if not duration:
            duration = self.default_duration
        self._interface.send(code)
        if duration:
            start = get_time()
            while (get_time() - start) * 1000 < duration:
                pass
        self._interface.send(0)
        if self._logging:
            expyriment._active_exp._event_file_log(
                "MarkerOutput,sent,{0}".format(code))
Пример #19
0
    def save(self):
        """Save the new data to data-file.

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        start = get_time()
        if len(self._subject_info) > 0 or len(self._experiment_info) > 0  \
                or self._variable_names_changed:
            # Re-write header and varnames
            tmpfile_name = "{0}{1}{2}".format(self.directory, os.path.sep, uuid.uuid4())
            os.rename(self._fullpath, tmpfile_name)
            fl = open(self._fullpath, 'w+')
            tmpfl = open(tmpfile_name, 'r')
            section = None
            while True:
                line = tmpfl.readline()
                if not line:
                    break
                if line.startswith(self.comment_char + "e"):
                    section = "e"
                elif line.startswith(self.comment_char + "s"):
                    section = "s"
                else:
                    if section == "e":  # Previous line was last #e
                        if len(self._experiment_info) > 0:
                            fl.write("".join(self._experiment_info))
                            self._experiment_info = []
                        section = None
                    elif section == "s":  # Previous line was last #s
                        if len(self._subject_info) > 0:
                            fl.write("".join(self._subject_info))
                            self._subject_info = []
                        section = None

                        # Re-write variable names after #s-section
                        fl.write(unicode2str(
                            self.variable_names + defaults.outputfile_eol))
                        self._variable_names_changed = False
                        line = ''  # Skip old varnames
                fl.write(line)
            tmpfl.close()
            fl.close()

            os.remove(tmpfile_name)
            self._subject_info = []
            self._experiment_info = []

        if self._buffer != []:
            OutputFile.save(self)
            if self._logging:
                expyriment._active_exp._event_file_log("Data,saved")

        return int((get_time() - start) * 1000)
Пример #20
0
    def save(self):
        """Save file to disk."""

        start = get_time()
        if self._buffer != []:
            with open(self._fullpath, 'a') as f:
                f.write("".join(self._buffer))
            self._buffer = []
        return int((get_time() - start) * 1000)
Пример #21
0
    def preload(self, inhibit_ogl_compress=False):
        """Preload the stimulus to memory.

        This will prepare the stimulus for a fast presentation.
        In OpenGL mode this method creates an OpenGL texture based on the
        surface of the stimulus.
        When OpenGL is switched off, this method will create a surface if it
        doesn't exists yet.
        If stimuli are not preloaded manually, this will happen
        automatically during presentation. However, stimulus presentation will
        take some time then!

        Always preload your stimuli when a timing acurate presentation is
        needed!

        Parameters
        ----------
        inhibit_ogl_compress : bool, optional
            inhibits OpenGL stimuli to be automatically compressed
            (default=False)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if not expyriment._active_exp.is_initialized:
            message = "Can't preload stimulus. Expyriment needs to be " + \
                      "initilized before preloading a stimulus."
            raise RuntimeError(message)
        self._was_compressed_before_preload = self.is_compressed
        if not self.is_preloaded:
            if expyriment._active_exp.screen.open_gl:
                self._ogl_screen = _LaminaPanelSurface(
                    self._get_surface(),
                    position=self.position)
                if not inhibit_ogl_compress:
                    self.compress()
            else:
                self.decompress()
                self._set_surface(self._get_surface())
            self._is_preloaded = True
        if self._logging:
            expyriment._active_exp._event_file_log(
                                "Stimulus,preloaded,{0}".format(self.id), 2)

        return int((get_time() - start) * 1000)
Пример #22
0
    def present(self, clear=True, update=True):
        """Present the stimulus on the screen.

        This clears and updates the screen automatically.
        When not preloaded, depending on the size of the stimulus, this method
        can take some time to compute!

        Parameters
        ----------
        clear : bool, optional
            if True the screen will be cleared automatically
            (default = True)
        update : bool, optional
            if False the screen will be not be updated automatically
            (default = True)

        Returns
        -------
        time : int
            the time it took to execute this method

        """

        if not expyriment._active_exp.is_initialized or\
                             expyriment._active_exp.screen is None:
            raise RuntimeError("Cannot not find a screen!")

        start = get_time()
        preloading_required = not(self.is_preloaded)

        if clear:
            expyriment._active_exp.screen.clear()
        if preloading_required:
            # Check if stimulus has surface
            keep_surface = self.has_surface
            self.preload(inhibit_ogl_compress=True)

        if expyriment._active_exp.screen.open_gl:
            self._ogl_screen.display()
        else:
            screen = expyriment._active_exp.screen.surface
            rect = pygame.Rect((0, 0), self.surface_size)
            screen_size = screen.get_size()
            rect.center = [self.position[0] + screen_size[0] / 2,
                           - self.position[1] + screen_size[1] / 2]
            screen.blit(self._get_surface(), rect)
        if self._logging:
            expyriment._active_exp._event_file_log("Stimulus,presented,{0}"\
                                   .format(self.id), 1)
        if update:
            expyriment._active_exp.screen.update()
        if preloading_required:
            self.unload(keep_surface=keep_surface)

        return int((get_time() - start) * 1000)
Пример #23
0
    def scale(self, factors):
        """Scale the stimulus.

        This is a surface operation. After this, a surface will be present!
        Negative scaling values will flip the stimulus.
        Scaling goes along with a quality loss. Thus, scaling an already
        scaled stimulus is not a good idea.

        Parameters
        ----------
        factors : (int, int) or (float, float)
            tuple representing the x and y factors to scale or a single number.
            In the case of a single number x and y scaling will be the
            identical (i.e., proportional scaling)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "scale()"))
        self.unload(keep_surface=True)
        flip = [False, False]
        if type(factors) in [types.IntType, types.FloatType]:
            factors = [factors, factors]
        else:
            factors = list(factors)
        if factors[0] < 0:
            flip[0] = True
            factors[0] = abs(factors[0])
        if factors[1] < 0:
            flip[1] = True
            factors[1] = abs(factors[1])
        self._set_surface(pygame.transform.smoothscale(
            self._get_surface(),
            (int(round(self.surface_size[0] * factors[0])),
             int(round(self.surface_size[1] * factors[1])))))
        if True in flip:
            self.flip(flip)
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,scaled,{0}, factors={1}".format(self.id, factors), 2)
        return int((get_time() - start) * 1000)
Пример #24
0
    def create_mask(self):
        """Creates a new visual mask.

        Notes
        -----
        CAUTION: Depending on the size of the stimulus, this method may take
        some time to execute.

        Returns
        -------
        time  : int
            the time it took to execute this method in ms

        """

        start = get_time()
        was_preloaded = self.is_preloaded
        if was_preloaded:
            self.unload()

        s = (self._size[0] + 4 * self.smoothing,
             self._size[1] + 4 * self.smoothing)  #somewhat larger mask
        im = Image.new("RGB", s)
        draw = ImageDraw.Draw(im)
        draw.rectangle([(0, 0), s],
                       outline=self.background_colour,
                       fill=self.background_colour)

        n_dots_x = int(s[0] / self.dot_size[0]) + 1
        n_dots_y = int(s[1] / self.dot_size[1]) + 1
        dots = range(n_dots_x * n_dots_y)
        shuffle(dots)
        for d in dots[:int(len(dots) * self.dot_percentage / 100)]:
            y = (d / n_dots_x) * self.dot_size[1]
            x = (d % n_dots_x) * self.dot_size[0]
            draw.rectangle([(x, y),
                            (x + self.dot_size[0], y + self.dot_size[1])],
                           outline=self.dot_colour,
                           fill=self.dot_colour)

        for x in range(self.smoothing):
            im = im.filter(ImageFilter.BLUR).filter(ImageFilter.SMOOTH_MORE)

        #crop image and save
        c = (im.size[0] / 2, im.size[1] / 2)
        box = (c[0] - self._size[0] / 2, c[1] - self._size[1] / 2,
               c[0] + self._size[0] / 2, c[1] + self._size[1] / 2)
        im = im.crop(box)
        im.save(self._filename, format="png")

        if was_preloaded:
            self.preload()
        return int((get_time() - start) * 1000)
Пример #25
0
    def unload(self, keep_surface=False):
        """Unload the stimulus from memory.

        This will unload preloaded stimuli.
        In OpenGL mode, this method will remove the reference to the OpenGL
        texture and the surface (when 'keep_surface' is False).
        When OpenGL is switched off, the reference to the surface will be
        removed (when 'keep_surface' is False).

        Parameters
        ----------
        keep_surface : bool, optional
            keep the surface after unload (default=False)

        Returns
        -------
        time : int
            the time it took to execute this method

        See Also
        --------
        clear_surface.

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if expyriment._active_exp.screen.open_gl:
            self._ogl_screen = None
            if self.is_preloaded and not self._was_compressed_before_preload \
                and keep_surface:
                self.decompress()
        else:  # Pygame surface
            if self.is_preloaded and self._was_compressed_before_preload \
                and keep_surface:
                self.compress()
        if self.is_preloaded and self._logging:
            expyriment._active_exp._event_file_log("Stimulus,unloaded,{0}"\
                                       .format(self.id), 2)
        if not keep_surface:
            self._is_compressed = False
            self._surface = None
            if self._logging:
                expyriment._active_exp._event_file_log("Stimulus,surface cleared,{0}"\
                                       .format(self.id), 2)

        self._is_preloaded = False
        return int((get_time() - start) * 1000)
Пример #26
0
    def wait_press(self, buttons=None, duration=None):
        """Wait for gamepad button press.

        Returns the found button and the reaction time.

        Parameters
        ----------
        buttons : int or list, optional
            specific buttons to wait for
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        button : int
            button _id of the pressed button
        rt : int
            reaction time in ms

        """

        start = get_time()
        rt = None
        _button = None
        self.clear()
        if buttons is None:
            buttons = range(self.get_numbuttons())
        if type(buttons) is not list:
            buttons = [buttons]
        done = False
        while not done:
            expyriment._active_exp._execute_wait_callback()
            for button in buttons:
                if self.get_button(button):
                    _button = button
                    rt = int((get_time() - start) * 1000)
                    done = True
                    break
                if _button is not None or Keyboard.process_control_keys():
                    done = True
                    break
                if duration:
                    if int((get_time() - start) * 1000) >= duration:
                        done = True
                        break

            time.sleep(0.0005)

        if self._logging:
            expyriment._active_exp._event_file_log(
                            "Gamepad,received,{0},wait_press".format(_button))
        return _button, rt
Пример #27
0
    def scramble(self, grain_size):
        """Scramble the stimulus.

        Attention: If the surface size is not a multiple of the grain size,
        you may loose some pixels on the edge.

        Parameters
        ----------
        grain_size : int or (int, int)
            size of a grain (use tuple of integers for different width & height)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if type(grain_size) is int:
            grain_size = [grain_size, grain_size]
        # Make Rect list
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "scramble()"))
        s = self.surface_size
        source = []
        for r in range(s[1] / int(grain_size[1])):
            for c in range(s[0] / int(grain_size[0])):
                xy = (c * int(grain_size[0]), r * int(grain_size[1]))
                source.append(pygame.Rect(xy, grain_size))
        # Make copy and shuffle
        dest = copy.deepcopy(source)
        random.shuffle(dest)
        # Create a new surface
        tmp_surface = pygame.surface.Surface(
            s, pygame.SRCALPHA).convert_alpha()
        for n, s in enumerate(source):
            tmp_surface.blit(self._get_surface(), dest[n], s)
        self._set_surface(tmp_surface)

        if self._logging:
            expyriment._active_exp._event_file_log(
                            "Stimulus,scrambled,{0}, grain_size={1}".format(
                                     self.id, grain_size), 2)
        return int((get_time() - start) * 1000)
Пример #28
0
    def create_mask(self):
        """Creates a new visual mask.

        Notes
        -----
        CAUTION: Depending on the size of the stimulus, this method may take
        some time to execute.

        Returns
        -------
        time  : int
            the time it took to execute this method in ms

        """

        start = get_time()
        was_preloaded = self.is_preloaded
        if was_preloaded:
            self.unload()

        s = (self._size[0] + 4 * self.smoothing,
             self._size[1] + 4 * self.smoothing) #somewhat larger mask 
        im = Image.new("RGB", s)
        draw = ImageDraw.Draw(im)
        draw.rectangle([(0, 0), s], outline=self.background_colour,
                       fill=self.background_colour)

        n_dots_x = int(s[0] / self.dot_size[0]) + 1
        n_dots_y = int(s[1] / self.dot_size[1]) + 1
        dots = list(range(n_dots_x * n_dots_y))
        shuffle(dots)
        for d in dots[:int(len(dots) * self.dot_percentage / 100)]:
            y = (d // n_dots_x) * self.dot_size[1]
            x = (d % n_dots_x) * self.dot_size[0]
            draw.rectangle([(x, y),
                            (x + self.dot_size[0], y + self.dot_size[1])],
                           outline=self.dot_colour, fill=self.dot_colour)

        for x in range(self.smoothing):
            im = im.filter(ImageFilter.BLUR).filter(ImageFilter.SMOOTH_MORE)

        #crop image and save
        c = (im.size[0] // 2, im.size[1] // 2)
        box = (c[0] - self._size[0] // 2, c[1] - self._size[1] // 2,
               c[0] + self._size[0] // 2, c[1] + self._size[1] // 2)
        im = im.crop(box)
        im.save(self._filename, format="png")

        if was_preloaded:
            self.preload()
        return int((get_time() - start) * 1000)
Пример #29
0
    def wait_char(self, char, duration=None, check_for_control_keys=True):
        """Wait for character(s) (optionally for a certain amount of time).

        This function will wait for one or more characters and returns the
        found character as well as the reaction time.
        (This function clears the event queue!)

        Parameters
        ----------
        char : int or list
            a specific character or list of characters to wait for
        duration : int, optional
            maximal time to wait in ms
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        found : char
            pressed charater
        rt : int
            reaction time in ms

        """

        start = get_time()
        rt = None
        found_char = None
        self.clear()
        if type(char) is not list:
            char = [char]
        pygame.event.pump()
        done = False
        while not done:
            expyriment._active_exp._execute_wait_callback()
            for event in pygame.event.get():
                if check_for_control_keys and Keyboard.process_control_keys(event):
                    done = True
                elif event.type == pygame.KEYDOWN:
                    if event.unicode in char:
                        rt = int((get_time() - start) * 1000)
                        found_char = event.unicode
                        done = True
            if duration and not done:
                done = int((get_time() - start) * 1000) >= duration
            time.sleep(0.0005)
        if self._logging:
            expyriment._active_exp._event_file_log(
                        "Keyboard,received,{0},wait_char".format(found_char))
        return found_char, rt
Пример #30
0
    def add_noise(self, grain_size, percentage, colour):
        """Add visual noise on top of the stimulus.

        This function might take very long for large stimuli.

        Parameters
        ----------
        grain_size : int
            size of the grains for the noise
        percentage : int
            percentage of covered area
        colour : (int, int, int)
            colour (RGB) of the noise

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """
        import _rectangle
        start = get_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "add_noise()"))
        self.unload(keep_surface=True)
        number_of_pixel_x = int(self.surface_size[0] / grain_size) + 1
        number_of_pixel_y = int(self.surface_size[1] / grain_size) + 1
        seq = range(number_of_pixel_x * number_of_pixel_y)
        random.seed()
        random.shuffle(seq)

        for idx in seq[:int(len(seq) * (percentage) / 100.0)]:
            x = (idx % number_of_pixel_x) * grain_size
            x = int(self.surface_size[0] / 2 - grain_size / 2 - x)
            y = (idx / number_of_pixel_x) * grain_size
            y = int(self.surface_size[1] / 2 - grain_size / 2 - y)
            dot = _rectangle.Rectangle(size=(grain_size, grain_size),
                            position=(x, y), colour=colour)
            dot.plot(self)
        if self._logging:
            expyriment._active_exp._event_file_log(
                    "Stimulus,noise added,{0}, grain_size={1}, percentage={2}"\
                        .format(self.id, grain_size, percentage))
        return int((get_time() - start) * 1000)
    def wait(self,
             duration=None,
             button_fields=None,
             check_for_control_keys=True):
        """Wait for a touchscreen button box click.

        Parameters
        ----------
        button_fields : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        pressed_button_field : Expyriment stimulus or None
            the button field defined by a stimulus that has been pressed
        rt : int
            reaction time

        Notes
        -----
        Don't forget to show the TouchScreenButtonBox.

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        self.clear_event_buffer()
        while True:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                return rtn_callback, int((get_time() - start) * 1000)
            pressed_button_field, touch_time = self.check(
                button_fields, check_for_control_keys)
            if pressed_button_field is not None:
                rt = int((get_time() - start) * 1000)
                break
            elif (duration is not None and int(
                (get_time() - start) * 1000) >= duration):
                pressed_button_field, rt = None, None
                break
        return pressed_button_field, rt
Пример #32
0
def get_time():
    """
    Get the current time (in seconds).
    This is a wrapper to Expyriment's get_time function
    :return: float
    """
    return xpy_timer.get_time()
Пример #33
0
    def wait(self, code=None, bitwise_comparison=False):
        """Wait for a trigger.

        Returns the code received and the reaction time [code, rt].

        If bitwise_comparison = True, the function performs a bitwise
        comparison (logical and) between code and received input and waits
        until a certain bit pattern is set.

        Parameters
        code -- a specific code to wait for (int) (optional)
        bitwise_comparison -- make a bitwise comparison (default=False)

        See Also
        --------
        design.experiment.register_wait_callback_function

       """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        found = None
        rt = None
        if code is None:
            code = self._default_code
        self.interface.clear()
        while True:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                return rtn_callback, int((get_time() - start) * 1000)
            read = self.interface.poll()
            if read is not None:
                if code is None:  #return for every event
                    rt = int((get_time() - start) * 1000)
                    found = read
                    break
                elif compare_codes(read, code, bitwise_comparison):
                    rt = int((get_time() - start) * 1000)
                    found = read
                    break
            if Keyboard.process_control_keys():
                break
        if self._logging:
            expyriment._active_exp._event_file_log(
                "TriggerInput,received,{0},wait".format(found))
        return found, rt
Пример #34
0
    def wait(self, code=None, bitwise_comparison=False):
        """Wait for a trigger.

        Returns the code received and the reaction time [code, rt].

        If bitwise_comparison = True, the function performs a bitwise
        comparison (logical and) between code and received input and waits
        until a certain bit pattern is set.

        Parameters
        code -- a specific code to wait for (int) (optional)
        bitwise_comparison -- make a bitwise comparison (default=False)

        See Also
        --------
        design.experiment.register_wait_callback_function

       """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        found = None
        rt = None
        if code is None:
            code = self._default_code
        self.interface.clear()
        while True:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                return rtn_callback, int((get_time() - start) * 1000)
            read = self.interface.poll()
            if read is not None:
                if code is None:  # return for every event
                    rt = int((get_time() - start) * 1000)
                    found = read
                    break
                elif compare_codes(read, code, bitwise_comparison):
                    rt = int((get_time() - start) * 1000)
                    found = read
                    break
            if Keyboard.process_control_keys():
                break
        if self._logging:
            expyriment._active_exp._event_file_log("TriggerInput,received,{0},wait".format(found))
        return found, rt
Пример #35
0
    def wait(self, duration=None, button_fields=None,
                check_for_control_keys=True):
        """Wait for a touchscreen button box click.

        Parameters
        ----------
        button_fields : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        pressed_button_field : Expyriment stimulus or None
            the button field defined by a stimulus that has been pressed
        rt : int
            reaction time

        Notes
        -----
        Don't forget to show the TouchScreenButtonBox.

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        self.clear_event_buffer()
        while True:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                return rtn_callback, int((get_time()-start)*1000)
            pressed_button_field, touch_time = self.check(button_fields,
                        check_for_control_keys)
            if pressed_button_field is not None:
                rt = int((get_time()-start)*1000)
                break
            elif (duration is not None and int((get_time()-start)*1000)>=duration):
                pressed_button_field, rt = None, None
                break
        return pressed_button_field, rt
Пример #36
0
    def plot(self, stim):
        """
        Plot the number line on another stimulus

        :param stim: Any Expyriment visual object
        :return: The time it took this function to run (seconds)
        """

        start_time = get_time()

        self.preload()

        #-- Plot all visual elements on the canvas
        if self._visible:
            for k in self._visual_objects:
                self._visual_objects[k].plot(stim)

        return get_time() - start_time
Пример #37
0
    def _wait(self):
        start = get_time()
        receive, rt = self._tcp.wait(package_size=8,
                                     duration=self.timeout,
                                     process_control_events=False)
        if receive is None:
            return None
        length = struct.unpack('!q', receive)[0]
        data = None
        timeout = self.timeout - int((get_time() - start) * 1000)
        if timeout > 0:
            data, rt = self._tcp.wait(package_size=length,
                                      duration=timeout,
                                      process_control_events=False)
        if data is None:
            return None

        return data[4:]
Пример #38
0
    def _test2():
        info = """This will test if stimulus presentation can be synchronized to the refreshrate of the screen.
A good result is a fast, constant and smooth flickering without any distortions (e.g. horizontal stripes, tearing).
The estimated refreshrate should resemble your actual screen refreshrate (common refreshrates are between 40 and 240 Hz).

[Press RETURN to continue]"""

        text = stimuli.TextScreen("Stimulus presentation test (2)", info)
        text.present()
        exp.keyboard.wait([constants.K_RETURN])
        black = stimuli.BlankScreen(colour=constants.C_BLACK)
        black.preload()
        white = stimuli.BlankScreen(colour=constants.C_WHITE)
        white.preload()
        times = []
        black.present()
        for _x in range(100):
            start = get_time()
            black.present()
            times.append(get_time() - start)
            start = get_time()
            white.present()
            times.append(get_time() - start)
        refresh_rate = 1000 / (statistics.mean(times) * 1000)
        info = """Your estimated refresh rate is {0} Hz.

[Press RETURN to continue]
""".format(refresh_rate)
        text = stimuli.TextScreen("Results", info)
        text.present()
        exp.keyboard.wait([constants.K_RETURN])
        text = stimuli.TextScreen(
            "Was the flickering fast, constant and smooth, without any distortions?",
            "[Press Y or N]")
        text.present()
        key, _rt = exp.keyboard.wait([constants.K_y,
                                      constants.K_n])
        if key == constants.K_y:
            response2 = "Yes"
        elif key == constants.K_n:
            response2 = "No"

        return refresh_rate, response2
Пример #39
0
    def plot(self, stimulus):
        """Plot the stimulus on the surface of another stimulus.

        Use this to plot more than one stimulus and to present them at the
        same time afterwards by presenting the stimulus on which they were
        plotted on.

        Parameters
        ----------
        stimulus : expyriment stimulus
            stimulus to whose surface should be plotted

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if not stimulus._set_surface(stimulus._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "plot()"))
        stimulus.unload(keep_surface=True)
        self._parent = stimulus
        rect = pygame.Rect((0, 0), self.surface_size)
        stimulus_surface_size = stimulus.surface_size
        rect.center = [self.position[0] + stimulus_surface_size[0] / 2,
                       - self.position[1] + stimulus_surface_size[1] / 2]
        stimulus._get_surface().blit(self._get_surface(), rect)
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Stimulus,plotted,{0},{1}".format(self.id, stimulus.id), 2)
        return int((get_time() - start) * 1000)
Пример #40
0
    def scale_to_fullscreen(self, keep_aspect_ratio=True):
        """Scale the stimulus to fullscreen.

        This is a surface operation. After this, a surface will be present!
        Scaling goes along with a quality loss. Thus, scaling an already
        scaled stimulus is not a good idea.

        Parameters
        ----------
        keep_aspect_ratio : boolean, optional
            if this boolean is False, stimulus will be stretched so that it
            fills out the whole screen (default = False)

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        Depending on the size of the stimulus, this method may take some time
        to compute!

        """

        start = get_time()
        if not self._set_surface(self._get_surface()):
            raise RuntimeError(Visual._compression_exception_message.format(
                "scale_to_fullscreen()"))
        surface_size = self.surface_size
        screen_size = expyriment._active_exp.screen.surface.get_size()
        scale = (screen_size[0]/float(surface_size[0]),
                     screen_size[1]/float(surface_size[1]))
        if keep_aspect_ratio:
            scale = [min(scale)]*2
        self.scale(factors=scale)
        return int((get_time() - start) * 1000)
Пример #41
0
    def move(self, offset):
        """Moves the stimulus in 2D space.

        Parameters
        ----------
        offset : list, optional
            translation along x and y axis

        Returns
        -------
        time : int
            the time it took to execute this method

        Notes
        -----
        When using OpenGL, this can take longer then 1ms!

        """

        start = get_time()
        moved = False
        x = offset[0]
        y = offset[1]
        if x > 0 or x < 0:
            self._position[0] = self._position[0] + x
            moved = True
        if y > 0 or y < 0:
            self._position[1] = self._position[1] + y
            moved = True
        if moved and self._ogl_screen is not None:
            self._ogl_screen.refresh_position()
        self._start_point[0] = self._start_point[0] + x
        self._start_point[1] = self._start_point[1] + y
        self._end_point[0] = self._end_point[0] + x
        self._end_point[1] = self._end_point[1] + y
        return int((get_time() - start) * 1000)
Пример #42
0
    def check(self, button_fields=None, check_for_control_keys=True):
        """Check if a button field is clicked.

        Parameters
        ----------
        button_fields : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        pressed_button_field : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        touch_time : integer
            The time when the button was touched. Function might return delayed,
            because button field comparison (after touch) takes time. The
            return time is most accurate.


        Notes
        -----
        Don't forget to show the TouchScreenButtonBox.

        """

        if button_fields is not None:
            try:
                button_fields = list(button_fields)
            except:
                button_fields = [button_fields]
        if check_for_control_keys:
            expyriment.io.Keyboard.process_control_keys()

        pressed_button_field = None
        touch_time = None
        if self._mouse.get_last_button_down_event() is not None:
            touch_time = get_time()
            self._last_touch_position = self._mouse.position
            pressed_button_field = self._get_button_field(self._last_touch_position,
                    button_fields)

            if self._logging and pressed_button_field is not None:
                expyriment._active_exp._event_file_log(
                                "{0},received, button press,check".format(
                                    self.__class__.__name__))
        return pressed_button_field, touch_time
    def check(self, button_fields=None, check_for_control_keys=True):
        """Check if a button field is clicked.

        Parameters
        ----------
        button_fields : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        pressed_button_field : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        touch_time : integer
            The time when the button was touched. Function might return delayed,
            because button field comparison (after touch) takes time. The
            return time is most accurate.


        Notes
        -----
        Don't forget to show the TouchScreenButtonBox.

        """

        if button_fields is not None:
            try:
                button_fields = list(button_fields)
            except:
                button_fields = [button_fields]
        if check_for_control_keys:
            expyriment.io.Keyboard.process_control_keys()

        pressed_button_field = None
        touch_time = None
        if self._mouse.get_last_button_down_event() is not None:
            touch_time = get_time()
            self._last_touch_position = self._mouse.position
            pressed_button_field = self._get_button_field(
                self._last_touch_position, button_fields)

            if self._logging and pressed_button_field is not None:
                expyriment._active_exp._event_file_log(
                    "{0},received, button press,check".format(
                        self.__class__.__name__))
        return pressed_button_field, touch_time
Пример #44
0
    def wait(self, duration=None, button_fields=None,
                check_for_control_keys=True):
        """Wait for a touchscreen button box click.

        Parameters
        ----------
        button_fields : Expyriment stimulus or list of stimuli, optional
            The button fields that will be checked for.
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        pressed_button_field : Expyriment stimulus or None
            the button field defined by a stimulus that has been pressed
        rt : int
            reaction time

        Notes
        -----
        Don't forget to show the TouchScreenButtonBox.

        """

        start = get_time()
        self.clear_event_buffer()
        while True:
            expyriment._active_exp._execute_wait_callback()
            pressed_button_field, touch_time = self.check(button_fields,
                        check_for_control_keys)
            if pressed_button_field is not None:
                rt = int((touch_time - start) * 1000)
                break
            elif (duration is not None and rt>= duration):
                pressed_button_field, rt = None, None
                break
        return pressed_button_field, rt
Пример #45
0
    def wait(self, events, duration=None, callback_function=None,
             process_control_events=True):
        """Wait for (a) certain event(s).

        Events to wait for are in the form of a list with 4 elements and do
        not include a timestamp: [status, data1, data2, data3]

        Parameters
        ----------
        events : int or list
            event(s) to wait for
        duration : int, optional
            maximal time to wait in ms
        callback_function : function, optional
            function to repeatedly execute during waiting loop
        process_control_events : bool, optional
            process ``io.Keyboard.process_control_keys()`` and
            ``io.Mouse.process_quit_event()`` (default = True)

        Returns
        -------
        evt : int
            found event
        rt : int
            reaction time in ms

        Notes
        -----
        This will also by default process control events (quit and pause).
        Thus, keyboard events will be cleared from the cue and cannot be
        received by a Keyboard().check() anymore!

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if _internals.skip_wait_methods:
            return None, None
        start = get_time()
        rt = None
        _event = None
        self.clear()
        if isinstance(events, (list, tuple)) and \
           len(events) == 4 and \
           isinstance(events[0], int) and \
           isinstance(events[1], int) and \
           isinstance(events[2], int) and \
           isinstance(events[3], int):
            events = [events]
        done = False
        while not done:
            if isinstance(callback_function, FunctionType):
                callback_function()
            if _internals.active_exp is not None and \
               _internals.active_exp.is_initialized:
                rtn_callback = _internals.active_exp._execute_wait_callback()
                if isinstance(rtn_callback, CallbackQuitEvent):
                    _event = rtn_callback
                    rt = int((get_time() - start) * 1000)
                    break
                if process_control_events:
                    if _internals.active_exp.mouse.process_quit_event() or \
                       _internals.active_exp.keyboard.process_control_keys():
                        break
                else:
                    _internals.pump_pygame_events()
            event = self.read(1)
            if event is not None and event[0][0] in events:
                rt = int((get_time() - start) * 1000)
                _event = event[0][0]
                done = True
                break
            if duration:
                if int((get_time() - start) * 1000) >= duration:
                    done = True
                    break

            time.sleep(0.0005)

        if self._logging:
            _internals.active_exp._event_file_log(
                "MIDI In ({0}),received,{1},wait".format(self.id, _event), 2)
        return _event, rt
Пример #46
0
    def wait(self,
             length,
             package_size=None,
             duration=None,
             callback_function=None,
             process_control_events=True):
        """Wait for data.

        Parameters
        ----------
        length : int
            The length of the data to be waited for in bytes.
            If not set, a single package will be waited for.
        package_size : int, optional
            The size of the package to be waited for, optional.
            If not set, the default package size will be used.
            If length < package_size, package_size = length.
        duration: int, optional
            The duration to wait in milliseconds.
        callback_function : function, optional
            function to repeatedly execute during waiting loop
        process_control_events : bool, optional
            process ``io.Keyboard.process_control_keys()`` and
            ``io.Mouse.process_quit_event()`` (default = True)

        Returns
        -------
        data : str
            The received data.
        rt : int
            The time it took to receive the data in milliseconds.

        Notes
        -----
        This will also by default process control events (quit and pause).
        Thus, keyboard events will be cleared from the cue and cannot be
        received by a Keyboard().check() anymore!

        """

        if _internals.skip_wait_methods:
            return None, None

        start = get_time()
        data = None
        rt = None

        if package_size is None:
            package_size = self._default_package_size
        if length is None:
            length = package_size
        elif length < package_size:
            package_size = length
        while True:
            try:
                if data is None:
                    data = self._client[0].recv(package_size)
                while len(data) < length:
                    if length - len(data) >= package_size:
                        data = data + self._client[0].recv(package_size)
                    else:
                        data = data + self._client[0].recv(length - len(data))
                    if duration:
                        if int((get_time() - start) * 1000) >= duration:
                            data = None
                            rt = None
                            break
                rt = int((get_time() - start) * 1000)
                break
            except socket.error as e:
                err = e.args[0]
                if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                    if isinstance(callback_function, FunctionType):
                        callback_function()
                    if _internals.active_exp is not None and \
                    _internals.active_exp.is_initialized:
                        rtn_callback = _internals.active_exp._execute_wait_callback(
                        )
                        if isinstance(rtn_callback, CallbackQuitEvent):
                            data = rtn_callback
                            rt = int((get_time() - start) * 1000)
                            break
                        if process_control_events:
                            if _internals.active_exp.mouse.process_quit_event() or \
                            _internals.active_exp.keyboard.process_control_keys():
                                break
                        else:
                            _internals.pump_pygame_events()

            if duration:
                if int((get_time() - start) * 1000) >= duration:
                    data = None
                    rt = None
                    break

        if self._logging:
            _internals.active_exp._event_file_log(
                "TcpServer,received,{0},wait".format(data))

        return data, rt
Пример #47
0
    def wait(self,
             keys=None,
             duration=None,
             wait_for_keyup=False,
             check_for_control_keys=True):
        """Wait for keypress(es) (optionally for a certain amount of time).

        This function will wait for a keypress and returns the found key as
        well as the reaction time.
        (This function clears the event queue!)

        Parameters
        ----------
        keys : int or list, optional
            a specific key or list of keys to wait for
        duration : int, optional
            maximal time to wait in ms
        wait_for_keyup : bool, optional
            if True it waits for key-up
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        found : char
            pressed character
        rt : int
            reaction time in ms

        Notes
        -----
        Keys are defined my keyboard constants (please use see misc.constants)

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        if android_show_keyboard is not None:
            android_show_keyboard()
        start = get_time()
        rt = None
        found_key = None
        self.clear()
        if keys is None:
            keys = self.default_keys
        else:
            try:
                keys = list(keys)
            except:
                keys = [keys]
        if wait_for_keyup:
            target_event = pygame.KEYUP
        else:
            target_event = pygame.KEYDOWN
        pygame.event.pump()
        done = False
        while not done:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                done = True
                found_key = rtn_callback
                rt = int((get_time() - start) * 1000)
            for event in pygame.event.get([pygame.KEYDOWN, pygame.KEYUP]):
                if check_for_control_keys and Keyboard.process_control_keys(
                        event):
                    done = True
                elif event.type == target_event:
                    if keys is not None:
                        if event.key in keys:
                            rt = int((get_time() - start) * 1000)
                            found_key = event.key
                            done = True
                    else:
                        rt = int((get_time() - start) * 1000)
                        found_key = event.key
                        done = True
            if duration and not done:
                done = int((get_time() - start) * 1000) >= duration
            time.sleep(0.0005)
        if self._logging:
            expyriment._active_exp._event_file_log("Keyboard,received,{0},wait"\
                                              .format(found_key))
        if android_hide_keyboard is not None:
            android_hide_keyboard()
        return found_key, rt
Пример #48
0
    def wait_event(self, wait_button=True, wait_motion=True, buttons=None,
                   duration=None, wait_for_buttonup=False):
        """Wait for a mouse event (i.e., motion, button press or wheel event)

        Parameters
        ----------
        wait_button : bool, optional
            set 'False' to ignore for a button presses (default=True)
        wait_motion : bool, optional
            set 'False' to ignore for a mouse motions (default=True)
        buttons : int or list, optional
            a specific button or list of buttons to wait for
        duration : int, optional
            the maximal time to wait in ms
        wait_for_buttonup : bool, optional
            if True it waits for button-up default=False)

        Returns
        -------
        event_id : int
            id of the event that quited waiting
        move : bool
            True if a motion occured
        pos : (int, int)
            mouse position (tuple)
        rt : int
            reaction time

        Notes
        ------
        button id coding

        - None    for no mouse button event or
        - 0,1,2   for left. middle and right button or
        - 3       for wheel up or
        - 4       for wheel down (wheel works only for keydown events).

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None, None, None
        start = get_time()
        self.clear()
        old_pos = pygame.mouse.get_pos()
        btn_id = None
        rt = None
        motion_occured = False
        if buttons is None:
            buttons = [0, 1, 2, 3, 4]
        else:
            try:
                buttons = list(buttons)
            except:
                buttons = [buttons]
        while True:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                btn_id = rtn_callback
                rt = int((get_time() - start) * 1000)
                break
            if wait_motion:
                motion_occured = old_pos != pygame.mouse.get_pos()
            if wait_button:
                if wait_for_buttonup:
                    btn_id = self.get_last_button_up_event()
                else:
                    btn_id = self.get_last_button_down_event()
            if btn_id ==-1:
                btn_id = None
                break
            elif btn_id in buttons or motion_occured:
                rt = int((get_time() - start) * 1000)
                break
            elif Keyboard.process_control_keys() or (duration is not None and \
                    int((get_time() - start) * 1000) >= duration):
                break

        position_in_expy_coordinates = self.position

        if self._logging:
            expyriment._active_exp._event_file_log(
            "Mouse,received,{0}-{1},wait_event".format(btn_id, motion_occured))
        return btn_id, motion_occured, position_in_expy_coordinates, rt
Пример #49
0
    def wait(self, events, duration=None):
        """Wait for (a) certain event(s).

        Events to wait for are in the form of a list with 4 elements and do
        not include a timestamp: [status, data1, data2, data3]

        Parameters
        ----------
        events : int or list
            event(s) to wait for
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        evt : int
            found event
        rt : int
            reaction time in ms

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        rt = None
        _event = None
        self.clear()
        if type(events) is list and \
           len(events) == 4 and \
           type(events[0]) is int and \
           type(events[1]) is int and \
           type(events[2]) is int and \
           type(events[3]) is int:
            events = [events]
        done = False
        while not done:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                return rtn_callback, int((get_time() - start) * 1000)
            event = self.read(1)
            if event is not None and event[0][0] in events:
                rt = int((get_time() - start) * 1000)
                _event = event[0][0]
                done = True
                break
            if Keyboard.process_control_keys():
                done = True
                break
            if duration:
                if int((get_time() - start) * 1000) >= duration:
                    done = True
                    break

            time.sleep(0.0005)

        if self._logging:
            expyriment._active_exp._event_file_log(
                "MIDI In ({0}),received,{1},wait".format(self.id, _event), 2)
        return _event, rt
Пример #50
0
    def wait(self, length, package_size=None, duration=None,
             check_control_keys=True):
        """Wait for data.

        Parameters:
        -----------
        length : int
            The length of the data to be waited for in bytes.
            If not set, a single package will be waited for.
        package_size : int, optional
            The size of the package to be waited for, optional.
            If not set, the default package size will be used.
            If length < package_size, package_size = length.
        duration: int, optional
            The duration to wait in milliseconds.
        process_control_keys : bool, optional
            Check if control key has been pressed (default = True).

        Returns:
        --------
        data : str
            The received data.
        rt : int
            The time it took to receive the data in milliseconds.
        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None

        start = get_time()
        data = None
        rt = None

        if package_size is None:
            package_size = self._default_package_size
        if length is None:
            length = package_size
        elif length < package_size:
            package_size = length
        while True:
            try:
                if data is None:
                    data = self._client[0].recv(package_size)
                while len(data) < length:
                    if length - len(data) >= package_size:
                        data = data + self._client[0].recv(package_size)
                    else:
                        data = data + self._client[0].recv(length - len(data))
                    if duration:
                        if int((get_time() - start) * 1000) >= duration:
                            data = None
                            rt = None
                            break
                rt = int((get_time() - start) * 1000)
                break
            except socket.error, e:
                err = e.args[0]
                if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
                    rtn_callback = expyriment._active_exp._execute_wait_callback()
                    if isinstance(rtn_callback,
                                      expyriment.control.CallbackQuitEvent):
                        return rtn_callback, int((get_time() - start) * 1000)

                    if check_control_keys:
                        if Keyboard.process_control_keys():
                            break
            if duration:
                if int((get_time() - start) * 1000) >= duration:
                    data = None
                    rt = None
                    break
Пример #51
0
    def wait_char(self, char, duration=None, check_for_control_keys=True):
        """Wait for character(s) (optionally for a certain amount of time).

        This function will wait for one or more characters and returns the
        found character as well as the reaction time.
        (This function clears the event queue!)

        Parameters
        ----------
        char : int or list
            a specific character or list of characters to wait for
        duration : int, optional
            maximal time to wait in ms
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        found : char
            pressed charater
        rt : int
            reaction time in ms

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        rt = None
        found_char = None
        self.clear()
        try:
            char = list(char)
        except:
            char = [char]
        pygame.event.pump()
        done = False

        while not done:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                done = True
                rt = int((get_time() - start) * 1000)
                found_char = rtn_callback

            for event in pygame.event.get([pygame.KEYUP, pygame.KEYDOWN]):
                if check_for_control_keys and Keyboard.process_control_keys(
                        event):
                    done = True
                elif event.type == pygame.KEYDOWN:
                    if event.unicode in char:
                        rt = int((get_time() - start) * 1000)
                        found_char = event.unicode
                        done = True
            if duration and not done:
                done = int((get_time() - start) * 1000) >= duration
            time.sleep(0.0005)
        if self._logging:
            expyriment._active_exp._event_file_log(
                "Keyboard,received,{0},wait_char".format(
                    unicode2str(found_char)))
        return found_char, rt
Пример #52
0
    def _test1():
        info = """This will test the visual stimulus presentation timing specifics of your system.
During the test, you will see two squares on the screen.
After the test, you will be asked to indicate which (if any) of those two squares were flickering.

[Press RETURN to continue]"""
        # TODO test very slow quit
        text = stimuli.TextScreen("Visual stimulus presentation test", info)
        #y = []
        #for x in [16, 32, 48, 64]:
        #    y.extend([x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ])
        #graph1 = _make_graph(range(60), y, [0, 255, 0])
        #y = range(80)
        #graph2 = _make_graph(range(60), y, [255, 0, 0])
        #graph1.position = (-200, -100)
        #graph2.position = (200, -100)
        text.present()
        #graph1.present(clear=False, update=False)
        #graph2.present(clear=False)
        exp.keyboard.wait([constants.K_RETURN])

        message = stimuli.TextScreen("Running", "Please wait...")
        message.present()
        message.present()
        message.present()
        c1 = stimuli.Canvas((400, 400))
        c2 = stimuli.Canvas((400, 400))
        c3 = stimuli.Canvas((400, 400))
        frame1 = stimuli.Rectangle((100, 100), position=(-100, 0))
        frame2 = stimuli.Rectangle((100, 100), position=(100, 0))
        bg = stimuli.Rectangle((90, 90), colour=exp.background_colour)
        bg.plot(frame1)
        bg.plot(frame2)
        frame1.plot(c1)
        frame2.plot(c2)
        frame1.plot(c3)
        frame2.plot(c3)
        c1.preload()
        c2.preload()
        c3.preload()
        c1.present(clear=False)
        c2.present(clear=False)
        c3.present(clear=False)

        s1 = stimuli.Circle(1, colour=exp.background_colour)
        s2 = stimuli.Circle(1, colour=exp.background_colour)
        s1.preload()
        s2.preload()
        todo_time = range(0, 60) * 3
        randomize.shuffle_list(todo_time)
        actual_time = []
        for x in todo_time:
            s1.present(clear=False)
            start = get_time()
            exp.clock.wait(x)
            s2.present(clear=False)
            actual_time.append((get_time() - start) * 1000)
            exp.clock.wait(expyriment.design.randomize.rand_int(30, 60))

        # determine refresh_rate
        tmp = []
        for _x in range(100):
            start = get_time()
            s1.present(clear=False)
            tmp.append(get_time() - start)
            start = get_time()
            s2.present(clear=False)
            tmp.append(get_time() - start)
        refresh_rate = 1000 / (statistics.mean(tmp) * 1000)

        #text = stimuli.TextScreen("Results", "[Press RETURN to continue]")
        #graph = _make_graph(todo_time, actual_time, [150, 150, 150])
        #graph.position = (0, -100)
        #text.present(update=False)
        #graph.present(clear=False)
        #exp.keyboard.wait([constants.K_RETURN])
        #text = stimuli.TextScreen(
        #    "Which picture looks most similar to the results?",
        #    "[Press LEFT or RIGHT arrow key]")
        #y = []
        #for x in [16, 32, 48, 64]:
        #    y.extend([x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, ])
        #graph1 = _make_graph(range(60), y, [0, 255, 0])
        #y = range(80)
        #graph2 = _make_graph(range(60), y, [255, 0, 0])
        #graph1.position = (-200, -100)
        #graph2.position = (200, -100)
        #text.present(update=False)
        #graph1.present(clear=False, update=False)
        #graph2.present(clear=False)
        #key, _rt = exp.keyboard.wait([constants.K_LEFT,
        #                             constants.K_RIGHT])
        #if key == constants.K_LEFT:
        #    response1 = "Steps"
        #elif key == constants.K_RIGHT:
        #    response1 = "Line"
        #else:
        #    response1 = None

        # show histogram of presentation delays
        def expected_delay(presentation_time, refresh_rate):
            refresh_time = 1000.0 / refresh_rate
            return refresh_time - (presentation_time % refresh_time)

        # delay = map(lambda x: x[1]- x[0], zip(todo_time, actual_time))
        unexplained_delay = map(
            lambda x: x[1] - x[0] - expected_delay(x[0], refresh_rate),
            zip(todo_time, actual_time))
        hist, hist_str = _histogram(unexplained_delay)
        inaccuracies = []
        delayed_presentations = 0
        for key in hist.keys():
            inaccuracies.extend([key % (1000 / refresh_rate)] * hist[key])
            if key != 0:
                delayed_presentations += hist[key]
        inaccuracy = int(round(sum(inaccuracies) / float(len(inaccuracies))))
        delayed = round(100 * delayed_presentations / 180.0, 2)

        text = stimuli.TextScreen(
            "How many of the two squares were flickering?",
            "[Press 0, 1 or 2]")
        text.present()
        key, _rt = exp.keyboard.wait(
            [constants.K_0, constants.K_1, constants.K_2])
        if key == constants.K_0:
            response = 0
        elif key == constants.K_1:
            response = 1
        elif key == constants.K_2:
            response = 2

        info = stimuli.TextScreen("Results", "")
        results1 = stimuli.TextScreen(
            "",
            "Estimated Screen Refresh Rate:     {0} Hz (~ every {1} ms)\n\n".
            format(int(round(refresh_rate)), int(1000.0 / refresh_rate)),
            text_font="freemono",
            text_size=16,
            text_bold=True,
            text_justification=0,
            position=(0, 40))
        results2 = stimuli.TextScreen(
            "",
            "Detected Framebuffer Pages:        {0}\n\n".format(response + 1),
            text_font="freemono",
            text_size=16,
            text_bold=True,
            text_justification=0,
            position=(0, 20))
        if inaccuracy != 0:
            results3_colour = [255, 0, 0]
        else:
            results3_colour = [0, 255, 0]
        results3 = stimuli.TextScreen(
            "",
            "Average Reporting Inaccuracy:      {0} ms\n\n".format(inaccuracy),
            text_font="freemono",
            text_size=16,
            text_bold=True,
            text_justification=0,
            text_colour=results3_colour,
            position=(0, -20))
        if delayed > 10:
            results4_colour = [255, 0, 0]
        elif 10 > delayed > 1:
            results4_colour = [255, 255, 0]
        else:
            results4_colour = [0, 255, 0]
        results4 = stimuli.TextScreen(
            "",
            "Unexplained Presentation Delays:   {0} %\n\n\n".format(delayed),
            text_font="freemono",
            text_size=16,
            text_bold=True,
            text_justification=0,
            text_colour=results4_colour,
            position=(0, -40))
        results5 = stimuli.TextScreen("",
                                      hist_str,
                                      text_font="freemono",
                                      text_size=16,
                                      text_bold=True,
                                      text_justification=0,
                                      position=(0, -100))
        results1.plot(info)
        results2.plot(info)
        results3.plot(info)
        results4.plot(info)
        results5.plot(info)
        info2 = stimuli.TextLine("[Press RETURN to continue]",
                                 position=(0, -160))
        info2.plot(info)
        info.present()
        exp.keyboard.wait([constants.K_RETURN])

        return todo_time, actual_time, refresh_rate, inaccuracy, delayed, response
Пример #53
0
exp.add_experiment_info(['Block {} - Test'.format(0)])  # Add listPictures
exp.add_experiment_info(presentationOrder)  # Add listPictures

for nCard in presentationOrder:
    m._cueCard.setPicture(m._matrix.item(
        nCard).stimuli[0].filename)  # Associate Picture to CueCard

    m.plotCueCard(True, bs, True)  # Show Cue

    exp.clock.wait(presentationCard)  # Wait presentationCard

    m.plotCueCard(False, bs, True)  # Hide Cue

    mouse.show_cursor(True, True)

    start = get_time()
    rt, position = readMouse(start, mouseButton, responseTime)

    mouse.hide_cursor(True, True)

    if rt is not None:

        currentCard = m.checkPosition(position)

        if currentCard is not None:
            m._matrix.item(currentCard).color = clickColor
            m.plotCard(currentCard, False, bs, True)

            exp.clock.wait(clicPeriod)  # Wait 500ms

            m._matrix.item(currentCard).color = cardColor
Пример #54
0
    def wait(self,
             codes=None,
             duration=None,
             no_clear_buffer=False,
             bitwise_comparison=False,
             check_for_control_keys=True):
        """Wait for responses defined as codes.

        Notes
        -----
        If bitwise_comparision = True, the function performs a bitwise
        comparison (logical and) between codes and received input and waits
        until a certain bit pattern is set.

        This will also by default check for control keys (quit and pause).
        Thus, keyboard events will be cleared from the cue and cannot be
        received by a Keyboard().check() anymore!

        Parameters
        ----------
        codes : int or list, optional
            bit pattern to wait for
            if codes is not set (None) the function returns for any
            event that differs from the baseline
        duration : int, optional
            maximal time to wait in ms
        no_clear_buffer : bool, optional
            do not clear the buffer (default = False)
        bitwise_comparison : bool, optional
            make a bitwise comparison (default = False)
        check_for_control_keys : bool, optional
            checks if control key has been pressed (default=True)

        Returns
        -------
        key : int
            key code (or None) that quitted waiting
        rt : int
            reaction time

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        rt = None
        if not no_clear_buffer:
            self.clear()
        while True:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                found = rtn_callback
                rt = int((get_time() - start) * 1000)
                break
            if duration is not None:
                if int((get_time() - start) * 1000) > duration:
                    return None, None
            found = self.check(codes, bitwise_comparison)
            if found is not None:
                rt = int((get_time() - start) * 1000)
                break
            if check_for_control_keys:
                if Keyboard.process_control_keys():
                    break
        if self._logging:
            expyriment._active_exp._event_file_log(
                "{0},received,{1},wait".format(self.__class__.__name__, found))
        return found, rt
Пример #55
0
    def process_quit_event(click_position=None):
        """Check if mouse exit action has been performed

        If Mouse.quit_rect_location is defined (i.e. 0, 1, 2 or 3), clicking
        quickly three times (i.e., within 1 second) in one of the corners of
        the screen forces the experiment to quit.

        The function is called automatically by all mouse get event and wait
        methods (similar to Keyboard.process_control_keys).  If no mouse
        functions are called by your program, this function can be polled to
        ensure quitting experiment by mouse.

        Mouse quit events are especially useful for experiments on devices
        without hardware keyboard, such as tablet PCs or smartphones.

        Parameters
        ----------
        click_position : tuple of int (x,y), optional
            clicked location to be processed. If not defined, the Pygame event
            queue will be checked for mouse down events and the current
            position is taken

        Returns
        -------
        out : bool, optional
            True if exit action has been performed
            False otherwise

        Notes
        -----
        To switch on or off the detection of mouse quit events, please use the
        static class property `quit_rect_location' (see below).

        The detection of mouse quit events is activated by default under
        Android.

        Static class properties
        ~~~~~~~~~~~~~~~~~~~~~~~

        `Mouse.quit_rect_location` = int, optional
            Location of the quit click action field or None.

            0 = upper left corner,  1 = upper right corner   (0) (1)
            2 = lower right corner, 3 = lower left corner    (3) (2)
            otherwise the detection of mouse quit events is deactivated.

            Default value under Android is 1, otherwise  None

        `Mouse.quit_click_rect_size` : tuple (int, int)
            size of the field (rect) that detects the quit action by
            triple clicking in one corner of the screen. (default = (30, 30))

        Changing the static class properties affects always all mouse
        instances.

        """

        if Mouse.quit_rect_location not in [0,1,2,3] or \
            expyriment._active_exp is None:
            return False

        if click_position is None:
            # check Pygame queu
            pos = None
            pygame.event.pump()
            screen_size = expyriment._active_exp.screen.surface.get_size()
            for event in pygame.event.get(pygame.MOUSEBUTTONDOWN):
                if event.button > 0:
                    pos = pygame.mouse.get_pos()
                    pos = (pos[0] - screen_size[0] / 2,
                          -pos[1] + screen_size[1] / 2)
                    break
            if pos is None:
                return False
            else:
                return Mouse.process_quit_event(click_position=pos)

        # determine threshold x & y
        if Mouse.quit_rect_location == 0 or Mouse.quit_rect_location == 3: # left
            threshold_x = -expyriment._active_exp.screen.center_x + \
                    Mouse.quit_click_rect_size[0]
        else:# right
            threshold_x = expyriment._active_exp.screen.center_x - \
                    Mouse.quit_click_rect_size[0]
        if Mouse.quit_rect_location == 0 or Mouse.quit_rect_location == 1: # upper
            threshold_y = expyriment._active_exp.screen.center_y - \
                    Mouse.quit_click_rect_size[1]
        else:# lower
            threshold_y = -expyriment._active_exp.screen.center_y + \
                    Mouse.quit_click_rect_size[1]
        # check
        if (Mouse.quit_rect_location == 0 and \
                click_position[0] < threshold_x and\
                click_position[1] > threshold_y) \
           or (Mouse.quit_rect_location == 1 and \
                click_position[0] > threshold_x and \
                click_position[1] > threshold_y) \
           or (Mouse.quit_rect_location == 2 and \
                click_position[0] > threshold_x and \
                click_position[1] < threshold_y) \
           or (Mouse.quit_rect_location == 3 and \
                click_position[0] < threshold_x and \
                click_position[1] < threshold_y):

            Mouse._quit_action_events.append(get_time())
            if len(Mouse._quit_action_events)>=3:
                diff = get_time()-Mouse._quit_action_events.pop(0)
                if (diff < 1):
                    # simulate quit key
                    simulated_key = pygame.event.Event(pygame.KEYDOWN,\
                                {'key': Keyboard.get_quit_key()})
                    return Keyboard.process_control_keys(
                        key_event=simulated_key)
        return False
Пример #56
0
    def wait_press(self, buttons=None, duration=None):
        """Wait for gamepad button press.

        Returns the found button and the reaction time.

        Parameters
        ----------
        buttons : int or list, optional
            specific buttons to wait for
        duration : int, optional
            maximal time to wait in ms

        Returns
        -------
        button : int
            button _id of the pressed button
        rt : int
            reaction time in ms

        See Also
        --------
        design.experiment.register_wait_callback_function

        """

        if expyriment.control.defaults._skip_wait_functions:
            return None, None
        start = get_time()
        rt = None
        _button = None
        self.clear()
        if buttons is None:
            buttons = range(self.get_numbuttons())
        try:
            buttons = list(buttons)
        except:
            buttons = [buttons]
        done = False
        while not done:
            rtn_callback = expyriment._active_exp._execute_wait_callback()
            if isinstance(rtn_callback, expyriment.control.CallbackQuitEvent):
                _button = rtn_callback
                rt = int((get_time() - start) * 1000)
                done = True

            for button in buttons:
                if self.get_button(button):
                    _button = button
                    rt = int((get_time() - start) * 1000)
                    done = True
                    break
                if _button is not None or Keyboard.process_control_keys():
                    done = True
                    break
                if duration:
                    if int((get_time() - start) * 1000) >= duration:
                        done = True
                        break

            time.sleep(0.0005)

        if self._logging:
            expyriment._active_exp._event_file_log(
                "Gamepad,received,{0},wait_press".format(_button))
        return _button, rt