[visionegg] DaqKeyboard and ResponseControl classes

Hi all,

I needed a solution to collect the responses and response times
of volunteers during a psychophysical experiment. So I needed
access to the keyboard during a presentation is running. One
way to achieve this is to use the pygame module (as described
in dots_simple_loop.py). But I want to keep the source code for
the stimulus as short and clean as possible. I also like to use
controllers in the Vision Egg...

For collecting responses and response times from the keyboard I
wrote two classes: DaqKeyboard and ResponseControl. Please look
at the attached files and let me know what you think about it.
Maybe their are useful for the Vision Egg community.

Best

        Hubertus

================================================================
                         DaqKeyboard.py
================================================================

# The Vision Egg: DaqKeyboard
#
# Author(s): Hubertus Becker <hubertus.becker@xxxxxxxxxxxxxxxx>
# Copyright: (C) 2005 by Hertie Institute for Clinical Brain Research,
#            Department of Cognitive Neurology, University of Tuebingen
# URL:       http://www.hubertus-becker.de/resources/visionegg/
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of
# the License, or (at your option) any later version.
#
# $Revision: 1.1 $  $Date: 2005/05/27 17:19:25 $


"""
Data acquisition and triggering over the keyboard.

This module was programmed using information from the web site
http://www.pygame.org/docs/ref/pygame_key.html

"""

####################################################################
#
#        Import all the necessary packages
#
####################################################################

import VisionEgg
import VisionEgg.Core
import VisionEgg.FlowControl
import VisionEgg.Daq
import VisionEgg.ParameterTypes as ve_types
import sys
import pygame

__version__ = VisionEgg.release_name
__cvs__ = '$Revision: 1.1 $'.split()[1]
__date__ = ' '.join('$Date: 2005/05/27 17:18:49 $'.split()[1:3])
__author__ = 'Hubertus Becker <hubertus.becker@xxxxxxxxxxxxxxxx>'

# Use Python's bool constants if available, make aliases if not
try:
    True
except NameError:
    True = 1==1
    False = 1==0

####################################################################
#
#        KeyboardInput
#
####################################################################

class KeyboardInput(VisionEgg.Daq.Input):

    def get_pygame_data(self):
        """Get keyboard input (return values are in pygame.locals.* 
notation)."""
        keys = pygame.key.get_pressed()
        return [k for k, v in enumerate(keys) if v]

    def get_string_data(self):
        """Get keyboard input (return values are converted to keyboard symbols 
(strings))."""
        pressed = self.get_pygame_data()
        keys_pressed = []
        for k in pressed: # Convert integers to keyboard symbols (strings)
            keys_pressed.append(pygame.key.name(k))
        return keys_pressed

    get_data = get_string_data # Create alias

####################################################################
#
#        KeyboardTriggerInController
#
####################################################################

class KeyboardTriggerInController(VisionEgg.FlowControl.Controller):
    """Use the keyboard to trigger the presentation."""

    def __init__(self,key=pygame.locals.K_1):
        VisionEgg.FlowControl.Controller.__init__(
            self,
            return_type=ve_types.Integer,
            eval_frequency=VisionEgg.FlowControl.Controller.EVERY_FRAME)
        self.key = key

    def during_go_eval(self):
        return 1

    def between_go_eval(self):
        for event in pygame.event.get():
#           if (event.type == pygame.locals.KEYUP) or (event.type == 
pygame.locals.KEYDOWN):
            if event.type == pygame.locals.KEYDOWN:
                if event.key == self.key:
                    return 1
                else:
                    return 0

================================================================
                        ResponseControl
================================================================

# The Vision Egg: ResponseControl
#
# Author(s): Hubertus Becker <hubertus.becker@xxxxxxxxxxxxxxxx>
# Copyright: (C) 2005 by Hertie Institute for Clinical Brain Research,
#            Department of Cognitive Neurology, University of Tuebingen
# URL:       http://www.hubertus-becker.de/resources/visionegg/
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of
# the License, or (at your option) any later version.
#
# $Revision: 1.1 $  $Date: 2005/05/27 17:18:49 $

"""
Response control during a presentation is running.

"""

####################################################################
#
#        Import all the necessary packages
#
####################################################################

try:
    import logging
    import logging.handlers
except ImportError:
    import VisionEgg.py_logging as logging

import VisionEgg
import VisionEgg.Core
import VisionEgg.FlowControl
import VisionEgg.Daq
import VisionEgg.DaqLPT
import DaqKeyboard
import VisionEgg.ParameterTypes as ve_types
import pygame

