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:
Dilyorbek 2023-04-04 03:56:39 +05:00 committed by GitHub
parent b40012e606
commit 29cfe8d932
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 82 deletions

View file

@ -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();
}

View file

@ -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) {