Loosing frames when keeping a button pressed

OS Win10 Pro
PsychoPy version: v2024.2.3
Standard Standalone? (y/n): yes
What are you trying to achieve?: I have an experiment where subjects are supposed to rotate a line towards a specific angle. The orientation can be manipulated by pressing one of two buttons (either clockwise or counterclockwise).

What did you try to make it work?:
Here is my code so far:
Begin routine

m_rot_kb.clock.reset()
m_rot_kb.start()
m_rot_kb.clearEvents()

decision_line_moving.ori= -45   # 0 is 45 for lines, not for other shapes though

#eyetracker.sendMessage('START_{:03d}'.format(trials.thisTrialN))

start_time = time.time()
time_diff = 0

Each frame

keys_obj = m_rot_kb.getKeys(accepted_keys, waitRelease=False, clear=False)

if len(keys_obj) > 0:
    key_name = keys_obj[-1].name
    key_duration = keys_obj[-1].duration
    if key_name == "f" and key_duration==None:
         decision_line_moving.ori -= 15*time_diff

    elif key_name == "j" and key_duration==None:
         decision_line_moving.ori += 15*time_diff

end_time = time.time()
time_diff = end_time - start_time
start_time = end_time

What specifically went wrong when you tried that?:
After some trials the line rotation starts to become laggy. However, it does not seem to be systematic, at some runs it starts to become laggy in early trials and gets worse with every new trial, in other runs it works kind of well.

I also printed the time_diff and in some cases it dropped from 60Hz (16ms) to 10Hz or worse (~100ms). The frame rate seems to drop when the key is pressed, because if you release the key the line moves smoothly for some time again at the next key press.

Before I introduced time_diff the orientation was altered every frame (0.1 degree) and this lead to some trials in which the line did not move at all when the key was pressed and only moved a bit when the key was pressed again - but definitely more than 0.1 degree.

I kept the task manager running during the experiment and RAM, CPU and GPU were stable and none of them ever reached a critical level.

Any idea what is happening there?
Best Vincent

I am currently working on a participant response paradigm that is basically the same for one of my experiments. Here is where I am at currently. The thing I am stuck on is that when holding the key down, it doesn’t continuously move the line.

 --- Begin Initialize Code ---
import math

# Initialize variables
current_angle = 0
thisExp.addData('aim_angle', 0)

# Create main aim line
aim_line = visual.Line(
    win=win,
    units='deg',
    start=(0, 0),
    end=(0.5, 0),
    lineColor='red',
    lineWidth=5,
    opacity=1.0,
    autoLog=False
)

# Create arrow head (triangle) for pointer
arrow_head = visual.Polygon(
    win=win,
    units='deg',
    edges=3,  # Triangle
    radius=0.15,  # Make it larger
    fillColor='red',
    lineColor='red',
    opacity=1.0,
    autoLog=False
)

# --- Begin Each Frame ---
# Simple keyboard check
press_me.clearEvents()  # Clear previous keys
keys = press_me.getKeys()  # Get new keys this frame

if 'left' in [key.name for key in keys]:
    current_angle = (current_angle - 2) % 360  # Adjust speed by changing 2
    
if 'right' in [key.name for key in keys]:
    current_angle = (current_angle + 2) % 360  # Adjust speed by changing 2

# Calculate line end point
line_length = 0.5
new_end_x = line_length * math.cos(math.radians(current_angle))
new_end_y = line_length * math.sin(math.radians(current_angle))

# Update line position
line_end = (
    circle.pos[0] + new_end_x,
    circle.pos[1] + new_end_y
)
aim_line.start = circle.pos
aim_line.end = line_end

# Draw line
aim_line.draw()

# Update arrow head position and orientation
arrow_head.pos = line_end  # Position at end of line
arrow_head.ori = 90 - current_angle  # Adjust orientation to point outward
arrow_head.draw()

# --- Begin End Routine ---
# Save the final angle
thisExp.addData('aim_angle', current_angle)

I plan on continuing this in January, so if no fix is found by then, I’ll gladly share my solution.
Issac

stanley1O1 I just started working with PsychoPy so I am not an expert, but I think your problem should be solved by doing press_me.getKeys(waitRelease=False)

Keyboard.getKeys() detects a key-down event and (optionally a key-up event) but does not constantly report a key while it remains pressed. That is, it doesn’t report the current state of the keyboard, it reports if an event has occurred.

I think you can use Keyboard.getState though, something like this (untested):

f_is_down, j_is_down = Keyboard.getState(['f', 'j'])
if f_is_down:
    decision_line_moving.ori -= 15*time_diff
if j_is_down:
    decision_line_moving.ori += 15*time_diff

In my key-down online demo I use two keyboard responses, one detecting key presses and the other key releases.

https://run.pavlovia.org/vespr/key-down/

Key Down code | try it | discussion thread

Compares the length of two keyboard components (one detecting key presses and the other key releases) to determine whether a key is currently pressed down.

if key_down.keys: # Online key_down.keys does not exit until a key has been pressed
    if not key_release.keys:
        keyDown = True
        if key_down.keys[-1] == 'right':
            thisOri += 1
        elif key_down.keys[-1] == 'left':
            thisOri -= 1
        msg = 'key_down.keys ' + str(len(key_down.keys)) + '\nkey_release.keys 0\nfudgeFactor ' + str(fudgeFactor)
    elif len(key_down.keys) > len(key_release.keys) + fudgeFactor:
        keyDown = True
        if key_down.keys[-1] == 'right':
            thisOri += 1
        elif key_down.keys[-1] == 'left':
            thisOri -= 1
        elif key_down.keys[-1] == 'space':
            continueRoutine = False
        # Sometime a key release gets missed
        if len(key_down.keys) > len(key_release.keys) + 1 + fudgeFactor:
            fudgeFactor += 1
        msg = 'key_down.keys ' + str(len(key_down.keys)) + '\nkey_release.keys ' + str(len(key_release.keys)) + '\nfudgeFactor ' + str(fudgeFactor)
    else:
        keyDown = False
        # Sometime a key press gets missed
        if len(key_down.keys) < len(key_release.keys) + fudgeFactor:
            fudgeFactor -= 1
        msg = 'key_down.keys ' + str(len(key_down.keys)) + '\nkey_release.keys ' + str(len(key_release.keys)) + '\nfudgeFactor ' + str(fudgeFactor)