From 44555e7863a66b906c47f0c94507d9e055922d3e Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Tue, 11 Apr 2017 15:44:42 +0100 Subject: Move keyboard utils to keydown and migrate normal/visual modes. --- lib/dom_utils.coffee | 19 +++++++++ lib/keyboard_utils.coffee | 103 +++++++--------------------------------------- 2 files changed, 34 insertions(+), 88 deletions(-) (limited to 'lib') diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 690d9969..df9ca390 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -315,6 +315,25 @@ DomUtils = false handlerStack.suppressEvent + consumeKeyup: (event, callback = null) -> + @suppressEvent event + keyChar = KeyboardUtils.getKeyCharString event + handlerStack.push + _name: "dom_utils/consumeKeyup" + keydown: (event) -> + @remove() + handlerStack.continueBubbling + keyup: (event) -> + return handlerStack.continueBubbling unless keyChar == KeyboardUtils.getKeyCharString event + @remove() + handlerStack.suppressEvent + # We cannot track keyup events if we lose the focus. + blur: (event) -> + @remove() if event.target == window + handlerStack.continueBubbling + callback?() + handlerStack.suppressEvent + # Adapted from: http://roysharon.com/blog/37. # This finds the element containing the selection focus. getElementWithFocus: (selection, backwards) -> diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee index ead8c037..97fd8a75 100644 --- a/lib/keyboard_utils.coffee +++ b/lib/keyboard_utils.coffee @@ -10,22 +10,6 @@ KeyboardUtils = keyNames: { 37: "left", 38: "up", 39: "right", 40: "down", 32: "space", 8: "backspace" } - # This is a mapping of the incorrect keyIdentifiers generated by Webkit on Windows during keydown events to - # the correct identifiers, which are correctly generated on Mac. We require this mapping to properly handle - # these keys on Windows. See https://bugs.webkit.org/show_bug.cgi?id=19906 for more details. - keyIdentifierCorrectionMap: - "U+00C0": ["U+0060", "U+007E"] # `~ - "U+00BD": ["U+002D", "U+005F"] # -_ - "U+00BB": ["U+003D", "U+002B"] # =+ - "U+00DB": ["U+005B", "U+007B"] # [{ - "U+00DD": ["U+005D", "U+007D"] # ]} - "U+00DC": ["U+005C", "U+007C"] # \| - "U+00BA": ["U+003B", "U+003A"] # ;: - "U+00DE": ["U+0027", "U+0022"] # '" - "U+00BC": ["U+002C", "U+003C"] # ,< - "U+00BE": ["U+002E", "U+003E"] # .> - "U+00BF": ["U+002F", "U+003F"] # /? - init: -> if (navigator.userAgent.indexOf("Mac") != -1) @platform = "Mac" @@ -34,17 +18,7 @@ KeyboardUtils = else @platform = "Windows" - # We are migrating from using event.keyIdentifier to using event.key. For some period of time, we must - # support both. This wrapper can be removed once Chrome 52 is considered too old to support. getKeyChar: (event) -> - # We favor using event.keyIdentifier due to Chromium's currently (Chrome 51) incorrect implementataion of - # event.key; see #2147. - if event.keyIdentifier? - @getKeyCharUsingKeyIdentifier event - else - @getKeyCharUsingKey event - - getKeyCharUsingKey: (event) -> if event.keyCode of @keyNames @keyNames[event.keyCode] # It appears that event.key is not always defined (see #2453). @@ -59,44 +33,25 @@ KeyboardUtils = else "" - getKeyCharUsingKeyIdentifier: (event) -> - # Handle named keys. - keyCode = event.keyCode - if keyCode - if keyCode of @keyNames - return @keyNames[keyCode] - # Function keys. - if @keyCodes.f1 <= keyCode <= @keyCodes.f12 - return "f" + (1 + keyCode - keyCodes.f1) - - keyIdentifier = event.keyIdentifier - - # Not a letter. - if not keyIdentifier.startsWith "U+" - return "" - - # On Windows, the keyIdentifiers for non-letter keys are incorrect. See - # https://bugs.webkit.org/show_bug.cgi?id=19906 for more details. - if ((@platform == "Windows" || @platform == "Linux") && @keyIdentifierCorrectionMap[keyIdentifier]) - correctedIdentifiers = @keyIdentifierCorrectionMap[keyIdentifier] - keyIdentifier = if event.shiftKey then correctedIdentifiers[1] else correctedIdentifiers[0] - unicodeKeyInHex = "0x" + keyIdentifier.substring(2) - character = String.fromCharCode(parseInt(unicodeKeyInHex)).toLowerCase() - if event.shiftKey then character.toUpperCase() else character + getKeyCharString: (event) -> + if keyChar = @getKeyChar event + modifiers = [] - isPrimaryModifierKey: (event) -> if (@platform == "Mac") then event.metaKey else event.ctrlKey + keyChar = keyChar.toUpperCase() if event.shiftKey and keyChar.length == 1 + # These must be in alphabetical order (to match the sorted modifier order in Commands.normalizeKey). + modifiers.push "a" if event.altKey + modifiers.push "c" if event.ctrlKey + modifiers.push "m" if event.metaKey - isEscape: do -> + keyChar = [modifiers..., keyChar].join "-" + keyChar = "<#{keyChar}>" if 1 < keyChar.length + keyChar = mapKeyRegistry[keyChar] ? keyChar + keyChar - # TODO(smblott) Change this to use event.key. - (event) -> - event.keyCode == @keyCodes.ESC || do => - keyChar = @getKeyCharString event - # is mapped to Escape in Vim by default. - keyChar == "" + isEscape: (event) -> + # is mapped to Escape in Vim by default. + event.keyCode == @keyCodes.ESC || @getKeyCharString(event) == "" - # TODO. This is probably a poor way of detecting printable characters. However, it shouldn't incorrectly - # identify any of chrome's own keyboard shortcuts as printable. isPrintable: (event) -> return false if event.metaKey or event.ctrlKey or event.altKey keyChar = @@ -106,34 +61,6 @@ KeyboardUtils = @getKeyChar event keyChar.length == 1 - # Return the Vimium key representation for this keyboard event. Return a falsy value (the empty string or - # undefined) when no Vimium representation is appropriate. - getKeyCharString: (event) -> - switch event.type - when "keypress" - # Ignore modifier keys by themselves. - if 31 < event.keyCode - String.fromCharCode event.charCode - - # TODO(smblott). Currently all (almost?) keyhandling is being done on keydown. All legacy code related - # to key handling on keypress should be reviewed and probably removed. This is not being done right now - # (2017-03-22) because it is better to wait until we've verified that the change to keydown is indeed - # correct and reliable. - when "keydown" - if keyChar = @getKeyChar event - modifiers = [] - - keyChar = keyChar.toUpperCase() if event.shiftKey and keyChar.length == 1 - # These must be in alphabetical order (to match the sorted modifier order in Commands.normalizeKey). - modifiers.push "a" if event.altKey - modifiers.push "c" if event.ctrlKey - modifiers.push "m" if event.metaKey - - keyChar = [modifiers..., keyChar].join "-" - keyChar = "<#{keyChar}>" if 1 < keyChar.length - keyChar = mapKeyRegistry[keyChar] ? keyChar - keyChar - KeyboardUtils.init() root = exports ? window -- cgit v1.2.3 From d03845e3151babbd63cf13e9e3d74d98351671f9 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Thu, 13 Apr 2017 14:57:26 +0100 Subject: Remove use of keyCodes entirely. event.keyCode` is depricated: - https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode --- lib/keyboard_utils.coffee | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee index 97fd8a75..1a1524af 100644 --- a/lib/keyboard_utils.coffee +++ b/lib/keyboard_utils.coffee @@ -3,12 +3,9 @@ mapKeyRegistry = {} Utils?.monitorChromeStorage "mapKeyRegistry", (value) => mapKeyRegistry = value KeyboardUtils = - keyCodes: - { ESC: 27, backspace: 8, deleteKey: 46, enter: 13, ctrlEnter: 10, space: 32, shiftKey: 16, ctrlKey: 17, f1: 112, - f12: 123, tab: 9, downArrow: 40, upArrow: 38 } - + # This maps event.key key names to Vimium key names. keyNames: - { 37: "left", 38: "up", 39: "right", 40: "down", 32: "space", 8: "backspace" } + "ArrowLeft": "left", "ArrowUp": "up", "ArrowRight": "right", "ArrowDown": "down", " ": "space", "Backspace": "backspace" init: -> if (navigator.userAgent.indexOf("Mac") != -1) @@ -19,8 +16,8 @@ KeyboardUtils = @platform = "Windows" getKeyChar: (event) -> - if event.keyCode of @keyNames - @keyNames[event.keyCode] + if event.key of @keyNames + @keyNames[event.key] # It appears that event.key is not always defined (see #2453). else if not event.key? "" @@ -50,7 +47,7 @@ KeyboardUtils = isEscape: (event) -> # is mapped to Escape in Vim by default. - event.keyCode == @keyCodes.ESC || @getKeyCharString(event) == "" + event.key == "Escape" || @getKeyCharString(event) == "" isPrintable: (event) -> return false if event.metaKey or event.ctrlKey or event.altKey @@ -65,5 +62,3 @@ KeyboardUtils.init() root = exports ? window root.KeyboardUtils = KeyboardUtils -# TODO(philc): A lot of code uses this keyCodes hash... maybe we shouldn't export it as a global. -root.keyCodes = KeyboardUtils.keyCodes -- cgit v1.2.3 From ee83d1a9603a304c9328d3587e2db829fcec7aaf Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Thu, 13 Apr 2017 15:28:43 +0100 Subject: Ignore keybiard repeats. Keyboard repeats were interfering with smooth scrolling. But we should be ignoreing them anyway. --- lib/dom_utils.coffee | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index df9ca390..8764bdbe 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -318,19 +318,20 @@ DomUtils = consumeKeyup: (event, callback = null) -> @suppressEvent event keyChar = KeyboardUtils.getKeyCharString event - handlerStack.push - _name: "dom_utils/consumeKeyup" - keydown: (event) -> - @remove() - handlerStack.continueBubbling - keyup: (event) -> - return handlerStack.continueBubbling unless keyChar == KeyboardUtils.getKeyCharString event - @remove() - handlerStack.suppressEvent - # We cannot track keyup events if we lose the focus. - blur: (event) -> - @remove() if event.target == window - handlerStack.continueBubbling + unless event.repeat + handlerStack.push + _name: "dom_utils/consumeKeyup" + keydown: (event) -> + @remove() + handlerStack.continueBubbling + keyup: (event) -> + return handlerStack.continueBubbling unless keyChar == KeyboardUtils.getKeyCharString event + @remove() + handlerStack.suppressEvent + # We cannot track keyup events if we lose the focus. + blur: (event) -> + @remove() if event.target == window + handlerStack.continueBubbling callback?() handlerStack.suppressEvent -- cgit v1.2.3 From b88ee579c4471d27dbb4aba59215f5e85b7d32a2 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Thu, 13 Apr 2017 15:57:32 +0100 Subject: Avoid repeating Backspace and Delete keys. --- lib/keyboard_utils.coffee | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee index 1a1524af..35e584e3 100644 --- a/lib/keyboard_utils.coffee +++ b/lib/keyboard_utils.coffee @@ -49,6 +49,9 @@ KeyboardUtils = # is mapped to Escape in Vim by default. event.key == "Escape" || @getKeyCharString(event) == "" + isBackspace: (event) -> + event.key in ["Backspace", "Delete"] + isPrintable: (event) -> return false if event.metaKey or event.ctrlKey or event.altKey keyChar = -- cgit v1.2.3 From 4c32c0383964e178e0196a87df7fc7a4ad7f8f27 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Fri, 14 Apr 2017 07:48:56 +0100 Subject: Use event.code to detect/suppress keyup events. This avoids the possibility of leaking keyup events if the keys a released in a different order from that in which they were pressed. Also, replace suppressKeyupAfterEscape with this same mechanism. This fixes a bug (in master/1.59) whereby we leak the keyup event for `i` when entering insert mode. TODO: - `/`, `` leaks a keyup event - `i` leaks a keyup event --- lib/dom_utils.coffee | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 8764bdbe..3f0bd7f3 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -305,27 +305,13 @@ DomUtils = event.preventDefault() @suppressPropagation(event) - # Suppress the next keyup event for Escape. - suppressKeyupAfterEscape: (handlerStack) -> - handlerStack.push - _name: "dom_utils/suppressKeyupAfterEscape" - keyup: (event) -> - return true unless KeyboardUtils.isEscape event - @remove() - false - handlerStack.suppressEvent - consumeKeyup: (event, callback = null) -> - @suppressEvent event - keyChar = KeyboardUtils.getKeyCharString event + code = event.code unless event.repeat handlerStack.push _name: "dom_utils/consumeKeyup" - keydown: (event) -> - @remove() - handlerStack.continueBubbling keyup: (event) -> - return handlerStack.continueBubbling unless keyChar == KeyboardUtils.getKeyCharString event + return handlerStack.continueBubbling unless event.code == code @remove() handlerStack.suppressEvent # We cannot track keyup events if we lose the focus. @@ -333,6 +319,7 @@ DomUtils = @remove() if event.target == window handlerStack.continueBubbling callback?() + @suppressEvent event handlerStack.suppressEvent # Adapted from: http://roysharon.com/blog/37. -- cgit v1.2.3 From 1979d60f224453d9508e55d82a7ccb590a3a2912 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Fri, 14 Apr 2017 13:37:24 +0100 Subject: Make the consumeKeyup handler a singleton. That is, allow at most one handler to be installed at any one time. I have not observed this to be necessary. However, if there were any systematic way in which we weren't seeing the necessary keyup events, then these handlers would just be added and added. So this seems safer. --- lib/dom_utils.coffee | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 3f0bd7f3..1864d973 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -305,22 +305,26 @@ DomUtils = event.preventDefault() @suppressPropagation(event) - consumeKeyup: (event, callback = null) -> - code = event.code - unless event.repeat - handlerStack.push - _name: "dom_utils/consumeKeyup" - keyup: (event) -> - return handlerStack.continueBubbling unless event.code == code - @remove() - handlerStack.suppressEvent - # We cannot track keyup events if we lose the focus. - blur: (event) -> - @remove() if event.target == window - handlerStack.continueBubbling - callback?() - @suppressEvent event - handlerStack.suppressEvent + consumeKeyup: do -> + handlerId = null + + (event, callback = null) -> + unless event.repeat + handlerStack.remove handlerId ? "not-an-id" + code = event.code + handlerId = handlerStack.push + _name: "dom_utils/consumeKeyup" + keyup: (event) -> + return handlerStack.continueBubbling unless event.code == code + @remove() + handlerStack.suppressEvent + # We cannot track keyup events if we lose the focus. + blur: (event) -> + @remove() if event.target == window + handlerStack.continueBubbling + callback?() + @suppressEvent event + handlerStack.suppressEvent # Adapted from: http://roysharon.com/blog/37. # This finds the element containing the selection focus. -- cgit v1.2.3 From b80f11b6f36b6302b1b5bb4d033681305fe961fc Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Fri, 14 Apr 2017 16:08:50 +0100 Subject: Set handlerId directly to a non-id. --- lib/dom_utils.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 1864d973..074062a8 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -306,11 +306,11 @@ DomUtils = @suppressPropagation(event) consumeKeyup: do -> - handlerId = null + handlerId = "not-an-id" (event, callback = null) -> unless event.repeat - handlerStack.remove handlerId ? "not-an-id" + handlerStack.remove handlerId code = event.code handlerId = handlerStack.push _name: "dom_utils/consumeKeyup" -- cgit v1.2.3 From 41907f524275415cfd0f5336655a285105aa86e7 Mon Sep 17 00:00:00 2001 From: Stephen Blott Date: Sat, 15 Apr 2017 07:47:07 +0100 Subject: Better check for handlerId. --- lib/dom_utils.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee index 074062a8..06db1b9b 100644 --- a/lib/dom_utils.coffee +++ b/lib/dom_utils.coffee @@ -306,11 +306,11 @@ DomUtils = @suppressPropagation(event) consumeKeyup: do -> - handlerId = "not-an-id" + handlerId = null (event, callback = null) -> unless event.repeat - handlerStack.remove handlerId + handlerStack.remove handlerId if handlerId? code = event.code handlerId = handlerStack.push _name: "dom_utils/consumeKeyup" -- cgit v1.2.3