mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-22 16:26:18 +08:00
Fix duration ordering and new algorithm for key overlap (#4141) drdilyor
* test2 * mod2 * mod3 * fix incomplete keystrokes now have duration * make loop go forward for readability * check if keysorder is empty * prettier * clean up * rename variables for readability * remove the algorithm and debug info * type casting * merged objects into one moved code around * removed "toolong" clientside type * fixed assignment --------- Co-authored-by: Miodec <jack@monkeytype.com>
This commit is contained in:
parent
b40012e606
commit
29cfe8d932
|
@ -1,6 +1,57 @@
|
|||
import * as TestWords from "./test-words";
|
||||
import { mean, roundTo2 } from "../utils/misc";
|
||||
|
||||
const keysToTrack = [
|
||||
"Backquote",
|
||||
"Digit1",
|
||||
"Digit2",
|
||||
"Digit3",
|
||||
"Digit4",
|
||||
"Digit5",
|
||||
"Digit6",
|
||||
"Digit7",
|
||||
"Digit8",
|
||||
"Digit9",
|
||||
"Digit0",
|
||||
"Minus",
|
||||
"Equal",
|
||||
"KeyQ",
|
||||
"KeyW",
|
||||
"KeyE",
|
||||
"KeyR",
|
||||
"KeyT",
|
||||
"KeyY",
|
||||
"KeyU",
|
||||
"KeyI",
|
||||
"KeyO",
|
||||
"KeyP",
|
||||
"BracketLeft",
|
||||
"BracketRight",
|
||||
"Backslash",
|
||||
"KeyA",
|
||||
"KeyS",
|
||||
"KeyD",
|
||||
"KeyF",
|
||||
"KeyG",
|
||||
"KeyH",
|
||||
"KeyJ",
|
||||
"KeyK",
|
||||
"KeyL",
|
||||
"Semicolon",
|
||||
"Quote",
|
||||
"KeyZ",
|
||||
"KeyX",
|
||||
"KeyC",
|
||||
"KeyV",
|
||||
"KeyB",
|
||||
"KeyN",
|
||||
"KeyM",
|
||||
"Comma",
|
||||
"Period",
|
||||
"Slash",
|
||||
"Space",
|
||||
];
|
||||
|
||||
interface Keypress {
|
||||
count: number;
|
||||
errors: number;
|
||||
|
@ -11,13 +62,18 @@ interface Keypress {
|
|||
interface KeypressTimings {
|
||||
spacing: {
|
||||
last: number;
|
||||
array: number[] | "toolong";
|
||||
array: number[];
|
||||
};
|
||||
duration: {
|
||||
array: number[] | "toolong";
|
||||
array: number[];
|
||||
};
|
||||
}
|
||||
|
||||
interface Keydata {
|
||||
timestamp: number;
|
||||
index: number;
|
||||
}
|
||||
|
||||
class Input {
|
||||
current: string;
|
||||
history: string[];
|
||||
|
@ -136,6 +192,8 @@ class Corrected {
|
|||
}
|
||||
}
|
||||
|
||||
let keyDownData: Record<string, Keydata> = {};
|
||||
|
||||
export const input = new Input();
|
||||
export const corrected = new Corrected();
|
||||
|
||||
|
@ -224,98 +282,49 @@ export function incrementAccuracy(correctincorrect: boolean): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function setKeypressTimingsTooLong(): void {
|
||||
keypressTimings.spacing.array = "toolong";
|
||||
keypressTimings.duration.array = "toolong";
|
||||
}
|
||||
|
||||
let keysObj: Record<string, number> = {};
|
||||
|
||||
const keysToTrack = [
|
||||
"Backquote",
|
||||
"Digit1",
|
||||
"Digit2",
|
||||
"Digit3",
|
||||
"Digit4",
|
||||
"Digit5",
|
||||
"Digit6",
|
||||
"Digit7",
|
||||
"Digit8",
|
||||
"Digit9",
|
||||
"Digit0",
|
||||
"Minus",
|
||||
"Equal",
|
||||
"KeyQ",
|
||||
"KeyW",
|
||||
"KeyE",
|
||||
"KeyR",
|
||||
"KeyT",
|
||||
"KeyY",
|
||||
"KeyU",
|
||||
"KeyI",
|
||||
"KeyO",
|
||||
"KeyP",
|
||||
"BracketLeft",
|
||||
"BracketRight",
|
||||
"Backslash",
|
||||
"KeyA",
|
||||
"KeyS",
|
||||
"KeyD",
|
||||
"KeyF",
|
||||
"KeyG",
|
||||
"KeyH",
|
||||
"KeyJ",
|
||||
"KeyK",
|
||||
"KeyL",
|
||||
"Semicolon",
|
||||
"Quote",
|
||||
"KeyZ",
|
||||
"KeyX",
|
||||
"KeyC",
|
||||
"KeyV",
|
||||
"KeyB",
|
||||
"KeyN",
|
||||
"KeyM",
|
||||
"Comma",
|
||||
"Period",
|
||||
"Slash",
|
||||
"Space",
|
||||
];
|
||||
|
||||
export function forceKeyup(): void {
|
||||
//using mean here because for words mode, the last keypress ends the test.
|
||||
//if we then force keyup on that last keypress, it will record a duration of 0
|
||||
//skewing the average and standard deviation
|
||||
const avg = roundTo2(mean(keypressTimings.duration.array as number[]));
|
||||
for (const key of Object.keys(keysObj)) {
|
||||
(keypressTimings.duration.array as number[]).push(avg);
|
||||
delete keysObj[key];
|
||||
const avg = roundTo2(mean(keypressTimings.duration.array));
|
||||
const keysOrder = Object.entries(keyDownData);
|
||||
keysOrder.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
||||
for (let i = 0; i < keysOrder.length - 1; i++) {
|
||||
recordKeyupTime(keysOrder[i][0]);
|
||||
}
|
||||
const last = keysOrder[keysOrder.length - 1];
|
||||
if (last !== undefined) {
|
||||
keypressTimings.duration.array[keyDownData[last[0]].index] = avg;
|
||||
}
|
||||
}
|
||||
|
||||
export function recordKeyupTime(key: string): void {
|
||||
if (keysObj[key] === undefined || !keysToTrack.includes(key)) {
|
||||
if (keyDownData[key] === undefined || !keysToTrack.includes(key)) {
|
||||
return;
|
||||
}
|
||||
const now = performance.now();
|
||||
const diff = Math.abs(keysObj[key] - now);
|
||||
(keypressTimings.duration.array as number[]).push(roundTo2(diff));
|
||||
delete keysObj[key];
|
||||
const diff = Math.abs(keyDownData[key].timestamp - now);
|
||||
keypressTimings.duration.array[keyDownData[key].index] = diff;
|
||||
delete keyDownData[key];
|
||||
|
||||
updateOverlap();
|
||||
updateOverlap(now);
|
||||
}
|
||||
|
||||
export function recordKeydownTime(key: string): void {
|
||||
if (keysObj[key] !== undefined || !keysToTrack.includes(key)) {
|
||||
if (keyDownData[key] !== undefined || !keysToTrack.includes(key)) {
|
||||
return;
|
||||
}
|
||||
keysObj[key] = performance.now();
|
||||
keyDownData[key] = {
|
||||
timestamp: performance.now(),
|
||||
index: keypressTimings.duration.array.length,
|
||||
};
|
||||
keypressTimings.duration.array.push(0);
|
||||
|
||||
updateOverlap();
|
||||
updateOverlap(keyDownData[key].timestamp);
|
||||
|
||||
if (keypressTimings.spacing.last !== -1) {
|
||||
const diff = Math.abs(performance.now() - keypressTimings.spacing.last);
|
||||
(keypressTimings.spacing.array as number[]).push(roundTo2(diff));
|
||||
keypressTimings.spacing.array.push(roundTo2(diff));
|
||||
if (spacingDebug) {
|
||||
console.log(
|
||||
"spacing debug",
|
||||
|
@ -331,9 +340,8 @@ export function recordKeydownTime(key: string): void {
|
|||
keypressTimings.spacing.last = performance.now();
|
||||
}
|
||||
|
||||
function updateOverlap(): void {
|
||||
const now = performance.now();
|
||||
const keys = Object.keys(keysObj);
|
||||
function updateOverlap(now: number): void {
|
||||
const keys = Object.keys(keyDownData);
|
||||
if (keys.length > 1) {
|
||||
if (keyOverlap.lastStartTime === -1) {
|
||||
keyOverlap.lastStartTime = now;
|
||||
|
@ -360,7 +368,7 @@ export function resetKeypressTimings(): void {
|
|||
total: 0,
|
||||
lastStartTime: -1,
|
||||
};
|
||||
keysObj = {};
|
||||
keyDownData = {};
|
||||
if (spacingDebug) console.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -1443,10 +1443,7 @@ function buildCompletedEvent(difficultyFailed: boolean): CompletedEvent {
|
|||
const stddev = Misc.stdDev(rawPerSecond);
|
||||
const avg = Misc.mean(rawPerSecond);
|
||||
let consistency = Misc.roundTo2(Misc.kogasa(stddev / avg));
|
||||
let keyConsistencyArray =
|
||||
TestInput.keypressTimings.spacing.array === "toolong"
|
||||
? []
|
||||
: TestInput.keypressTimings.spacing.array.slice();
|
||||
let keyConsistencyArray = TestInput.keypressTimings.spacing.array.slice();
|
||||
if (keyConsistencyArray.length > 0) {
|
||||
keyConsistencyArray = keyConsistencyArray.slice(
|
||||
0,
|
||||
|
@ -1757,7 +1754,6 @@ export async function finish(difficultyFailed = false): Promise<void> {
|
|||
completedEvent.chartData = "toolong";
|
||||
completedEvent.keySpacing = "toolong";
|
||||
completedEvent.keyDuration = "toolong";
|
||||
TestInput.setKeypressTimingsTooLong();
|
||||
}
|
||||
|
||||
if (dontSave) {
|
||||
|
|
Loading…
Reference in a new issue