diff --git a/examples/Animated/Flock.html b/examples/Animated/Flock.html
index 63c1cc17..1c217eea 100644
--- a/examples/Animated/Flock.html
+++ b/examples/Animated/Flock.html
@@ -287,7 +287,7 @@
var layer = document.activeLayer;
function onKeyDown(event) {
- if (event.keyCode == 'space')
+ if (event.key == 'space')
layer.selected = !layer.selected;
}
diff --git a/src/paper.js b/src/paper.js
index d039753d..e19e4cf3 100644
--- a/src/paper.js
+++ b/src/paper.js
@@ -118,6 +118,12 @@ Base.inject({
});
},
+ camelize: function(str) {
+ return str.replace(/-(\w)/g, function(all, chr) {
+ return chr.toUpperCase();
+ });
+ },
+
formatNumber: function(num) {
return (Math.round(num * 100000) / 100000).toString();
}
diff --git a/src/ui/Key.js b/src/ui/Key.js
index 1342a8d7..61d86a98 100644
--- a/src/ui/Key.js
+++ b/src/ui/Key.js
@@ -24,10 +24,13 @@ var Key = this.Key = new function() {
13: 'enter',
16: 'shift',
17: 'control',
- 19: 'option', // was alt
- 20: 'capsLock',
+ 18: 'option',
+ 19: 'pause',
+ 20: 'caps-lock',
27: 'escape',
32: 'space',
+ 35: 'end',
+ 36: 'home',
37: 'left',
38: 'up',
39: 'right',
@@ -44,54 +47,69 @@ var Key = this.Key = new function() {
capsLock: false
},
- keyCodes = {},
- downCode,
- downTimer;
+ // Since only keypress gets proper keyCodes that are actually representing
+ // characters, we need to perform a little trickery here to use these codes
+ // in onKeyDown/Up: keydown is used to store the downCode and handle
+ // modifiers and special keys such as arrows, space, etc, keypress fires the
+ // actual onKeyDown event and maps the keydown keyCode to the keypress
+ // charCode so keyup can do the right thing too.
+ charCodeMap = {}, // keyCode -> charCode mappings for pressed keys
+ downCode; // The last keyCode from keydown
- function handleKey(down, code, event) {
- var character = String.fromCharCode(code),
- keyCode = keys[code] || character.toLowerCase(),
+ function handleKey(down, keyCode, charCode, event) {
+ var character = String.fromCharCode(charCode),
+ key = keys[keyCode] || 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]) {
+ 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);
+ var keyEvent = new KeyEvent(down, key, 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);
+ downCode = event.which || event.keyCode;
+ // If the keyCode is in keys, it needs to be handled by keydown and
+ // won't fire a keypress after.
+ var key = keys[downCode],
+ name;
+ if (key) {
+ // Do not fire handleKey for modifiers, but for other keys such
+ // ass arrows, delete, backspace, etc.
+ if (modifiers[name = Base.camelize(key)] !== undefined) {
+ modifiers[name] = true;
+ } else {
+ // No char code for special keys, but mark as pressed
+ charCodeMap[downCode] = 0;
+ handleKey(true, downCode, null, event);
+ }
+ }
},
keypress: function(event) {
- clearTimeout(downTimer);
var code = event.which || event.keyCode;
- keyCodes[downCode] = code;
- handleKey(true, code, event);
+ // Link the downCode from keydown with the code form keypress, so
+ // keyup can retrieve that code again.
+ charCodeMap[downCode] = code;
+ handleKey(true, downCode, code, event);
},
keyup: function(event) {
- var code = event.which || event.keyCode;
- handleKey(false, keyCodes[code], event);
- delete keyCodes[code];
+ var code = event.which || event.keyCode,
+ key = keys[code],
+ name;
+ if (key && modifiers[name = Base.camelize(key)] !== undefined) {
+ modifiers[name] = false
+ } else if (charCodeMap[code] !== undefined) {
+ handleKey(false, code, charCodeMap[code], event);
+ delete charCodeMap[code];
+ }
}
});
diff --git a/src/ui/KeyEvent.js b/src/ui/KeyEvent.js
index 3ea14f7c..1f208a0b 100644
--- a/src/ui/KeyEvent.js
+++ b/src/ui/KeyEvent.js
@@ -16,11 +16,19 @@
var KeyEvent = this.KeyEvent = Event.extend(new function() {
return {
- initialize: function(down, keyCode, character, event) {
+ initialize: function(down, key, character, event) {
this.base(event);
this.type = down ? 'key-down' : 'key-up';
- this.keyCode = keyCode;
+ this.key = key;
this.character = character;
+ },
+
+ toString: function() {
+ return '{ type: ' + this.type
+ + ', key: ' + this.key
+ + ', character: ' + this.character
+ + ', modifiers: ' + this.modifiers
+ + ' }';
}
};
});