From 6608ba3e2dd4f9082958336460bf442ff3e8b159 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Aug 2021 22:26:25 -0700 Subject: [PATCH] GUACAMOLE-1386: Centralize abstraction of KeyboardEvent contents within KeyEvent and its subclasses. --- .../src/main/webapp/modules/Keyboard.js | 232 ++++++------------ 1 file changed, 75 insertions(+), 157 deletions(-) diff --git a/guacamole-common-js/src/main/webapp/modules/Keyboard.js b/guacamole-common-js/src/main/webapp/modules/Keyboard.js index 86e1aa674..f6ec68594 100644 --- a/guacamole-common-js/src/main/webapp/modules/Keyboard.js +++ b/guacamole-common-js/src/main/webapp/modules/Keyboard.js @@ -136,24 +136,59 @@ Guacamole.Keyboard = function Keyboard(element) { * * @private * @constructor - * @param {Guacamole.Keyboard.ModifierState} [modifiers] - * The state of all local keyboard modifiers at the time this event was - * received. + * @param {KeyboardEvent} [orig] + * The relevant DOM keyboard event. */ - var KeyEvent = function KeyEvent(modifiers) { + var KeyEvent = function KeyEvent(orig) { /** * Reference to this key event. */ var key_event = this; + /** + * The JavaScript key code of the key pressed. For most events (keydown + * and keyup), this is a scancode-like value related to the position of + * the key on the US English "Qwerty" keyboard. For keypress events, + * this is the Unicode codepoint of the character that would be typed + * by the key pressed. + * + * @type {Number} + */ + this.keyCode = orig ? (orig.which || orig.keyCode) : 0; + + /** + * The legacy DOM3 "keyIdentifier" of the key pressed, as defined at: + * http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#events-Events-KeyboardEvent + * + * @type {String} + */ + this.keyIdentifier = orig && orig.keyIdentifier; + + /** + * The standard name of the key pressed, as defined at: + * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent + * + * @type {String} + */ + this.key = orig && orig.key; + + /** + * The location on the keyboard corresponding to the key pressed, as + * defined at: + * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent + * + * @type {Number} + */ + this.location = orig ? getEventLocation(orig) : 0; + /** * The state of all local keyboard modifiers at the time this event was * received. * * @type {Guacamole.Keyboard.ModifierState} */ - this.modifiers = modifiers || new Guacamole.Keyboard.ModifierState(); + this.modifiers = orig ? Guacamole.Keyboard.ModifierState.fromKeyboardEvent(orig) : new Guacamole.Keyboard.ModifierState(); /** * An arbitrary timestamp in milliseconds, indicating this event's @@ -209,66 +244,17 @@ Guacamole.Keyboard = function Keyboard(element) { * @private * @constructor * @augments Guacamole.Keyboard.KeyEvent - * - * @param {Guacamole.Keyboard.ModifierState} [modifiers] - * The state of all local keyboard modifiers at the time this event was - * received. - * - * @param {number} keyCode - * The JavaScript key code of the key pressed. - * - * @param {string} keyIdentifier - * The legacy DOM3 "keyIdentifier" of the key pressed, as defined at: - * http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#events-Events-KeyboardEvent - * - * @param {string} key - * The standard name of the key pressed, as defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent - * - * @param {number} location - * The location on the keyboard corresponding to the key pressed, as - * defined at: http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent + * @param {KeyboardEvent} orig + * The relevant DOM "keydown" event. */ - var KeydownEvent = function KeydownEvent(modifiers, keyCode, keyIdentifier, key, location) { + var KeydownEvent = function KeydownEvent(orig) { // We extend KeyEvent - KeyEvent.call(this, modifiers); - - /** - * The JavaScript key code of the key pressed. - * - * @type {Number} - */ - this.keyCode = keyCode; - - /** - * The legacy DOM3 "keyIdentifier" of the key pressed, as defined at: - * http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#events-Events-KeyboardEvent - * - * @type {String} - */ - this.keyIdentifier = keyIdentifier; - - /** - * The standard name of the key pressed, as defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent - * - * @type {String} - */ - this.key = key; - - /** - * The location on the keyboard corresponding to the key pressed, as - * defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent - * - * @type {Number} - */ - this.location = location; + KeyEvent.call(this, orig); // If key is known from keyCode or DOM3 alone, use that - this.keysym = keysym_from_key_identifier(key, location) - || keysym_from_keycode(keyCode, location); + this.keysym = keysym_from_key_identifier(this.key, this.location) + || keysym_from_keycode(this.keyCode, this.location); /** * Whether the keyup following this keydown event is known to be @@ -284,12 +270,12 @@ Guacamole.Keyboard = function Keyboard(element) { this.reliable = true; // Use legacy keyIdentifier as a last resort, if it looks sane - if (!this.keysym && key_identifier_sane(keyCode, keyIdentifier)) - this.keysym = keysym_from_key_identifier(keyIdentifier, location, guac_keyboard.modifiers.shift); + if (!this.keysym && key_identifier_sane(this.keyCode, this.keyIdentifier)) + this.keysym = keysym_from_key_identifier(this.keyIdentifier, this.location, this.modifiers.shift); // If a key is pressed while meta is held down, the keyup will // never be sent in Chrome (bug #108404) - if (guac_keyboard.modifiers.meta && this.keysym !== 0xFFE7 && this.keysym !== 0xFFE8) + if (this.modifiers.meta && this.keysym !== 0xFFE7 && this.keysym !== 0xFFE8) this.keyupReliable = false; // We cannot rely on receiving keyup for Caps Lock on certain platforms @@ -297,21 +283,21 @@ Guacamole.Keyboard = function Keyboard(element) { this.keyupReliable = false; // Determine whether default action for Alt+combinations must be prevented - var prevent_alt = !guac_keyboard.modifiers.ctrl && !quirks.altIsTypableOnly; + var prevent_alt = !this.modifiers.ctrl && !quirks.altIsTypableOnly; // Determine whether default action for Ctrl+combinations must be prevented - var prevent_ctrl = !guac_keyboard.modifiers.alt; + var prevent_ctrl = !this.modifiers.alt; // We must rely on the (potentially buggy) keyIdentifier if preventing // the default action is important - if ((prevent_ctrl && guac_keyboard.modifiers.ctrl) - || (prevent_alt && guac_keyboard.modifiers.alt) - || guac_keyboard.modifiers.meta - || guac_keyboard.modifiers.hyper) + if ((prevent_ctrl && this.modifiers.ctrl) + || (prevent_alt && this.modifiers.alt) + || this.modifiers.meta + || this.modifiers.hyper) this.reliable = true; // Record most recently known keysym by associated key code - recentKeysym[keyCode] = this.keysym; + recentKeysym[this.keyCode] = this.keysym; }; @@ -325,25 +311,16 @@ Guacamole.Keyboard = function Keyboard(element) { * @private * @constructor * @augments Guacamole.Keyboard.KeyEvent - * @param {number} charCode - * The Unicode codepoint of the character that would be typed by the - * key pressed. + * @param {KeyboardEvent} orig + * The relevant DOM "keypress" event. */ - var KeypressEvent = function KeypressEvent(modifiers, charCode) { + var KeypressEvent = function KeypressEvent(orig) { // We extend KeyEvent - KeyEvent.call(this, modifiers); - - /** - * The Unicode codepoint of the character that would be typed by the - * key pressed. - * - * @type {Number} - */ - this.charCode = charCode; + KeyEvent.call(this, orig); // Pull keysym from char code - this.keysym = keysym_from_charcode(charCode); + this.keysym = keysym_from_charcode(this.keyCode); // Keypress is always reliable this.reliable = true; @@ -353,68 +330,30 @@ Guacamole.Keyboard = function Keyboard(element) { KeypressEvent.prototype = new KeyEvent(); /** - * Information related to the pressing of a key, which need not be a key + * Information related to the releasing of a key, which need not be a key * associated with a printable character. The presence or absence of any * information within this object is browser-dependent. * * @private * @constructor * @augments Guacamole.Keyboard.KeyEvent - * @param {Number} keyCode The JavaScript key code of the key released. - * @param {String} keyIdentifier The legacy DOM3 "keyIdentifier" of the key - * released, as defined at: - * http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#events-Events-KeyboardEvent - * @param {String} key The standard name of the key released, as defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent - * @param {Number} location The location on the keyboard corresponding to - * the key released, as defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent + * @param {KeyboardEvent} orig + * The relevant DOM "keyup" event. */ - var KeyupEvent = function(modifiers, keyCode, keyIdentifier, key, location) { + var KeyupEvent = function KeyupEvent(orig) { // We extend KeyEvent - KeyEvent.call(this, modifiers); + KeyEvent.call(this, orig); - /** - * The JavaScript key code of the key released. - * - * @type {Number} - */ - this.keyCode = keyCode; - - /** - * The legacy DOM3 "keyIdentifier" of the key released, as defined at: - * http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/#events-Events-KeyboardEvent - * - * @type {String} - */ - this.keyIdentifier = keyIdentifier; - - /** - * The standard name of the key released, as defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent - * - * @type {String} - */ - this.key = key; - - /** - * The location on the keyboard corresponding to the key released, as - * defined at: - * http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent - * - * @type {Number} - */ - this.location = location; - - // If key is known from keyCode or DOM3 alone, use that - this.keysym = keysym_from_keycode(keyCode, location) - || keysym_from_key_identifier(key, location); // keyCode is still more reliable for keyup when dead keys are in use + // If key is known from keyCode or DOM3 alone, use that (keyCode is + // still more reliable for keyup when dead keys are in use) + this.keysym = keysym_from_keycode(this.keyCode, this.location) + || keysym_from_key_identifier(this.key, this.location); // Fall back to the most recently pressed keysym associated with the // keyCode if the inferred key doesn't seem to actually be pressed if (!guac_keyboard.pressed[this.keysym]) - this.keysym = recentKeysym[keyCode] || this.keysym; + this.keysym = recentKeysym[this.keyCode] || this.keysym; // Keyup is as reliable as it will ever be this.reliable = true; @@ -1343,16 +1282,11 @@ Guacamole.Keyboard = function Keyboard(element) { // Ignore events which have already been handled if (!markEvent(e)) return; - var keyCode; - if (window.event) keyCode = window.event.keyCode; - else if (e.which) keyCode = e.which; - - var modifiers = Guacamole.Keyboard.ModifierState.fromKeyboardEvent(e); - var keydownEvent = new KeydownEvent(modifiers, keyCode, e.keyIdentifier, e.key, getEventLocation(e)); + var keydownEvent = new KeydownEvent(e); // Ignore (but do not prevent) the "composition" keycode sent by some // browsers when an IME is in use (see: http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html) - if (keyCode === 229) + if (keydownEvent.keyCode === 229) return; // Log event @@ -1373,16 +1307,8 @@ Guacamole.Keyboard = function Keyboard(element) { // Ignore events which have already been handled if (!markEvent(e)) return; - var charCode; - if (window.event) charCode = window.event.keyCode; - else if (e.which) charCode = e.which; - - // Fix modifier states - var modifiers = Guacamole.Keyboard.ModifierState.fromKeyboardEvent(e); - var keypressEvent = new KeypressEvent(modifiers, charCode); - // Log event - eventLog.push(keypressEvent); + eventLog.push(new KeypressEvent(e)); // Interpret as many events as possible, prevent default if indicated if (interpret_events()) @@ -1401,16 +1327,8 @@ Guacamole.Keyboard = function Keyboard(element) { e.preventDefault(); - var keyCode; - if (window.event) keyCode = window.event.keyCode; - else if (e.which) keyCode = e.which; - - // Fix modifier states - var modifiers = Guacamole.Keyboard.ModifierState.fromKeyboardEvent(e); - var keyupEvent = new KeyupEvent(modifiers, keyCode, e.keyIdentifier, e.key, getEventLocation(e)); - // Log event, call for interpretation - eventLog.push(keyupEvent); + eventLog.push(new KeyupEvent(e)); interpret_events(); }, true);