diff --git a/spec/atom/command-map-spec.coffee b/spec/atom/command-map-spec.coffee deleted file mode 100644 index 769d75730..000000000 --- a/spec/atom/command-map-spec.coffee +++ /dev/null @@ -1,107 +0,0 @@ -CommandMap = require 'command-map' - -describe "CommandMap", -> - commandMap = null - delegate = null - d = null - a = null - y = null - - beforeEach -> - d = keydownEvent 'd' - a = keydownEvent 'a' - y = keydownEvent 'y' - delegate = { - action1: jasmine.createSpy('action1') - action2: jasmine.createSpy('action2') - } - commandMap = new CommandMap delegate - - describe "handleKeyEvent(event)", -> - describe "when there is a single-character mapping to a command method", -> - beforeEach -> - commandMap.mapKey 'd', 'action1' - - it "calls the named method on the delegate with the given event when the event matches the pattern", -> - commandMap.handleKeyEvent keydownEvent('z') - expect(delegate.action1).not.toHaveBeenCalled() - - event = keydownEvent 'd' - commandMap.handleKeyEvent event - expect(delegate.action1).toHaveBeenCalled() - - describe "when there is a multi-character mapping to a command method", -> - beforeEach -> - commandMap.mapKey 'dad', 'action1' - - it "calls the named method on the delegate with the given event when the event matches the pattern", -> - commandMap.handleKeyEvent d - expect(delegate.action1).not.toHaveBeenCalled() - - commandMap.handleKeyEvent a - expect(delegate.action1).not.toHaveBeenCalled() - - commandMap.handleKeyEvent d - expect(delegate.action1).toHaveBeenCalled() - - describe "when there is more than one pattern matching a prefix of key events", -> - inputTimeout = null - - beforeEach -> - commandMap.mapKey 'da', 'action1' - commandMap.mapKey 'dad', 'action2' - - spyOn(window, 'setTimeout').andCallFake (fn) -> - inputTimeout = fn - 'handle' - - spyOn(window, 'clearTimeout') - - commandMap.handleKeyEvent d - expect(window.setTimeout).toHaveBeenCalled() - window.setTimeout.reset() - - commandMap.handleKeyEvent a - expect(window.clearTimeout).toHaveBeenCalledWith 'handle' - expect(window.setTimeout).toHaveBeenCalled() - expect(delegate.action1).not.toHaveBeenCalled() - expect(delegate.action2).not.toHaveBeenCalled() - - describe "when no additional key is pressed before the input timeout", -> - it "calls the method for the shorter pattern on the delegate and clears the event buffer", -> - inputTimeout() - expect(delegate.action1).toHaveBeenCalled() - - commandMap.handleKeyEvent d - expect(delegate.action2).not.toHaveBeenCalled() - - describe "when an additional matching key is pressed before the input timeout", -> - it "calls the method for the longer pattern on the delegate, cancels the timeout, and clears the event buffer", -> - commandMap.handleKeyEvent d - expect(window.clearTimeout).toHaveBeenCalledWith 'handle' - expect(delegate.action2).toHaveBeenCalled() - - # ensure the input buffer has been cleared, so we can match da - commandMap.handleKeyEvent d - commandMap.handleKeyEvent a - inputTimeout() - - expect(delegate.action1).toHaveBeenCalled() - - describe ".keyEventsMatchPattern(events, pattern)", -> - it "returns true only if the given events match the given pattern", -> - events = [d, a, d] - - expect(commandMap.keyEventsMatchPattern(events, "dad")).toBeTruthy() - expect(commandMap.keyEventsMatchPattern(events, "day")).toBeFalsy() - expect(commandMap.keyEventsMatchPattern(events, "da")).toBeFalsy() - - expect(commandMap.keyEventsMatchPattern([d], "d")).toBeTruthy() - - describe "keyEventsMatchPatternPrefix(events, pattern)", -> - it "returns true only if the given events match a prefix of the given pattern", -> - expect(commandMap.keyEventsMatchPatternPrefix([d, a], "dad")).toBeTruthy() - expect(commandMap.keyEventsMatchPatternPrefix([d, a], "da")).toBeTruthy() - expect(commandMap.keyEventsMatchPatternPrefix([d, a], "d")).toBeFalsy() - expect(commandMap.keyEventsMatchPatternPrefix([d, a, y], "da")).toBeFalsy() - diff --git a/spec/atom/key-binder-spec.coffee b/spec/atom/key-binder-spec.coffee deleted file mode 100644 index f282abc31..000000000 --- a/spec/atom/key-binder-spec.coffee +++ /dev/null @@ -1,34 +0,0 @@ -KeyBinder = require 'key-binder' - -describe "KeyBinder", -> - keyBinder = null - beforeEach -> keyBinder = new KeyBinder - - describe 'keyEventMatchesPattern', -> - expectMatch = (pattern) -> - expect(keyBinder.keyEventMatchesPattern(window.keydownEvent(pattern), pattern)).toBeTruthy() - - expectNoMatch = (eventPattern, patternToTest) -> - event = window.keydownEvent(eventPattern) - expect(keyBinder.keyEventMatchesPattern(event, patternToTest)).toBeFalsy() - - it 'returns true if the modifiers and letter in the pattern match the key event', -> - expectMatch 'meta+a' - expectMatch 'meta+1' - expectMatch 'alt+1' - expectMatch 'ctrl+1' - expectMatch 'shift+1' - expectMatch 'shift+a' - expectMatch 'meta+alt+1' - expectMatch 'meta+alt+ctrl+1' - expectMatch 'meta+alt+ctrl+shift+1' - - expectNoMatch 'meta+alt+ctrl+shift+1', 'meta+1' - expectNoMatch 'meta+1', 'meta+alt+1' - expectNoMatch 'meta+a', 'meta+b' - expectNoMatch 'meta+a', 'meta+b' - expectNoMatch 'meta+1', 'alt+1' - - it 'handles named special keys (e.g. arrows, home)', -> - expectMatch 'up' - diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index c82977845..0c9526da5 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -2,6 +2,7 @@ nakedLoad 'jasmine-jquery' $ = require 'jquery' _ = require 'underscore' Native = require 'native' +BindingSet = require 'binding-set' afterEach -> (new Native).resetMainMenu() @@ -9,10 +10,12 @@ afterEach -> window.atom = new (require 'app') window.keypressEvent = (pattern, properties={}) -> - $.Event "keypress", _.extend(atom.keyBinder.parseKeyPattern(pattern), properties) + bindingSet = new BindingSet("*", {}) + $.Event "keypress", _.extend(bindingSet.parseKeyPattern(pattern), properties) window.keydownEvent = (pattern, properties={}) -> - $.Event "keydown", _.extend(atom.keyBinder.parseKeyPattern(pattern), properties) + bindingSet = new BindingSet("*", {}) + $.Event "keydown", _.extend(bindingSet.parseKeyPattern(pattern), properties) window.waitsForPromise = (fn) -> window.waitsFor (moveOn) -> diff --git a/spec/stdlib/native-spec.coffee b/spec/stdlib/native-spec.coffee index b17dc5802..db96f856e 100644 --- a/spec/stdlib/native-spec.coffee +++ b/spec/stdlib/native-spec.coffee @@ -40,7 +40,7 @@ describe "Native", -> expect(item1).toBeDefined() it "adds a key equivalent to menu item when one is given", -> - nativeModule.addMenuItem('Submenu 1 > Item 1', "meta+r") + nativeModule.addMenuItem('Submenu 1 > Item 1', "meta-r") submenu1 = mainMenu.itemWithTitle('Submenu 1').submenu item1 = submenu1.itemWithTitle('Item 1') diff --git a/src/atom/app.coffee b/src/atom/app.coffee index 4ce4c2e44..a91af243c 100644 --- a/src/atom/app.coffee +++ b/src/atom/app.coffee @@ -1,14 +1,11 @@ Native = require 'native' -KeyBinder = require 'key-binder' module.exports = class App native: null - keyBinder: null constructor: -> @native = new Native - @keyBinder = new KeyBinder open: (url) -> OSX.NSApp.open url diff --git a/src/atom/command-map.coffee b/src/atom/command-map.coffee deleted file mode 100644 index 914b230ee..000000000 --- a/src/atom/command-map.coffee +++ /dev/null @@ -1,70 +0,0 @@ -_ = require 'underscore' -KeyBinder = require 'key-binder' - -module.exports = -class CommandMap - delegate: null - mappings: null - bufferedEvents: null - namedKeys: - backspace: 8, tab: 9, clear: 12, - enter: 13, 'return': 13, - esc: 27, escape: 27, space: 32, - left: 37, up: 38, - right: 39, down: 40, - del: 46, 'delete': 46, - home: 36, end: 35, - pageup: 33, pagedown: 34, - ',': 188, '.': 190, '/': 191, - '`': 192, '-': 189, '=': 187, - ';': 186, '\'': 222, - '[': 219, ']': 221, '\\': 220 - - inputTimeout: 200 - - constructor: (@delegate) -> - @mappings = {} - @bufferedEvents = [] - - mapKey: (pattern, action) -> - @mappings[pattern] = action - - handleKeyEvent: (event) -> - window.clearTimeout(@inputTimeoutHandle) if @inputTimeoutHandle - @bufferedEvents.push(event) - - candidatePatterns = - (pattern for pattern of @mappings when @keyEventsMatchPatternPrefix(@bufferedEvents, pattern)) - - if candidatePatterns.length > 1 - @inputTimeoutHandle = _.delay (=> @triggerActionForBufferedKeyEvents()), @inputTimeout - else if candidatePatterns.length == 1 - @triggerActionForBufferedKeyEvents() - else - @clearBufferedEvents() - - triggerActionForBufferedKeyEvents: -> - for pattern, action of @mappings - if @keyEventsMatchPattern(@bufferedEvents, pattern) - @delegate[action](event) - @clearBufferedEvents() - - keyEventsMatchPattern: (events, pattern) -> - patternKeys = @parseKeyPattern(pattern) - return false unless events.length == patternKeys.length - _.all(_.zip(events, patternKeys), ([event, pattern]) -> - event.which == pattern.which) - - keyEventsMatchPatternPrefix: (events, pattern) -> - patternKeys = @parseKeyPattern(pattern) - return false if events.length > patternKeys.length - _.all(_.zip(events, patternKeys[0...events.length]), ([event, pattern]) -> - event.which == pattern.which) - - parseKeyPattern: (pattern) -> - for char in pattern - { which: char.toUpperCase().charCodeAt(0) } - - clearBufferedEvents: -> - @bufferedEvents = [] - diff --git a/src/stdlib/key-binder.coffee b/src/stdlib/key-binder.coffee deleted file mode 100644 index b007a1dd2..000000000 --- a/src/stdlib/key-binder.coffee +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = -class KeyBinder - namedKeys: - backspace: 8, tab: 9, clear: 12, - enter: 13, 'return': 13, - esc: 27, escape: 27, space: 32, - left: 37, up: 38, - right: 39, down: 40, - del: 46, 'delete': 46, - home: 36, end: 35, - pageup: 33, pagedown: 34, - ',': 188, '.': 190, '/': 191, - '`': 192, '-': 189, '=': 187, - ';': 186, '\'': 222, - '[': 219, ']': 221, '\\': 220 - - keyEventMatchesPattern: (event, pattern) -> - pattern = @parseKeyPattern pattern - pattern.ctrlKey == event.ctrlKey and - pattern.altKey == event.altKey and - pattern.shiftKey == event.shiftKey and - pattern.metaKey == event.metaKey and - pattern.which == event.which - - parseKeyPattern: (pattern) -> - [modifiers..., key] = pattern.split '+' - - if @namedKeys[key] - charCode = @namedKeys[key] - key = null - else - charCode = key.toUpperCase().charCodeAt 0 - - ctrlKey: 'ctrl' in modifiers - altKey: 'alt' in modifiers - shiftKey: 'shift' in modifiers - metaKey: 'meta' in modifiers - which: charCode - key: key - diff --git a/src/stdlib/native.coffee b/src/stdlib/native.coffee index bff0536d7..3302b5f55 100644 --- a/src/stdlib/native.coffee +++ b/src/stdlib/native.coffee @@ -51,10 +51,11 @@ class Native title = _.last(itemPathComponents) unless submenu.itemWithTitle(title) item = OSX.AtomMenuItem.alloc.initWithTitle_itemPath(title, itemPath).autorelease - item.setKeyEquivalentModifierMask 0 # Because it Cocoa defaults it to NSCommandKeyMask + item.setKeyEquivalentModifierMask 0 # Because in Cocoa defaults it to NSCommandKeyMask if keyPattern - keys = atom.keyBinder.parseKeyPattern keyPattern + bindingSet = new (require('binding-set'))("*", {}) + keys = bindingSet.parseKeyPattern keyPattern modifierMask = (keys.metaKey and OSX.NSCommandKeyMask ) | (keys.shiftKey and OSX.NSShiftKeyMask) | diff --git a/src/stdlib/template.coffee b/src/stdlib/template.coffee index 3555e168b..b0812eb96 100644 --- a/src/stdlib/template.coffee +++ b/src/stdlib/template.coffee @@ -53,7 +53,8 @@ $.fn.view = -> $.fn.bindKey = (pattern, action) -> @on 'keydown', (event) => - if atom.keyBinder.keyEventMatchesPattern(event, pattern) + bindingSet = new (require('binding-set'))("*", {}) + if bindingSet.eventMatchesPattern(event, pattern) if _.isString(action) this.view()[action]() else