From b26caee702d55d36d2be9e395fabbec9679efe13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 8 May 2011 13:43:52 +0100 Subject: [PATCH] Improve key event handling, work in progress. --- examples/Animated/Flock.html | 2 +- src/browser/DomEvent.js | 17 +++++ src/load.js | 14 ++-- src/ui/Event.js | 39 ++++++++++ src/ui/Key.js | 144 +++++++++++++++++++++-------------- src/ui/KeyEvent.js | 43 +++++++++++ 6 files changed, 193 insertions(+), 66 deletions(-) create mode 100644 src/ui/Event.js create mode 100644 src/ui/KeyEvent.js diff --git a/examples/Animated/Flock.html b/examples/Animated/Flock.html index ee167a1e..63c1cc17 100644 --- a/examples/Animated/Flock.html +++ b/examples/Animated/Flock.html @@ -287,7 +287,7 @@ var layer = document.activeLayer; function onKeyDown(event) { - if (event.character == 'space') + if (event.keyCode == 'space') layer.selected = !layer.selected; } diff --git a/src/browser/DomEvent.js b/src/browser/DomEvent.js index 1c411688..b5ef6557 100644 --- a/src/browser/DomEvent.js +++ b/src/browser/DomEvent.js @@ -62,6 +62,23 @@ var DomEvent = { // Remove target offsets from page coordinates return DomEvent.getPoint(event).subtract( DomElement.getOffset(DomEvent.getElement(event), true)); + }, + + preventDefault: function(event) { + if (event.preventDefault) { + event.preventDefault(); + } else { + // IE + event.returnValue = false; + } + }, + + stopPropagation: function(event) { + if (event.stopPropagation) { + event.stopPropagation(); + } else { + event.cancelBubble = true; + } } }; diff --git a/src/load.js b/src/load.js index bcc2ad15..23c1793d 100644 --- a/src/load.js +++ b/src/load.js @@ -62,19 +62,21 @@ var sources = [ 'src/color/Gradient.js', 'src/color/GradientStop.js', + 'src/browser/DomElement.js', + 'src/browser/DomEvent.js', + + 'src/ui/Event.js', + 'src/ui/KeyEvent.js', + 'src/ui/Key.js', + 'src/tool/ToolEvent.js', 'src/tool/ToolHandler.js', 'src/tool/Tool.js', - 'src/browser/DomElement.js', - 'src/browser/DomEvent.js', - 'src/util/CanvasProvider.js', 'src/util/Numerical.js', 'src/util/PaperScript.js', - 'src/util/BlendMode.js', - - 'src/ui/Key.js' + 'src/util/BlendMode.js' ]; // Load unit tests after library if asked to do so diff --git a/src/ui/Event.js b/src/ui/Event.js new file mode 100644 index 00000000..8a7d0919 --- /dev/null +++ b/src/ui/Event.js @@ -0,0 +1,39 @@ +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * All rights reserved. + */ + +var Event = this.Event = Base.extend({ + initialize: function(event) { + this.event = event; + }, + + // PORT: Add to Sg + preventDefault: function() { + DomEvent.preventDefault(this.event); + }, + + stopPropagation: function() { + DomEvent.stopPropagation(this.event); + }, + + stop: function() { + this.stopPropagation(); + this.preventDefault(); + }, + + getModifiers: function() { + return Key.modifiers; + } +}); diff --git a/src/ui/Key.js b/src/ui/Key.js index 30980c15..1342a8d7 100644 --- a/src/ui/Key.js +++ b/src/ui/Key.js @@ -1,23 +1,41 @@ -var Key = new function() { +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * All rights reserved. + */ + +var Key = this.Key = new function() { // TODO: make sure the keys are called the same as in Scriptographer // Missing: tab, cancel, clear, pause, page-down, page-up, end, home, comma, // minus, period, slash, etc etc etc. + var keys = { - '8': 'backspace', - '13': 'enter', - '16': 'shift', - '17': 'control', - '19': 'option', // was alt - '20': 'capsLock', - '27': 'escape', - '32': 'space', - '37': 'left', - '38': 'up', - '39': 'right', - '40': 'down', - '46': 'delete', - '91': 'command' + 8: 'backspace', + 13: 'enter', + 16: 'shift', + 17: 'control', + 19: 'option', // was alt + 20: 'capsLock', + 27: 'escape', + 32: 'space', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 46: 'delete', + 91: 'command' }, + modifiers = { shift: false, control: false, @@ -25,53 +43,61 @@ var Key = new function() { command: false, capsLock: false }, - activeKeys = {}; - - Event.add(document, Base.each(['keyDown', 'keyUp'], function(type) { - var toolHandler = 'on' + Base.capitalize(type), - keyDown = type === 'keyDown'; - this[type.toLowerCase()] = function(event) { - var code = event.which || event.keyCode, - key = keys[code] || String.fromCharCode(code).toLowerCase(); - activeKeys[key] = keyDown; - - // If the key is a modifier, update the modifiers: - if (modifiers[key] !== undefined) - modifiers[key] = keyDown; - - // Call the onKeyDown or onKeyUp handler if present: - // TODO: don't call the key handler if the key is a modifier? - if (paper.tool && paper.tool[toolHandler]) { - // TODO: Introduce a class for this? - var keyEvent = { - type: keyDown ? 'key-down' : 'key-up', - keyCode: code, - character: key, - modifiers: modifiers, - // 'preventDefault: event.preventDefault' throws - // an error in Safari when called, so we have to wrap - // it into a function. - // PORT: Add to Sg - preventDefault: function() { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - } - }; - var res = paper.tool[toolHandler](keyEvent); - // PORT: Add to Sg - // When the handler function returns false, prevent the - // default behaviour of the key event: - if (res === false) - keyEvent.preventDefault(); + + keyCodes = {}, + downCode, + downTimer; + + function handleKey(down, code, event) { + var character = String.fromCharCode(code), + keyCode = keys[code] || character.toLowerCase(), + handler = down ? 'onKeyDown' : 'onKeyUp'; + console.log(handler, keyCode, character); + if (modifiers[keyCode] !== undefined) { + modifiers[keyCode] = down; + } else if (paper.tool && paper.tool[handler]) { + // Call the onKeyDown or onKeyUp handler if present + // When the handler function returns false, prevent the + // default behaviour of the key event: + // PORT: Add to Sg + var keyEvent = new KeyEvent(down, keyCode, character, event); + if (paper.tool[handler](keyEvent) === false) { + keyEvent.preventDefault(); } - }; - }, {})); - + } + } + + // Since only keypress gest proper keyCodes that are actually representing + // characters, we need to add a little timeout to keydown events to see if + // they are follow immediately by a keypress, and if so, map the keyCode + // from the keydown to the one from keypress, so keyup still knows what + // code has now been released. + DomEvent.add(document, { + keydown: function(event) { + var code = downCode = event.which || event.keyCode; + downTimer = setTimeout(function() { + keyCodes[code] = code; + handleKey(true, code, event); + }, 1); + }, + + keypress: function(event) { + clearTimeout(downTimer); + var code = event.which || event.keyCode; + keyCodes[downCode] = code; + handleKey(true, code, event); + }, + + keyup: function(event) { + var code = event.which || event.keyCode; + handleKey(false, keyCodes[code], event); + delete keyCodes[code]; + } + }); + return { modifiers: modifiers, + isDown: function(key) { return !!activeKeys[key]; } diff --git a/src/ui/KeyEvent.js b/src/ui/KeyEvent.js new file mode 100644 index 00000000..012388cb --- /dev/null +++ b/src/ui/KeyEvent.js @@ -0,0 +1,43 @@ +/* + * Paper.js + * + * This file is part of Paper.js, a JavaScript Vector Graphics Library, + * based on Scriptographer.org and designed to be largely API compatible. + * http://paperjs.org/ + * http://scriptographer.org/ + * + * Distributed under the MIT license. See LICENSE file for details. + * + * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey + * http://lehni.org/ & http://jonathanpuckey.com/ + * + * All rights reserved. + */ + +var KeyEvent = this.KeyEvent = Event.extend(new function() { + var keys = { + 8: 'backspace', + 13: 'enter', + 16: 'shift', + 17: 'control', + 19: 'option', // was alt + 20: 'capsLock', + 27: 'escape', + 32: 'space', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 46: 'delete', + 91: 'command' + }; + + return { + initialize: function(down, keyCode, character, event) { + this.base(event); + this.type = down ? 'key-down' : 'key-up'; + this.keyCode = keyCode; + this.character = character; + } + }; +});