aboutsummaryrefslogtreecommitdiffstats
path: root/lib/keyboard_utils.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'lib/keyboard_utils.coffee')
-rw-r--r--lib/keyboard_utils.coffee190
1 files changed, 82 insertions, 108 deletions
diff --git a/lib/keyboard_utils.coffee b/lib/keyboard_utils.coffee
index c49fb3f4..673289b9 100644
--- a/lib/keyboard_utils.coffee
+++ b/lib/keyboard_utils.coffee
@@ -1,26 +1,11 @@
-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 }
+mapKeyRegistry = {}
+# NOTE: "?" here for the tests.
+Utils?.monitorChromeStorage "mapKeyRegistry", (value) => mapKeyRegistry = value
+KeyboardUtils =
+ # This maps event.key key names to Vimium key names.
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"] # /?
+ "ArrowLeft": "left", "ArrowUp": "up", "ArrowRight": "right", "ArrowDown": "down", " ": "space"
init: ->
if (navigator.userAgent.indexOf("Mac") != -1)
@@ -30,106 +15,95 @@ 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]
- else if event.key.length == 1
- event.key
- else if event.key.length == 2 and "F1" <= event.key <= "F9"
- event.key.toLowerCase() # F1 to F9.
- else if event.key.length == 3 and "F10" <= event.key <= "F12"
- event.key.toLowerCase() # F10 to F12.
+ unless Settings.get "ignoreKeyboardLayout"
+ key = event.key
+ else unless event.code
+ key = ""
+ else if event.code[...6] == "Numpad"
+ # We cannot correctly emulate the numpad, so fall back to event.key; see #2626.
+ key = event.key
else
+ # The logic here is from the vim-like-key-notation project (https://github.com/lydell/vim-like-key-notation).
+ key = event.code
+ key = key[3..] if key[...3] == "Key"
+ # Translate some special keys to event.key-like strings and handle <Shift>.
+ if @enUsTranslations[key]
+ key = if event.shiftKey then @enUsTranslations[key][1] else @enUsTranslations[key][0]
+ else if key.length == 1 and not event.shiftKey
+ key = key.toLowerCase()
+
+ # It appears that key is not always defined (see #2453).
+ unless key
""
+ else if key of @keyNames
+ @keyNames[key]
+ else if @isModifier event
+ "" # Don't resolve modifier keys.
+ else if key.length == 1
+ key
+ else
+ key.toLowerCase()
- 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 ""
+ getKeyCharString: (event) ->
+ if keyChar = @getKeyChar event
+ modifiers = []
- # 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
+ 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
- isPrimaryModifierKey: (event) -> if (@platform == "Mac") then event.metaKey else event.ctrlKey
+ keyChar = [modifiers..., keyChar].join "-"
+ keyChar = "<#{keyChar}>" if 1 < keyChar.length
+ keyChar = mapKeyRegistry[keyChar] ? keyChar
+ keyChar
isEscape: do ->
- mapKeyRegistry = {}
- # NOTE: "?" here for the tests.
- Utils?.monitorChromeStorage "mapKeyRegistry", (value) => mapKeyRegistry = value
+ useVimLikeEscape = true
+ Utils.monitorChromeStorage "useVimLikeEscape", (value) -> useVimLikeEscape = value
- # TODO(smblott) Change this to use event.key.
(event) ->
- event.keyCode == @keyCodes.ESC || do =>
- keyChar = @getKeyCharString event, true
- keyChar = mapKeyRegistry[keyChar] ? keyChar
- # <c-[> is mapped to Escape in Vim by default.
- keyChar == "<c-[>"
-
- # 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 =
- if event.type == "keypress"
- String.fromCharCode event.charCode
- else
- @getKeyChar event
- keyChar.length == 1
+ # <c-[> is mapped to Escape in Vim by default.
+ event.key == "Escape" or (useVimLikeEscape and @getKeyCharString(event) == "<c-[>")
- # 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, allKeydownEvents = false) ->
- switch event.type
- when "keypress"
- # Ignore modifier keys by themselves.
- if 31 < event.keyCode
- String.fromCharCode event.charCode
+ isBackspace: (event) ->
+ event.key in ["Backspace", "Delete"]
- when "keydown"
- # Handle special keys and normal input keys with modifiers being pressed.
- keyChar = @getKeyChar event
- if 1 < keyChar.length or (keyChar.length == 1 and (event.metaKey or event.ctrlKey or event.altKey)) or allKeydownEvents
- modifiers = []
-
- keyChar = keyChar.toUpperCase() if event.shiftKey
- # 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 "-"
- if 1 < keyChar.length then "<#{keyChar}>" else keyChar
+ isPrintable: (event) ->
+ @getKeyCharString(event)?.length == 1
+
+ isModifier: (event) ->
+ event.key in ["Control", "Shift", "Alt", "OS", "AltGraph", "Meta"]
+
+ enUsTranslations:
+ "Backquote": ["`", "~"]
+ "Minus": ["-", "_"]
+ "Equal": ["=", "+"]
+ "Backslash": ["\\","|"]
+ "IntlBackslash": ["\\","|"]
+ "BracketLeft": ["[", "{"]
+ "BracketRight": ["]", "}"]
+ "Semicolon": [";", ":"]
+ "Quote": ["'", '"']
+ "Comma": [",", "<"]
+ "Period": [".", ">"]
+ "Slash": ["/", "?"]
+ "Space": [" ", " "]
+ "Digit1": ["1", "!"]
+ "Digit2": ["2", "@"]
+ "Digit3": ["3", "#"]
+ "Digit4": ["4", "$"]
+ "Digit5": ["5", "%"]
+ "Digit6": ["6", "^"]
+ "Digit7": ["7", "&"]
+ "Digit8": ["8", "*"]
+ "Digit9": ["9", "("]
+ "Digit0": ["0", ")"]
KeyboardUtils.init()
-root = exports ? window
+root = exports ? (window.root ?= {})
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
+extend window, root unless exports?