aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Blott2016-02-29 15:43:26 +0000
committerStephen Blott2016-03-05 05:40:11 +0000
commitff6d4b92df924b93de4366b1f0e3cc7411ac8065 (patch)
treea72f5029216f67aee0ec76d8b1b0159fcdf5a7a5
parent7bf8cb11db08c61417a4d72b95c2905a4869cf67 (diff)
downloadvimium-ff6d4b92df924b93de4366b1f0e3cc7411ac8065.tar.bz2
Key bindings; more small tweaks.
-rw-r--r--content_scripts/mode_key_handler.coffee66
1 files changed, 38 insertions, 28 deletions
diff --git a/content_scripts/mode_key_handler.coffee b/content_scripts/mode_key_handler.coffee
index 78ce3680..df177c4a 100644
--- a/content_scripts/mode_key_handler.coffee
+++ b/content_scripts/mode_key_handler.coffee
@@ -1,9 +1,26 @@
+# Example key mapping (@keyMapping):
+# i:
+# command: "enterInsertMode", ... # This is a registryEntry object (as too are the other commands).
+# g:
+# g:
+# command: "scrollToTop", ...
+# t:
+# command: "nextTab", ...
+#
+# This key-mapping structure is generated by Commands.generateKeyStateMapping() and may be arbitrarily deep.
+# Observe that @keyMapping["g"] is itself also a valid key mapping. At any point, the key state (@keyState)
+# consists of a (non-empty) list of such mappings.
class KeyHandlerMode extends Mode
keydownEvents: {}
setKeyMapping: (@keyMapping) -> @reset()
setPassKeys: (@passKeys) -> @reset()
+ # Reset the key state, optionally retaining the count provided.
+ reset: (@countPrefix = 0) ->
+ bgLog "Clearing key state, set count=#{@countPrefix}."
+ @keyState = [@keyMapping]
+
constructor: (options) ->
@commandHandler = options.commandHandler ? (->)
@setKeyMapping options.keyMapping ? {}
@@ -17,22 +34,22 @@ class KeyHandlerMode extends Mode
onKeydown: (event) ->
keyChar = KeyboardUtils.getKeyCharString event
- if KeyboardUtils.isEscape event
- if @countPrefix == 0 and @keyState.length == 1
- @continueBubbling
- else
- @keydownEvents[event.keyCode] = true
- @reset()
- false # Suppress event.
- else if keyChar and @keyCharIsMapped keyChar
+ isEscape = KeyboardUtils.isEscape event
+ if isEscape and @countPrefix == 0 and @keyState.length == 1
+ @continueBubbling
+ else if isEscape
+ @keydownEvents[event.keyCode] = true
+ @reset()
+ false # Suppress event.
+ else if @keyCharIsMapped keyChar
@unlessKeyCharIsPassKey keyChar, =>
@keydownEvents[event.keyCode] = true
@handleKeyChar event, keyChar
else if keyChar
@continueBubbling
else if (keyChar = KeyboardUtils.getKeyChar event) and (@keyCharIsMapped(keyChar) or @isCountKey keyChar)
- # It looks like we will be handling a subsequent keypress event, so suppress propagation of this event
- # to prevent triggering page event listeners (e.g. Google instant Search).
+ # It looks like we will possibly be handling a subsequent keypress event, so suppress propagation of
+ # this event to prevent triggering page event listeners (e.g. Google instant Search).
@unlessKeyCharIsPassKey keyChar, =>
@keydownEvents[event.keyCode] = true
DomUtils.suppressPropagation event
@@ -43,7 +60,7 @@ class KeyHandlerMode extends Mode
onKeypress: (event) ->
keyChar = KeyboardUtils.getKeyCharString event
@unlessKeyCharIsPassKey keyChar, =>
- if keyChar and @keyCharIsMapped keyChar
+ if @keyCharIsMapped keyChar
@handleKeyChar event, keyChar
else if @isCountKey keyChar
digit = parseInt keyChar
@@ -61,35 +78,28 @@ class KeyHandlerMode extends Mode
else
@continueBubbling
+ # This tests whether there is a mapping of keyChar in the current key state.
+ keyCharIsMapped: (keyChar) ->
+ (mapping for mapping in @keyState when keyChar of mapping)[0]?
+
handleKeyChar: (event, keyChar) ->
bgLog "Handling key #{keyChar}, mode=#{@name}."
- @advanceKeyState keyChar
- command = (@keyState.filter (entry) -> entry.command)[0]
+ # Advance the key state. The new key state is the current mappings of keyChar, plus @keyMapping.
+ @keyState = (mapping[keyChar] for mapping in @keyState when keyChar of mapping)
+ @keyState.push @keyMapping
+ command = (mapping for mapping in @keyState when mapping.command)[0]
if command?
count = if 0 < @countPrefix then @countPrefix else 1
- @reset()
bgLog "Calling mode=#{@name}, command=#{command.command}, count=#{count}."
+ @reset()
@commandHandler {command, count}
false # Suppress event.
- keyCharIsMapped: (keyChar) ->
- (mapping for mapping in @keyState when keyChar of mapping)[0]?
-
- # The next key state is the current mappings matching keyChar plus @keyMapping.
- advanceKeyState: (keyChar) ->
- newMappings = (mapping[keyChar] for mapping in @keyState when keyChar of mapping)
- @keyState = [newMappings..., @keyMapping]
-
- # Reset the state (as if no keys had been handled), but optionally retaining the count provided.
- reset: (@countPrefix = 0) ->
- bgLog "Clearing key queue, set count=#{@countPrefix}."
- @keyState = [@keyMapping]
-
isCountKey: (keyChar) ->
keyChar?.length == 1 and (if 0 < @countPrefix then '0' else '1') <= keyChar <= '9'
# Keystrokes are *never* considered passKeys if the user has begun entering a command. So, for example, if
- # 't' is a passKey, then 'gt' and '99t' are neverthless handled as regular keys.
+ # 't' is a passKey, then the "t"-s of 'gt' and '99t' are neverthless handled as regular keys.
unlessKeyCharIsPassKey: (keyChar, nonPassKeyCallback) ->
if @countPrefix == 0 and @keyState.length == 1 and keyChar in (@passKeys ? "")
@stopBubblingAndTrue