简体   繁体   中英

How to stop 'enter spamming' in a python reaction timer

I have been trying to make a reaction timer for a project to test reaction times. It uses 'perf_counter' to record the times before and after an input to test how long it takes to press the enter key. The issue is that the enter key can be spammed which makes it seem if they have a reaction time of 0.000001 seconds. I have made a class which disables the keyboard and enables it when I want. Even in that case, people are able to sneak in extra enter presses between the disables and enables. I have attached the code below. Any ideas how to prevent enter spamming?

import time, random, msvcrt
from math import log10, floor
def round_sig(x, sig=5):
    return round(x, sig-int(floor(log10(abs(x))))-1)

class keyboardDisable():

    def start(self):
        self.on = True

    def stop(self):
        self.on = False

    def __call__(self): 
        while self.on:
            msvcrt.getwch()

    def __init__(self):
        self.on = False
        import msvcrt






disable = keyboardDisable()


disable.start() 


print('When I say __GO__ you hit ENTER! This will happen 3 times. Got it?')
time.sleep(2)
print('Ready')
time.sleep(1)
print('Steady')
time.sleep(random.randint(2,5))
print('#####__GO__######')


disable.stop()




tic = time.perf_counter()
a = input()
toc = time.perf_counter()
if msvcrt.kbhit():
    disable.start()
timeSpent = toc-tic
print('Your first time was '+str(timeSpent) + ' seconds')
time.sleep(1)
print('The next one is coming up.')
time.sleep(1)
print('Ready')
time.sleep(1)
print('Steady')

time.sleep(random.randint(2,5))
 
print('#####__GO__######')
disable.stop()

tic2 = time.perf_counter()
b = input()
toc2 = time.perf_counter()
if msvcrt.kbhit():
    disable.start()     
timeSpent2 = toc2-tic2
print('Your second time was '+str(timeSpent2) + ' seconds')
time.sleep(1)
     
print('The last one is coming up.')
time.sleep(1)
print('Ready')
time.sleep(1)
print('Steady')

time.sleep(random.randint(2,5))

print('#####__GO__######')
disable.stop()
tic3 = time.perf_counter()
c = input()
toc3 = time.perf_counter()
    
timeSpent3 = toc3-tic3
print('Your last time was '+str(timeSpent3) + ' seconds')
     
average = (timeSpent + timeSpent2 + timeSpent3)/3
numAverage = round_sig(average)
     
print('Your average time is '+str(numAverage) + ' seconds')

The keyboard-disabling code never really runs.

Here's a simplification of your program that uses a function to capture one reaction time and calls it thrice.

The clear_keyboard_buffer() function (that should consume all outstanding keystrokes) was borrowed from https://stackoverflow.com/a/2521054/51685 .

import time, random, msvcrt, math


def round_sig(x, sig=5):
    return round(x, sig - int(math.floor(math.log10(abs(x)))) - 1)


def clear_keyboard_buffer():
    while msvcrt.kbhit():
        msvcrt.getwch()


def get_reaction_time():
    print("Ready")
    time.sleep(1)
    print("Steady")
    time.sleep(random.randint(2, 5))
    print("#####__GO__######")
    clear_keyboard_buffer()
    tic = time.perf_counter()
    a = input()
    toc = time.perf_counter()
    return toc - tic


print("When I say __GO__ you hit ENTER! This will happen 3 times. Got it?")
time1 = get_reaction_time()
print(f"Your first time was {time1} seconds")
time.sleep(1)
print("The next one is coming up.")
time2 = get_reaction_time()
print(f"Your first time was {time2} seconds")
time.sleep(1)
print("The last one is coming up.")
time3 = get_reaction_time()
print(f"Your first time was {time3} seconds")
average = (time1 + time2 + time3) / 3
print(f"Your average time is {round_sig(average)} seconds")

This solution uses a Thread to start the timer, while the main thread waits for input all the time. That way, it is possible to catch early key presses:

from threading import Thread
import random
import time

def start():
    global started
    started = None
    time.sleep(random.randint(2,5))
    print("#### GO ####")
    started = time.time()

t = Thread(target=start)

print("ready...")

# start the thread and directly wait for input:
t.start()
input()

end = time.time()

if not started:
    print("Fail")
else:
    print(end-started)

t.join()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM