From 742c9da82255383d7273f9fcd5f02caadfcec8d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sun, 8 May 2011 15:16:41 +0100 Subject: [PATCH] More work on key handling and rename KeyEvent#keyCode -> KeyEvent#key. --- examples/Animated/Flock.html | 2 +- src/paper.js | 6 +++ src/ui/Key.js | 76 ++++++++++++++++++++++-------------- src/ui/KeyEvent.js | 12 +++++- 4 files changed, 64 insertions(+), 32 deletions(-) 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 + + ' }'; } }; });