Search code examples
pythoninputstdinenter

How to prevent users from pressing key too early in a reaction time test


I try to make a reaction time test in python.

The code works fine but users can press enter key too early which results in their reaction time being 0.0.

Code

import time
import random

print('When you see GO! press enter.')
q1 = input('Type y to start:')
if q1 == 'y' or q1 == ' y' or q1 == 'Y' or q1 == ' Y':
    pass
else:
    print('---------')
    print('***END***')
    print('---------')
    quit()

print('Get Ready!')
time.sleep(random.randint(3,5))
print('---------')
print('   G0!   ')
print('---------')
a = time.perf_counter()
input()
b = time.perf_counter()

timespent =  b-a

print('Your reaction time is ', round(timespent, 3))

I am very new to python. How to prevent or ignore premature key presses?


Solution

  • Issue supposed

    I can't figure out the issue. Seems like if enter pressed it is recorded in the STDIN buffer. When input() is invoked later, it will be returned there immediately - without waiting on a new key pressed. See Python STDIN User Input Issue.

    Solution

    But you can use any other key input library as explained in How to detect key presses?.

    Example with pynput

    Install pynput and modify your code as shown below:

    import time
    import random
    
    # Use pynput to listen for key press and release events
    from pynput.keyboard import Key, Listener
    
    def on_press(key):
        print('{0} pressed'.format(key))
        # could also react on ENTER key pressed here
    
    def on_release(key):
        print('{0} release'.format(key))
        if key == Key.enter:  # react on ENTER key released
            # Stop listener
            return False
    
    # What you had so far
    print('When you see GO! press enter.')
    q1 = input('Type y to start:')
    if q1 == 'y' or q1 == ' y' or q1 == 'Y' or q1 == ' Y':
        pass
    else:
        print('---------')
        print('***END***')
        print('---------')
        quit()
    
    print('Get Ready!')
    time.sleep(random.randint(3,5))
    print('---------')
    print('   G0!   ')
    print('---------')
    
    a = time.perf_counter()
    
    # instead of input() collect events until released
    with Listener(on_press=on_press, on_release=on_release) as listener:
        listener.join()
    
    b = time.perf_counter()
    timespent =  b-a
    print(f"start: {a}, end: {b}, duration: {timespent}")  # debug print
    
    print('Your reaction time is ', round(timespent, 3), 'seconds')  # added unit seconds