; ACT-R tutorial unit 2 demo2 task.
; This experiment opens a window, displays a character,
; waits for a keypress, clears the window after there
; is a keypress, and then reports the key that was pressed.

; Start by loading the corresponding tutorial model

(load-act-r-model "ACT-R:tutorial;unit2;demo2-model.lisp")


; Create a variable to store the key that was pressed.

(defvar *response* nil)


; This is the function which we will have ACT-R call when
; a key is pressed in the experiment window which is signaled
; by the output-key action.
; That action provides two parameters to the function called.
; The first is the name of the model that performed the keypress
; or nil if it wasn't generated by a model, and the second
; is a string with the name of the key that was pressed.

(defun respond-to-key-press (model key)
  ; we aren't using the model so declare that to avoid warnings
  
  (declare (ignore model))
  
  ; store the key that was pressed in the *response* variable
  
  (setf *response* key)
  
  ; call the AGI command that clears the window
  
  (clear-exp-window))


; This is the function that runs the experiment for either a
; person or a model.  It has one optional parameter which if
; provided as a true value (anything not nil) will run a person.
; If it is not provided or nil is specified then it will run the
; ACT-R model.

(defun demo2-experiment (&optional human)
  
  ; Reset the ACT-R system and any models that are defined to
  ; their initial states.
  
  (reset)
  
  ; Create three variable:
  ;   items - a randomized list of letter strings which is randomized
  ;           using the ACT-R function permute-list
  ;   text1 - the first string from the randomized list which will be the
  ;           one presented in the experiment
  ;   window - the ACT-R window device list returned by using the ACT-R
  ;            function open-exp-window to create a new window for 
  ;            displaying the experiment 
  
  (let* ((items (permute-list '("B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" 
                                "P" "Q" "R" "S" "T" "V" "W" "X" "Y" "Z")))
         (text1 (first items))
         (window (open-exp-window "Letter recognition")))
    
    ; display the text1 item in the window that was opened
    
    (add-text-to-exp-window window text1 :x 125 :y 150)
    
    ; These next two function calls are how we tell ACT-R that it should
    ; call our respond-to-key-press function when there is a keypress
    ; in the experiment.
    
    ; First we need to create a command in ACT-R that corresponds
    ; to our function so that ACT-R is able to use the function.
    
    (add-act-r-command "demo2-key-press" 'respond-to-key-press 
                       "Demo2 task output-key monitor")
    
    ; Then, we use that command which we created to 'monitor' 
    ; the output-key action which is triggered by keypress in the
    ; experiment window of ACT-R so that when an output-key happens
    ; our function is called.
    
    (monitor-act-r-command "output-key" "demo2-key-press")
    
    ; Set the *response* value to nil to remove any value it may
    ; have from a previous run of the experiment.
    
    (setf *response* nil) 
    
    ; Here is where we actually "run" the experiment.
    ; It either waits for a person to press a key or runs ACT-R
    ; for up to 10 seconds giving the model a chance to do the
    ; experiment.
    
    (if human
        
        ; If a person is doing the task then for safety 
        ; we make sure there is a visible window that they
        ; can use to do the task, and if so, loop until the
        ; *response* variable is non-nil calling the 
        ; process-events function to allow the system a 
        ; chance to handle any interactions.
        
        (when (visible-virtuals-available?)
          (while (null *response*)
            (process-events)))
      
      ; If it is not a human then use install-device so that
      ; the features in the window will be seen by the model
      ; (that will also automatically provide the model with
      ; access to a virtual keyboard and mouse).  Then use
      ; the ACT-R run function to run the model for up to 10
      ; seconds in real-time mode.
           
      (progn
        (install-device window)
        (run 10 t)))
    
    ; To avoid any issues with our function for keypresses in this
    ; experiment interfering with other experiments we should stop
    ; monitoring output-key and then remove our command.
    
    (remove-act-r-command-monitor "output-key" "demo2-key-press")
    (remove-act-r-command "demo2-key-press")
    
    ; return the result of the keypress
    
    *response*))

