aboutsummaryrefslogtreecommitdiffstats
path: root/lib/keyboard_utils.coffee
blob: e14e8b3efc48d53fbaf50d6eb22830d205ddbae2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
mapKeyRegistry = {}
# NOTE: "?" here for the tests.
Utils?.monitorChromeStorage "mapKeyRegistry", (value) => mapKeyRegistry = value

KeyboardUtils =
  # This maps event.key key names to Vimium key names.
  keyNames:
    "ArrowLeft": "left", "ArrowUp": "up", "ArrowRight": "right", "ArrowDown": "down", " ": "space", "Backspace": "backspace"

  init: ->
    if (navigator.userAgent.indexOf("Mac") != -1)
      @platform = "Mac"
    else if (navigator.userAgent.indexOf("Linux") != -1)
      @platform = "Linux"
    else
      @platform = "Windows"

  getKeyChar: (event) ->
    unless Settings.get "ignoreKeyboardLayout"
      key = event.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()

    if key of @keyNames
      @keyNames[key]
    # It appears that key is not always defined (see #2453).
    else if not key?
      ""
    else if key.length == 1
      key
    else if key.length == 2 and "F1" <= key <= "F9"
      key.toLowerCase() # F1 to F9.
    else if key.length == 3 and "F10" <= key <= "F12"
      key.toLowerCase() # F10 to F12.
    else
      ""

  getKeyCharString: (event) ->
    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

  isEscape: (event) ->
    # <c-[> is mapped to Escape in Vim by default.
    event.key == "Escape" || @getKeyCharString(event) == "<c-[>"

  isBackspace: (event) ->
    event.key in ["Backspace", "Delete"]

  isPrintable: (event) ->
    @getKeyCharString(event)?.length == 1

  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.KeyboardUtils = KeyboardUtils