__version__ = VisionEgg.release_name
__cvs__ = '$Revision: 1.1 $'.split()[1]
__date__ = ' '.join('$Date: 2005/05/27 17:59:49 $'.split()[1:3])
__author__ = 'Hubertus Becker <hubertus.becker@xxxxxxxxxxxxxxxx>'

# Use Python's bool constants if available, make aliases if not
try:
    True
except NameError:
    True = 1==1
    False = 1==0

####################################################################
#
#        ResponseController
#
####################################################################

class ResponseController(VisionEgg.FlowControl.Controller):
    """This abstract base class defines the interface to any 
ResponseController.

    This module provides an interface to collect responses during a
    presentation is running. To interface with real data acquisition devices,
    use a module that subclasses the classes defined here.

    """

    def _reset(self):
        self.responses = []
        self.responses_since_go = []
        self.time_responses_since_go = []
        self.first_responses_since_go = []
        self.time_first_responses_since_go = None
        self.status_first_responses_since_go = False
        self.last_responses_since_go = []
        self.time_last_responses_since_go = None

    def __init__(self, **kw):
        self._reset()

    def get_responses(self):
        """Returns the responses in the current frame."""
        return self.responses

    get_data = get_responses # For backward compatibility

    def get_responses_since_go(self):
        """Returns all responses since the main 'go' loop has been
        started."""
        return self.responses_since_go

    def get_time_responses_since_go(self):
        """Returns the time stamps for all responses since the main 'go'
        loop has been started."""
        return self.time_responses_since_go

    def get_first_response_since_go(self, index=0):
        """Returns the first response since the main 'go' loop has been
        started."""
        if self.first_responses_since_go == []:
            return []
        else:
            return self.first_responses_since_go[index]

    def get_first_responses_since_go(self):
        """Returns the first responses since the main 'go' loop has been
        started."""
        return self.first_responses_since_go

    def get_time_first_response_since_go(self):
        """Returns the time stamp for first responses since the main 'go'
        loop has been started."""
        return self.time_first_responses_since_go

    get_time_first_responses_since_go = get_time_first_response_since_go

    def get_last_response_since_go(self, index=0):
        """Returns the last response since the main 'go' loop has been
        started."""
        if self.last_responses_since_go == []:
            return []
        else:
            return self.last_responses_since_go[index]

    def get_last_responses_since_go(self):
        """Returns the last responses since the main 'go' loop has been
        started."""
        return self.last_responses_since_go

    def get_time_last_response_since_go(self):
        """Returns the time stamp for last response since the main 'go'
        loop has been started."""
        return self.time_last_responses_since_go

    get_time_last_responses_since_go = get_time_last_response_since_go

    def between_go_eval(self):
        """Evaluate between runs of the main 'go' loop.

        Override this method in subclasses."""
        raise RuntimeError("%s: Definition of between_go_eval() in abstract 
base class ResponseController must be overriden."%(str(self),))

    def during_go_eval(self):
        """Evaluate during the main 'go' loop.

        Override this method in subclasses."""
        raise RuntimeError("%s: Definition of during_go_eval() in abstract 
base class ResponseController must be overriden."%(str(self),))


####################################################################
#
#        KeyboardResponseController
#
####################################################################

#class KeyboardResponseController(VisionEgg.ReponseController):
class KeyboardResponseController(ResponseController):
    """Use the keyboard to collect responses during a presentation is 
running."""

    def __init__(self):
        VisionEgg.FlowControl.Controller.__init__(self,
            return_type=ve_types.get_type(None),
            eval_frequency=VisionEgg.FlowControl.Controller.EVERY_FRAME,
            
temporal_variables=VisionEgg.FlowControl.Controller.TIME_SEC_SINCE_GO
        )
        self.input = DaqKeyboard.KeyboardInput()

    def between_go_eval(self):
        return None # Ignore keyboard

    def during_go_eval(self):
        if self.time_sec_since_go <= 0.01: # Reset it every presentation
            self._reset()
#       self.responses = self.input.get_pygame_data()
        self.responses = self.input.get_string_data()
        if len(self.responses) > 0:
            self.responses_since_go.append(self.responses)
            self.time_responses_since_go.append(self.time_sec_since_go)
            if self.status_first_responses_since_go == False:
                self.time_first_responses_since_go = self.time_sec_since_go
                self.first_responses_since_go = self.responses
                self.status_first_responses_since_go = True
            self.time_last_responses_since_go = self.time_sec_since_go
            self.last_responses_since_go = self.responses
        return None

-- 
Hubertus Becker, Hertie Institute for Clinical Brain Research
Department of Cognitive Neurology, Visual Perception Laboratory
University of Tuebingen, Hoppe-Seyler-Str. 3, D-72076 Tuebingen
Homepage: http://www.hubertus-becker.de (GnuPG-Key available)


Other related posts: