var data = {}; var audio = {}; var hits_correct = 0; var hits_wrong = 0; var start_time = 0; var hpm = 0; var ratio = 0; data.chars = " jfkdlsahgyturieowpqbnvmcxz6758493021`-=[]\\;',./ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}|:\"<>?"; data.consecutive = 5; data.word_length = 7; data.current_layout = "qwerty"; layouts={}; layouts["qwerty"] = " jfkdlsahgyturieowpqbnvmcxz6758493021`-=[]\\;',./ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}|:\"<>?"; layouts["azerty"] = " jfkdlsmqhgyturieozpabnvcxw6758493021`-=[]\\;',./ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}|:\"<>?"; layouts["colemak"] = " ntesiroahdjglpufywqbkvmcxz1234567890'\",.!?:;/@$%&#*()_ABCDEFGHIJKLMNOPQRSTUVWXYZ~+-={}|^<>`[]\\"; layouts["bépo"] = " tesirunamc,èvodpléjbk'.qxghyfàzw6758493021`-=[]\\;/ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}|:\"<>?"; layouts["norman"] = " ntieosaygjkufrdlw;qbpvmcxz1234567890'\",.!?:;/@$%&#*()_ABCDEFGHIJKLMNOPQRSTUVWXYZ~+-={}|^<>`[]\\"; layouts["code-es6"] = " {}',;():.>= -1){ e.preventDefault(); } else { return; } data.keys_hit += key; if(key == data.word[data.word_index]) { hits_correct += 1; data.in_a_row[key] += 1; play_audio_sample("correct"); } else { hits_wrong += 1; data.in_a_row[data.word[data.word_index]] = 0; data.in_a_row[key] = 0; play_audio_sample("mistake"); data.word_errors[data.word_index] = true; } data.word_index += 1; if (data.word_index >= data.word.length) { setTimeout(next_word, 400); } update_stats(); render(); save(); } function next_word(){ if(get_training_chars().length == 0) { level_up(); } data.word = generate_word(); data.word_index = 0; data.keys_hit = ""; data.word_errors = {}; update_stats(); render(); save(); } function level_up() { if (data.level + 1 <= data.chars.length - 1) { play_audio_sample("level_up"); } l = Math.min(data.level + 1, data.chars.length); set_level(l); } function save() { localStorage.data = JSON.stringify(data); } function load() { data = JSON.parse(localStorage.data); } function load_audio() { audio.samples = {}; audio.context = new (window.AudioContext || window.webkitAudioContext)(); load_audio_sample("correct", "/maydo/keyzen/click.wav"); load_audio_sample("mistake", "/maydo/keyzen/clack.wav"); load_audio_sample("level_up", "/maydo/keyzen/ding.wav"); } function load_audio_sample(name, url) { if (!audio.samples[name]) { // fetch the .wav file via XMLHttpRequest as jQuery doesn't support 'arraybuffer' dataType var request = new XMLHttpRequest(); request.open("GET", url, true); request.responseType = "arraybuffer"; request.onload = function () { audio.context.decodeAudioData(request.response).then(function (buffer) { audio.samples[name] = buffer; }); }; request.send(); } } function play_audio_sample(name) { if (audio.samples[name]) { var source = audio.context.createBufferSource(); source.buffer = audio.samples[name]; source.onended source.connect(audio.context.destination); source.start(); } } function render() { render_layout(); render_level(); render_word(); render_level_bar(); render_rigor(); render_stats(); } function render_layout() { var layouts_html = ""; for(var layout in layouts){ if(data.current_layout == layout){ layouts_html += " " } else { layouts_html += " " } layouts_html += layout + ""; } layouts_html += ""; $("#layout").html('Choose layout : ' + layouts_html); } function render_level() { var chars = ""; var level_chars = get_level_chars(); var training_chars = get_training_chars(); for (var c in data.chars) { if(training_chars.indexOf(data.chars[c]) != -1) { chars += "" } else if (level_chars.indexOf(data.chars[c]) != -1) { chars += "" } else { chars += "" } if (data.chars[c] == ' ') { chars += "⎵"; } else { chars += data.chars[c]; } chars += ""; } chars += ""; $("#level-chars").html('click to set level: ' + chars); } function render_rigor() { chars = ""; chars += '' + data.consecutive; chars += ''; $('#rigor').html('click to set required repititions: ' + chars); } function render_stats() { $("#stats").text([ "hits per minute: ", hpm, " ", "correctness: ", ratio, "%" ].join("")); } function inc_rigor() { data.consecutive += 1; if (data.consecutive > 9) { data.consecutive = 2; } render_rigor(); } function render_level_bar() { training_chars = get_training_chars(); if(training_chars.length == 0) { m = data.consecutive; } else { m = 1e100; for(c in training_chars) { m = Math.min(data.in_a_row[training_chars[c]], m); } } m = Math.floor($('#level-chars-wrap').innerWidth() * Math.min(1.0, m / data.consecutive)); $('#next-level').css({'width': '' + m + 'px'}); } function render_word() { var word = ""; for (var i = 0; i < data.word.length; i++) { sclass = "normalChar"; if (i > data.word_index) { sclass = "normalChar"; } else if (i == data.word_index) { sclass = "currentChar"; } else if(data.word_errors[i]) { sclass = "errorChar"; } else { sclass = "goodChar"; } word += ""; if(data.word[i] == " ") { word += "⎵" } else if(data.word[i] == "&") { word += "&" } else { word += data.word[i]; } word += ""; } var keys_hit = ""; for(var d in data.keys_hit) { if (data.keys_hit[d] == ' ') { keys_hit += "⎵"; } else if (data.keys_hit[d] == '&') { keys_hit += "&"; } else { keys_hit += data.keys_hit[d]; } } for(var i = data.word_index; i < data.word_length; i++) { keys_hit += " "; } keys_hit += ""; $("#word").html(word + "
" + keys_hit); } function generate_word() { word = ''; for(var i = 0; i < data.word_length; i++) { c = choose(get_training_chars()); if(c != undefined && c != word[word.length-1]) { word += c; } else { word += choose(get_level_chars()); } } return word; } function get_level_chars() { return data.chars.slice(0, data.level + 1).split(''); } function get_training_chars() { var training_chars = []; var level_chars = get_level_chars(); for(var x in level_chars) { if (data.in_a_row[level_chars[x]] < data.consecutive) { training_chars.push(level_chars[x]); } } return training_chars; } function choose(a) { return a[Math.floor(Math.random() * a.length)]; }