{"id":3217,"date":"2026-07-06T07:00:34","date_gmt":"2026-07-06T05:00:34","guid":{"rendered":"https:\/\/fotografeer.nl\/?p=3217"},"modified":"2026-08-21T14:53:07","modified_gmt":"2026-08-21T12:53:07","slug":"rehab-typing-test","status":"publish","type":"post","link":"https:\/\/fotografeer.nl\/?p=3217","title":{"rendered":"Rehab &#8211; Typing Test &#8211; v1.3"},"content":{"rendered":"\n<script>\n    var logLevel = \"INFO\"; \/\/ DEBUG, INFO, ERROR or OFF\n    var translation = {\n        \"en\": {\n                \"duration\": \"Duration\",\n                \"accuracy\": \"Accuracy\",\n\t\t\t\t\"words\": \"Words\",\n                \"cps\": \"Char\/s\",\n                \"cpm\": \"Char\/min\",\n                \"wpm\": \"Words\/min\",\n                \"presets\": \"Autocomplete Presets and Text Refresh\",\n                \"settings\": \"Autocomplete settings\",\n                \"readError\": \"Error while reading from \",\n                \"forbidden\": \"Forbidden to read from \",\n                \"notFound\": \"Unable to find \",\n                \"F1\": \"Simple(F1)\",\n                \"F2\": \"Intermediate(F2)\",\n                \"F3\": \"Advanced(F3)\",\n                \"F4\": \"Type Test(F4)\",\n                \"F5\": \"Refresh(F5)\",\n                \"F6\": \"Punctuation(F6)\",\n                \"F7\": \"Caps(F7)\",\n                \"F8\": \"Numbers(F8)\",\n                \"F9\": \"Special Chars(F9)\",\n                \"F10\": \"Space(F10)\",\n                \"loading\": \"Loading Text...\",\n                \"source\": \"<i>Source<\/i>\",\n                \"errorArea\": '<b style=\"color:red; font-size:26px;\">Error Area. No errors detected yet...<\/b>',\n                \"textArea\": \"<i>Text Area<\/i>\",\n                \"mobile\": \"This application<br\/> requires a PC or<br\/>laptop with a<br\/>physical keyboard.<br\/>Mobile phones and<br\/>tablets are<br\/>not supported!\",\n                \"tablet\": '<b style=\"color:red;\">Mobile Phones and<br\/>Tablets Not Supported<\/b>',\n            },\n        \"nl\": {\n                \"duration\": \"Duur\",\n                \"accuracy\": \"Nauwkeurigheid\",\n\t\t\t\t\"words\": \"Wrdn\",\n                \"cps\": \"Kar\/s\",\n                \"cpm\": \"Kar\/min\",\n                \"wpm\": \"Woorden\/min\",\n                \"presets\": \"Moeilijkheidsgraad en Ververs Tekst\",\n                \"settings\": \"Automatische Aanvul Instellingen\",\n                \"readError\": \"Fout bij lezen van \",\n                \"forbidden\": \"Verboden om te lezen van \",\n                \"notFound\": \"Niet gevonden: \",\n                \"F1\": \"Beginner(F1)\",\n                \"F2\": \"Gevorderd(F2)\",\n                \"F3\": \"Expert(F3)\",\n                \"F4\": \"Type Test(F4)\",\n                \"F5\": \"Ververs(F5)\",\n                \"F6\": \"Tekens(F6)\",\n                \"F7\": \"Hfdletters(F7)\",\n                \"F8\": \"Nummers(F8)\",\n                \"F9\": \"Speciale Kars(F9)\",\n                \"F10\": \"Spatie(F10)\",\n                \"loading\": 'Tekst Laden...',\n                \"source\": \"<i>Bron<\/i>\",\n                \"errorArea\": '<b style=\"color:red; font-size:26px;\">Fout Meldingen. Nog geen fouten ontdekt...<\/b>',\n                \"textArea\": \"<i>Tekst Veld<\/i>\",\n                \"mobile\": \"Voor deze applicatie<br\/>is een PC of laptop met<br\/>een fysiek toetsenbord<br\/>nodig.<br\/>Mobiele telefoons en<br\/>tablets zijn<br\/>niet geschikt!\",\n                \"tablet\": '<b style=\"color:red;\">Mobiele Telefoons en<br\/>Tablets zijn niet geschikt<\/b>',\n              },\n    };\n    var language = \"en\"; \/\/ Default language, overridden by page language\n    var country = \"GB\"; \/\/ Default country, overridden by page country\n    var altDown = false;\n    var kar = \"\";\n    var _buffer = null;\n    var disabledOrigin = false;\n    var loadPage = \"\";\n    var error = \"\";\n    var veld = \"\";\n    var tekst = \"\";\n    var source = \"\";\n    var sel = \"\";\n    var beforeCursor = \"\";\n    var atCursor = \"\";\n    var afterCursor = \"\";\n    var cursorPosition = 1;\n    var start = 0;\n    var end = 0;\n    var time = 0;\n    var duration = 0;\n    var accuracy = 0;\n\tvar words = 0;\n    var cps = 0;\n    var cpm = 0;\n\tvar wpm = 0;\n\tvar minutes = 0;\n\tvar seconds = 0;\n\tvar remainder = 0;\n    var numberOfKeysPressed = 0;\n    var correctKeysPressed = 0;\n    var urls = [];\n    var originalText = \"\";\n    var mode = \"Simple\";\n    var punctuation = \".?!,;:-\u2013\u2014()[]{}'\" + '\"';  \/\/ Punctuation marks\n    var space = \" \"; \/\/ Space\n    var numbers = \"0123456789\"; \/\/ Numbers\n    \/\/ Special characters exculding punctuation marks\n    var speci = \"#$%&*+\/<=>@^_`|~\\\\\u00b0\u00a3\u20ac\u00a5\u00a2\u00e1\u00e9\u00ed\u00f3\u00fa\u00fd\u00c1\u00c9\u00cd\u00d3\u00da\u00dd\u00e0\u00e8\u00ec\u00f2\u00f9\u00c0\u00c8\u00cc\u00d2\u00d9\u00e2\u00ea\u00ee\u00f4\u00fb\u00c2\u00ca\u00ce\u00d4\u00db\u00e4\u00eb\u00ef\u00f6\u00fc\u00ff\u00c4\u00cb\u00cf\u00d6\u00dc\u00e3\u00f1\u00f5\u00c3\u00d1\u00d5\u00e7\u0123\u0137\u013c\u0146\u00c7\u0122\u0136\u013b\u0145\u00e5\u00c5\u010d\u0161\u017e\u010c\u0160\u017d\u0101\u0113\u012b\u014d\u016b\u0100\u0112\u012a\u014c\u016a\u00e6\u0153\u00df\u00f0\u00f8\u00fe\u00c6\u0152\u1e9e\u00d0\u00d8\u00de\";\n    const raw = \"https:\/\/raw.githubusercontent.com\/dsnpevl\/rehabilitation.typing.test\/refs\/heads\/main\/\";\n    const apiurl = \"https:\/\/api.github.com\/repos\/dsnpevl\/rehabilitation.typing.test\/git\/trees\/main?recursive=1\";\n    const digitsOnly = string => [...string].every(c => '0123456789'.includes(c));\n    document.addEventListener(\"keyup\", upKey);\n    document.addEventListener(\"keydown\", downKey);\n    window.addEventListener(\"load\", (event) => {\n        info(\"Start Typing Test\");\n        \/\/ Determine the document's language (e.g. en) and country (e.g. GB)\n        \/\/ from locale (e.g. en-GB); Then get the matching URLs.\n        var locale = document.documentElement.lang.split(\"-\"); \/\/ e.g. en-GB\n        language = locale[0];\n        country = locale[1];\n        \/\/ Set text of errors, source field, results field and buttons to match the language of the current page.\n        document.getElementById(\"duration\").innerHTML = i18n(language, \"duration\") + ': <b style=\"color:red\">0<\/b> min <b style=\"color:red\">0<\/b> s&nbsp;';\n        document.getElementById(\"accuracy\").innerHTML = i18n(language, \"accuracy\") + ': <b style=\"color:red\">0<\/b> %&nbsp;';\n        document.getElementById(\"words\").innerHTML = i18n(language, \"words\") + ': <b style=\"color:red\">0<\/b>';\n        document.getElementById(\"cps\").innerHTML = i18n(language, \"cps\") + ': <b style=\"color:red\">0<\/b>&nbsp;';\n        document.getElementById(\"cpm\").innerHTML = i18n(language, \"cpm\") + ': <b style=\"color:red\">0<\/b>&nbsp;';\n        document.getElementById(\"wpm\").innerHTML = i18n(language, \"wpm\") + ': <b style=\"color:red\">0<\/b>';\n        document.getElementById(\"presets\").textContent = i18n(language, \"presets\");\n        document.getElementById(\"settings\").textContent = i18n(language, \"settings\");\n        document.getElementById(\"F1\").textContent = i18n(language, \"F1\");\n        document.getElementById(\"F2\").textContent = i18n(language, \"F2\");\n        document.getElementById(\"F3\").textContent = i18n(language, \"F3\");\n        document.getElementById(\"F4\").textContent = i18n(language, \"F4\");\n        document.getElementById(\"F5\").textContent = i18n(language, \"F5\");\n        document.getElementById(\"F6\").textContent = i18n(language, \"F6\");\n        document.getElementById(\"F7\").textContent = i18n(language, \"F7\");\n        document.getElementById(\"F8\").textContent = i18n(language, \"F8\");\n        document.getElementById(\"F9\").textContent = i18n(language, \"F9\");\n        document.getElementById(\"F10\").textContent = i18n(language, \"F10\");\n        document.getElementById(\"error\").innerHTML = i18n(language, \"errorArea\");\n        document.getElementById(\"blauw\").innerHTML = i18n(language, \"textArea\");\n        document.getElementById(\"source\").innerHTML = i18n(language, \"source\");\n        debug(\"Mobile or tablet? \" + mobileAndTabletCheck());\n\n        if (mobileAndTabletCheck()) {\n            document.getElementById(\"tekst\").innerHTML = i18n(language, \"mobile\");\n            document.getElementById(\"error\").innerHTML = i18n(language, \"tablet\");\n            return;\n        }\n\n        debug(dateAsString());\n        start = new Date().getTime();\n        setTimeout(() => {\n            error = document.getElementById(\"error\");\n            veld = document.getElementById(\"veld\");\n            tekst = document.getElementById(\"tekst\");\n            source = document.getElementById(\"source\");\n\t\t\tsel = document.getElementById(\"files\");\n            sel.addEventListener('change', function(){\n                debug(\"New file Selected\");\n                var lev = \"\"; \/\/ Selected difficulty lev\n\t\t\t\tif (!document.getElementById(\"F1\").disabled) lev = \"F1\";\n\t\t        if (!document.getElementById(\"F2\").disabled) lev = \"F2\";\n\t\t        if (!document.getElementById(\"F3\").disabled) lev = \"F3\";\n\t\t        if (!document.getElementById(\"F4\").disabled) lev = \"F4\";\n\t\t\t\tvar x = sel.selectedIndex;\n                var filename = document.getElementsByTagName(\"option\")[x].value;\n                debug(\"Index \" + x + \" name: \" + filename);\n                cursorPosition = 0;\t\t\t\t\n\t\t\t\tgetText(raw + \"\/\" + language + \"\/\" + lev + \"\/\" + filename);\n                var veldEl1 = document.getElementById(\"veld\");\n                veldEl1.scroll({top: 0, behavior: 'smooth'});\n\t\t\t\thideResults();\n\t\t\t\tresetResults();\n\t\t\t\tshowResults();\n\t\t\t});\n            debug(dateAsString());\n        }, 300);\n        \/\/ Wait a short while and then press F1 (select Simple) and F5 (display text)\n        setTimeout(() => {\n            error.innerHTML = '';\n            source.innerHTML = '';\n            debug(dateAsString());\n        }, 400);\n        setTimeout(() => {\n            tekst.innerHTML = '<b style=\"color: blue\"><i>' + i18n(language, \"loading\") + '<\/i><\/b>';\n            debug(dateAsString());\n        }, 500);\n        setTimeout(() => {\n            info(\"Getting Data\");\n            getData();\n            debug(dateAsString());\n            info(\"Got Data\");\n        }, 1000);\n        setTimeout(() => {\n            info(\"Getting Text\");\n\t\t\tpopulateFilesList();\n            pressF1();\n            pressF5();\n            info(\"Got Text\");\n            debug(dateAsString());\n        }, 2000);\n    });\n\n    \/\/ Based on https:\/\/medium.com\/@mihura.ian\/translations-in-vanilla-javascript-c942c2095170\n    function i18n(lang, param) {\n        lang = lang ?? \"en\";\n        return translation[lang][param];\n    }\n\n    function upKey(key)\n    {\n        if (key.getModifierState(\"NumLock\")) {\n                debug(\"NumLock: is ON\");\n                numLock = true;\n        }\n        if (!key.getModifierState(\"NumLock\")) {\n                debug(\"NumLock: is OFF\");\n                numLock = false;\n        }\n\n        if (key.key == \"Alt\") {\n            key.preventDefault();\n            debug(\"ALT is UP \" + kar + \"-\" + digitsOnly(kar) + \"-\");\n            if (kar.length > 0) {\n                \/\/ Increase the total number of keys pressed.\n                numberOfKeysPressed = numberOfKeysPressed + 1;\n                if (digitsOnly(kar)) {\n                    const altCode = kar\n                    \/\/ 1. Maak er het getal van, e.g. \"0128\" -> 128  \n                    const byteWaarde = parseInt(altCode, 10); \n                    \/\/ 2. Plaats de byte in een Uint8Array (byte-buffer)\n                    const byteBuffer = new Uint8Array([byteWaarde]);\n                    \/\/ 3. Decodeer de buffer expliciet als windows-1252\n                    const decoder = new TextDecoder('windows-1252');\n                    const letter = decoder.decode(byteBuffer);\n                    debug(\"ALT is UP \" + kar + \"-\" + byteWaarde + \":\" + letter + \"=\" + atCursor + \" - \");\n\n                    if (atCursor != letter) {\n                        \/\/ Wrong character was pressed on keyboard! Keep yellow cursor at same spot.\n                        \/\/ Display wanted character in bold and red.\n                        updateWrongChar();\n                    } else {\n                        \/\/ Count the number of correct keys pressed\n                        correctKeysPressed = correctKeysPressed + 1;\n                        \/\/ Move the cursor to the next character.\n                        cursorPosition = cursorPosition + 1;\n                        \/\/ Refresh the text\n                        updateVeld(cursorPosition);\n                        autoComplete();\n                        updateVeld(cursorPosition);\n                    }\n                }\n            }\n            kar = \"\";\n            altDown = false;\n            tekst.focus();\n        }\n    }\n\n    function downKey(key)\n    {\n        \/\/ Get the original tekst inside the text area\n        tekst = document.getElementById(\"tekst\");\n        originalText = tekst.textContent.trim();\n\n        \/\/ Prevent unwanted scrolling to bottom when pressing space bar\n        \/\/ Source - https:\/\/stackoverflow.com\/a\/43054031\n        \/\/ Posted by lhavCoder, modified by community. See post 'Timeline' for change history\n        \/\/ Retrieved 2026-06-03, License - CC BY-SA 3.0\n        key.preventDefault();\n        if (key.keyCode == 32 && key.target == document.body) {\n            key.preventDefault();\n        }\n\n        \/\/ Function Keys F1, F2 and F3\n        if (key.code == \"F1\") {\n            key.preventDefault();\n            pressF1();\n            return;\n        }\n        if (key.code == \"F2\") {\n            key.preventDefault();\n            pressF2();\n            return;\n        }\n        if (key.code == \"F3\") {\n            key.preventDefault();\n            pressF3();\n            return;\n        }\n        if (key.code == \"F4\") {\n            key.preventDefault();\n            pressF4();\n            return;\n        }\n        if (key.code == \"F5\") {\n            key.preventDefault();\n            setTimeout(() => {pressF5();}, 300);\n            return;\n        }\n        if (key.code == \"F6\" ||\n            key.code == \"F7\" ||\n            key.code == \"F8\" ||\n            key.code == \"F9\" ||\n            key.code == \"F10\") {\n                key.preventDefault();\n                toggleButton(document.getElementById(key.code));\n            return;\n        }\n        if (key.code == \"F11\") {\n            key.preventDefault();\n            var veldEl = document.getElementById(\"veld\");\n            var offset = veldEl.offsetHeight;\n            veldEl.scroll({top: offset, behavior: 'smooth'});\n            return;\n        }\n        if (key.code == \"F12\") {\n            key.preventDefault();\n            var veldEl = document.getElementById(\"veld\");\n            veldEl.scroll({top: 0, behavior: 'smooth'});\n            return;\n        }\n\n        \/\/ Get Special keys (e.g. Shift, Windows key, CTRL, ALT, ALT GR, FN\n        \/\/ key.altKey\n        \/\/ key.ctrlKey\n        \/\/ key.metaKey\n        \/\/ key.repeat\n        \/\/ key.isComposing\n\n        \/\/ Backspace\n        if (key.key == \"Backspace\") {\n            \/\/ TODO add removal of character and adapt cursor position\n            return;\n        }\n        \/\/ Shift\n        if (key.key == \"Shift\") {\n            return;\n        }\n        \/\/ Ctrl\n        if (key.key == \"Control\") { \n            return;\n        }\n        \/\/ Meta (Window key or Command key on Mac)\n        if (key.key == \"Meta\") { \n            return;\n        }\n        if (!key.getModifierState(\"NumLock\")) {\n                debug(\"NumLock: is OFF\");\n                numLock = false;\n        }\n\n        debug(\"2 downKey - \");\n        \/\/ Alt\n        if (key.key == \"Alt\") {\n                key.preventDefault();\n                debug(\"ALT is DOWN - \");\n                altDown = true;\n            return;\n        }\n\n        \/\/ Alt Gr\n        if (key.key == \"AltGraph\") { \n            return;\n        }\n        \/\/ Dead? e.g. \" followed by space on locales that generate umlaut characters by typing\n        \/\/ a double quote followed by a character like a, u, i (e.g. Dutch, German) \n        if (key.key == \"Dead\") { \n            return;\n        }\n        \/\/ Alt + Numeric keypad numbers 0-9.\n        if (altDown) {\n           debug(\"Key code: \" + key.code + \" - \");\n           if (key.code.includes(\"Numpad\")) {\n                kar = kar + key.key;\n                debug(\"Alt + \" + kar + \" - \");\n           }\n           return;\n        }\n        if (key.key == \"Dead\") { \n            return;\n        }\n              \n        \/\/ Update the text field.\n        updateVeld(cursorPosition);\n\n        var scroll = scrollNow(beforeCursor + atCursor);\n        debug(\" Scroll \" + scroll);\n        if (scroll) {\n            var veldEl = document.getElementById(\"veld\");\n            var offset = veldEl.offsetHeight;\n            veldEl.scroll({top: offset, behavior: 'smooth'});\n        }\n\n \n        \/\/ Count the complete number of keys pressed (disregard special keys like shift, alt, etc.)\n        numberOfKeysPressed = numberOfKeysPressed + 1;\n\n        \/\/ If a &nbsp; (160) before a space (32) is detected, remove the nbsp from the text\n        if (atCursor.charCodeAt(0) == 160 && afterCursor.charCodeAt(0) == 32) {\n           tekst.innerHTML = '<span style=\"color: green\">' + beforeCursor + '<\/span><span style=\"background-color: yellow; color: blue;\"><b> <\/b><\/span><span style=\"color: blue;\">' + afterCursor.substring(1,afterCursor.length) + '<\/span>';\n           originalText = tekst.textContent;\n           updateVeld(cursorPosition);\n           debug(\"Removed '&nbsp; ' from: \" + originalText + \" - \");\n        }\n\n        \/\/ Check if correct character was pressed on keyboard depending on the mode.\n        \/\/ Allow for case-insensitive check if Caps (F7) button is active\n        debug(\"Check correct character -\" + atCursor + \"-\" + atCursor.charCodeAt(0) + \"-\" + key.key + \"-\" + key.keyCode + \"-\" + afterCursor.charCodeAt(0));\n        if ((!document.getElementById(\"F7\").disabled && atCursor.toLowerCase() != key.key.toLowerCase()) || (document.getElementById(\"F7\").disabled && atCursor != key.key)) {\n            \/\/ Wrong character was pressed on keyboard! Keep yellow cursor at same spot.\n            \/\/ Sound warning and display wanted character in bold and red.\n            updateWrongChar();\n            return;\n        }\n\n        debug(\"correct character found-\" + atCursor + \"-\" + key.key + \"-\");\n\n        \/\/ Count the number of correct keys pressed\n        correctKeysPressed = correctKeysPressed + 1;\n\n        \/\/ Get the start time when first correct key is pressed.\n        if (correctKeysPressed == 1) {\n            \/\/ Get the time the user entered the first character\n            start = new Date().getTime();\n            \/\/ Hide results (like duration and accuracy)\n            hideResults();\n        }\n\n        \/\/ Move the cursor to the next character.\n        cursorPosition = cursorPosition + 1;\n \n        \/\/ Refresh the text\n        updateVeld(cursorPosition);\n\n        \/\/ Autocomplete according to selected autocomplete buttons (F6-F10)\n        autoComplete();\n\n        \/\/ Refresh the text\n        updateVeld(cursorPosition);\n        \n        \/\/ If next character is a space and autoComplete for space is off, check for auto wrap by comparing the line numbers of the space and the next word\n        if (atCursor === \" \" && document.getElementById(\"F10\").disabled) {\n            debug(\"NEXTCHAR:-\" + atCursor + \"-\" + afterCursor.charAt(0) +  \"-\");\n            lineSpace = lineNumber(beforeCursor + atCursor);\n            debug(\"Line \" + lineSpace + \"-\");\n            lineNext = lineNumber(beforeCursor + atCursor + afterCursor.replace(\/ .*\/,''));\n            debug(lineNext + \" - \");\n            if (lineNext > lineSpace) {\n               debug(\"Add &nbsp; (160)\");\n                \/\/ Temporarily add nbsp before space in text to force a cursor at the end of auto-wrapped line.\n               atCursor = String.fromCharCode(160) + \" \";\n               tekst.innerHTML = '<span style=\"color: green\">' + beforeCursor + '<\/span><span style=\"background-color: yellow; color: blue;\"><b>' + atCursor + '<\/b><\/span><span style=\"color: blue;\">' + afterCursor + '<\/span>';\n               \/\/ Add nbsp to original text\n               originalText = tekst.textContent;\n            } \n        }\n\n        \/\/ If there is nothing below the cursor, you've reached the end of the text\n        if (atCursor === \"\" || cursorPosition > tekst.textContent.length) {\n            \/\/ Show the calculated results\n            calculateResults();\n            showResults();\n        }\n\n        \/\/ Put focus on the code-tag that contains the text\n        tekst.focus();\n    }\n\n    function dateAsString() {\n        var currentdate = new Date(); \n        return currentdate.getDate() + \"\/\"\n                + (currentdate.getMonth()+1)  + \"\/\" \n                + currentdate.getFullYear() + \" @ \"  \n                + currentdate.getHours() + \":\"  \n                + currentdate.getMinutes() + \":\" \n                + currentdate.getSeconds();\n    }\n\n    \/\/ Add the text file URLs to the array\n    function addUrl(location) {\n        urls.push(location);\n        debug(\"Added URL: \" + location);\n    }\n\n    \/\/ Read the github API repositories directory and find the entries with blob typ\n    async function getData() {\n        debug(\"Entered getData()\");\n        try {\n            debug(\"Fetching Data...\");\n            const response = await fetch(apiurl);\n            if (!response.ok) {\n                debug(\"Response NOT OK!\");\n                throw new Error(\"Response status: ${response.status}\");\n            }\n\n            const result = await response.json();\n            debug(\"Got JSON Result\");\n            result.tree.forEach((item) => {\n                if (item.type === \"blob\") {\n                    addUrl(raw + item.path);\n                }\n            })\n            debug(\"Set URLs...\");\n            error.innerHTML = '';\n            source.innerHTML = '';\n       } catch (error) {\n            var displayError = i18n(language, \"readError\") + apiurl + \"; \" + error;\n            if (error.message.includes(\"403\")) {\n                displayError = i18n(language, \"forbidden\") + apiurl + \"; \" + error;\n            }\n            if (error.message.includes(\"404\")) {\n                displayError = i18n(language, \"notFound\") + apiurl + \"; \" + error;\n            }\n            error.innerHTML = '<span style=\"color: red\"><b>' + displayError + '<\/b><\/span>';\n            tekst.innerHTML = displayError;\n        }\n    }\n\n    \/\/ Populate the pulldown list with the filenames.\n    function populateFilesList() {\n\t\tdebug(\"populateFilesList()\");\n        var lev = \"\"; \/\/ Selected difficulty level\n\t\tif (!document.getElementById(\"F1\").disabled) lev = \"F1\";\n\t\tif (!document.getElementById(\"F2\").disabled) lev = \"F2\";\n\t\tif (!document.getElementById(\"F3\").disabled) lev = \"F3\";\n\t\tif (!document.getElementById(\"F4\").disabled) lev = \"F4\";\n\t\tvar substr = language + \"\/\" + lev + \"\/\";\n\t\tdebug(\"substr: \" + substr);\n\t\t\/\/ The select element to hold the option tags with the found filenames.\n\t\tvar select = document.getElementById(\"files\");\n\t\t\/\/ Remove any existing options\n\t\tselect.options.length = 0;\n        \/\/ Get the language and difficulty related text file urls\n        var langURLs = urls.filter(str => str.includes(substr));\n\t\tlet len = langURLs.length;\n\t\tdebug(\"Found files: \" + len);\n\t\t\n        for (let i = 0; i < len; i++) {\n            \/\/ Source - https:\/\/stackoverflow.com\/a\/8376542\n            \/\/ Posted by T.J. Crowder, modified by community. See post 'Timeline' for change history\n            \/\/ Retrieved 2026-08-02, License - CC BY-SA 3.0\n            var parts = langURLs[i].split(\"\/\");\n            var filename = parts.pop();\n            var el = document.createElement(\"option\");\n            el.textContent = filename;\n            \/\/ el.value = raw + \"\/\" + language + \"\/\" + lev + \"\/\" + filename;\n            el.value = filename;\n            select.appendChild(el);\n        }\n\t}\n\t\n\tfunction setURLselected(url) {\n\t        \/\/ Source - https:\/\/stackoverflow.com\/a\/8376542\n            \/\/ Posted by T.J. Crowder, modified by community. See post 'Timeline' for change history\n            \/\/ Retrieved 2026-08-02, License - CC BY-SA 3.0\n            var parts = url.split(\"\/\");\n            var filename = parts.pop();\n\t\t\t\/\/ Source - https:\/\/stackoverflow.com\/a\/12265656\n            \/\/ Posted by Michal Klouda, modified by community. See post 'Timeline' for change history\n            \/\/ Retrieved 2026-08-02, License - CC BY-SA 4.0\n\t\t\tdebug(\"Set selected URL: \" + url + \" - \" + filename);\n\t\t\tvar sel = document.getElementById('files');\n            sel.value = filename;\n\t}\n\t\n    \/\/ Retrieve URL for one random text file based on language and selected difficulty level.\n    function randomURL() {\n            var substr = '\/' + language + '\/';\n            debug(\"language: \" + language + \" country: \" + country);\n\n            \/\/ Select text difficulty level\n            if (!document.getElementById(\"F1\").disabled) {\n                substr = substr + 'F1\/';\n            }\n            if (!document.getElementById(\"F2\").disabled) {\n                substr = substr + 'F2\/';\n            }\n            if (!document.getElementById(\"F3\").disabled) {\n                substr = substr + 'F3\/';\n            }\n            if (!document.getElementById(\"F4\").disabled) {\n                substr = substr + 'F4\/';\n            }\n\n            \/\/ If URL data is empty don't try to read from it.\n            if (urls.length <= 0) return;\n\n            \/\/ Get the language and difficulty related text file urls\n            var langURLs = urls.filter(str => str.includes(substr));\n            \/\/ If none exist: exit\n            if (langURLs.length <= 0) return;\n\n            \/\/ for debugging\n            \/\/ var langURLs = urls.filter(str => str.includes(\"specialcharacters.txt\"));\n\n            \/\/ Pseudo random number to select one of the langues specific URLs\n            var n = Math.floor(Math.random() * langURLs.length);\n            debug(\"Randomly selected \" + langURLs[n]);\n            return langURLs[n];\n    }\n\n    \/\/ Read text file from a given URL.\n    async function getText(url) {\n        debug(\"Entered getText()\");\n        try {\n            debug(\"Fetching Text from \"+ url);\n            const response = await fetch(url);\n            if (!response.ok) {\n                debug(\"Text Response NOT OK!\");\n                throw new Error(\"Response status: ${response.status}\");\n            }\n\n            const result = await response.text();\n            debug(\"Got Text Result...\");\n            lines = result.split(\/\\r\\n|\\r|\\n\/);\n            firstLine = lines[0];\n            secondLine = lines[1];\n            debug(\"1st line: \" + firstLine);\n            debug(\"2nd line: \" + secondLine);\n            source.innerHTML = '';\n            error.innerHTML = '';\n            if (firstLine.startsWith(\"#\")) {\n                source.innerHTML = '<i>' + firstLine.substring(2, firstLine.length) + '<\/i>';\n                originalText = secondLine;\n            } else {\n                source.innerHTML = '<i>Source not specified<\/i>';\n                originalText = request.responseText;\n            }\n            \/\/ Make sure the text field shows the newly loaded text.\n            updateVeld(cursorPosition);\n            autoComplete();\n            updateVeld(cursorPosition);\n\t\t\tsetURLselected(url);\n\t\t\thideResults();\n\t\t\tresetResults();\n\t\t\tshowResults();\n        } catch (error) {\n            var displayError = i18n(language, \"readError\") + url + \"; \" + error;\n            if (error.message.includes(\"403\")) {\n                displayError = i18n(language, \"forbidden\") + url + \"; \" + error;\n            }\n            if (error.message.includes(\"404\")) {\n                displayError = i18n(\"notFound\") + url + \"; \" + error;\n            }\n            error.innerHTML = '<span style=\"color: red\"><b>' + displayError + '<\/b><\/span>';\n            source.innerHTML = '';\n        }\n    }\n\n    function toggleButton(el)\n    {\n      if (el.disabled) {\n        el.disabled = false;\n      } else {\n        el.disabled = true;\n      }\n      tekst.focus();\n    }\n\n    function pressF1()\n    {\n        debug(\"F1 key was pressed\");\n        document.getElementById(\"F1\").disabled = false;\n        document.getElementById(\"F2\").disabled = true;\n        document.getElementById(\"F3\").disabled = true;\n        document.getElementById(\"F4\").disabled = true;\n        document.getElementById(\"F5\").disabled = true;\n        document.getElementById(\"F6\").disabled = false;\n        document.getElementById(\"F7\").disabled = false;\n        document.getElementById(\"F8\").disabled = false;\n        document.getElementById(\"F9\").disabled = false;\n        document.getElementById(\"F10\").disabled = false;\n\t\tpopulateFilesList();\n        tekst.focus();\n        mode = \"Simple\";\n    }\n    \n    function pressF2()\n    {\n        debug(\"F2 key was pressed\");\n        document.getElementById(\"F1\").disabled = true;\n        document.getElementById(\"F2\").disabled = false;\n        document.getElementById(\"F3\").disabled = true;\n        document.getElementById(\"F4\").disabled = true;\n        document.getElementById(\"F5\").disabled = true;\n        document.getElementById(\"F6\").disabled = false;\n        document.getElementById(\"F7\").disabled = true;\n        document.getElementById(\"F8\").disabled = false;\n        document.getElementById(\"F9\").disabled = false;\n        document.getElementById(\"F10\").disabled = true;\n\t\tpopulateFilesList();\n        tekst.focus();\n        mode = \"Intermediate\";\n    }\n\n    function pressF3()\n    {\n        debug(\"F3 key was pressed\");\n        document.getElementById(\"F1\").disabled = true;\n        document.getElementById(\"F2\").disabled = true;\n        document.getElementById(\"F3\").disabled = false;\n        document.getElementById(\"F4\").disabled = true;\n        document.getElementById(\"F5\").disabled = true;\n        document.getElementById(\"F6\").disabled = true;\n        document.getElementById(\"F7\").disabled = true;\n        document.getElementById(\"F8\").disabled = true;\n        document.getElementById(\"F9\").disabled = false;\n        document.getElementById(\"F10\").disabled = true;\n\t\tpopulateFilesList();\n        tekst.focus();\n        mode = \"Advanced\";\n    }\n\n    function pressF4()\n    {\n        debug(\"F4 key was pressed\");\n        document.getElementById(\"F1\").disabled = true;\n        document.getElementById(\"F2\").disabled = true;\n        document.getElementById(\"F3\").disabled = true;\n        document.getElementById(\"F4\").disabled = false;\n        document.getElementById(\"F5\").disabled = true;\n        document.getElementById(\"F6\").disabled = true;\n        document.getElementById(\"F7\").disabled = true;\n        document.getElementById(\"F8\").disabled = true;\n        document.getElementById(\"F9\").disabled = true;\n        document.getElementById(\"F10\").disabled = true;\n\t\tpopulateFilesList();\n        tekst.focus();\n        mode = \"Type Test\";\n    }\n\n   function pressF5()\n    {\n        debug(\"F5 key was pressed\");\n        \/\/ Retrieve a random Text\n        getText(randomURL());\n        \/\/ Reset the text\n        cursorPosition = 1;\n        start = 0;\n        end = 0;\n        time = 0;\n        accuracy = 0;\n\t\twords = 0;\n        cps = 0;\n        cpm = 0;\n\t\twpm = 0;\n        numberOfKeysPressed = 0;\n        correctKeysPressed = 0;\n        \/\/ Make sure the scroll position is a the top of the text\n        veld.scroll({top: 0, behavior: 'smooth'});\n    }\n\n    \/\/ Auto-Complete special characters depending on selected mode.\n    \/\/ TODO Add functionality for the different autocomplete setting: \n    \/\/ TODO Punctuation, Caps, Numbers, Special Character and Space\n    function autoComplete() {\n        \/\/ debug Skip AutoComplete\n        debug(\" auto complete '\" + atCursor + \"' - \");\n        \/\/ Punctuation auto-complete when toggle button for F5 is active\n        if (!document.getElementById(\"F6\").disabled && punctuation.includes(atCursor)) complete();\n\n        \/\/ Capital characters auto-complete when toggle button for F6 is active\n        \/\/ Basically typing becomes case insensitive (is already handled in main script)\n\n        \/\/ Numbers auto-complete when toggle button for F7 is active\n        if (!document.getElementById(\"F8\").disabled && numbers.includes(atCursor)) complete();\n\n        \/\/ Special Characters auto-complete when toggle button for F8 is active\n        if (!document.getElementById(\"F9\").disabled && speci.includes(atCursor)) complete();\n\n        if (!document.getElementById(\"F10\").disabled && space.includes(atCursor)) {\n            complete();\n        }\n        if (document.getElementById(\"F10\").disabled) {\n            \/\/ Remove temporary nbsp before space when toggle button for F10 is not active\n            if (atCursor == String.fromCharCode(160)) {\n                atCursor = \" \";\n            }\n        }\n    }\n\n    function complete() {\n        debug(\"Complete '\" + atCursor + \"' - \");\n        cursorPosition = cursorPosition + 1;\n        if (cursorPosition > tekst.textContent.length) return;\n        \/\/ call this again to make sure consequtive occurences are also handled.\n        beforeCursor = originalText.substring(0, cursorPosition -1);\n        atCursor = originalText.substring(cursorPosition - 1, cursorPosition);\n        afterCursor =  originalText.substring(cursorPosition, originalText.length);\n        debug(\"Moved cursor to \" + cursorPosition + \" - '\" + atCursor + \"' - \");\n        autoComplete();\n    }\n\n    \/\/ Update the text in the text field.\n    function updateVeld(cur) {\n        debug(\"In UpdateVeld cur \" + cur + \" - \" + originalText.length + \" - \");\n        if (originalText.length <= 0) return;\n        \/\/ Get the characters before, at and after the current cursor position\n        beforeCursor = originalText.substring(0, cur - 1);\n        atCursor = originalText.substring((cur - 1), cur);\n        afterCursor =  originalText.substring(cur, originalText.length);\n        tekst.innerHTML = '<span style=\"color: green\">' + beforeCursor + '<\/span><span style=\"background-color: yellow; color: blue;\"><b>' + atCursor + '<\/b><\/span><span style=\"color: blue;\">' + afterCursor + '<\/span>';\n    }\n\n    function updateWrongChar(cur) {\n            tekst.innerHTML = '<span style=\"color: green\">' + beforeCursor.substring(0, (beforeCursor.length)) + '<\/span>' +'<span style=\"background-color: yellow; color: red\"><b>' + atCursor + '<\/b><\/span>' + '<span style=\"color:#FFCCCB;\">' + afterCursor + '<\/span>';\n    }\n\n    \/\/ Reset results for Duration, Accuray, Char\/s, Char\/min, Words\/min\n    function resetResults() {\n        start = 0;\n        end = 0;\n        time = 0;\n        duration = 0;\n        accuracy = 0;\n\t\twords = 0;\n        cps = 0;\n        cpm = 0;\n        wpm = 0;\n        numberOfKeysPressed = 0;\n        correctKeysPressed = 0;\n\t\tminutes = 0;\n\t\tseconds = 0;\n\t\tremainder = 0;\n    }\n\n    \/\/ Hide Duration, Accuray, Char\/s, Char\/min, Words\/min\n    function hideResults() {\n        document.getElementById(\"duration\").style.visibility = 'hidden';\n        document.getElementById(\"accuracy\").style.visibility = 'hidden';\n        document.getElementById(\"words\").style.visibility = 'hidden';\n        document.getElementById(\"cps\").style.visibility = 'hidden';\n        document.getElementById(\"cpm\").style.visibility = 'hidden';\n        document.getElementById(\"wpm\").style.visibility = 'hidden';\n    }\n\n    function calculateResults() {\n        debug(\" 1 calculateResults \" + correctKeysPressed + \"\/\" + numberOfKeysPressed + \" - \");\n        end = new Date().getTime();\n        time = (end - start) \/ 1000; \/\/ Time in seconds\n        accuracy = (correctKeysPressed \/ numberOfKeysPressed) * 100;\n\t\twords = originalText.trim().split(\/\\s+\/).length; \/\/ Number of words in the current text\n        cps = numberOfKeysPressed \/ time;\n        cpm = cps * 60;\n        debug(\" 2 calculateResults time \" + time + \"=\" + end + \"-\" + start + \" - \");\n        accuracy = Math.round((accuracy + Number.EPSILON) * 100) \/ 100;\n        cps = Math.round((cps + Number.EPSILON) * 100) \/ 100;\n        cpm = Math.round(cpm);\n\t\tvar min = time\/60; \/\/ seconds to minutes\n        wpm = words\/min;\n        wpm = Math.round(wpm);\n        debug(\"Number of words: \" + words + \" minutes: \" + min + \" wpm: \" + wpm);\n        \/\/ Expired full minutes -> quotient (The integer number resulting from the division of one number by another)\n\t    minutes = Math.floor(time\/60);\n        \/\/ The total number of seconds (rounded to nearest full second)\n        seconds = Math.round(time);\n        \/\/ The remaining number of seconds after the full minutes\n        remainder = seconds - (minutes * 60);\n    }\n\n    \/\/ Show Duration, Accuray, Char\/s, Char\/min, words\/min.\n    function showResults() {\n        words = originalText.trim().split(\/\\s+\/).length; \/\/ Number of words in the current text\n        var kleur = 'green';\n        if (accuracy < 60) {\n            kleur = 'yellow';\n        }\n        if (accuracy < 40) {\n            kleur = 'red';\n        }\n        document.getElementById(\"duration\").innerHTML = i18n(language, \"duration\") + \": <b style='color:\" + kleur + \"'>\" + minutes + \"<\/b> min <b style='color:\" + kleur + \"'>\" + remainder + \"<\/b> s&nbsp;\";\n        document.getElementById(\"accuracy\").innerHTML = i18n(language, \"accuracy\") +  \": <b style='color:\" + kleur + \"'>\" + accuracy + \"<\/b> %&nbsp;\";\n        document.getElementById(\"words\").innerHTML = i18n(language, \"words\") +  \": <b style='color:\" + kleur + \"'>\" + words + \"<\/b>\";\n        document.getElementById(\"cps\").innerHTML = i18n(language, \"cps\") + \": <b style='color:\" + kleur + \"'>\" + cps + \"<\/b>&nbsp;\";\n        document.getElementById(\"cpm\").innerHTML = i18n(language, \"cpm\") + \": <b style='color:\" + kleur + \"'>\" + cpm + \"<\/b>&nbsp;\";\n        document.getElementById(\"wpm\").innerHTML = i18n(language, \"wpm\") + \": <b style='color:\" + kleur + \"'>\" + wpm + \"<\/b>\";\n        \/\/ show duration and accuracy, characters per seconds and chars per minute\n        document.getElementById(\"duration\").style.visibility = 'visible';\n        document.getElementById(\"accuracy\").style.visibility = 'visible';\n        document.getElementById(\"words\").style.visibility = 'visible';\n        document.getElementById(\"cps\").style.visibility = 'visible';\n        document.getElementById(\"cpm\").style.visibility = 'visible';\n        document.getElementById(\"wpm\").style.visibility = 'visible';\n    }\n\n    \/\/ F1-F10 mouse clicks\n    function hover(fKey) {\n        disabledOrigin = document.getElementById(fKey).disabled;\n        debug('hover ' + fKey + '-' + disabledOrigin);\n        document.getElementById(fKey).disabled = false;\n        document.getElementById(fKey).style.background='orange';\n    }\n\n    function clickFunction(fKey) {\n        debug('click ' + fKey + '-' + document.getElementById(fKey).disabled);\n        if (fKey == \"F1\") {\n            pressF1();\n            disabledOrigin = false;\n        } else if (fKey == \"F2\") {\n            pressF2();\n            disabledOrigin = false;\n        } else if (fKey == \"F3\") {\n            pressF3();\n            disabledOrigin = false;\n        } else if (fKey == \"F4\") {\n            pressF4();\n            disabledOrigin = false;\n        } else if (fKey == \"F5\") {\n            setTimeout(() => {autoComplete(); updateVeld(cursorPosition);}, 600);\n        } else {\n            document.getElementById(fKey).disabled = disabledOrigin;\n            toggleButton(document.getElementById(fKey));\n            disabledOrigin = document.getElementById(fKey).disabled;\n        }\n        document.getElementById(fKey).disabled = disabledOrigin;\n        document.getElementById(fKey).style.background='';\n    }\n\n    function leave(fKey) {\n        debug('leave ' + fKey + '-' + document.getElementById(fKey).disabled);\n        document.getElementById(fKey).disabled = disabledOrigin;\n        document.getElementById(fKey).style.background='';\n    }\n\n    function lineNumber(textIncludingCursor) {\n        var el = document.getElementById(\"veld\");\n        if (_buffer == null) {\n            _buffer = document.createElement('tekst');\n            _buffer.style.border = 'none';\n            _buffer.style.height = '0';\n            _buffer.style.overflow = 'hidden';\n            _buffer.style.padding = '0';\n            _buffer.style.position = 'absolute';\n            _buffer.style.left = '0';\n            _buffer.style.top = '0';\n            _buffer.style.zIndex = '-1';\n            document.body.appendChild(_buffer);\n        }\n        _buffer.value = el.value;\n        _buffer.innerHTML = el.innerHTML;\n\n        var newCodeElement = null;\n        var element = _buffer.querySelectorAll('code').forEach(element => {\n             newCodeElement = element;\n        })\n        newCodeElement.textContent = textIncludingCursor;\n\n        var positionInfo = el.getBoundingClientRect();\n        var height = positionInfo.height;\n        var width = positionInfo.width;\n        var cs = window.getComputedStyle(el);\n        var pl = parseInt(cs.paddingLeft);\n        var pr = parseInt(cs.paddingRight);\n        var pb = parseInt(cs.paddingBottom);\n        var pt = parseInt(cs.paddingTop);\n        var lh = parseInt(cs.lineHeight);\n\n        \/\/ Copy content width.\n        _buffer.style.width = (el.clientWidth - pl - pr) + 'px';\n\n        \/\/ Copy content width.\n        _buffer.style.width = (width - pl - pr) + 'px';\n\n        var bufResult = Math.floor(_buffer.scrollHeight \/ lh);\n        \/\/ var divResult = Math.floor(el.scrollHeight \/ lh);\n        return bufResult;\n    }\n\n    function scrollNow(textIncludingCursor) {\n        var line = lineNumber(textIncludingCursor);\n\n        if (line == 0) result = 1;\n        if (line > 7) {\n            return true;\n        }\n        return false;\n    }\n\n    function debug(debugMessage) {\n        if (logLevel.includes(\"DEBUG\")) {\n            console.debug(debugMessage);\n        }\n    }\n\n    function info(infoMessage) {\n        if (logLevel.includes(\"DEBUG\") || logLevel.includes(\"INFO\")) {\n            console.info(infoMessage);\n        }\n    }\n\n    function warn(warnMessage) {\n        if (logLevel.includes(\"DEBUG\") || logLevel.includes(\"INFO\") || logLevel.includes(\"WARN\")) {\n            console.warn(warnMessage);\n        }\n    }\n\n    function error(errorMessage) {\n        if (logLevel.includes(\"DEBUG\") || logLevel.includes(\"INFO\") || logLevel.includes(\"WARN\") || logLevel.includes(\"ERROR\")) {\n            console.error(errorMessage);\n        }\n    }\n\n\/\/ Source - https:\/\/stackoverflow.com\/a\/11381730\n\/\/ Posted by Michael Zaporozhets, modified by community. See post 'Timeline' for change history\n\/\/ Retrieved 2026-06-22, License - CC BY-SA 4.0\nwindow.mobileAndTabletCheck = function() {\n  let check = false;\n  (function(a){if(\/(android|bb\\d+|meego).+mobile|avantgo|bada\\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk\/i.test(a)||\/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-\/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);\n  return check;\n};\n\n<\/script>\n     \n<\/head>\n<body>\n    \n<div id=\"top\" style=\"font-size:26px;\">\n    <span id=\"error\" style=\"font-size: 20px\"><b style=\"color:red; font-size:26px;\">Error Area. No errors detected yet&#8230;<\/b><\/span>\n<\/div>\n<div id=\"veld\" style=\"width:730px; height:300px; background-color:lightblue; overflow:scroll; padding-right:3px; padding-left:3px; line-height:30px;\">\n    <code id=\"tekst\" contenteditable=\"false\" style=\"font-size:26px; line-height:30px;\">\n        <span id=\"blauw\" style=\"color: blue\"><i>Text Area<\/i><\/span>\n    <\/code>\n<\/div>\n<div style=\"width:730px;font-size:0px;\">\n    <span id=\"source\" style=\"font-size:10px;\"><i>source<\/i><\/span>\n    <span id=\"fileslist\" style=\"float:right\">\n\t    <select name=\"files\" id=\"files\" style=\"font-size:10px\">\n        <\/select>\n    <\/span>\n<\/div>\n<div>\n    <span id=\"duration\" style=\"font-size: 20px\">Duration: <b style=\"color:red\">0<\/b> min <b style=\"color:red\">0<\/b> s<\/span>&nbsp;\n    <span id=\"accuracy\" style=\"font-size: 20px\">Accuracy: <b style=\"color:red\">0<\/b> %<\/span>\n    <span id=\"words\" style=\"font-size: 20px\">Words: <b style=\"color:red\">0<\/b><\/span><br\/>\n    <span id=\"cps\" style=\"font-size: 20px\">Char\/s: <b style=\"color:red\">0<\/b><\/span>&nbsp;\n    <span id=\"cpm\" style=\"font-size: 20px\">Char\/min: <b style=\"color:red\">0<\/b><\/span>&nbsp;\n    <span id=\"wpm\" style=\"font-size: 20px\">Words\/min: <b style=\"color:red\">0<\/b><\/span>\n<\/div>\n<div>\n    <span id=\"presets\">Autocomplete Presets and Text Refresh<\/span><br\/>\n    <button id=\"F1\" type=\"button\" onmouseover=\"hover('F1')\" onmouseleave=\"leave('F1')\" onclick=\"clickFunction('F1');\" disabled=\"\">Simple(F1)<\/button> \n    <button id=\"F2\" type=\"button\" onmouseover=\"hover('F2')\" onmouseleave=\"leave('F2')\" onclick=\"clickFunction('F2');\" disabled=\"\">Intermediate(F2)<\/button> \n    <button id=\"F3\" type=\"button\" onmouseover=\"hover('F3')\" onmouseleave=\"leave('F3')\" onclick=\"clickFunction('F3');\" disabled=\"\">Advanced(F3)<\/button>\n    <button id=\"F4\" type=\"button\" onmouseover=\"hover('F4')\" onmouseleave=\"leave('F4')\" onclick=\"clickFunction('F4');\" disabled=\"\">Type Test(F4)<\/button>\n    <button id=\"F5\" type=\"button\" onmouseover=\"hover('F5')\" onmouseleave=\"leave('F5')\" onclick=\"clickFunction('F5'); pressF5();\" disabled=\"\">Refresh(F5)<\/button>\n    <br\/><span id=\"settings\">Autocomplete settings<\/span><br\/>\n    <button id=\"F6\" type=\"button\" onmouseover=\"hover('F6')\" onmouseleave=\"leave('F6')\" onclick=\"clickFunction('F6')\" disabled=\"\">Punctuation(F6)<\/button>\n    <button id=\"F7\" type=\"button\" onmouseover=\"hover('F7')\" onmouseleave=\"leave('F7')\" onclick=\"clickFunction('F7')\" disabled=\"\">Caps(F7)<\/button>\n    <button id=\"F8\" type=\"button\" onmouseover=\"hover('F8')\" onmouseleave=\"leave('F8')\" onclick=\"clickFunction('F8')\" disabled=\"\">Numbers(F8)<\/button>\n    <button id=\"F9\" type=\"button\" onmouseover=\"hover('F9')\" onmouseleave=\"leave('F9')\" onclick=\"clickFunction('F9')\" disabled=\"\">Special Chars(F9)<\/button>\n    <button id=\"F10\" type=\"button\" onmouseover=\"hover('F10')\" onmouseleave=\"leave('F10')\" onclick=\"clickFunction('F10')\" disabled=\"\">Space(F10)<\/button>\n<\/div>\n\n\n<style>.kb-table-of-content-nav.kb-table-of-content-id3217_30550b-38 .kb-table-of-content-wrap{padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-right:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);padding-left:var(--global-kb-spacing-sm, 1.5rem);}.kb-table-of-content-nav.kb-table-of-content-id3217_30550b-38 .kb-table-of-contents-title-wrap{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id3217_30550b-38 .kb-table-of-contents-title{font-weight:regular;font-style:normal;}.kb-table-of-content-nav.kb-table-of-content-id3217_30550b-38 .kb-table-of-content-wrap .kb-table-of-content-list{font-weight:regular;font-style:normal;margin-top:var(--global-kb-spacing-sm, 1.5rem);margin-right:0px;margin-bottom:0px;margin-left:0px;}<\/style>\n\n\n<h2 class=\"wp-block-heading\">Consult Medical Professional<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Consult a medical professional before using this typing test as part of your rehabilitation program.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Manual<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Quick Start<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select the difficulty level (F1 &#8211; F4) with the function keys or mouse buttons: <strong>Simple (F1)<\/strong>, <strong>Intermediate (F2)<\/strong>, <strong>Advanced (F3)<\/strong> or <strong>Type Test (F4)<\/strong>.<\/li>\n\n\n\n<li>Select <strong>Refresh (F5)<\/strong> to show a text from the selected difficulty level.<\/li>\n\n\n\n<li>Or select a text file name from the pull-down list below the Text Field<\/li>\n\n\n\n<li>The default difficulty level is the <strong>Simple (F1)<\/strong> mode.<\/li>\n\n\n\n<li>Note the yellow cursor in the top left corner of the text area.<\/li>\n\n\n\n<li>Type the characters you see at the cursor.<\/li>\n\n\n\n<li>If you&#8217;ve typed the correct chararcter the cursor wil advance to the next character.<\/li>\n\n\n\n<li>If you&#8217;ve typed a wrong character the cursor will stay in place, the expected character shows up in bold red.<\/li>\n\n\n\n<li>The <strong>Simple (F1)<\/strong> level only focusses one typing the correct letter of the alphabet.<\/li>\n\n\n\n<li>No need to type spaces, digits or special characters. They will be autocompleted.<\/li>\n\n\n\n<li>No need to use Shift or Caps Lock. Uppercase is ignored.<\/li>\n\n\n\n<li>The results like duration, accuracy, characters\/second and characters\/minute will be displayed once you completed typing the text. During typing they are hidden.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Design Principles<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This typing test is designed for people who need to relearn typing during a medical rehabilitation process, e.g. due to loss of fine motor skills in one or both hands caused by physical trauma or neurological damage. Several auto-complete options help avoiding key combinations and far key stretches to match typist&#8217;s current typing abbilities.<br>But in the Type Test mode all auto-completion is switched off and it becomes another regular online typing test.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>As with most typing tests, best results can be achieved when using a PC or a laptop with a relative large screen, a physical keyboard and mouse. This typing test is not supported on mobile phones or tablets.<\/li>\n\n\n\n<li>Your browser needs to have Javascript enabled for this to work.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Features<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Pull-down list to select available text files for each difficulty level<\/li>\n\n\n\n<li>Duration, accuracy and typing speed are displayed when typing a text is completed<\/li>\n\n\n\n<li>Presets (F1-F4), Refresh (F5) and Auto-complete settings (F6-F10)<\/li>\n\n\n\n<li>4 preset modes with different levels of difficulties\n<ul class=\"wp-block-list\">\n<li>Simple (F1)<\/li>\n\n\n\n<li>Intermediate (F2)<\/li>\n\n\n\n<li>Advanced (F3)<\/li>\n\n\n\n<li>Type Test (F4)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Presets (F1-F4) selection with the corresponding function key or mouse click<\/li>\n\n\n\n<li>A refresh option to load the next (randomly chosen) text: Refresh (F5)<\/li>\n\n\n\n<li>Refresh (F5) triggering on page load, with F5 key and by mouse click<\/li>\n\n\n\n<li>5 auto-complete settings that can be toggled by function keys or mouse clicks\n<ul class=\"wp-block-list\">\n<li>Punctuation (F6)<\/li>\n\n\n\n<li>Caps (F7)<\/li>\n\n\n\n<li>Numbers (F8)<\/li>\n\n\n\n<li>Special Characters (F9)<\/li>\n\n\n\n<li>Space (F10)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Auto-complete settings (F6-F10) toggle with the corresponding function key or mouse click<\/li>\n\n\n\n<li>Cursor doesn&#8217;t move and the expected character is shown in bold red if the wrong character is typed<\/li>\n\n\n\n<li>Auto-scroll for text that is larger than the visible text field when cursor gets near the end of the visible part<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Text Field<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The text field displays the text to be typed. Note the yellow cursor in the top left corner. It is not blinking. It indicates the next character to type. If characters are auto-completed the cursor will move to the next character to type.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"424\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TextField-1024x424.jpg\" alt=\"\" class=\"wp-image-3966\" style=\"aspect-ratio:2.415086049273303;width:413px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TextField-1024x424.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TextField-300x124.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TextField-768x318.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TextField-1536x636.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TextField.jpg 1629w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If the wrong character is typed, the cursor stays in place and the expected character will be displayed bold red until the correct character is typed. The remaining text will turn black instead of blue. Correctly typed text will become green.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"846\" height=\"146\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/wrongCharacter.jpg\" alt=\"\" class=\"wp-image-3967\" style=\"aspect-ratio:5.794417414713732;width:406px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/wrongCharacter.jpg 846w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/wrongCharacter-300x52.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/wrongCharacter-768x133.jpg 768w\" sizes=\"auto, (max-width: 846px) 100vw, 846px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Caption<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If available, a caption with a descriptive text regarding the current content in the Text Field is displayed.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"364\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-4-1024x364.png\" alt=\"\" class=\"wp-image-4612\" style=\"aspect-ratio:2.813102119460501;width:402px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-4-1024x364.png 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-4-300x106.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-4-768x273.png 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-4.png 1293w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Text File Pull-Down List<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Below the Text Field, a text file pull-down list allows you to select from the available files. There is a different list per difficulty level, that will show after selecting a Difficulty Level (F1-F4) followed by Refresh (F5).<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"904\" height=\"326\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-2.png\" alt=\"\" class=\"wp-image-4608\" style=\"aspect-ratio:2.7730294396961064;width:407px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-2.png 904w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-2-300x108.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-2-768x277.png 768w\" sizes=\"auto, (max-width: 904px) 100vw, 904px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Select a specific text file from the pull-down list to display it in the text field.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"428\" height=\"782\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-3.png\" alt=\"\" class=\"wp-image-4609\" style=\"aspect-ratio:0.5473173452158533;width:171px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-3.png 428w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-3-164x300.png 164w\" sizes=\"auto, (max-width: 428px) 100vw, 428px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Results <\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Display Values<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When the page is first loaded the results are shown with values 0 in red, because no typing occured yet.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"822\" height=\"150\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-5.png\" alt=\"\" class=\"wp-image-4614\" style=\"aspect-ratio:5.479795113376837;width:322px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-5.png 822w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-5-300x55.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-5-768x140.png 768w\" sizes=\"auto, (max-width: 822px) 100vw, 822px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">During typing this line will disappear. When the last character in the text is typed results are calculated and displayed again, this time in green.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"970\" height=\"137\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-6.png\" alt=\"\" class=\"wp-image-4616\" style=\"aspect-ratio:7.080504469485862;width:369px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-6.png 970w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-6-300x42.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-6-768x108.png 768w\" sizes=\"auto, (max-width: 970px) 100vw, 970px\" \/><\/figure>\n\n\n\n<h5 class=\"wp-block-heading\">Duration<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">When the first correct key press is detected a start time (<math><mrow><mi>s<\/mi><\/mrow> <mn><\/mn> <\/math>) is set. When the last character in the text is typed a end time (<math><mrow><mi>e<\/mi><\/mrow> <mn><\/mn> <\/math>) is set. The duration (<math><mrow><mi>d<\/mi><\/mrow> <mn><\/mn> <\/math>) is the end time minus the start time (in milliseconds) divided by 1000 to convert to seconds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><math>\n<mrow>\n    <mi>d<\/mi>\n    <mo>=<\/mo>\n    <mfrac>\n        <mrow>\n            <mo>(<\/mo><mi>e<\/mi><mo>\u2212<\/mo><mi>s<\/mi><mo>)<\/mo>\n        <\/mrow>\n        <mrow><mi>1000<\/mi><\/mrow>\n    <\/mfrac>\n<\/mrow>\n<\/math><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Accuracy<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">The accuracy percentage (<math> <mrow><mi>a<\/mi><\/mrow> <mn><\/mn> <\/math>) is calculated from the number of correct pressed keys (<math><mrow><mi>c<\/mi><\/mrow> <mn><\/mn> <\/math>) divided by the total number of pressed keys (<math><mrow><mi>t<\/mi><\/mrow> <mn><\/mn> <\/math>) mutiplied by hundred.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><math><mrow><msup><mi>a<\/mi><mn><\/mn><\/msup><mo>=<\/mo><mo>(<\/mo><mfrac><mrow><mi>c<\/mi><mn><\/mn><\/mrow><mrow><mi>t<\/mi><mn><\/mn><\/mrow><\/mfrac><mo>)<\/mo><mo>\u00d7<\/mo><mn>100<\/mn><\/mrow><\/math><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that autocompleted characters are not counted. Only key presses contribute to the accuracy calculation.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Words<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">The number of  words (<math><mrow><mi>w<\/mi><\/mrow><\/math>) in the current text.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Characters per Second<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">The charaters per second (<math><mrow><mi>cps<\/mi><\/mrow><\/math>) are calculated from the total number of pressed keys (<math><mrow><mi>t<\/mi><\/mrow><\/math>) divided by the duration (<math><mrow><mi>d<\/mi><\/mrow><\/math>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><math><mrow><mi>cps<\/mi><mo>=<\/mo><mfrac><mrow><mi>t<\/mi><\/mrow><mrow><mi>d<\/mi><\/mrow><\/mfrac><\/mrow><\/math><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Characters per Minute<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">The charaters per minute (<math><mrow><mi>cpm<\/mi><\/mrow><\/math>) are the characters per second (<math><mrow><mi>cps<\/mi><\/mrow><\/math>) times 60.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><math><mrow>\n        <mi>cpm<\/mi>\n        <mo>=<\/mo>\n        <mi>cps<\/mi>\n        <mo>\u00d7<\/mo>\n        <mi>60<\/mi>\n    <\/mrow>\n<\/math><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Words per Minute<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">The words per minute (<math><mrow><mi>wpm<\/mi><\/mrow><\/math>) are calculated from the number of words (<math><mrow><mi>w<\/mi><\/mrow><\/math>) in the current text divided by the duration (<math><mrow><mi>d<\/mi><\/mrow><\/math>) (divided by 60 to convert from seconds to minutes).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><math><mrow><msup><mi>wpm<\/mi><mn><\/mn><\/msup><mo>=<\/mo><mo>(<\/mo><mfrac><mrow><mi>w<\/mi><mn><\/mn><\/mrow><mrow><mi>d\/60<\/mi><mn><\/mn><\/mrow><\/mfrac><mo>)<\/mo><\/mrow><\/math><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Preset Buttons<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use F1 &#8211; F4 to select a auto-complete preset and set the text difficulty level. If you hover the mouse over any of the buttons the background colour will turn orange.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"90\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-19-1024x90.png\" alt=\"\" class=\"wp-image-4302\" style=\"aspect-ratio:11.376623827515592;width:444px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-19-1024x90.png 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-19-300x26.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-19-768x67.png 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-19.png 1303w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you click the button background colour will become (or stay) dark blue. The presets not selected will become light blue.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"87\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-18-1024x87.png\" alt=\"\" class=\"wp-image-4300\" style=\"aspect-ratio:11.771029341470479;width:447px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-18-1024x87.png 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-18-300x25.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-18-768x65.png 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/afbeelding-18.png 1308w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Simple (F1)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">All auto-complete options are on.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"206\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/SimpleF1-1024x206.jpg\" alt=\"\" class=\"wp-image-3944\" style=\"aspect-ratio:4.97105869703143;width:547px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/SimpleF1-1024x206.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/SimpleF1-300x60.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/SimpleF1-768x154.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/SimpleF1-1536x309.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/SimpleF1.jpg 1602w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"> The typist only needs to worry about pressing the key with the correct character from the alphabet and can disregard uppercase. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardSimpleF1-1024x307.jpg\" alt=\"\" class=\"wp-image-3943\"\/ style=\"object-position: 14% 50%;\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardSimpleF1-1024x307.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardSimpleF1-300x90.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardSimpleF1-768x230.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardSimpleF1-1536x461.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardSimpleF1-2048x614.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Intermediate (F2)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The Caps (F7) and Space (F10) auto-complete options are off.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"206\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/IntermediateF2-1024x206.jpg\" alt=\"\" class=\"wp-image-3945\" style=\"aspect-ratio:4.97105869703143;width:557px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/IntermediateF2-1024x206.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/IntermediateF2-300x60.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/IntermediateF2-768x154.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/IntermediateF2-1536x309.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/IntermediateF2.jpg 1606w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This means that the typist must also use the Shift key (or Caps Lock) for capital characters in the text and the Space Bar for Space.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardIntermediateF2-1-1024x307.jpg\" alt=\"\" class=\"wp-image-3947\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardIntermediateF2-1-1024x307.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardIntermediateF2-1-300x90.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardIntermediateF2-1-768x230.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardIntermediateF2-1-1536x461.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardIntermediateF2-1-2048x614.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Advanced (F3)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Except for Special Chars (F9), all auto-complete options are off.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"201\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AdvancedF3-1024x201.jpg\" alt=\"\" class=\"wp-image-3952\" style=\"aspect-ratio:5.094800258609572;width:545px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AdvancedF3-1024x201.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AdvancedF3-300x59.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AdvancedF3-768x151.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AdvancedF3-1536x302.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AdvancedF3.jpg 1604w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This means the typist needs to type punctuation, capitals, numbers and spaces.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAdvancedF3-1024x307.jpg\" alt=\"\" class=\"wp-image-3953\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAdvancedF3-1024x307.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAdvancedF3-300x90.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAdvancedF3-768x230.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAdvancedF3-1536x461.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAdvancedF3-2048x614.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Type Test (F4)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">All auto-complete options are off.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"207\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TypeTextF4-1024x207.jpg\" alt=\"\" class=\"wp-image-3958\" style=\"aspect-ratio:4.946916681944413;width:534px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TypeTextF4-1024x207.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TypeTextF4-300x61.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TypeTextF4-768x156.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TypeTextF4-1536x311.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/TypeTextF4.jpg 1605w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The typist must use any key combination required to display the correct and case-sensitive character from the text.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardTypeTextF4-1024x307.jpg\" alt=\"\" class=\"wp-image-3956\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardTypeTextF4-1024x307.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardTypeTextF4-300x90.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardTypeTextF4-768x230.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardTypeTextF4-1536x461.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardTypeTextF4-2048x614.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Characters that don&#8217;t apear on the keyboard can be displayed by using key combinations like &lt;Alt&gt; + &lt;numbers on numeric keypad&gt;. (Make sure Num Lock is on.) See <a href=\"https:\/\/support.microsoft.com\/en-US\/Word\/insert-ascii-or-unicode-latin-based-symbols-and-characters\">https:\/\/support.microsoft.com\/en-US\/Word\/insert-ascii-or-unicode-latin-based-symbols-and-characters<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"307\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAltNumericKeyPad-1024x307.jpg\" alt=\"\" class=\"wp-image-3957\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAltNumericKeyPad-1024x307.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAltNumericKeyPad-300x90.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAltNumericKeyPad-768x230.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAltNumericKeyPad-1536x461.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/keyboardAltNumericKeyPad-2048x614.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Example:<\/em> <strong>&lt;Alt&gt; + 0176<\/strong> will display a degree sign \u00b0<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Techniques like &#8220;chained dead keys&#8221;, combining characters and compose keys can also be used to create characters not available on the keyboard. This might differ between keyboard layouts and OS locales. Search for more info online.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Refresh (F5) Button<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Press the F5 function key or click the Refresh button to jump to another text. The button background colour will stay light blue.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Auto-complete Buttons<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The Preset Buttons will select some of the auto-complete buttons to a desired combination. Regardless of the Preset you can toggle the auto-complete buttons by using F6 &#8211; F10 function keys or using the mouse to click the buttons. This allows you to choose any combination of auto-complete options.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"98\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AutocompleteToggle-1024x98.jpg\" alt=\"\" class=\"wp-image-3959\" style=\"aspect-ratio:10.448472978185029;width:543px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AutocompleteToggle-1024x98.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AutocompleteToggle-300x29.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AutocompleteToggle-768x74.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AutocompleteToggle-1536x147.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/AutocompleteToggle.jpg 1604w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h4 class=\"wp-block-heading\">Punctuation (F6) button<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When displayed with a dark blue background, the auto-complete option for Punctuaton is switched on. No need to type punctuation characters like <strong>.?!,;:-\u2013\u2014()[]{}'&#8221;<\/strong>. They are auto-completed and the cursor moves to the next character.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Caps (F7) button<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When displayed with a dark blue background, the auto-complete option for Captial Chararacters is switched on. The typing becomes case-insensitive. This means that the typist doesn&#8217;t have to use the key combination Shift + &lt;character key&gt; and only has to type the lower-case characters. It will be automatically converted to upper-case where needed in the text.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Numbers (F8) button<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When displayed with a dark blue background, the auto-complete option for Numbers is switched on. No need to type the numbers 0123456789. They are auto-completed and the cursor moves to the next character.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Special Chars (F9) button<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When displayed with a dark blue background, the auto-complete option for Special Characters is switched on. No need to type special characters like <strong>#$%^&amp;*_+`|\\\u00b0\u00a3<\/strong>. They are auto-completed and the cursor moves to the next character. More special characters may be added over time.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Space (F10) button<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When displayed with a dark blue background, the auto-complete option for Space is switched on. No need to use the space bar. Spaces are auto-completed and the cursor moves to the next character.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Scroll Text<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes the text that needs to be typed is a bit longer and takes up more space than is visible in the text field. You can scroll it using the scrollbar on the right of the text field. Or the scroll wheel of your mouse while hovering over the text field. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"459\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/TextFieldScroll-1024x459.jpg\" alt=\"\" class=\"wp-image-4003\" style=\"aspect-ratio:2.230937651437629;width:506px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/TextFieldScroll-1024x459.jpg 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/TextFieldScroll-300x134.jpg 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/TextFieldScroll-768x344.jpg 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/TextFieldScroll-1536x688.jpg 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/06\/TextFieldScroll.jpg 1645w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Allthough manual scrolling is not really needed because of the Auto Scroll functionality.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Auto Scroll<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Auto-scroll applies for text that is larger than the visible text field when the cursor gets near the end of the visible part. The text is automatically scrolled to the bottom to reveal the next part of the text to the typist, allowing uninterrupted typing experience.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Scroll Down (F11)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">For a scrollable text the F11 function key can be used to jump to the bottom.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Scroll Up (F12)<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">For a scrollable text that has been scrolled down, the F12 function key can be used to jump back to the top.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Dark Mode<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you prefer a light text on a dark background you can switch to the dark mode.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"180\" height=\"84\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-16.png\" alt=\"\" class=\"wp-image-4724\" style=\"width:82px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Locate the floating menu featuring sun and moon icons in the lower right corner of the screen. Select the sun for normal mode and the moon voor dark mode.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"188\" height=\"94\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-19.png\" alt=\"\" class=\"wp-image-4739\" style=\"width:81px;height:auto\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"928\" src=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-15-1024x928.png\" alt=\"\" class=\"wp-image-4721\" style=\"aspect-ratio:1.1034413532921712;width:335px;height:auto\" srcset=\"https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-15-1024x928.png 1024w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-15-300x272.png 300w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-15-768x696.png 768w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-15-1536x1392.png 1536w, https:\/\/fotografeer.nl\/wp-content\/uploads\/2026\/07\/afbeelding-15.png 1786w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Change History<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">V1.3<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2026-08-19<\/li>\n\n\n\n<li>Changed duration to minutes and seconds<\/li>\n\n\n\n<li>2026-08-17<\/li>\n\n\n\n<li>Improved value reset for words\/minute calculation<\/li>\n\n\n\n<li>Show and hide the results more consistently<\/li>\n\n\n\n<li>Added the number of words in the current text to the results<\/li>\n<\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">Fixed issues in this version<\/h5>\n\n\n\n<ul class=\"wp-block-list\">\n<li><s>Words per minute sometimes seems low (when achieving a a reasonalble char\/min value). The duration determintation is not reset when using the pull-down files list to select a new text. Fix needed. Also hide the results when typing starts on the new text.<\/s><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">V1.2 <\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2026-08-08<\/li>\n\n\n\n<li>Added dark mode option by <a href=\"https:\/\/wordpress.org\/plugins\/darkify\/\" target=\"_blank\" rel=\"noreferrer noopener\">Darkify<\/a> (to whole website)<\/li>\n\n\n\n<li>Added auto-complete for several special characters:\n<ul class=\"wp-block-list\">\n<li>Acute Accent (\u00b4) \u2013 \u00e1, \u00e9, \u00ed, \u00f3, \u00fa, \u00fd (\u00c1, \u00c9, \u00cd, \u00d3, \u00da, \u00dd)<\/li>\n\n\n\n<li>Grave Accent (` ) \u2013 \u00e0, \u00e8, \u00ec, \u00f2, \u00f9 (\u00c0, \u00c8, \u00cc, \u00d2, \u00d9)<\/li>\n\n\n\n<li>Circumflex Accent (^) \u2013 \u00e2, \u00ea, \u00ee, \u00f4, \u00fb (\u00c2, \u00ca, \u00ce, \u00d4, \u00db)<\/li>\n\n\n\n<li>Umlaut \/ Diaeresis (\u00a8) \u2013 \u00e4, \u00eb, \u00ef, \u00f6, \u00fc, \u00ff (\u00c4, \u00cb, \u00cf, \u00d6, \u00dc)<\/li>\n\n\n\n<li>Tilde (\u02dc) \u2013 \u00e3, \u00f1, \u00f5 (\u00c3, \u00d1, \u00d5)<\/li>\n\n\n\n<li>Cedilla (\u00b8) \u2013 \u00e7, \u0123, \u0137, \u013c, \u0146 (\u00c7, \u0122, \u0136, \u013b, \u0145)<\/li>\n\n\n\n<li>Ring Above (\u02da) \u2013 \u00e5 (\u00c5)<\/li>\n\n\n\n<li>Caron \/ Hacek (\u02c7) \u2013 \u010d, \u0161, \u017e (\u010c, \u0160, \u017d)<\/li>\n\n\n\n<li>Macron (\u00af) \u2013 \u0101, \u0113, \u012b, \u014d, \u016b (\u0100, \u0112, \u012a, \u014c, \u016a)<\/li>\n\n\n\n<li>Ligatures &amp; Special Symbols \u2013 \u00e6, \u0153, \u00df, \u00f0, \u00f8, \u00fe (\u00c6, \u0152, \u1e9e, \u00d0, \u00d8, \u00de)<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Full list of special characters that can currently be auto-completed:\n<ul class=\"wp-block-list\">\n<li>$%&amp;*+\/&lt;=&gt;@^_`|~\\\u00b0\u00a3\u20ac\u00a5\u00a2\u00e1\u00e9\u00ed\u00f3\u00fa\u00fd\u00c1\u00c9\u00cd\u00d3\u00da\u00dd\u00e0\u00e8\u00ec\u00f2\u00f9\u00c0\u00c8\u00cc\u00d2\u00d9\u00e2\u00ea\u00ee\u00f4\u00fb\u00c2\u00ca\u00ce\u00d4\u00db\u00e4\u00eb\u00ef\u00f6\u00fc\u00ff\u00c4\u00cb\u00cf\u00d6\u00dc\u00e3\u00f1\u00f5\u00c3\u00d1\u00d5\u00e7\u0123\u0137\u013c\u0146\u00c7\u0122\u0136\u013b\u0145\u00e5\u00c5\u010d\u0161\u017e\u010c\u0160\u017d\u0101\u0113\u012b\u014d\u016b\u0100\u0112\u012a\u014c\u016a\u00e6\u0153\u00df\u00f0\u00f8\u00fe\u00c6\u0152\u1e9e\u00d0\u00d8\u00de<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">Fixed issues in this version<\/h5>\n\n\n\n<ul class=\"wp-block-list\">\n<li><s>A lot of special characters like umlaut, accent circonflex are not yet supported.<\/s><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">v1.1<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2026-08-02<\/li>\n\n\n\n<li>Added words\/minute to the results<\/li>\n\n\n\n<li>Added text file pull-down menu below the Text Field to facilitate a file list per selected difficulty level<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading has-theme-palette-3-color has-text-color has-link-color wp-elements-1\">V1.0 <\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>2026-07-06<\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-2\">First release and public availability<\/li>\n<\/ul>\n\n\n\n<h5 class=\"wp-block-heading has-theme-palette-3-color has-text-color has-link-color wp-elements-3\">Fixed issues in this version<\/h5>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-4\"><s><em>When clicking refresh, text is not scrolled to the top<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-5\"><s><em>The degree sign &#8220;\u00b0&#8221; is not auto-completed. (Alt + 0176 on numeric keypad.)<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-6\"><s><em>trading.txt is too long for proper scrolling.<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-7\"><s><em>budget.txt is too long for proper scrolling.<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-8\"><s><em>health.txt might be too long for proper scrolling.<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-9\"><s><em>In preset mode F2 with Caps auto-complete swithed off, uppercase is still ignored.<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-10\"><s><em>Missing extensive manual<\/em><\/s>.<\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-11\"><s><em>Education.txt is to long for proper scrolling.<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-12\"><s><em>When punctuation auto-complete is on, the last period is not auto-completed.<\/em><\/s><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-13\"><em><s>Doesn&#8217;t work on tablet and mobile phone. Show warning if detected.<\/s><\/em><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-14\"><em><s>Alt code (e.g. Alt + 0128 =&gt; \u20ac) don&#8217;t work!<\/s><\/em><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-15\"><em><s>When space auto-complete is off, cursor is not shown at the end of line before wrapping.<\/s><\/em><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-16\"><em><s>Occasionally typing freezes. Not clear what causes this. Wasn&#8217;t able to reproduce.<\/s><\/em><\/li>\n\n\n\n<li class=\"has-theme-palette-3-color has-text-color has-link-color wp-elements-17\"><s><em>Code works in preview mode on admin pages, but stays frozen on the normal browser page. Not sure what is happening here!<\/em><\/s><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">v0.9<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Development and beta test version<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Known issues<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Only tested on Firefox 151.0.2 (64 bits) and<br>Microsoft Edge 149.0.4022.69 (Offici\u00eble build) (64-bits) browsers on Windows 11<\/li>\n\n\n\n<li>Only tested on a qwerty keyboard<\/li>\n\n\n\n<li>Green outlined keys in images in manual may not be entirely correct.<\/li>\n\n\n\n<li>Ocassionly, text isn&#8217;t shown on page load. Then select difficulty (F1- F4) and Refresh (F5).<\/li>\n\n\n\n<li>When the end of the word is at the edge of the right border of the text field pressing space will make the text jump around a bit. Leave in this version.<\/li>\n\n\n\n<li>Backspace is not supported. The cursor stays in the same place until you type the correct character.<\/li>\n\n\n\n<li>Refresh (F5) is often fast but sometimes it may take a few seconds to load a text, since it has to retrieve the text from the internet.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Disclaimer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">THIS PROGRAM IS PROVIDED &#8220;AS IS&#8221;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN THIS PROGRAM.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you need to relearn typing due to physical trauma or neurological damage try this type test. It features several auto-complete options that avoid key combinations and far key stretches to help your medical rehabilitation in  a step-by-step fashion.<\/p>\n","protected":false},"author":2,"featured_media":3943,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[199],"tags":[178,180,172,162],"class_list":["post-3217","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-rehabilitation___en","tag-medical-rehabilitation","tag-rehab","tag-test","tag-typing"],"lang":"en","translations":{"en":3217,"nl":4157},"pll_sync_post":{},"_links":{"self":[{"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/posts\/3217","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3217"}],"version-history":[{"count":834,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/posts\/3217\/revisions"}],"predecessor-version":[{"id":4771,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/posts\/3217\/revisions\/4771"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=\/wp\/v2\/media\/3943"}],"wp:attachment":[{"href":"https:\/\/fotografeer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3217"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3217"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fotografeer.nl\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3217"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}