| var _testing = false; |
| |
| // The index into _keyTable of the key currently being tested. |
| var _currKey = 0; |
| |
| var _keysTotal = 0; |
| var _keysGood = 0; |
| var _keysBad = 0; |
| var _keysSkipped = 0; |
| |
| var _modifierMode = "None"; |
| |
| var _keydownCapture = []; |
| var _keyupCapture = []; |
| |
| var CAPTURE_KEYCODE = 0; |
| var CAPTURE_CODE = 1; |
| var CAPTURE_KEY = 2; |
| var CAPTURE_SHIFTKEY = 3; |
| var CAPTURE_CONTROLKEY = 4; |
| var CAPTURE_ALTKEY = 5; |
| var CAPTURE_METAKEY = 6; |
| |
| // An array of KeyInfo for each key to be tested. |
| var _keyTable = []; |
| |
| // KeyInfo fields. |
| var KEYINFO_CODE = 0; // |code| for this key |
| var KEYINFO_ROW = 1; // Keyboard row |
| var KEYINFO_TYPE = 2; // Key type (see below) |
| var KEYINFO_WIDTH = 3; // Width of key: 0=normal |
| var KEYINFO_KEYCAP = 4; // Keycap string to display |
| var KEYINFO_KEY = 5; // Unmodified key value |
| var KEYINFO_KEY_SHIFT = 6; // Shifted key value |
| |
| var KEYTYPE_NORMAL = 0; |
| var KEYTYPE_DISABLED = 1; // Key cannot be tested: e.g., CapsLock |
| var KEYTYPE_END = 2; // Used to mark end of KeyTable |
| var KEYTYPE_MODIFIER = 3; // Modifer key |
| |
| function clearChildren(e) { |
| while (e.firstChild !== null) { |
| e.removeChild(e.firstChild); |
| } |
| } |
| |
| function setText(e, text) { |
| clearChildren(e); |
| e.appendChild(document.createTextNode(text)); |
| } |
| |
| function setUserAgent() { |
| var userAgent = navigator.userAgent; |
| uaDiv = document.getElementById("useragent"); |
| setText(uaDiv, userAgent); |
| } |
| |
| function addEventListener(obj, etype, handler) { |
| if (obj.addEventListener) { |
| obj.addEventListener(etype, handler, false); |
| } else if (obj.attachEvent) { |
| obj.attachEvent("on"+etype, handler); |
| } else { |
| obj["on"+etype] = handler; |
| } |
| } |
| |
| function addClass(obj, className) { |
| obj.classList.add(className); |
| } |
| |
| function removeClass(obj, className) { |
| obj.classList.remove(className); |
| } |
| |
| function addInnerText(obj, text) { |
| obj.appendChild(document.createTextNode(text)); |
| } |
| |
| function calcLocation(loc) { |
| if (loc == 1) return "LEFT"; |
| if (loc == 2) return "RIGHT"; |
| if (loc == 3) return "NUMPAD"; |
| return loc; |
| } |
| |
| function isModifierKey(e) { |
| // Shift, Control, Alt |
| if (e.keyCode >= 16 && e.keyCode <= 18) { |
| return true; |
| } |
| // Windows, Command or Meta key. |
| if (e.keyCode == 224 // Right/Left: Gecko |
| || e.keyCode == 91 // Left: WebKit/Blink |
| || e.keyCode == 93 // Right: WebKit/Blink |
| ) { |
| return true; |
| } |
| return false; |
| } |
| |
| function init(title, keytable) { |
| _keyTable = keytable; |
| |
| createBody(title, keytable); |
| |
| setUserAgent(); |
| |
| var input = document.getElementById("input"); |
| input.disabled = true; |
| addEventListener(input, "keydown", onKeyDown); |
| addEventListener(input, "keyup", onKeyUp); |
| //addEventListener(input, "beforeInput", onBeforeInput); |
| //addEventListener(input, "input", onInput); |
| } |
| |
| function onKeyDown(e) { |
| // Ignore modifier keys when checking modifier combinations. |
| if (_modifierMode != "None" && isModifierKey(e)) { |
| return; |
| } |
| |
| _keydownInfo = [e.keyCode, e.code, e.key, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey]; |
| if (e.keyCode == 9 || e.code == "Tab") { |
| e.preventDefault(); |
| } |
| } |
| |
| function onKeyUp(e) { |
| // Ignore modifier keys when checking modifier combinations. |
| if (_modifierMode != "None" && isModifierKey(e)) { |
| return; |
| } |
| |
| _keyupInfo = [e.keyCode, e.code, e.key, e.shiftKey, e.ctrlKey, e.altKey, e.metaKey]; |
| |
| if (_testing) { |
| verifyKey(); |
| nextKey(); |
| } |
| } |
| |
| function onBeforeInput(e) { |
| } |
| |
| function onInput(e) { |
| } |
| |
| function addError(elem, str) { |
| var p = document.createElement('p'); |
| p.classList.add("error2"); |
| p.textContent = str; |
| elem.appendChild(p); |
| } |
| |
| function addErrorIncorrect(elem, eventName, attrName, keyEventInfo, attr, expected) { |
| addError(elem, "Incorrect " + eventName |
| + " |" + attrName + "| = " + keyEventInfo[attr] |
| + " - Expected " + expected); |
| } |
| |
| function verifyKeyEventFields(eventName, keyEventInfo, code, key, error) { |
| var verifyCode = document.getElementById("opt_attr_code").checked; |
| var verifyKey = document.getElementById("opt_attr_key").checked; |
| var verifyModifiers = document.getElementById("opt_attr_modifiers").checked; |
| var good = true; |
| |
| if (!verifyCode && !verifyKey && !verifyModifiers) { |
| good = false; |
| addError(error, "Invalid test: At least one attribute must be selected for testing."); |
| } |
| if (verifyCode && keyEventInfo[CAPTURE_CODE] != code) { |
| good = false; |
| addErrorIncorrect(error, eventName, "code", keyEventInfo, CAPTURE_CODE, code); |
| } |
| if (verifyKey && keyEventInfo[CAPTURE_KEY] != key) { |
| good = false; |
| addErrorIncorrect(error, eventName, "key", keyEventInfo, CAPTURE_KEY, key); |
| } |
| if (verifyModifiers) { |
| if (keyEventInfo[CAPTURE_SHIFTKEY] != (_modifierMode == "Shift")) { |
| good = false; |
| addErrorIncorrect(error, eventName, "shiftKey", keyEventInfo, CAPTURE_SHIFTKEY, false); |
| } |
| if (keyEventInfo[CAPTURE_CONTROLKEY]) { |
| good = false; |
| addErrorIncorrect(error, eventName, "controlKey", keyEventInfo, CAPTURE_CONTROLKEY, false); |
| } |
| if (keyEventInfo[CAPTURE_ALTKEY]) { |
| good = false; |
| addErrorIncorrect(error, eventName, "altKey", keyEventInfo, CAPTURE_ALTKEY, false); |
| } |
| if (keyEventInfo[CAPTURE_METAKEY]) { |
| good = false; |
| addErrorIncorrect(error, eventName, "metaKey", keyEventInfo, CAPTURE_METAKEY, false); |
| } |
| } |
| |
| return good; |
| } |
| |
| function verifyKey() { |
| _keysTotal++; |
| |
| var keyInfo = _keyTable[_currKey]; |
| var code = keyInfo[KEYINFO_CODE]; |
| var key = keyInfo[KEYINFO_KEY]; |
| var keyShift = keyInfo[KEYINFO_KEY_SHIFT]; |
| |
| var keyCheck = key; |
| if (_modifierMode == "Shift") { |
| keyCheck = keyShift; |
| } |
| |
| var verifyKeydown = document.getElementById("opt_event_keydown").checked; |
| var verifyKeyup = document.getElementById("opt_event_keyup").checked; |
| |
| var error = document.createElement('div'); |
| error.classList.add("error"); |
| var good = true; |
| |
| if (verifyKeydown) { |
| good = verifyKeyEventFields("keydown", _keydownInfo, code, keyCheck, error); |
| } |
| if (verifyKeyup) { |
| good = verifyKeyEventFields("keyup", _keyupInfo, code, keyCheck, error); |
| } |
| |
| if (!verifyKeydown && !verifyKeyup) { |
| good = false; |
| addError(error, "Invalid test: At least one event must be selected for testing."); |
| } |
| |
| // Allow Escape key to skip the current key. |
| var skipped = false; |
| if (_keydownInfo[CAPTURE_KEYCODE] == 27 || _keydownInfo[CAPTURE_CODE] == "Escape") { |
| good = true; |
| skipped = true; |
| } |
| |
| if (!good) { |
| var p = document.createElement('p'); |
| p.classList.add("error1"); |
| p.textContent = "Error : " + code; |
| error.insertBefore(p, error.firstChild); |
| } |
| |
| removeNextKeyHilight(); |
| if (skipped) { |
| _keysSkipped++; |
| document.getElementById(code).classList.add("skippedKey") |
| } else if (good) { |
| _keysGood++; |
| document.getElementById(code).classList.add("goodKey") |
| } else { |
| _keysBad++; |
| document.getElementById(code).classList.add("badKey") |
| } |
| updateTestSummary(good ? null : error); |
| } |
| |
| function updateTestSummary(error) { |
| document.getElementById("keys-total").textContent = _keysTotal; |
| document.getElementById("keys-good").textContent = _keysGood; |
| document.getElementById("keys-bad").textContent = _keysBad; |
| document.getElementById("keys-skipped").textContent = _keysSkipped; |
| |
| if (error) { |
| var errors = document.getElementById("errors"); |
| errors.insertBefore(error, errors.firstChild); |
| } |
| } |
| |
| function resetTest() { |
| _keysTotal = 0; |
| _keysGood = 0; |
| _keysBad = 0; |
| |
| _currKey = -1; |
| nextKey(); |
| |
| updateTestSummary(); |
| |
| // Remove previous test results. |
| clearChildren(document.getElementById("errors")); |
| |
| // Remove highlighting from keys. |
| for (var i = 0; i < _keyTable.length; i++) { |
| var code = _keyTable[i][KEYINFO_CODE]; |
| var type = _keyTable[i][KEYINFO_TYPE]; |
| if (type != KEYTYPE_END) { |
| var key = document.getElementById(code); |
| key.classList.remove("goodKey"); |
| key.classList.remove("badKey"); |
| key.classList.remove("skippedKey"); |
| } |
| } |
| } |
| |
| function startTest() { |
| if (_testing) { |
| // Cancel the currently running test. |
| endTest(); |
| return; |
| } |
| |
| resetTest(); |
| _testing = true; |
| document.getElementById("start").value = "Stop Test" |
| |
| var input = document.getElementById("input"); |
| input.value = ""; |
| input.disabled = false; |
| input.focus(); |
| |
| // Show test instructions and info. |
| document.getElementById("test-info").style.display = 'block'; |
| document.getElementById("instructions").style.display = 'block'; |
| document.getElementById("test-done").style.display = 'none'; |
| } |
| |
| function endTest() { |
| _testing = false; |
| removeNextKeyHilight(); |
| document.getElementById("start").value = "Restart Test" |
| document.getElementById("input").disabled = true; |
| document.getElementById("instructions").style.display = 'none'; |
| document.getElementById("test-done").style.display = 'block'; |
| } |
| |
| function removeNextKeyHilight() { |
| var curr = document.getElementById(_keyTable[_currKey][KEYINFO_CODE]); |
| if (curr) { |
| removeClass(curr, "nextKey") |
| } |
| } |
| |
| function addNextKeyHilight() { |
| var curr = document.getElementById(_keyTable[_currKey][KEYINFO_CODE]); |
| if (curr) { |
| addClass(curr, "nextKey") |
| } |
| } |
| |
| function nextKey() { |
| var keyInfo; |
| var keepLooking = true; |
| do { |
| _currKey++; |
| keyInfo = _keyTable[_currKey]; |
| var type = keyInfo[KEYINFO_TYPE]; |
| |
| // Skip over disabled keys. |
| keepLooking = (type == KEYTYPE_DISABLED); |
| |
| // Skip over modifier keys if we're testing modifier combinations. |
| if (_modifierMode != "None" && type == KEYTYPE_MODIFIER) { |
| keepLooking = true; |
| } |
| |
| // Skip over keys in disabled rows. |
| if (type != KEYTYPE_END) { |
| var row = keyInfo[KEYINFO_ROW]; |
| var rowEnabled = document.getElementById("opt_row_" + row).checked; |
| keepLooking = keepLooking || !rowEnabled; |
| } |
| } while (keepLooking); |
| |
| if (keyInfo[KEYINFO_TYPE] == KEYTYPE_END) { |
| endTest(); |
| } else { |
| addNextKeyHilight(); |
| } |
| } |
| |
| function toggleOptions() { |
| var link = document.getElementById("optionstoggle"); |
| var options = document.getElementById("options"); |
| clearChildren(link); |
| if (options.style.display == "block") { |
| options.style.display = "none"; |
| addInnerText(link, "Show Options"); |
| } |
| else { |
| options.style.display = "block"; |
| addInnerText(link, "Hide Options"); |
| } |
| } |
| |
| function toggleHelp() { |
| var link = document.getElementById("helptoggle"); |
| var help = document.getElementById("help"); |
| clearChildren(link); |
| if (help.style.display == "block") { |
| help.style.display = "none"; |
| addInnerText(link, "Show Help"); |
| } |
| else { |
| help.style.display = "block"; |
| addInnerText(link, "Hide Help"); |
| } |
| } |
| |
| function createBody(title, keytable) { |
| var body = document.getElementsByTagName("body")[0]; |
| var p; |
| var span; |
| |
| var h1 = document.createElement('h1'); |
| h1.textContent = "Keyboard Event Manual Test - " + title; |
| body.appendChild(h1); |
| |
| // Display useragent. |
| p = document.createElement('p'); |
| p.textContent = "UserAgent: "; |
| var useragent = document.createElement('span'); |
| useragent.id = "useragent"; |
| p.appendChild(useragent); |
| body.appendChild(p); |
| |
| // Display input textedit. |
| p = document.createElement('p'); |
| p.textContent = "Test Input: "; |
| var input1 = document.createElement('input'); |
| input1.id = "input"; |
| input1.type = "text"; |
| input1.size = 80; |
| p.appendChild(input1); |
| p.appendChild(document.createTextNode(" ")); |
| var input2 = document.createElement('input'); |
| input2.id = "start"; |
| input2.type = "button"; |
| input2.onclick = function() { startTest(); return false; } |
| input2.value = "Start Test"; |
| p.appendChild(input2); |
| p.appendChild(document.createTextNode(" ")); |
| var optionsToggle = document.createElement('a'); |
| optionsToggle.id = "optionstoggle"; |
| optionsToggle.href = "javascript:toggleOptions()"; |
| optionsToggle.textContent = "Show Options"; |
| p.appendChild(optionsToggle); |
| p.appendChild(document.createTextNode(" ")); |
| var helpToggle = document.createElement('a'); |
| helpToggle.id = "helptoggle"; |
| helpToggle.href = "javascript:toggleHelp()"; |
| helpToggle.textContent = "Show Help"; |
| p.appendChild(helpToggle); |
| body.appendChild(p); |
| |
| createOptions(body); |
| |
| createHelp(body); |
| |
| createKeyboard(body, keytable); |
| |
| // Test info and summary. |
| var test_info = document.createElement('div'); |
| test_info.id = "test-info"; |
| test_info.style.display = "none"; |
| |
| var instructions = document.createElement('div'); |
| instructions.id = "instructions"; |
| p = document.createElement('p'); |
| p.textContent = "Press the highlighted key."; |
| instructions.appendChild(p); |
| test_info.appendChild(instructions); |
| |
| var test_done = document.createElement('div'); |
| test_done.id = "test-done"; |
| p = document.createElement('p'); |
| p.textContent = "Test complete!"; |
| test_done.appendChild(p); |
| test_info.appendChild(test_done); |
| |
| var summary = document.createElement('div'); |
| summary.id = "summary"; |
| p = document.createElement('p'); |
| summary.appendChild(document.createTextNode("Keys Tested: ")); |
| span = document.createElement('span'); |
| span.id = "keys-total"; |
| span.textContent = 0; |
| summary.appendChild(span); |
| summary.appendChild(document.createTextNode("; Passed ")); |
| span = document.createElement('span'); |
| span.id = "keys-good"; |
| span.textContent = 0; |
| summary.appendChild(span); |
| summary.appendChild(document.createTextNode("; Failed ")); |
| span = document.createElement('span'); |
| span.id = "keys-bad"; |
| span.textContent = 0; |
| summary.appendChild(span); |
| summary.appendChild(document.createTextNode("; Skipped ")); |
| span = document.createElement('span'); |
| span.id = "keys-skipped"; |
| span.textContent = 0; |
| summary.appendChild(span); |
| test_info.appendChild(summary); |
| |
| var errors = document.createElement('div'); |
| errors.id = "errors"; |
| test_info.appendChild(errors); |
| |
| body.appendChild(test_info); |
| } |
| |
| function addOptionTitle(cell, title) { |
| var span = document.createElement('span'); |
| span.classList.add("opttitle"); |
| span.textContent = title; |
| cell.appendChild(span); |
| cell.appendChild(document.createElement("br")); |
| } |
| |
| function addOptionCheckbox(cell, id, text) { |
| var label = document.createElement("label"); |
| |
| var input = document.createElement("input"); |
| input.type = "checkbox"; |
| input.id = id; |
| input.checked = true; |
| label.appendChild(input); |
| |
| label.appendChild(document.createTextNode(" " + text)); |
| cell.appendChild(label); |
| |
| cell.appendChild(document.createElement("br")); |
| } |
| |
| function addOptionRadio(cell, group, text, handler, checked) { |
| var label = document.createElement("label"); |
| |
| var input = document.createElement("input"); |
| input.type = "radio"; |
| input.name = group; |
| input.value = text; |
| input.onclick = handler; |
| input.checked = checked; |
| label.appendChild(input); |
| |
| label.appendChild(document.createTextNode(" " + text)); |
| cell.appendChild(label); |
| |
| cell.appendChild(document.createElement("br")); |
| } |
| |
| function handleModifierGroup() { |
| var radio = document.querySelector("input[name=opt_modifier]:checked"); |
| var oldMode = _modifierMode; |
| _modifierMode = radio.value; |
| |
| if (oldMode == "Shift") { |
| document.getElementById("ShiftLeft").classList.remove("activeModifierKey"); |
| document.getElementById("ShiftRight").classList.remove("activeModifierKey"); |
| } |
| |
| if (_modifierMode == "Shift") { |
| document.getElementById("ShiftLeft").classList.add("activeModifierKey"); |
| document.getElementById("ShiftRight").classList.add("activeModifierKey"); |
| } |
| } |
| |
| function createOptions(body) { |
| var options = document.createElement('div'); |
| options.id = "options"; |
| options.style.display = "none"; |
| |
| var table = document.createElement('table'); |
| table.classList.add("opttable"); |
| var row = document.createElement('tr'); |
| var cell; |
| |
| cell = document.createElement('td'); |
| cell.classList.add("optcell"); |
| addOptionTitle(cell, "Keyboard Rows"); |
| addOptionCheckbox(cell, "opt_row_0", "Row E (top)"); |
| addOptionCheckbox(cell, "opt_row_1", "Row D"); |
| addOptionCheckbox(cell, "opt_row_2", "Row C"); |
| addOptionCheckbox(cell, "opt_row_3", "Row B"); |
| addOptionCheckbox(cell, "opt_row_4", "Row A (bottom)"); |
| row.appendChild(cell); |
| |
| cell = document.createElement('td'); |
| cell.classList.add("optcell"); |
| addOptionTitle(cell, "Events"); |
| addOptionCheckbox(cell, "opt_event_keydown", "keydown"); |
| addOptionCheckbox(cell, "opt_event_keyup", "keyup"); |
| row.appendChild(cell); |
| |
| cell = document.createElement('td'); |
| cell.classList.add("optcell"); |
| addOptionTitle(cell, "Attributes"); |
| addOptionCheckbox(cell, "opt_attr_code", "code"); |
| addOptionCheckbox(cell, "opt_attr_key", "key"); |
| addOptionCheckbox(cell, "opt_attr_modifiers", "modifiers"); |
| row.appendChild(cell); |
| |
| cell = document.createElement('td'); |
| cell.classList.add("optcell"); |
| addOptionTitle(cell, "Modifiers"); |
| addOptionRadio(cell, "opt_modifier", "None", handleModifierGroup, true); |
| addOptionRadio(cell, "opt_modifier", "Shift", handleModifierGroup, false); |
| row.appendChild(cell); |
| |
| table.appendChild(row); |
| options.appendChild(table); |
| |
| body.appendChild(options); |
| } |
| |
| function addHelpText(div, text) { |
| var p = document.createElement('p'); |
| p.classList.add("help"); |
| p.textContent = text; |
| div.appendChild(p); |
| } |
| |
| function createHelp(body) { |
| var help = document.createElement('div'); |
| help.id = "help"; |
| help.style.display = "none"; |
| |
| addHelpText(help, "Click on the \"Start Test\" button to begin testing."); |
| addHelpText(help, "Press the hilighted key to test it."); |
| addHelpText(help, "Clicking anywhere outside the \"Test Input\" editbox will pause testing. To resume, click back inside the editbox."); |
| addHelpText(help, "To skip a key while testing, press Escape."); |
| addHelpText(help, "When testing with modifier keys, the modifier must be pressed before the keydown and released after the keyup of the key being tested."); |
| |
| body.appendChild(help); |
| } |
| |
| function createKeyboard(body, keytable) { |
| var keyboard = document.createElement('div'); |
| keyboard.classList.add("keyboard"); |
| |
| var currRow = 0; |
| var row = document.createElement('div'); |
| row.classList.add("key-row"); |
| |
| for (var i = 0; i < keytable.length; i++) { |
| var code = keytable[i][KEYINFO_CODE]; |
| var rowId = keytable[i][KEYINFO_ROW]; |
| var type = keytable[i][KEYINFO_TYPE]; |
| var width = keytable[i][KEYINFO_WIDTH]; |
| var keyCap = keytable[i][KEYINFO_KEYCAP]; |
| |
| if (type == KEYTYPE_END) { |
| continue; |
| } |
| |
| if (rowId != currRow) { |
| keyboard.appendChild(row); |
| row = document.createElement('div'); |
| row.classList.add("key-row"); |
| currRow = rowId; |
| } |
| |
| var key = document.createElement('div'); |
| key.id = code; |
| key.classList.add("key"); |
| if (width != 0) { |
| key.classList.add("wide" + width); |
| } |
| key.textContent = keyCap; |
| |
| row.appendChild(key); |
| } |
| |
| keyboard.appendChild(row); |
| body.appendChild(keyboard); |
| } |