// *********************************** // * Global variables // *********************************** const kIsWin = navigator.platform.indexOf("Win") == 0; // Bit value for the keyboard events const kKeyDown = 0x01; const kKeyPress = 0x02; const kKeyUp = 0x04; // Pair the event name to its bit value const kEventCode = { 'keydown' : kKeyDown, 'keypress' : kKeyPress, 'keyup' : kKeyUp }; // Holding the current test case's infomation: var gCurrentTest; // The current used input method of this test var gInputMethod; // *********************************** // * Utilities // *********************************** function addKeyEventListeners(eventTarget, handler) { Object.keys(kEventCode).forEach(function(type) { eventTarget.addEventListener(type, handler); }); } function eventToCode(type) { return kEventCode[type]; } // To test key events that will be generated by input method here, // we need to convert alphabets to native key code. // (Our input method for testing will handle alphabets) // On the other hand, to test key events that will not be generated by IME, // we use 0-9 for such case in our testing. function guessNativeKeyCode(key) { let nativeCodeName = (kIsWin)? 'WIN_VK_' : 'MAC_VK_ANSI_'; if (/^[A-Z]$/.test(key)) { nativeCodeName += key; } else if (/^[a-z]$/.test(key)) { nativeCodeName += key.toUpperCase(); } else if (/^[0-9]$/.test(key)) { nativeCodeName += key.toString(); } else { return 0; } return eval(nativeCodeName); } // *********************************** // * Frame loader and frame scripts // *********************************** function frameScript() { function handler(e) { sendAsyncMessage("forwardevent", { type: e.type, key: e.key }); } function notifyFinish(e) { if (e.type != 'keyup') return; sendAsyncMessage("finish"); } let input = content.document.getElementById('test-input'); input.addEventListener('keydown', handler); input.addEventListener('keypress', handler); input.addEventListener('keyup', handler); input.addEventListener('keyup', notifyFinish); } function loadTestFrame(goNext) { let iframe = document.createElement('iframe'); iframe.src = 'file_test_empty_app.html'; iframe.setAttribute('mozbrowser', true); iframe.addEventListener("mozbrowserloadend", function onloadend() { iframe.removeEventListener("mozbrowserloadend", onloadend); iframe.focus(); var mm = SpecialPowers.getBrowserFrameMessageManager(iframe); mm.addMessageListener("forwardevent", function(msg) { inputtextEventReceiver(msg.json); }); mm.addMessageListener("finish", function(msg) { if(goNext) { goNext(); } }); mm.loadFrameScript("data:,(" + frameScript.toString() + ")();", false); return; }); document.body.appendChild(iframe); } // *********************************** // * Event firer and listeners // *********************************** function fireEvent(callback) { let key = gCurrentTest.key; synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, guessNativeKeyCode(key), {}, key, key, (callback) ? callback : null); } function hardwareEventReceiver(evt) { if (!gCurrentTest) { return; } gCurrentTest.hardwareinput.receivedEvents |= eventToCode(evt.type); gCurrentTest.hardwareinput.receivedKeys += evt.key; } function inputtextEventReceiver(evt) { if (!gCurrentTest) { return; } gCurrentTest.inputtext.receivedEvents |= eventToCode(evt.type); gCurrentTest.inputtext.receivedKeys += evt.key; } // *********************************** // * Event verifier // *********************************** function verifyResults(test) { // Verify results received from inputcontent.hardwareinput is(test.hardwareinput.receivedEvents, test.hardwareinput.expectedEvents, "received events from inputcontent.hardwareinput are wrong"); is(test.hardwareinput.receivedKeys, test.hardwareinput.expectedKeys, "received keys from inputcontent.hardwareinput are wrong"); // Verify results received from actual input text is(test.inputtext.receivedEvents, test.inputtext.expectedEvents, "received events from input text are wrong"); is(test.inputtext.receivedKeys, test.inputtext.expectedKeys, "received keys from input text are wrong"); } function areEventsSame(test) { return (test.hardwareinput.receivedEvents == test.hardwareinput.expectedEvents) && (test.inputtext.receivedEvents == test.inputtext.expectedEvents); } // *********************************** // * Input Method // *********************************** // The method input used in this test // only handles alphabets function InputMethod(inputContext) { this._inputContext = inputContext; this.init(); } InputMethod.prototype = { init: function im_init() { this._setKepMap(); }, handler: function im_handler(evt) { // Ignore the key if the event is defaultPrevented if (evt.defaultPrevented) { return; } // Finish if there is no _inputContext if (!this._inputContext) { return; } // Generate the keyDict for inputcontext.keydown/keyup let keyDict = this._generateKeyDict(evt); // Ignore the key if IME doesn't want to handle it if (!keyDict) { return; } // Call preventDefault if the key will be handled. evt.preventDefault(); // Call inputcontext.keydown/keyup this._inputContext[evt.type](keyDict); }, mapKey: function im_keymapping(key) { if (!this._mappingTable) { return; } return this._mappingTable[key]; }, _setKepMap: function im_setKeyMap() { // A table to map characters: // { // 'A': 'B' // 'a': 'b' // 'B': 'C' // 'b': 'c' // .. // .. // 'Z': 'A', // 'z': 'a', // } this._mappingTable = {}; let rotation = 1; for (let i = 0 ; i < 26 ; i++) { // Convert 'A' to 'B', 'B' to 'C', ..., 'Z' to 'A' this._mappingTable[String.fromCharCode(i + 'A'.charCodeAt(0))] = String.fromCharCode((i+rotation)%26 + 'A'.charCodeAt(0)); // Convert 'a' to 'b', 'b' to 'c', ..., 'z' to 'a' this._mappingTable[String.fromCharCode(i + 'a'.charCodeAt(0))] = String.fromCharCode((i+rotation)%26 + 'a'.charCodeAt(0)); } }, _generateKeyDict: function im_generateKeyDict(evt) { let mappedKey = this.mapKey(evt.key); if (!mappedKey) { return; } let keyDict = { key: mappedKey, code: this._guessCodeFromKey(mappedKey), repeat: evt.repeat, }; return keyDict; }, _guessCodeFromKey: function im_guessCodeFromKey(key) { if (/^[A-Z]$/.test(key)) { return "Key" + key; } else if (/^[a-z]$/.test(key)) { return "Key" + key.toUpperCase(); } else if (/^[0-9]$/.test(key)) { return "Digit" + key.toString(); } else { return 0; } }, };